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/. */
7 /* A namespace class for static layout utilities. */
9 #include "nsContentUtils.h"
19 #include "BrowserChild.h"
20 #include "DecoderTraits.h"
21 #include "ErrorList.h"
22 #include "HTMLSplitOnSpacesTokenizer.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"
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"
40 #include "js/ArrayBuffer.h"
41 #include "js/BuildId.h"
45 #include "js/PropertyAndElement.h" // JS_DefineElement, JS_GetProperty
46 #include "js/PropertyDescriptor.h"
48 #include "js/RegExp.h"
49 #include "js/RegExpFlags.h"
50 #include "js/RootingAPI.h"
51 #include "js/TypeDecls.h"
53 #include "js/Wrapper.h"
55 #include "jsfriendapi.h"
56 #include "mozAutoDocUpdate.h"
57 #include "mozIDOMWindow.h"
58 #include "nsIOService.h"
59 #include "mozilla/AlreadyAddRefed.h"
60 #include "mozilla/ArrayIterator.h"
61 #include "mozilla/ArrayUtils.h"
62 #include "mozilla/AsyncEventDispatcher.h"
63 #include "mozilla/AtomArray.h"
64 #include "mozilla/Atomics.h"
65 #include "mozilla/Attributes.h"
66 #include "mozilla/AutoRestore.h"
67 #include "mozilla/AutoTimelineMarker.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/Components.h"
77 #include "mozilla/ContentBlockingAllowList.h"
78 #include "mozilla/CycleCollectedJSContext.h"
79 #include "mozilla/DOMEventTargetHelper.h"
80 #include "mozilla/DebugOnly.h"
81 #include "mozilla/ErrorResult.h"
82 #include "mozilla/EventDispatcher.h"
83 #include "mozilla/EventListenerManager.h"
84 #include "mozilla/EventQueue.h"
85 #include "mozilla/EventStateManager.h"
86 #include "mozilla/FlushType.h"
87 #include "mozilla/FOGIPC.h"
88 #include "mozilla/HTMLEditor.h"
89 #include "mozilla/HangAnnotations.h"
90 #include "mozilla/IMEStateManager.h"
91 #include "mozilla/InputEventOptions.h"
92 #include "mozilla/InternalMutationEvent.h"
93 #include "mozilla/Latin1.h"
94 #include "mozilla/Likely.h"
95 #include "mozilla/LoadInfo.h"
96 #include "mozilla/Logging.h"
97 #include "mozilla/MacroForEach.h"
98 #include "mozilla/ManualNAC.h"
99 #include "mozilla/Maybe.h"
100 #include "mozilla/MediaFeatureChange.h"
101 #include "mozilla/MouseEvents.h"
102 #include "mozilla/NotNull.h"
103 #include "mozilla/NullPrincipal.h"
104 #include "mozilla/OriginAttributes.h"
105 #include "mozilla/Preferences.h"
106 #include "mozilla/PresShell.h"
107 #include "mozilla/ProfilerRunnable.h"
108 #include "mozilla/RangeBoundary.h"
109 #include "mozilla/RefPtr.h"
110 #include "mozilla/Result.h"
111 #include "mozilla/ResultExtensions.h"
112 #include "mozilla/ScrollbarPreferences.h"
113 #include "mozilla/Span.h"
114 #include "mozilla/StaticAnalysisFunctions.h"
115 #include "mozilla/StaticPrefs_browser.h"
116 #include "mozilla/StaticPrefs_dom.h"
118 # include "mozilla/StaticPrefs_fuzzing.h"
120 #include "mozilla/StaticPrefs_nglayout.h"
121 #include "mozilla/StaticPrefs_privacy.h"
122 #include "mozilla/StaticPrefs_test.h"
123 #include "mozilla/StaticPrefs_ui.h"
124 #include "mozilla/StaticPtr.h"
125 #include "mozilla/TextControlState.h"
126 #include "mozilla/TextEditor.h"
127 #include "mozilla/TextEvents.h"
128 #include "mozilla/UniquePtr.h"
129 #include "mozilla/Unused.h"
130 #include "mozilla/Variant.h"
131 #include "mozilla/ViewportUtils.h"
132 #include "mozilla/dom/AncestorIterator.h"
133 #include "mozilla/dom/AutoEntryScript.h"
134 #include "mozilla/dom/AutocompleteInfoBinding.h"
135 #include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
136 #include "mozilla/dom/BindingDeclarations.h"
137 #include "mozilla/dom/BindingUtils.h"
138 #include "mozilla/dom/BlobImpl.h"
139 #include "mozilla/dom/BlobURLProtocolHandler.h"
140 #include "mozilla/dom/BorrowedAttrInfo.h"
141 #include "mozilla/dom/BrowserBridgeParent.h"
142 #include "mozilla/dom/BrowserParent.h"
143 #include "mozilla/dom/BrowsingContext.h"
144 #include "mozilla/dom/BrowsingContextGroup.h"
145 #include "mozilla/dom/CallbackFunction.h"
146 #include "mozilla/dom/CallbackObject.h"
147 #include "mozilla/dom/ChromeMessageBroadcaster.h"
148 #include "mozilla/dom/ContentChild.h"
149 #include "mozilla/dom/ContentFrameMessageManager.h"
150 #include "mozilla/dom/ContentParent.h"
151 #include "mozilla/dom/CustomElementRegistry.h"
152 #include "mozilla/dom/CustomElementRegistryBinding.h"
153 #include "mozilla/dom/CustomElementTypes.h"
154 #include "mozilla/dom/DOMArena.h"
155 #include "mozilla/dom/DOMException.h"
156 #include "mozilla/dom/DOMExceptionBinding.h"
157 #include "mozilla/dom/DOMSecurityMonitor.h"
158 #include "mozilla/dom/DOMTypes.h"
159 #include "mozilla/dom/DataTransfer.h"
160 #include "mozilla/dom/DocGroup.h"
161 #include "mozilla/dom/Document.h"
162 #include "mozilla/dom/DocumentFragment.h"
163 #include "mozilla/dom/DocumentInlines.h"
164 #include "mozilla/dom/Element.h"
165 #include "mozilla/dom/ElementBinding.h"
166 #include "mozilla/dom/ElementInlines.h"
167 #include "mozilla/dom/Event.h"
168 #include "mozilla/dom/EventTarget.h"
169 #include "mozilla/dom/FileBlobImpl.h"
170 #include "mozilla/dom/FileSystemSecurity.h"
171 #include "mozilla/dom/FilteredNodeIterator.h"
172 #include "mozilla/dom/FormData.h"
173 #include "mozilla/dom/FragmentOrElement.h"
174 #include "mozilla/dom/FromParser.h"
175 #include "mozilla/dom/HTMLElement.h"
176 #include "mozilla/dom/HTMLFormElement.h"
177 #include "mozilla/dom/HTMLImageElement.h"
178 #include "mozilla/dom/HTMLInputElement.h"
179 #include "mozilla/dom/HTMLTextAreaElement.h"
180 #include "mozilla/dom/IPCBlob.h"
181 #include "mozilla/dom/IPCBlobUtils.h"
182 #include "mozilla/dom/MessageBroadcaster.h"
183 #include "mozilla/dom/MessageListenerManager.h"
184 #include "mozilla/dom/MessagePort.h"
185 #include "mozilla/dom/MouseEventBinding.h"
186 #include "mozilla/dom/NameSpaceConstants.h"
187 #include "mozilla/dom/NodeBinding.h"
188 #include "mozilla/dom/NodeInfo.h"
189 #include "mozilla/dom/PBrowser.h"
190 #include "mozilla/dom/PContentChild.h"
191 #include "mozilla/dom/PrototypeList.h"
192 #include "mozilla/dom/ReferrerPolicyBinding.h"
193 #include "mozilla/dom/ScriptSettings.h"
194 #include "mozilla/dom/Selection.h"
195 #include "mozilla/dom/ShadowRoot.h"
196 #include "mozilla/dom/Text.h"
197 #include "mozilla/dom/UserActivation.h"
198 #include "mozilla/dom/WindowContext.h"
199 #include "mozilla/dom/WorkerCommon.h"
200 #include "mozilla/dom/WorkerPrivate.h"
201 #include "mozilla/dom/WorkerRunnable.h"
202 #include "mozilla/dom/XULCommandEvent.h"
203 #include "mozilla/fallible.h"
204 #include "mozilla/gfx/2D.h"
205 #include "mozilla/gfx/BaseMargin.h"
206 #include "mozilla/gfx/BasePoint.h"
207 #include "mozilla/gfx/BaseSize.h"
208 #include "mozilla/gfx/DataSurfaceHelpers.h"
209 #include "mozilla/gfx/Point.h"
210 #include "mozilla/gfx/Rect.h"
211 #include "mozilla/gfx/Types.h"
212 #include "mozilla/ipc/ProtocolUtils.h"
213 #include "mozilla/ipc/SharedMemory.h"
214 #include "mozilla/net/UrlClassifierCommon.h"
215 #include "mozilla/Tokenizer.h"
216 #include "mozilla/widget/IMEData.h"
217 #include "nsAboutProtocolUtils.h"
218 #include "nsAlgorithm.h"
219 #include "nsArrayUtils.h"
220 #include "nsAtomHashKeys.h"
221 #include "nsAttrName.h"
222 #include "nsAttrValue.h"
223 #include "nsAttrValueInlines.h"
224 #include "nsBaseHashtable.h"
225 #include "nsCCUncollectableMarker.h"
226 #include "nsCOMPtr.h"
228 #include "nsCRTGlue.h"
229 #include "nsCanvasFrame.h"
230 #include "nsCaseTreatment.h"
231 #include "nsCharSeparatedTokenizer.h"
232 #include "nsCharTraits.h"
233 #include "nsCompatibility.h"
234 #include "nsComponentManagerUtils.h"
235 #include "nsContainerFrame.h"
236 #include "nsContentCreatorFunctions.h"
237 #include "nsContentDLF.h"
238 #include "nsContentList.h"
239 #include "nsContentListDeclarations.h"
240 #include "nsContentPolicyUtils.h"
242 #include "nsCycleCollectionNoteChild.h"
243 #include "nsDOMMutationObserver.h"
244 #include "nsDOMString.h"
245 #include "nsTHashMap.h"
247 #include "nsDocShell.h"
248 #include "nsDocShellCID.h"
250 #include "nsFocusManager.h"
251 #include "nsFrameList.h"
252 #include "nsFrameLoader.h"
253 #include "nsFrameLoaderOwner.h"
254 #include "nsGenericHTMLElement.h"
255 #include "nsGkAtoms.h"
256 #include "nsGlobalWindowInner.h"
257 #include "nsGlobalWindowOuter.h"
258 #include "nsHTMLDocument.h"
259 #include "nsHTMLTags.h"
260 #include "nsHashKeys.h"
261 #include "nsHtml5StringParser.h"
262 #include "nsIAboutModule.h"
263 #include "nsIAnonymousContentCreator.h"
264 #include "nsIAppShell.h"
265 #include "nsIArray.h"
266 #include "nsIAsyncVerifyRedirectCallback.h"
267 #include "nsIBidiKeyboard.h"
268 #include "nsIBrowser.h"
269 #include "nsICacheInfoChannel.h"
270 #include "nsICategoryManager.h"
271 #include "nsIChannel.h"
272 #include "nsIChannelEventSink.h"
273 #include "nsIClassifiedChannel.h"
274 #include "nsIConsoleService.h"
275 #include "nsIContent.h"
276 #include "nsIContentInlines.h"
277 #include "nsIContentPolicy.h"
278 #include "nsIContentSecurityPolicy.h"
279 #include "nsIContentSink.h"
280 #include "nsIContentViewer.h"
281 #include "nsIDOMWindowUtils.h"
282 #include "nsIDocShell.h"
283 #include "nsIDocShellTreeItem.h"
284 #include "nsIDocumentEncoder.h"
285 #include "nsIDocumentLoaderFactory.h"
286 #include "nsIDragService.h"
287 #include "nsIDragSession.h"
289 #include "nsIFocusManager.h"
290 #include "nsIFormControl.h"
291 #include "nsIFragmentContentSink.h"
292 #include "nsIFrame.h"
293 #include "nsIGlobalObject.h"
294 #include "nsIHttpChannel.h"
295 #include "nsIHttpChannelInternal.h"
296 #include "nsIIOService.h"
297 #include "nsIImageLoadingContent.h"
298 #include "nsIInputStream.h"
299 #include "nsIInterfaceRequestor.h"
300 #include "nsIInterfaceRequestorUtils.h"
301 #include "nsILoadContext.h"
302 #include "nsILoadGroup.h"
303 #include "nsILoadInfo.h"
304 #include "nsIMIMEService.h"
305 #include "nsIMemoryReporter.h"
306 #include "nsINetUtil.h"
308 #include "nsIObjectLoadingContent.h"
309 #include "nsIObserver.h"
310 #include "nsIObserverService.h"
311 #include "nsIParserUtils.h"
312 #include "nsIPermissionManager.h"
313 #include "nsIPluginTag.h"
314 #include "nsIPrincipal.h"
315 #include "nsIProperties.h"
316 #include "nsIProtocolHandler.h"
317 #include "nsIRequest.h"
318 #include "nsIRunnable.h"
319 #include "nsIScreen.h"
320 #include "nsIScriptError.h"
321 #include "nsIScriptGlobalObject.h"
322 #include "nsIScriptObjectPrincipal.h"
323 #include "nsIScriptSecurityManager.h"
324 #include "nsISerialEventTarget.h"
325 #include "nsIStreamConverter.h"
326 #include "nsIStreamConverterService.h"
327 #include "nsIStringBundle.h"
328 #include "nsISupports.h"
329 #include "nsISupportsPrimitives.h"
330 #include "nsISupportsUtils.h"
331 #include "nsITransferable.h"
333 #include "nsIURIMutator.h"
334 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
335 # include "nsIURIWithSpecialOrigin.h"
337 #include "nsIUserIdleServiceInternal.h"
338 #include "nsIWeakReferenceUtils.h"
339 #include "nsIWebNavigation.h"
340 #include "nsIWebNavigationInfo.h"
341 #include "nsIWidget.h"
342 #include "nsIWindowMediator.h"
343 #include "nsIXPConnect.h"
344 #include "nsJSPrincipals.h"
345 #include "nsJSUtils.h"
346 #include "nsLayoutUtils.h"
347 #include "nsLiteralString.h"
348 #include "nsMargin.h"
349 #include "nsMimeTypes.h"
350 #include "nsNameSpaceManager.h"
351 #include "nsNetCID.h"
352 #include "nsNetUtil.h"
353 #include "nsNodeInfoManager.h"
354 #include "nsPIDOMWindow.h"
355 #include "nsPIDOMWindowInlines.h"
356 #include "nsParser.h"
357 #include "nsParserConstants.h"
358 #include "nsPluginHost.h"
360 #include "nsPointerHashKeys.h"
361 #include "nsPresContext.h"
362 #include "nsQueryFrame.h"
363 #include "nsQueryObject.h"
365 #include "nsRefPtrHashtable.h"
366 #include "nsSandboxFlags.h"
367 #include "nsScriptSecurityManager.h"
368 #include "nsServiceManagerUtils.h"
369 #include "nsStreamUtils.h"
370 #include "nsString.h"
371 #include "nsStringBuffer.h"
372 #include "nsStringBundle.h"
373 #include "nsStringFlags.h"
374 #include "nsStringFwd.h"
375 #include "nsStringIterator.h"
376 #include "nsStringStream.h"
377 #include "nsTArray.h"
378 #include "nsTLiteralString.h"
379 #include "nsTPromiseFlatString.h"
380 #include "nsTStringRepr.h"
381 #include "nsTextFragment.h"
382 #include "nsTextNode.h"
383 #include "nsThreadManager.h"
384 #include "nsThreadUtils.h"
385 #include "nsTreeSanitizer.h"
386 #include "nsUGenCategory.h"
387 #include "nsURLHelper.h"
388 #include "nsUnicodeProperties.h"
389 #include "nsVariant.h"
390 #include "nsWidgetsCID.h"
392 #include "nsViewManager.h"
394 #include "nsXPCOMCID.h"
395 #include "nsXULAppAPI.h"
396 #include "nsXULElement.h"
397 #include "nsXULPopupManager.h"
399 #include "prinrval.h"
400 #include "xpcprivate.h"
401 #include "xpcpublic.h"
404 // Undefine LoadImage to prevent naming conflict with Windows.
408 extern "C" int MOZ_XMLTranslateEntity(const char* ptr
, const char* end
,
409 const char** next
, char16_t
* result
);
410 extern "C" int MOZ_XMLCheckQName(const char* ptr
, const char* end
, int ns_aware
,
413 using namespace mozilla::dom
;
414 using namespace mozilla::ipc
;
415 using namespace mozilla::gfx
;
416 using namespace mozilla::layers
;
417 using namespace mozilla::widget
;
418 using namespace mozilla
;
420 const char kLoadAsData
[] = "loadAsData";
422 nsIXPConnect
* nsContentUtils::sXPConnect
;
423 nsIScriptSecurityManager
* nsContentUtils::sSecurityManager
;
424 nsIPrincipal
* nsContentUtils::sSystemPrincipal
;
425 nsIPrincipal
* nsContentUtils::sNullSubjectPrincipal
;
426 nsIConsoleService
* nsContentUtils::sConsoleService
;
428 static nsTHashMap
<RefPtr
<nsAtom
>, EventNameMapping
>* sAtomEventTable
;
429 static nsTHashMap
<nsStringHashKey
, EventNameMapping
>* sStringEventTable
;
430 static nsTArray
<RefPtr
<nsAtom
>>* sUserDefinedEvents
;
431 nsIStringBundleService
* nsContentUtils::sStringBundleService
;
433 static StaticRefPtr
<nsIStringBundle
>
434 sStringBundles
[nsContentUtils::PropertiesFile_COUNT
];
436 nsIContentPolicy
* nsContentUtils::sContentPolicyService
;
437 bool nsContentUtils::sTriedToGetContentPolicy
= false;
438 StaticRefPtr
<nsIBidiKeyboard
> nsContentUtils::sBidiKeyboard
;
439 uint32_t nsContentUtils::sScriptBlockerCount
= 0;
440 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount
= 0;
441 AutoTArray
<nsCOMPtr
<nsIRunnable
>, 8>* nsContentUtils::sBlockedScriptRunners
=
443 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker
= 0;
444 nsIInterfaceRequestor
* nsContentUtils::sSameOriginChecker
= nullptr;
446 bool nsContentUtils::sIsHandlingKeyBoardEvent
= false;
448 nsString
* nsContentUtils::sShiftText
= nullptr;
449 nsString
* nsContentUtils::sControlText
= nullptr;
450 nsString
* nsContentUtils::sCommandOrWinText
= nullptr;
451 nsString
* nsContentUtils::sAltText
= nullptr;
452 nsString
* nsContentUtils::sModifierSeparator
= nullptr;
454 bool nsContentUtils::sInitialized
= false;
455 #ifndef RELEASE_OR_BETA
456 bool nsContentUtils::sBypassCSSOMOriginCheck
= false;
459 nsCString
* nsContentUtils::sJSScriptBytecodeMimeType
= nullptr;
460 nsCString
* nsContentUtils::sJSModuleBytecodeMimeType
= nullptr;
462 nsContentUtils::UserInteractionObserver
*
463 nsContentUtils::sUserInteractionObserver
= nullptr;
465 nsHtml5StringParser
* nsContentUtils::sHTMLFragmentParser
= nullptr;
466 nsParser
* nsContentUtils::sXMLFragmentParser
= nullptr;
467 nsIFragmentContentSink
* nsContentUtils::sXMLFragmentSink
= nullptr;
468 bool nsContentUtils::sFragmentParsingActive
= false;
470 bool nsContentUtils::sMayHaveFormCheckboxStateChangeListeners
= false;
471 bool nsContentUtils::sMayHaveFormRadioStateChangeListeners
= false;
473 mozilla::LazyLogModule
nsContentUtils::gResistFingerprintingLog(
474 "nsResistFingerprinting");
475 mozilla::LazyLogModule
nsContentUtils::sDOMDumpLog("Dump");
477 int32_t nsContentUtils::sInnerOrOuterWindowCount
= 0;
478 uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter
= 0;
480 template Maybe
<int32_t> nsContentUtils::ComparePoints(
481 const RangeBoundary
& aFirstBoundary
, const RangeBoundary
& aSecondBoundary
);
482 template Maybe
<int32_t> nsContentUtils::ComparePoints(
483 const RangeBoundary
& aFirstBoundary
,
484 const RawRangeBoundary
& aSecondBoundary
);
485 template Maybe
<int32_t> nsContentUtils::ComparePoints(
486 const RawRangeBoundary
& aFirstBoundary
,
487 const RangeBoundary
& aSecondBoundary
);
488 template Maybe
<int32_t> nsContentUtils::ComparePoints(
489 const RawRangeBoundary
& aFirstBoundary
,
490 const RawRangeBoundary
& aSecondBoundary
);
492 template int32_t nsContentUtils::ComparePoints_Deprecated(
493 const RangeBoundary
& aFirstBoundary
, const RangeBoundary
& aSecondBoundary
,
494 bool* aDisconnected
);
495 template int32_t nsContentUtils::ComparePoints_Deprecated(
496 const RangeBoundary
& aFirstBoundary
,
497 const RawRangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
498 template int32_t nsContentUtils::ComparePoints_Deprecated(
499 const RawRangeBoundary
& aFirstBoundary
,
500 const RangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
501 template int32_t nsContentUtils::ComparePoints_Deprecated(
502 const RawRangeBoundary
& aFirstBoundary
,
503 const RawRangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
506 // http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
507 enum AutocompleteUnsupportedFieldName
: uint8_t {
508 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
509 eAutocompleteUnsupportedFieldName_##name_,
510 #include "AutocompleteFieldList.h"
511 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
514 enum AutocompleteNoPersistFieldName
: uint8_t {
515 #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
516 eAutocompleteNoPersistFieldName_##name_,
517 #include "AutocompleteFieldList.h"
518 #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
521 enum AutocompleteUnsupportFieldContactHint
: uint8_t {
522 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
523 eAutocompleteUnsupportedFieldContactHint_##name_,
524 #include "AutocompleteFieldList.h"
525 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
528 enum AutocompleteFieldName
: uint8_t {
529 #define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_,
530 #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
531 AUTOCOMPLETE_FIELD_NAME(name_, value_)
532 #include "AutocompleteFieldList.h"
533 #undef AUTOCOMPLETE_FIELD_NAME
534 #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
537 enum AutocompleteFieldHint
: uint8_t {
538 #define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_,
539 #include "AutocompleteFieldList.h"
540 #undef AUTOCOMPLETE_FIELD_HINT
543 enum AutocompleteFieldContactHint
: uint8_t {
544 #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
545 eAutocompleteFieldContactHint_##name_,
546 #include "AutocompleteFieldList.h"
547 #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
550 enum AutocompleteCategory
{
551 #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_,
552 #include "AutocompleteFieldList.h"
553 #undef AUTOCOMPLETE_CATEGORY
556 static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable
[] = {
557 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
558 {value_, eAutocompleteUnsupportedFieldName_##name_},
559 #include "AutocompleteFieldList.h"
560 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
563 static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable
[] = {
564 #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
565 {value_, eAutocompleteNoPersistFieldName_##name_},
566 #include "AutocompleteFieldList.h"
567 #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
570 static const nsAttrValue::EnumTable
571 kAutocompleteUnsupportedContactFieldHintTable
[] = {
572 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
573 {value_, eAutocompleteUnsupportedFieldContactHint_##name_},
574 #include "AutocompleteFieldList.h"
575 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
578 static const nsAttrValue::EnumTable kAutocompleteFieldNameTable
[] = {
579 #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
580 {value_, eAutocompleteFieldName_##name_},
581 #include "AutocompleteFieldList.h"
582 #undef AUTOCOMPLETE_FIELD_NAME
585 static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable
[] = {
586 #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
587 {value_, eAutocompleteFieldName_##name_},
588 #include "AutocompleteFieldList.h"
589 #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
592 static const nsAttrValue::EnumTable kAutocompleteFieldHintTable
[] = {
593 #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
594 {value_, eAutocompleteFieldHint_##name_},
595 #include "AutocompleteFieldList.h"
596 #undef AUTOCOMPLETE_FIELD_HINT
599 static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable
[] = {
600 #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
601 {value_, eAutocompleteFieldContactHint_##name_},
602 #include "AutocompleteFieldList.h"
603 #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
608 static PLDHashTable
* sEventListenerManagersHash
;
610 // A global hashtable to for keeping the arena alive for cross docGroup node
612 static nsRefPtrHashtable
<nsPtrHashKey
<const nsINode
>, mozilla::dom::DOMArena
>*
615 class DOMEventListenerManagersHashReporter final
: public nsIMemoryReporter
{
616 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf
)
618 ~DOMEventListenerManagersHashReporter() = default;
623 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
624 nsISupports
* aData
, bool aAnonymize
) override
{
625 // We don't measure the |EventListenerManager| objects pointed to by the
626 // entries because those references are non-owning.
628 sEventListenerManagersHash
629 ? sEventListenerManagersHash
->ShallowSizeOfIncludingThis(
634 "explicit/dom/event-listener-managers-hash", KIND_HEAP
, UNITS_BYTES
,
635 amount
, "Memory used by the event listener manager's hash table.");
641 NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter
, nsIMemoryReporter
)
643 class EventListenerManagerMapEntry
: public PLDHashEntryHdr
{
645 explicit EventListenerManagerMapEntry(const void* aKey
) : mKey(aKey
) {}
647 ~EventListenerManagerMapEntry() {
648 NS_ASSERTION(!mListenerManager
, "caller must release and disconnect ELM");
651 protected: // declared protected to silence clang warnings
652 const void* mKey
; // must be first, to look like PLDHashEntryStub
655 RefPtr
<EventListenerManager
> mListenerManager
;
658 static void EventListenerManagerHashInitEntry(PLDHashEntryHdr
* entry
,
660 // Initialize the entry with placement new
661 new (entry
) EventListenerManagerMapEntry(key
);
664 static void EventListenerManagerHashClearEntry(PLDHashTable
* table
,
665 PLDHashEntryHdr
* entry
) {
666 EventListenerManagerMapEntry
* lm
=
667 static_cast<EventListenerManagerMapEntry
*>(entry
);
669 // Let the EventListenerManagerMapEntry clean itself up...
670 lm
->~EventListenerManagerMapEntry();
673 class SameOriginCheckerImpl final
: public nsIChannelEventSink
,
674 public nsIInterfaceRequestor
{
675 ~SameOriginCheckerImpl() = default;
678 NS_DECL_NSICHANNELEVENTSINK
679 NS_DECL_NSIINTERFACEREQUESTOR
684 void AutoSuppressEventHandling::SuppressDocument(Document
* aDoc
) {
685 // Note: Document::SuppressEventHandling will also automatically suppress
686 // event handling for any in-process sub-documents. However, since we need
687 // to deal with cases where remote BrowsingContexts may be interleaved
688 // with in-process ones, we still need to walk the entire tree ourselves.
689 // This may be slightly redundant in some cases, but since event handling
690 // suppressions maintain a count of current blockers, it does not cause
692 aDoc
->SuppressEventHandling();
695 void AutoSuppressEventHandling::UnsuppressDocument(Document
* aDoc
) {
696 aDoc
->UnsuppressEventHandlingAndFireEvents(true);
699 AutoSuppressEventHandling::~AutoSuppressEventHandling() {
700 UnsuppressDocuments();
703 void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document
* aDoc
) {
704 AutoSuppressEventHandling::SuppressDocument(aDoc
);
705 if (nsCOMPtr
<nsPIDOMWindowInner
> win
= aDoc
->GetInnerWindow()) {
707 mWindows
.AppendElement(win
);
711 AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() {
712 for (const auto& win
: mWindows
) {
718 * This class is used to determine whether or not the user is currently
719 * interacting with the browser. It listens to observer events to toggle the
720 * value of the sUserActive static.
722 * This class is an internal implementation detail.
723 * nsContentUtils::GetUserIsInteracting() should be used to access current
724 * user interaction status.
726 class nsContentUtils::UserInteractionObserver final
727 : public nsIObserver
,
728 public BackgroundHangAnnotator
{
735 void AnnotateHang(BackgroundHangAnnotations
& aAnnotations
) override
;
737 static Atomic
<bool> sUserActive
;
740 ~UserInteractionObserver() = default;
743 static constexpr nsLiteralCString kRfpPrefs
[] = {
744 "privacy.resistFingerprinting"_ns
,
745 "privacy.resistFingerprinting.pbmode"_ns
,
746 "privacy.fingerprintingProtection"_ns
,
747 "privacy.fingerprintingProtection.pbmode"_ns
,
748 "privacy.fingerprintingProtection.overrides"_ns
,
751 static void RecomputeResistFingerprintingAllDocs(const char*, void*) {
752 AutoTArray
<RefPtr
<BrowsingContextGroup
>, 5> bcGroups
;
753 BrowsingContextGroup::GetAllGroups(bcGroups
);
754 for (auto& bcGroup
: bcGroups
) {
755 AutoTArray
<DocGroup
*, 5> docGroups
;
756 bcGroup
->GetDocGroups(docGroups
);
757 for (auto* docGroup
: docGroups
) {
758 for (Document
* doc
: *docGroup
) {
759 if (doc
->RecomputeResistFingerprinting()) {
760 if (auto* pc
= doc
->GetPresContext()) {
761 pc
->MediaFeatureValuesChanged(
762 {MediaFeatureChangeReason::PreferenceChange
},
763 MediaFeatureChangePropagation::JustThisDocument
);
772 nsresult
nsContentUtils::Init() {
774 NS_WARNING("Init() called twice");
779 nsHTMLTags::AddRefTable();
781 sXPConnect
= nsXPConnect::XPConnect();
782 // We hold a strong ref to sXPConnect to ensure that it does not go away until
783 // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be
784 // triggered by xpcModuleDtor late in shutdown and cause crashes due to
785 // various stuff already being torn down by then. Note that this means that
786 // we are effectively making sure that if we leak nsLayoutStatics then we also
788 NS_ADDREF(sXPConnect
);
790 sSecurityManager
= nsScriptSecurityManager::GetScriptSecurityManager();
791 if (!sSecurityManager
) return NS_ERROR_FAILURE
;
792 NS_ADDREF(sSecurityManager
);
794 sSecurityManager
->GetSystemPrincipal(&sSystemPrincipal
);
795 MOZ_ASSERT(sSystemPrincipal
);
797 RefPtr
<NullPrincipal
> nullPrincipal
=
798 NullPrincipal::CreateWithoutOriginAttributes();
799 if (!nullPrincipal
) {
800 return NS_ERROR_FAILURE
;
803 nullPrincipal
.forget(&sNullSubjectPrincipal
);
805 if (!InitializeEventTable()) return NS_ERROR_FAILURE
;
807 if (!sEventListenerManagersHash
) {
808 static const PLDHashTableOps hash_table_ops
= {
809 PLDHashTable::HashVoidPtrKeyStub
, PLDHashTable::MatchEntryStub
,
810 PLDHashTable::MoveEntryStub
, EventListenerManagerHashClearEntry
,
811 EventListenerManagerHashInitEntry
};
813 sEventListenerManagersHash
=
814 new PLDHashTable(&hash_table_ops
, sizeof(EventListenerManagerMapEntry
));
816 RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
819 sBlockedScriptRunners
= new AutoTArray
<nsCOMPtr
<nsIRunnable
>, 8>;
821 #ifndef RELEASE_OR_BETA
822 sBypassCSSOMOriginCheck
= getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
825 Element::InitCCCallbacks();
827 RefPtr
<nsRFPService
> rfpService
= nsRFPService::GetOrCreate();
828 MOZ_ASSERT(rfpService
);
830 if (XRE_IsParentProcess()) {
831 AsyncPrecreateStringBundles();
834 RefPtr
<UserInteractionObserver
> uio
= new UserInteractionObserver();
836 uio
.forget(&sUserInteractionObserver
);
838 for (const auto& pref
: kRfpPrefs
) {
839 Preferences::RegisterCallback(RecomputeResistFingerprintingAllDocs
, pref
);
847 bool nsContentUtils::InitJSBytecodeMimeType() {
848 MOZ_ASSERT(NS_IsMainThread());
849 MOZ_ASSERT(!sJSScriptBytecodeMimeType
);
850 MOZ_ASSERT(!sJSModuleBytecodeMimeType
);
852 JS::BuildIdCharVector jsBuildId
;
853 if (!JS::GetScriptTranscodingBuildId(&jsBuildId
)) {
857 nsDependentCSubstring
jsBuildIdStr(jsBuildId
.begin(), jsBuildId
.length());
858 sJSScriptBytecodeMimeType
=
859 new nsCString("javascript/moz-script-bytecode-"_ns
+ jsBuildIdStr
);
860 sJSModuleBytecodeMimeType
=
861 new nsCString("javascript/moz-module-bytecode-"_ns
+ jsBuildIdStr
);
865 void nsContentUtils::GetShiftText(nsAString
& text
) {
866 if (!sShiftText
) InitializeModifierStrings();
867 text
.Assign(*sShiftText
);
870 void nsContentUtils::GetControlText(nsAString
& text
) {
871 if (!sControlText
) InitializeModifierStrings();
872 text
.Assign(*sControlText
);
875 void nsContentUtils::GetCommandOrWinText(nsAString
& text
) {
876 if (!sCommandOrWinText
) {
877 InitializeModifierStrings();
879 text
.Assign(*sCommandOrWinText
);
882 void nsContentUtils::GetAltText(nsAString
& text
) {
883 if (!sAltText
) InitializeModifierStrings();
884 text
.Assign(*sAltText
);
887 void nsContentUtils::GetModifierSeparatorText(nsAString
& text
) {
888 if (!sModifierSeparator
) InitializeModifierStrings();
889 text
.Assign(*sModifierSeparator
);
892 void nsContentUtils::InitializeModifierStrings() {
893 // load the display strings for the keyboard accelerators
894 nsCOMPtr
<nsIStringBundleService
> bundleService
=
895 mozilla::components::StringBundle::Service();
896 nsCOMPtr
<nsIStringBundle
> bundle
;
897 DebugOnly
<nsresult
> rv
= NS_OK
;
899 rv
= bundleService
->CreateBundle(
900 "chrome://global-platform/locale/platformKeys.properties",
901 getter_AddRefs(bundle
));
905 NS_SUCCEEDED(rv
) && bundle
,
906 "chrome://global/locale/platformKeys.properties could not be loaded");
907 nsAutoString shiftModifier
;
908 nsAutoString commandOrWinModifier
;
909 nsAutoString altModifier
;
910 nsAutoString controlModifier
;
911 nsAutoString modifierSeparator
;
913 // macs use symbols for each modifier key, so fetch each from the bundle,
914 // which also covers i18n
915 bundle
->GetStringFromName("VK_SHIFT", shiftModifier
);
916 bundle
->GetStringFromName("VK_COMMAND_OR_WIN", commandOrWinModifier
);
917 bundle
->GetStringFromName("VK_ALT", altModifier
);
918 bundle
->GetStringFromName("VK_CONTROL", controlModifier
);
919 bundle
->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator
);
921 // if any of these don't exist, we get an empty string
922 sShiftText
= new nsString(shiftModifier
);
923 sCommandOrWinText
= new nsString(commandOrWinModifier
);
924 sAltText
= new nsString(altModifier
);
925 sControlText
= new nsString(controlModifier
);
926 sModifierSeparator
= new nsString(modifierSeparator
);
929 mozilla::EventClassID
nsContentUtils::GetEventClassIDFromMessage(
930 EventMessage aEventMessage
) {
931 switch (aEventMessage
) {
932 #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
935 #include "mozilla/EventNameList.h"
936 #undef MESSAGE_TO_EVENT
938 MOZ_ASSERT_UNREACHABLE("Invalid event message?");
939 return eBasicEventClass
;
943 bool nsContentUtils::IsExternalProtocol(nsIURI
* aURI
) {
944 bool doesNotReturnData
= false;
945 nsresult rv
= NS_URIChainHasFlags(
946 aURI
, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA
, &doesNotReturnData
);
947 return NS_SUCCEEDED(rv
) && doesNotReturnData
;
951 nsAtom
* nsContentUtils::GetEventTypeFromMessage(EventMessage aEventMessage
) {
952 switch (aEventMessage
) {
953 #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
955 return nsGkAtoms::on##name_;
956 #include "mozilla/EventNameList.h"
957 #undef MESSAGE_TO_EVENT
963 bool nsContentUtils::InitializeEventTable() {
964 NS_ASSERTION(!sAtomEventTable
, "EventTable already initialized!");
965 NS_ASSERTION(!sStringEventTable
, "EventTable already initialized!");
967 static const EventNameMapping eventArray
[] = {
968 #define EVENT(name_, _message, _type, _class) \
969 {nsGkAtoms::on##name_, _type, _message, _class},
970 #define WINDOW_ONLY_EVENT EVENT
971 #define DOCUMENT_ONLY_EVENT EVENT
972 #define NON_IDL_EVENT EVENT
973 #include "mozilla/EventNameList.h"
974 #undef WINDOW_ONLY_EVENT
980 new nsTHashMap
<RefPtr
<nsAtom
>, EventNameMapping
>(ArrayLength(eventArray
));
981 sStringEventTable
= new nsTHashMap
<nsStringHashKey
, EventNameMapping
>(
982 ArrayLength(eventArray
));
983 sUserDefinedEvents
= new nsTArray
<RefPtr
<nsAtom
>>(64);
985 // Subtract one from the length because of the trailing null
986 for (uint32_t i
= 0; i
< ArrayLength(eventArray
) - 1; ++i
) {
987 MOZ_ASSERT(!sAtomEventTable
->Contains(eventArray
[i
].mAtom
),
988 "Double-defining event name; fix your EventNameList.h");
989 sAtomEventTable
->InsertOrUpdate(eventArray
[i
].mAtom
, eventArray
[i
]);
990 sStringEventTable
->InsertOrUpdate(
991 Substring(nsDependentAtomString(eventArray
[i
].mAtom
), 2),
998 void nsContentUtils::InitializeTouchEventTable() {
999 static bool sEventTableInitialized
= false;
1000 if (!sEventTableInitialized
&& sAtomEventTable
&& sStringEventTable
) {
1001 sEventTableInitialized
= true;
1002 static const EventNameMapping touchEventArray
[] = {
1003 #define EVENT(name_, _message, _type, _class)
1004 #define TOUCH_EVENT(name_, _message, _type, _class) \
1005 {nsGkAtoms::on##name_, _type, _message, _class},
1006 #include "mozilla/EventNameList.h"
1010 // Subtract one from the length because of the trailing null
1011 for (uint32_t i
= 0; i
< ArrayLength(touchEventArray
) - 1; ++i
) {
1012 sAtomEventTable
->InsertOrUpdate(touchEventArray
[i
].mAtom
,
1013 touchEventArray
[i
]);
1014 sStringEventTable
->InsertOrUpdate(
1015 Substring(nsDependentAtomString(touchEventArray
[i
].mAtom
), 2),
1016 touchEventArray
[i
]);
1021 static bool Is8bit(const nsAString
& aString
) {
1022 static const char16_t EIGHT_BIT
= char16_t(~0x00FF);
1024 for (nsAString::const_char_iterator start
= aString
.BeginReading(),
1025 end
= aString
.EndReading();
1026 start
!= end
; ++start
) {
1027 if (*start
& EIGHT_BIT
) {
1035 nsresult
nsContentUtils::Btoa(const nsAString
& aBinaryData
,
1036 nsAString
& aAsciiBase64String
) {
1037 if (!Is8bit(aBinaryData
)) {
1038 aAsciiBase64String
.Truncate();
1039 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1042 return Base64Encode(aBinaryData
, aAsciiBase64String
);
1045 nsresult
nsContentUtils::Atob(const nsAString
& aAsciiBase64String
,
1046 nsAString
& aBinaryData
) {
1047 if (!Is8bit(aAsciiBase64String
)) {
1048 aBinaryData
.Truncate();
1049 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1052 const char16_t
* start
= aAsciiBase64String
.BeginReading();
1053 const char16_t
* cur
= start
;
1054 const char16_t
* end
= aAsciiBase64String
.EndReading();
1055 bool hasWhitespace
= false;
1058 if (nsContentUtils::IsHTMLWhitespace(*cur
)) {
1059 hasWhitespace
= true;
1067 if (hasWhitespace
) {
1068 nsString trimmedString
;
1070 if (!trimmedString
.SetCapacity(aAsciiBase64String
.Length(), fallible
)) {
1071 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1074 trimmedString
.Append(start
, cur
- start
);
1077 if (!nsContentUtils::IsHTMLWhitespace(*cur
)) {
1078 trimmedString
.Append(*cur
);
1082 rv
= Base64Decode(trimmedString
, aBinaryData
);
1084 rv
= Base64Decode(aAsciiBase64String
, aBinaryData
);
1087 if (NS_FAILED(rv
) && rv
== NS_ERROR_INVALID_ARG
) {
1088 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1093 bool nsContentUtils::IsAutocompleteEnabled(
1094 mozilla::dom::HTMLInputElement
* aInput
) {
1095 MOZ_ASSERT(aInput
, "aInput should not be null!");
1097 nsAutoString autocomplete
;
1098 aInput
->GetAutocomplete(autocomplete
);
1100 if (autocomplete
.IsEmpty()) {
1101 auto* form
= aInput
->GetForm();
1106 form
->GetAutocomplete(autocomplete
);
1109 return !autocomplete
.EqualsLiteral("off");
1112 nsContentUtils::AutocompleteAttrState
1113 nsContentUtils::SerializeAutocompleteAttribute(
1114 const nsAttrValue
* aAttr
, nsAString
& aResult
,
1115 AutocompleteAttrState aCachedState
) {
1117 aCachedState
== nsContentUtils::eAutocompleteAttrState_Invalid
) {
1118 return aCachedState
;
1121 if (aCachedState
== nsContentUtils::eAutocompleteAttrState_Valid
) {
1122 uint32_t atomCount
= aAttr
->GetAtomCount();
1123 for (uint32_t i
= 0; i
< atomCount
; i
++) {
1125 aResult
.Append(' ');
1127 aResult
.Append(nsDependentAtomString(aAttr
->AtomAt(i
)));
1129 nsContentUtils::ASCIIToLower(aResult
);
1130 return aCachedState
;
1135 mozilla::dom::AutocompleteInfo info
;
1136 AutocompleteAttrState state
=
1137 InternalSerializeAutocompleteAttribute(aAttr
, info
);
1138 if (state
== eAutocompleteAttrState_Valid
) {
1139 // Concatenate the info fields.
1140 aResult
= info
.mSection
;
1142 if (!info
.mAddressType
.IsEmpty()) {
1143 if (!aResult
.IsEmpty()) {
1146 aResult
+= info
.mAddressType
;
1149 if (!info
.mContactType
.IsEmpty()) {
1150 if (!aResult
.IsEmpty()) {
1153 aResult
+= info
.mContactType
;
1156 if (!info
.mFieldName
.IsEmpty()) {
1157 if (!aResult
.IsEmpty()) {
1160 aResult
+= info
.mFieldName
;
1167 nsContentUtils::AutocompleteAttrState
1168 nsContentUtils::SerializeAutocompleteAttribute(
1169 const nsAttrValue
* aAttr
, mozilla::dom::AutocompleteInfo
& aInfo
,
1170 AutocompleteAttrState aCachedState
, bool aGrantAllValidValue
) {
1172 aCachedState
== nsContentUtils::eAutocompleteAttrState_Invalid
) {
1173 return aCachedState
;
1176 return InternalSerializeAutocompleteAttribute(aAttr
, aInfo
,
1177 aGrantAllValidValue
);
1181 * Helper to validate the @autocomplete tokens.
1183 * @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
1185 nsContentUtils::AutocompleteAttrState
1186 nsContentUtils::InternalSerializeAutocompleteAttribute(
1187 const nsAttrValue
* aAttrVal
, mozilla::dom::AutocompleteInfo
& aInfo
,
1188 bool aGrantAllValidValue
) {
1189 // No autocomplete attribute so we are done
1191 return eAutocompleteAttrState_Invalid
;
1194 uint32_t numTokens
= aAttrVal
->GetAtomCount();
1196 return eAutocompleteAttrState_Invalid
;
1199 uint32_t index
= numTokens
- 1;
1200 nsString tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1201 AutocompleteCategory category
;
1202 nsAttrValue enumValue
;
1204 bool unsupported
= false;
1205 if (!aGrantAllValidValue
) {
1206 unsupported
= enumValue
.ParseEnumValue(
1207 tokenString
, kAutocompleteUnsupportedFieldNameTable
, false);
1209 return eAutocompleteAttrState_Invalid
;
1215 enumValue
.ParseEnumValue(tokenString
, kAutocompleteFieldNameTable
, false);
1217 // Off/Automatic/Normal categories.
1218 if (enumValue
.Equals(u
"off"_ns
, eIgnoreCase
) ||
1219 enumValue
.Equals(u
"on"_ns
, eIgnoreCase
)) {
1220 if (numTokens
> 1) {
1221 return eAutocompleteAttrState_Invalid
;
1223 enumValue
.ToString(str
);
1225 aInfo
.mFieldName
.Assign(str
);
1226 aInfo
.mCanAutomaticallyPersist
=
1227 !enumValue
.Equals(u
"off"_ns
, eIgnoreCase
);
1228 return eAutocompleteAttrState_Valid
;
1231 // Only allow on/off if form autofill @autocomplete values aren't enabled
1232 // and it doesn't grant all valid values.
1233 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1234 !aGrantAllValidValue
) {
1235 return eAutocompleteAttrState_Invalid
;
1239 if (numTokens
> 3) {
1240 return eAutocompleteAttrState_Invalid
;
1242 category
= eAutocompleteCategory_NORMAL
;
1243 } else { // Check if the last token is of the contact category instead.
1244 // Only allow on/off if form autofill @autocomplete values aren't enabled
1245 // and it doesn't grant all valid values.
1246 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1247 !aGrantAllValidValue
) {
1248 return eAutocompleteAttrState_Invalid
;
1251 result
= enumValue
.ParseEnumValue(
1252 tokenString
, kAutocompleteContactFieldNameTable
, false);
1253 if (!result
|| numTokens
> 4) {
1254 return eAutocompleteAttrState_Invalid
;
1257 category
= eAutocompleteCategory_CONTACT
;
1260 enumValue
.ToString(str
);
1262 aInfo
.mFieldName
.Assign(str
);
1264 aInfo
.mCanAutomaticallyPersist
= !enumValue
.ParseEnumValue(
1265 tokenString
, kAutocompleteNoPersistFieldNameTable
, false);
1267 // We are done if this was the only token.
1268 if (numTokens
== 1) {
1269 return eAutocompleteAttrState_Valid
;
1273 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1275 if (category
== eAutocompleteCategory_CONTACT
) {
1276 if (!aGrantAllValidValue
) {
1277 unsupported
= enumValue
.ParseEnumValue(
1278 tokenString
, kAutocompleteUnsupportedContactFieldHintTable
, false);
1280 return eAutocompleteAttrState_Invalid
;
1284 nsAttrValue contactFieldHint
;
1285 result
= contactFieldHint
.ParseEnumValue(
1286 tokenString
, kAutocompleteContactFieldHintTable
, false);
1288 nsAutoString contactFieldHintString
;
1289 contactFieldHint
.ToString(contactFieldHintString
);
1290 ASCIIToLower(contactFieldHintString
);
1291 aInfo
.mContactType
.Assign(contactFieldHintString
);
1293 return eAutocompleteAttrState_Valid
;
1296 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1300 // Check for billing/shipping tokens
1301 nsAttrValue fieldHint
;
1302 if (fieldHint
.ParseEnumValue(tokenString
, kAutocompleteFieldHintTable
,
1304 nsString fieldHintString
;
1305 fieldHint
.ToString(fieldHintString
);
1306 ASCIIToLower(fieldHintString
);
1307 aInfo
.mAddressType
.Assign(fieldHintString
);
1309 return eAutocompleteAttrState_Valid
;
1312 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1315 // Check for section-* token
1316 const nsDependentSubstring
& section
= Substring(tokenString
, 0, 8);
1317 if (section
.LowerCaseEqualsASCII("section-")) {
1318 ASCIIToLower(tokenString
);
1319 aInfo
.mSection
.Assign(tokenString
);
1321 return eAutocompleteAttrState_Valid
;
1325 // Clear the fields as the autocomplete attribute is invalid.
1326 aInfo
.mSection
.Truncate();
1327 aInfo
.mAddressType
.Truncate();
1328 aInfo
.mContactType
.Truncate();
1329 aInfo
.mFieldName
.Truncate();
1331 return eAutocompleteAttrState_Invalid
;
1334 // Parse an integer according to HTML spec
1335 template <class CharT
>
1336 int32_t nsContentUtils::ParseHTMLIntegerImpl(
1337 const CharT
* aStart
, const CharT
* aEnd
,
1338 ParseHTMLIntegerResultFlags
* aResult
) {
1339 int result
= eParseHTMLInteger_NoFlags
;
1341 const CharT
* iter
= aStart
;
1343 while (iter
!= aEnd
&& nsContentUtils::IsHTMLWhitespace(*iter
)) {
1344 result
|= eParseHTMLInteger_NonStandard
;
1349 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorNoValue
;
1350 *aResult
= (ParseHTMLIntegerResultFlags
)result
;
1355 if (*iter
== CharT('-')) {
1357 result
|= eParseHTMLInteger_Negative
;
1359 } else if (*iter
== CharT('+')) {
1360 result
|= eParseHTMLInteger_NonStandard
;
1364 bool foundValue
= false;
1365 CheckedInt32 value
= 0;
1367 // Check for leading zeros first.
1368 uint64_t leadingZeros
= 0;
1369 while (iter
!= aEnd
) {
1370 if (*iter
!= CharT('0')) {
1379 while (iter
!= aEnd
) {
1380 if (*iter
>= CharT('0') && *iter
<= CharT('9')) {
1381 value
= (value
* 10) + (*iter
- CharT('0')) * sign
;
1383 if (!value
.isValid()) {
1384 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorOverflow
;
1394 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorNoValue
;
1397 if (value
.isValid() &&
1398 ((leadingZeros
> 1 || (leadingZeros
== 1 && !(value
== 0))) ||
1399 (sign
== -1 && value
== 0))) {
1400 result
|= eParseHTMLInteger_NonStandard
;
1404 result
|= eParseHTMLInteger_DidNotConsumeAllInput
;
1407 *aResult
= (ParseHTMLIntegerResultFlags
)result
;
1408 return value
.isValid() ? value
.value() : 0;
1411 // Parse an integer according to HTML spec
1412 int32_t nsContentUtils::ParseHTMLInteger(const char16_t
* aStart
,
1413 const char16_t
* aEnd
,
1414 ParseHTMLIntegerResultFlags
* aResult
) {
1415 return ParseHTMLIntegerImpl(aStart
, aEnd
, aResult
);
1418 int32_t nsContentUtils::ParseHTMLInteger(const char* aStart
, const char* aEnd
,
1419 ParseHTMLIntegerResultFlags
* aResult
) {
1420 return ParseHTMLIntegerImpl(aStart
, aEnd
, aResult
);
1423 #define SKIP_WHITESPACE(iter, end_iter, end_res) \
1424 while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
1427 if ((iter) == (end_iter)) { \
1431 #define SKIP_ATTR_NAME(iter, end_iter) \
1432 while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
1437 bool nsContentUtils::GetPseudoAttributeValue(const nsString
& aSource
,
1438 nsAtom
* aName
, nsAString
& aValue
) {
1441 const char16_t
* start
= aSource
.get();
1442 const char16_t
* end
= start
+ aSource
.Length();
1443 const char16_t
* iter
;
1445 while (start
!= end
) {
1446 SKIP_WHITESPACE(start
, end
, false)
1448 SKIP_ATTR_NAME(iter
, end
)
1450 if (start
== iter
) {
1454 // Remember the attr name.
1455 const nsDependentSubstring
& attrName
= Substring(start
, iter
);
1457 // Now check whether this is a valid name="value" pair.
1459 SKIP_WHITESPACE(start
, end
, false)
1460 if (*start
!= '=') {
1461 // No '=', so this is not a name="value" pair. We don't know
1462 // what it is, and we have no way to handle it.
1466 // Have to skip the value.
1468 SKIP_WHITESPACE(start
, end
, false)
1469 char16_t q
= *start
;
1470 if (q
!= kQuote
&& q
!= kApostrophe
) {
1471 // Not a valid quoted value, so bail.
1475 ++start
; // Point to the first char of the value.
1478 while (iter
!= end
&& *iter
!= q
) {
1483 // Oops, unterminated quoted string.
1487 // At this point attrName holds the name of the "attribute" and
1488 // the value is between start and iter.
1490 if (aName
->Equals(attrName
)) {
1491 // We'll accumulate as many characters as possible (until we hit either
1492 // the end of the string or the beginning of an entity). Chunks will be
1493 // delimited by start and chunkEnd.
1494 const char16_t
* chunkEnd
= start
;
1495 while (chunkEnd
!= iter
) {
1496 if (*chunkEnd
== kLessThan
) {
1502 if (*chunkEnd
== kAmpersand
) {
1503 aValue
.Append(start
, chunkEnd
- start
);
1505 const char16_t
* afterEntity
= nullptr;
1507 uint32_t count
= MOZ_XMLTranslateEntity(
1508 reinterpret_cast<const char*>(chunkEnd
),
1509 reinterpret_cast<const char*>(iter
),
1510 reinterpret_cast<const char**>(&afterEntity
), result
);
1517 aValue
.Append(result
, count
);
1519 // Advance to after the entity and begin a new chunk.
1520 start
= chunkEnd
= afterEntity
;
1526 // Append remainder.
1527 aValue
.Append(start
, iter
- start
);
1532 // Resume scanning after the end of the attribute value (past the quote
1540 bool nsContentUtils::IsJavaScriptLanguage(const nsString
& aName
) {
1541 // Create MIME type as "text/" + given input
1542 nsAutoString
mimeType(u
"text/");
1543 mimeType
.Append(aName
);
1545 return IsJavascriptMIMEType(mimeType
);
1548 void nsContentUtils::SplitMimeType(const nsAString
& aValue
, nsString
& aType
,
1549 nsString
& aParams
) {
1552 int32_t semiIndex
= aValue
.FindChar(char16_t(';'));
1553 if (-1 != semiIndex
) {
1554 aType
= Substring(aValue
, 0, semiIndex
);
1556 Substring(aValue
, semiIndex
+ 1, aValue
.Length() - (semiIndex
+ 1));
1557 aParams
.StripWhitespace();
1561 aType
.StripWhitespace();
1565 * A helper function that parses a sandbox attribute (of an <iframe> or a CSP
1566 * directive) and converts it to the set of flags used internally.
1568 * @param aSandboxAttr the sandbox attribute
1569 * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is
1572 uint32_t nsContentUtils::ParseSandboxAttributeToFlags(
1573 const nsAttrValue
* aSandboxAttr
) {
1574 if (!aSandboxAttr
) {
1575 return SANDBOXED_NONE
;
1578 uint32_t out
= SANDBOX_ALL_FLAGS
;
1580 #define SANDBOX_KEYWORD(string, atom, flags) \
1581 if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \
1584 #include "IframeSandboxKeywordList.h"
1585 #undef SANDBOX_KEYWORD
1591 * A helper function that checks if a string matches a valid sandbox flag.
1593 * @param aFlag the potential sandbox flag.
1594 * @return true if the flag is a sandbox flag.
1596 bool nsContentUtils::IsValidSandboxFlag(const nsAString
& aFlag
) {
1597 #define SANDBOX_KEYWORD(string, atom, flags) \
1598 if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \
1601 #include "IframeSandboxKeywordList.h"
1602 #undef SANDBOX_KEYWORD
1607 * A helper function that returns a string attribute corresponding to the
1610 * @param aFlags the sandbox flags
1611 * @param aString the attribute corresponding to the flags (null if aFlags
1614 void nsContentUtils::SandboxFlagsToString(uint32_t aFlags
, nsAString
& aString
) {
1616 SetDOMStringToNull(aString
);
1622 #define SANDBOX_KEYWORD(string, atom, flags) \
1623 if (!(aFlags & (flags))) { \
1624 if (!aString.IsEmpty()) { \
1625 aString.AppendLiteral(u" "); \
1627 aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \
1629 #include "IframeSandboxKeywordList.h"
1630 #undef SANDBOX_KEYWORD
1633 nsIBidiKeyboard
* nsContentUtils::GetBidiKeyboard() {
1634 if (!sBidiKeyboard
) {
1635 sBidiKeyboard
= nsIWidget::CreateBidiKeyboard();
1637 return sBidiKeyboard
;
1641 * This is used to determine whether a character is in one of the classes
1642 * which CSS says should be part of the first-letter. Currently, that is
1643 * all punctuation classes (P*). Note that this is a change from CSS2
1644 * which excluded Pc and Pd.
1646 * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo
1647 * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode
1648 * general category [UAX44]) [...]"
1652 bool nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar
) {
1653 switch (mozilla::unicode::GetGeneralCategory(aChar
)) {
1654 case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION
: /* Pc */
1655 case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION
: /* Pd */
1656 case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION
: /* Pe */
1657 case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION
: /* Pf */
1658 case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION
: /* Pi */
1659 case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION
: /* Po */
1660 case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION
: /* Ps */
1668 bool nsContentUtils::IsAlphanumeric(uint32_t aChar
) {
1669 nsUGenCategory cat
= mozilla::unicode::GetGenCategory(aChar
);
1671 return (cat
== nsUGenCategory::kLetter
|| cat
== nsUGenCategory::kNumber
);
1675 bool nsContentUtils::IsAlphanumericOrSymbol(uint32_t aChar
) {
1676 nsUGenCategory cat
= mozilla::unicode::GetGenCategory(aChar
);
1678 return cat
== nsUGenCategory::kLetter
|| cat
== nsUGenCategory::kNumber
||
1679 cat
== nsUGenCategory::kSymbol
;
1683 bool nsContentUtils::IsHTMLWhitespace(char16_t aChar
) {
1684 return aChar
== char16_t(0x0009) || aChar
== char16_t(0x000A) ||
1685 aChar
== char16_t(0x000C) || aChar
== char16_t(0x000D) ||
1686 aChar
== char16_t(0x0020);
1690 bool nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar
) {
1691 return IsHTMLWhitespace(aChar
) || aChar
== char16_t(0xA0);
1695 bool nsContentUtils::IsHTMLBlockLevelElement(nsIContent
* aContent
) {
1696 return aContent
->IsAnyOfHTMLElements(
1697 nsGkAtoms::address
, nsGkAtoms::article
, nsGkAtoms::aside
,
1698 nsGkAtoms::blockquote
, nsGkAtoms::center
, nsGkAtoms::dir
, nsGkAtoms::div
,
1699 nsGkAtoms::dl
, // XXX why not dt and dd?
1700 nsGkAtoms::fieldset
,
1701 nsGkAtoms::figure
, // XXX shouldn't figcaption be on this list
1702 nsGkAtoms::footer
, nsGkAtoms::form
, nsGkAtoms::h1
, nsGkAtoms::h2
,
1703 nsGkAtoms::h3
, nsGkAtoms::h4
, nsGkAtoms::h5
, nsGkAtoms::h6
,
1704 nsGkAtoms::header
, nsGkAtoms::hgroup
, nsGkAtoms::hr
, nsGkAtoms::li
,
1705 nsGkAtoms::listing
, nsGkAtoms::menu
, nsGkAtoms::nav
, nsGkAtoms::ol
,
1706 nsGkAtoms::p
, nsGkAtoms::pre
, nsGkAtoms::section
, nsGkAtoms::table
,
1707 nsGkAtoms::ul
, nsGkAtoms::xmp
);
1711 bool nsContentUtils::ParseIntMarginValue(const nsAString
& aString
,
1712 nsIntMargin
& result
) {
1713 nsAutoString
marginStr(aString
);
1714 marginStr
.CompressWhitespace(true, true);
1715 if (marginStr
.IsEmpty()) {
1719 int32_t start
= 0, end
= 0;
1720 for (int count
= 0; count
< 4; count
++) {
1721 if ((uint32_t)end
>= marginStr
.Length()) return false;
1723 // top, right, bottom, left
1725 end
= Substring(marginStr
, start
).FindChar(',');
1727 end
= Substring(marginStr
, start
).Length();
1729 if (end
<= 0) return false;
1732 int32_t val
= nsString(Substring(marginStr
, start
, end
)).ToInteger(&ec
);
1733 if (NS_FAILED(ec
)) return false;
1743 result
.bottom
= val
;
1755 int32_t nsContentUtils::ParseLegacyFontSize(const nsAString
& aValue
) {
1756 nsAString::const_iterator iter
, end
;
1757 aValue
.BeginReading(iter
);
1758 aValue
.EndReading(end
);
1760 while (iter
!= end
&& nsContentUtils::IsHTMLWhitespace(*iter
)) {
1768 bool relative
= false;
1769 bool negate
= false;
1770 if (*iter
== char16_t('-')) {
1774 } else if (*iter
== char16_t('+')) {
1779 if (iter
== end
|| *iter
< char16_t('0') || *iter
> char16_t('9')) {
1783 // We don't have to worry about overflow, since we can bail out as soon as
1784 // we're bigger than 7.
1786 while (iter
!= end
&& *iter
>= char16_t('0') && *iter
<= char16_t('9')) {
1787 value
= 10 * value
+ (*iter
- char16_t('0'));
1802 return clamped(value
, 1, 7);
1806 void nsContentUtils::GetOfflineAppManifest(Document
* aDocument
, nsIURI
** aURI
) {
1807 MOZ_ASSERT(NS_IsMainThread());
1808 MOZ_ASSERT(aDocument
);
1811 if (aDocument
->GetController().isSome()) {
1815 Element
* docElement
= aDocument
->GetRootElement();
1820 nsAutoString manifestSpec
;
1821 docElement
->GetAttr(nsGkAtoms::manifest
, manifestSpec
);
1823 // Manifest URIs can't have fragment identifiers.
1824 if (manifestSpec
.IsEmpty() || manifestSpec
.Contains('#')) {
1828 nsContentUtils::NewURIWithDocumentCharset(aURI
, manifestSpec
, aDocument
,
1829 aDocument
->GetDocBaseURI());
1833 bool nsContentUtils::OfflineAppAllowed(nsIURI
* aURI
) { return false; }
1836 bool nsContentUtils::OfflineAppAllowed(nsIPrincipal
* aPrincipal
) {
1840 bool nsContentUtils::IsErrorPage(nsIURI
* aURI
) {
1845 if (!aURI
->SchemeIs("about")) {
1850 nsresult rv
= NS_GetAboutModuleName(aURI
, name
);
1851 NS_ENSURE_SUCCESS(rv
, false);
1853 return name
.EqualsLiteral("certerror") || name
.EqualsLiteral("neterror") ||
1854 name
.EqualsLiteral("blocked");
1858 void nsContentUtils::Shutdown() {
1859 sInitialized
= false;
1861 nsHTMLTags::ReleaseTable();
1863 NS_IF_RELEASE(sContentPolicyService
);
1864 sTriedToGetContentPolicy
= false;
1865 for (StaticRefPtr
<nsIStringBundle
>& bundle
: sStringBundles
) {
1869 NS_IF_RELEASE(sStringBundleService
);
1870 NS_IF_RELEASE(sConsoleService
);
1871 NS_IF_RELEASE(sXPConnect
);
1872 NS_IF_RELEASE(sSecurityManager
);
1873 NS_IF_RELEASE(sSystemPrincipal
);
1874 NS_IF_RELEASE(sNullSubjectPrincipal
);
1876 sBidiKeyboard
= nullptr;
1878 delete sAtomEventTable
;
1879 sAtomEventTable
= nullptr;
1880 delete sStringEventTable
;
1881 sStringEventTable
= nullptr;
1882 delete sUserDefinedEvents
;
1883 sUserDefinedEvents
= nullptr;
1885 if (sEventListenerManagersHash
) {
1886 NS_ASSERTION(sEventListenerManagersHash
->EntryCount() == 0,
1887 "Event listener manager hash not empty at shutdown!");
1889 // See comment above.
1891 // However, we have to handle this table differently. If it still
1892 // has entries, we want to leak it too, so that we can keep it alive
1893 // in case any elements are destroyed. Because if they are, we need
1894 // their event listener managers to be destroyed too, or otherwise
1895 // it could leave dangling references in DOMClassInfo's preserved
1898 if (sEventListenerManagersHash
->EntryCount() == 0) {
1899 delete sEventListenerManagersHash
;
1900 sEventListenerManagersHash
= nullptr;
1904 if (sDOMArenaHashtable
) {
1905 MOZ_ASSERT(sDOMArenaHashtable
->Count() == 0);
1906 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
1907 delete sDOMArenaHashtable
;
1908 sDOMArenaHashtable
= nullptr;
1911 NS_ASSERTION(!sBlockedScriptRunners
|| sBlockedScriptRunners
->Length() == 0,
1912 "How'd this happen?");
1913 delete sBlockedScriptRunners
;
1914 sBlockedScriptRunners
= nullptr;
1917 sShiftText
= nullptr;
1918 delete sControlText
;
1919 sControlText
= nullptr;
1920 delete sCommandOrWinText
;
1921 sCommandOrWinText
= nullptr;
1924 delete sModifierSeparator
;
1925 sModifierSeparator
= nullptr;
1927 delete sJSScriptBytecodeMimeType
;
1928 sJSScriptBytecodeMimeType
= nullptr;
1930 delete sJSModuleBytecodeMimeType
;
1931 sJSModuleBytecodeMimeType
= nullptr;
1933 NS_IF_RELEASE(sSameOriginChecker
);
1935 if (sUserInteractionObserver
) {
1936 sUserInteractionObserver
->Shutdown();
1937 NS_RELEASE(sUserInteractionObserver
);
1940 for (const auto& pref
: kRfpPrefs
) {
1941 Preferences::UnregisterCallback(RecomputeResistFingerprintingAllDocs
, pref
);
1944 TextControlState::Shutdown();
1948 * Checks whether two nodes come from the same origin. aTrustedNode is
1949 * considered 'safe' in that a user can operate on it.
1952 nsresult
nsContentUtils::CheckSameOrigin(const nsINode
* aTrustedNode
,
1953 const nsINode
* unTrustedNode
) {
1954 MOZ_ASSERT(aTrustedNode
);
1955 MOZ_ASSERT(unTrustedNode
);
1958 * Get hold of each node's principal
1961 nsIPrincipal
* trustedPrincipal
= aTrustedNode
->NodePrincipal();
1962 nsIPrincipal
* unTrustedPrincipal
= unTrustedNode
->NodePrincipal();
1964 if (trustedPrincipal
== unTrustedPrincipal
) {
1969 // XXXbz should we actually have a Subsumes() check here instead? Or perhaps
1970 // a separate method for that, with callers using one or the other?
1971 if (NS_FAILED(trustedPrincipal
->Equals(unTrustedPrincipal
, &equal
)) ||
1973 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
1980 bool nsContentUtils::CanCallerAccess(nsIPrincipal
* aSubjectPrincipal
,
1981 nsIPrincipal
* aPrincipal
) {
1983 nsresult rv
= aSubjectPrincipal
->Subsumes(aPrincipal
, &subsumes
);
1984 NS_ENSURE_SUCCESS(rv
, false);
1990 // The subject doesn't subsume aPrincipal. Allow access only if the subject
1992 return IsCallerChrome();
1996 bool nsContentUtils::CanCallerAccess(const nsINode
* aNode
) {
1997 nsIPrincipal
* subject
= SubjectPrincipal();
1998 if (subject
->IsSystemPrincipal()) {
2002 if (aNode
->ChromeOnlyAccess()) {
2006 return CanCallerAccess(subject
, aNode
->NodePrincipal());
2010 bool nsContentUtils::CanCallerAccess(nsPIDOMWindowInner
* aWindow
) {
2011 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptObject
= do_QueryInterface(aWindow
);
2012 NS_ENSURE_TRUE(scriptObject
, false);
2014 return CanCallerAccess(SubjectPrincipal(), scriptObject
->GetPrincipal());
2018 bool nsContentUtils::PrincipalHasPermission(nsIPrincipal
& aPrincipal
,
2019 const nsAtom
* aPerm
) {
2020 // Chrome gets access by default.
2021 if (aPrincipal
.IsSystemPrincipal()) {
2025 // Otherwise, only allow if caller is an addon with the permission.
2026 return BasePrincipal::Cast(aPrincipal
).AddonHasPermission(aPerm
);
2030 bool nsContentUtils::CallerHasPermission(JSContext
* aCx
, const nsAtom
* aPerm
) {
2031 return PrincipalHasPermission(*SubjectPrincipal(aCx
), aPerm
);
2035 nsIPrincipal
* nsContentUtils::GetAttrTriggeringPrincipal(
2036 nsIContent
* aContent
, const nsAString
& aAttrValue
,
2037 nsIPrincipal
* aSubjectPrincipal
) {
2038 nsIPrincipal
* contentPrin
= aContent
? aContent
->NodePrincipal() : nullptr;
2040 // If the subject principal is the same as the content principal, or no
2041 // explicit subject principal was provided, we don't need to do any further
2042 // checks. Just return the content principal.
2043 if (contentPrin
== aSubjectPrincipal
|| !aSubjectPrincipal
) {
2047 // Only use the subject principal if the URL string we are going to end up
2048 // fetching is under the control of that principal, which is never the case
2049 // for relative URLs.
2050 if (aAttrValue
.IsEmpty() ||
2051 !IsAbsoluteURL(NS_ConvertUTF16toUTF8(aAttrValue
))) {
2055 // Only use the subject principal as the attr triggering principal if it
2056 // should override the CSP of the node's principal.
2057 if (BasePrincipal::Cast(aSubjectPrincipal
)->OverridesCSP(contentPrin
)) {
2058 return aSubjectPrincipal
;
2065 bool nsContentUtils::IsAbsoluteURL(const nsACString
& aURL
) {
2066 nsAutoCString scheme
;
2067 if (NS_FAILED(net_ExtractURLScheme(aURL
, scheme
))) {
2068 // If we can't extract a scheme, it's not an absolute URL.
2072 // If it parses as an absolute StandardURL, it's definitely an absolute URL,
2073 // so no need to check with the IO service.
2074 if (net_IsAbsoluteURL(aURL
)) {
2078 nsresult rv
= NS_OK
;
2079 nsCOMPtr
<nsIIOService
> io
= mozilla::components::IO::Service(&rv
);
2080 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
));
2081 if (NS_FAILED(rv
)) {
2086 if (NS_SUCCEEDED(io
->GetProtocolFlags(scheme
.get(), &flags
))) {
2087 return flags
& nsIProtocolHandler::URI_NORELATIVE
;
2094 bool nsContentUtils::InProlog(nsINode
* aNode
) {
2095 MOZ_ASSERT(aNode
, "missing node to nsContentUtils::InProlog");
2097 nsINode
* parent
= aNode
->GetParentNode();
2098 if (!parent
|| !parent
->IsDocument()) {
2102 const Document
* doc
= parent
->AsDocument();
2103 const nsIContent
* root
= doc
->GetRootElement();
2107 const Maybe
<uint32_t> indexOfNode
= doc
->ComputeIndexOf(aNode
);
2108 const Maybe
<uint32_t> indexOfRoot
= doc
->ComputeIndexOf(root
);
2109 if (MOZ_LIKELY(indexOfNode
.isSome() && indexOfRoot
.isSome())) {
2110 return *indexOfNode
< *indexOfRoot
;
2112 // XXX Keep the odd traditional behavior for now.
2113 return indexOfNode
.isNothing() && indexOfRoot
.isSome();
2116 bool nsContentUtils::IsCallerChrome() {
2117 MOZ_ASSERT(NS_IsMainThread());
2118 return SubjectPrincipal() == sSystemPrincipal
;
2122 bool nsContentUtils::IsFuzzingEnabled() {
2123 return StaticPrefs::fuzzing_enabled();
2128 bool nsContentUtils::IsCallerChromeOrElementTransformGettersEnabled(
2129 JSContext
* aCx
, JSObject
*) {
2130 return ThreadsafeIsSystemCaller(aCx
) ||
2131 StaticPrefs::dom_element_transform_getters_enabled();
2134 // Older Should RFP Functions ----------------------------------
2137 bool nsContentUtils::ShouldResistFingerprinting(RFPTarget aTarget
) {
2138 return nsRFPService::IsRFPEnabledFor(aTarget
);
2142 bool nsContentUtils::ShouldResistFingerprinting(nsIGlobalObject
* aGlobalObject
,
2143 RFPTarget aTarget
) {
2144 if (!aGlobalObject
) {
2145 return ShouldResistFingerprinting("Null Object", aTarget
);
2147 return aGlobalObject
->ShouldResistFingerprinting(aTarget
);
2150 // Newer Should RFP Functions ----------------------------------
2151 // Utilities ---------------------------------------------------
2153 inline void LogDomainAndPrefList(const char* urlType
,
2154 const char* exemptedDomainsPrefName
,
2155 nsAutoCString
& url
, bool isExemptDomain
) {
2157 Preferences::GetCString(exemptedDomainsPrefName
, list
);
2158 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2159 ("%s \"%s\" is %s the exempt list \"%s\"", urlType
,
2160 PromiseFlatCString(url
).get(), isExemptDomain
? "in" : "NOT in",
2161 PromiseFlatCString(list
).get()));
2164 inline already_AddRefed
<nsICookieJarSettings
> GetCookieJarSettings(
2165 nsILoadInfo
* aLoadInfo
) {
2166 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
2168 aLoadInfo
->GetCookieJarSettings(getter_AddRefs(cookieJarSettings
));
2169 if (rv
== NS_ERROR_NOT_IMPLEMENTED
) {
2170 // The TRRLoadInfo in particular does not implement this method
2171 // In that instance. We will return false and let other code decide if
2172 // we shouldRFP for this connection
2175 if (NS_WARN_IF(NS_FAILED(rv
))) {
2176 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2177 ("Called CookieJarSettingsSaysShouldResistFingerprinting but the "
2178 "loadinfo's CookieJarSettings couldn't be retrieved"));
2182 MOZ_ASSERT(cookieJarSettings
);
2183 return cookieJarSettings
.forget();
2186 bool ETPSaysShouldNotResistFingerprinting(nsIChannel
* aChannel
,
2187 nsILoadInfo
* aLoadInfo
) {
2188 // A positive return from this function should always be obeyed.
2189 // A negative return means we should keep checking things.
2191 // We do not want this check to apply to RFP, only to FPP
2192 // There is one problematic combination of prefs; however:
2193 // If RFP is enabled in PBMode only and FPP is enabled globally
2194 // (so, in non-PBM mode) - we need to know if we're in PBMode or not.
2195 // But that's kind of expensive and we'd like to avoid it if we
2196 // don't have to, so special-case that scenario
2197 if (StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly() &&
2198 !StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
2199 StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
2200 if (NS_UsePrivateBrowsing(aChannel
)) {
2201 // In PBM (where RFP is enabled) do not exempt based on the ETP toggle
2204 } else if (StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() ||
2206 privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
2207 // In RFP, never use the ETP toggle to exempt.
2208 // We can safely return false here even if we are not in PBM mode
2209 // and RFP_pbmode is enabled because we will later see that and
2210 // return false from the ShouldRFP function entirely.
2214 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
=
2215 GetCookieJarSettings(aLoadInfo
);
2216 if (!cookieJarSettings
) {
2220 return ContentBlockingAllowList::Check(cookieJarSettings
);
2223 inline bool CookieJarSettingsSaysShouldResistFingerprinting(
2224 nsILoadInfo
* aLoadInfo
) {
2225 // A positive return from this function should always be obeyed.
2226 // A negative return means we should keep checking things.
2228 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
=
2229 GetCookieJarSettings(aLoadInfo
);
2230 if (!cookieJarSettings
) {
2233 return cookieJarSettings
->GetShouldResistFingerprinting();
2236 inline bool SchemeSaysShouldNotResistFingerprinting(nsIURI
* aURI
) {
2237 return aURI
->SchemeIs("chrome") || aURI
->SchemeIs("resource") ||
2238 aURI
->SchemeIs("view-source") || aURI
->SchemeIs("moz-extension") ||
2239 (aURI
->SchemeIs("about") && !NS_IsContentAccessibleAboutURI(aURI
));
2242 inline bool SchemeSaysShouldNotResistFingerprinting(nsIPrincipal
* aPrincipal
) {
2243 if (aPrincipal
->SchemeIs("chrome") || aPrincipal
->SchemeIs("resource") ||
2244 aPrincipal
->SchemeIs("view-source") ||
2245 aPrincipal
->SchemeIs("moz-extension")) {
2249 if (!aPrincipal
->SchemeIs("about")) {
2253 bool isContentAccessibleAboutURI
;
2254 Unused
<< aPrincipal
->IsContentAccessibleAboutURI(
2255 &isContentAccessibleAboutURI
);
2256 return !isContentAccessibleAboutURI
;
2259 const char* kExemptedDomainsPrefName
=
2260 "privacy.resistFingerprinting.exemptedDomains";
2262 inline bool PartionKeyIsAlsoExempted(
2263 const mozilla::OriginAttributes
& aOriginAttributes
) {
2264 // If we've gotten here we have (probably) passed the CookieJarSettings
2265 // check that would tell us that if we _are_ a subdocument, then we are on
2266 // an exempted top-level domain and we should see if we ourselves are
2267 // exempted. But we may have gotten here because we directly called the
2268 // _dangerous function and we haven't done that check, but we _were_
2269 // instatiated from a state where we could have been partitioned.
2270 // So perform this last-ditch check for that scenario.
2271 // We arbitrarily use https as the scheme, but it doesn't matter.
2272 nsresult rv
= NS_ERROR_NOT_INITIALIZED
;
2273 nsCOMPtr
<nsIURI
> uri
;
2274 if (StaticPrefs::privacy_firstparty_isolate() &&
2275 !aOriginAttributes
.mFirstPartyDomain
.IsEmpty()) {
2276 rv
= NS_NewURI(getter_AddRefs(uri
),
2277 u
"https://"_ns
+ aOriginAttributes
.mFirstPartyDomain
);
2278 } else if (!aOriginAttributes
.mPartitionKey
.IsEmpty()) {
2279 rv
= NS_NewURI(getter_AddRefs(uri
),
2280 u
"https://"_ns
+ aOriginAttributes
.mPartitionKey
);
2283 if (!NS_FAILED(rv
)) {
2284 bool isExemptPartitionKey
=
2285 nsContentUtils::IsURIInPrefList(uri
, kExemptedDomainsPrefName
);
2286 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),
2287 mozilla::LogLevel::Debug
)) {
2290 LogDomainAndPrefList("Partition Key", kExemptedDomainsPrefName
, url
,
2291 isExemptPartitionKey
);
2293 return isExemptPartitionKey
;
2298 // Functions ---------------------------------------------------
2301 bool nsContentUtils::ShouldResistFingerprinting(const char* aJustification
,
2302 RFPTarget aTarget
) {
2303 // See comment in header file for information about usage
2304 return ShouldResistFingerprinting(aTarget
);
2308 bool nsContentUtils::ShouldResistFingerprinting(CallerType aCallerType
,
2309 nsIGlobalObject
* aGlobalObject
,
2310 RFPTarget aTarget
) {
2311 if (aCallerType
== CallerType::System
) {
2314 return ShouldResistFingerprinting(aGlobalObject
, aTarget
);
2317 bool nsContentUtils::ShouldResistFingerprinting(nsIDocShell
* aDocShell
,
2318 RFPTarget aTarget
) {
2320 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2321 ("Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
2322 "with NULL docshell"));
2323 return ShouldResistFingerprinting("Null Object", aTarget
);
2325 Document
* doc
= aDocShell
->GetDocument();
2327 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2328 ("Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
2330 return ShouldResistFingerprinting(aTarget
);
2332 return doc
->ShouldResistFingerprinting(aTarget
);
2336 bool nsContentUtils::ShouldResistFingerprinting(nsIChannel
* aChannel
,
2337 RFPTarget aTarget
) {
2339 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2340 ("Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
2341 "aChannel) with NULL channel"));
2342 return ShouldResistFingerprinting("Null Object", aTarget
);
2345 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
2347 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2348 ("Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
2349 "aChannel) but the channel's loadinfo was NULL"));
2350 return ShouldResistFingerprinting("Null Object", aTarget
);
2353 // With this check, we can ensure that the prefs and target say yes, so only
2354 // an exemption would cause us to return false.
2355 if (!ShouldResistFingerprinting("Positive return check", aTarget
)) {
2359 if (ETPSaysShouldNotResistFingerprinting(aChannel
, loadInfo
)) {
2360 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2361 ("Inside ShouldResistFingerprinting(nsIChannel*)"
2362 " ETPSaysShouldNotResistFingerprinting said false"));
2366 if (CookieJarSettingsSaysShouldResistFingerprinting(loadInfo
)) {
2367 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2368 ("Inside ShouldResistFingerprinting(nsIChannel*)"
2369 " CookieJarSettingsSaysShouldResistFingerprinting said true"));
2373 // Document types have no loading principal. Subdocument types do have a
2374 // loading principal, but it is the loading principal of the parent
2375 // document; not the subdocument.
2376 auto contentType
= loadInfo
->GetExternalContentPolicyType();
2377 // Case 1: Document or Subdocument load
2378 if (contentType
== ExtContentPolicy::TYPE_DOCUMENT
||
2379 contentType
== ExtContentPolicy::TYPE_SUBDOCUMENT
) {
2380 nsCOMPtr
<nsIURI
> channelURI
;
2381 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
2384 "Failed to get URI in "
2385 "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)");
2386 // this check is to ensure that we do not crash in non-debug builds.
2387 if (NS_FAILED(rv
)) {
2392 if (loadInfo
->GetExternalContentPolicyType() == ExtContentPolicy::TYPE_SUBDOCUMENT
) {
2393 nsCOMPtr
<nsIURI
> channelURI
;
2394 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
2395 nsAutoCString channelSpec
;
2396 channelURI
->GetSpec(channelSpec
);
2398 if (!loadInfo
->GetLoadingPrincipal()) {
2399 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2400 ("Sub Document Type. FinalChannelURI is %s, Loading Principal is NULL\n",
2401 channelSpec
.get()));
2404 nsAutoCString loadingPrincipalSpec
;
2405 loadInfo
->GetLoadingPrincipal()->GetOrigin(loadingPrincipalSpec
);
2407 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2408 ("Sub Document Type. FinalChannelURI is %s, Loading Principal Origin is %s\n",
2409 channelSpec
.get(), loadingPrincipalSpec
.get()));
2415 return ShouldResistFingerprinting_dangerous(
2416 channelURI
, loadInfo
->GetOriginAttributes(), "Internal Call", aTarget
);
2419 // Case 2: Subresource Load
2420 // Because this code is only used for subresource loads, this
2421 // will check the parent's principal
2422 nsIPrincipal
* principal
= loadInfo
->GetLoadingPrincipal();
2424 MOZ_ASSERT_IF(principal
&& !principal
->IsSystemPrincipal() &&
2425 !principal
->GetIsAddonOrExpandedAddonPrincipal(),
2426 BasePrincipal::Cast(principal
)->OriginAttributesRef() ==
2427 loadInfo
->GetOriginAttributes());
2428 return ShouldResistFingerprinting_dangerous(principal
, "Internal Call",
2433 bool nsContentUtils::ShouldResistFingerprinting_dangerous(
2434 nsIURI
* aURI
, const mozilla::OriginAttributes
& aOriginAttributes
,
2435 const char* aJustification
, RFPTarget aTarget
) {
2436 // With this check, we can ensure that the prefs and target say yes, so only
2437 // an exemption would cause us to return false.
2438 if (!ShouldResistFingerprinting("Positive return check", aTarget
)) {
2442 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2443 ("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"
2444 " OriginAttributes) and the URI is %s",
2445 aURI
->GetSpecOrDefault().get()));
2447 if (!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
2448 !StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly()) {
2449 // If neither of the 'regular' RFP prefs are set, then one (or both)
2450 // of the PBM-Only prefs are set (or we would have failed the
2451 // Positive return check.) Therefore, if we are not in PBM, return false
2452 if (aOriginAttributes
.mPrivateBrowsingId
== 0) {
2457 // Exclude internal schemes and web extensions
2458 if (SchemeSaysShouldNotResistFingerprinting(aURI
)) {
2459 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2460 ("Inside ShouldResistFingerprinting(nsIURI*)"
2461 " SchemeSaysShouldNotResistFingerprinting said false"));
2465 bool isExemptDomain
= false;
2467 Preferences::GetCString(kExemptedDomainsPrefName
, list
);
2469 isExemptDomain
= IsURIInList(aURI
, list
);
2471 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),
2472 mozilla::LogLevel::Debug
)) {
2475 LogDomainAndPrefList("URI", kExemptedDomainsPrefName
, url
, isExemptDomain
);
2478 if (isExemptDomain
) {
2479 isExemptDomain
&= PartionKeyIsAlsoExempted(aOriginAttributes
);
2482 return !isExemptDomain
;
2486 bool nsContentUtils::ShouldResistFingerprinting_dangerous(
2487 nsIPrincipal
* aPrincipal
, const char* aJustification
, RFPTarget aTarget
) {
2489 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info
,
2490 ("Called nsContentUtils::ShouldResistFingerprinting(nsILoadInfo* "
2491 "aChannel) but the loadinfo's loadingprincipal was NULL"));
2492 return ShouldResistFingerprinting("Null object", aTarget
);
2495 // With this check, we can ensure that the prefs and target say yes, so only
2496 // an exemption would cause us to return false.
2497 if (!ShouldResistFingerprinting("Positive return check", aTarget
)) {
2501 if (aPrincipal
->IsSystemPrincipal()) {
2505 auto originAttributes
=
2506 BasePrincipal::Cast(aPrincipal
)->OriginAttributesRef();
2507 if (!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
2508 !StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly()) {
2509 // If neither of the 'regular' RFP prefs are set, then one (or both)
2510 // of the PBM-Only prefs are set (or we would have failed the
2511 // Positive return check.) Therefore, if we are not in PBM, return false
2512 if (originAttributes
.mPrivateBrowsingId
== 0) {
2517 // Exclude internal schemes and web extensions
2518 if (SchemeSaysShouldNotResistFingerprinting(aPrincipal
)) {
2519 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2520 ("Inside ShouldResistFingerprinting(nsIPrincipal*)"
2521 " SchemeSaysShouldNotResistFingerprinting said false"));
2525 // Web extension principals are also excluded
2526 if (BasePrincipal::Cast(aPrincipal
)->AddonPolicy()) {
2527 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug
,
2528 ("Inside ShouldResistFingerprinting_dangerous(nsIPrincipal*)"
2529 " and AddonPolicy said false"));
2533 bool isExemptDomain
= false;
2534 aPrincipal
->IsURIInPrefList(kExemptedDomainsPrefName
, &isExemptDomain
);
2536 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),
2537 mozilla::LogLevel::Debug
)) {
2538 nsAutoCString origin
;
2539 aPrincipal
->GetOrigin(origin
);
2540 LogDomainAndPrefList("URI", kExemptedDomainsPrefName
, origin
,
2544 if (isExemptDomain
) {
2545 isExemptDomain
&= PartionKeyIsAlsoExempted(originAttributes
);
2548 return !isExemptDomain
;
2551 // --------------------------------------------------------------------
2554 void nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
2555 int32_t aChromeWidth
, int32_t aChromeHeight
, int32_t aScreenWidth
,
2556 int32_t aScreenHeight
, int32_t aInputWidth
, int32_t aInputHeight
,
2557 bool aSetOuterWidth
, bool aSetOuterHeight
, int32_t* aOutputWidth
,
2558 int32_t* aOutputHeight
) {
2559 MOZ_ASSERT(aOutputWidth
);
2560 MOZ_ASSERT(aOutputHeight
);
2562 int32_t availContentWidth
= 0;
2563 int32_t availContentHeight
= 0;
2565 availContentWidth
= std::min(StaticPrefs::privacy_window_maxInnerWidth(),
2566 aScreenWidth
- aChromeWidth
);
2567 #ifdef MOZ_WIDGET_GTK
2568 // In the GTK window, it will not report outside system decorations
2569 // when we get available window size, see Bug 581863. So, we leave a
2570 // 40 pixels space for them when calculating the available content
2571 // height. It is not necessary for the width since the content width
2572 // is usually pretty much the same as the chrome width.
2573 availContentHeight
= std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2574 (-40 + aScreenHeight
) - aChromeHeight
);
2576 availContentHeight
= std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2577 aScreenHeight
- aChromeHeight
);
2580 // Ideally, we'd like to round window size to 1000x1000, but the
2581 // screen space could be too small to accommodate this size in some
2582 // cases. If it happens, we would round the window size to the nearest
2584 availContentWidth
= availContentWidth
- (availContentWidth
% 200);
2585 availContentHeight
= availContentHeight
- (availContentHeight
% 100);
2587 // If aIsOuter is true, we are setting the outer window. So we
2588 // have to consider the chrome UI.
2589 int32_t chromeOffsetWidth
= aSetOuterWidth
? aChromeWidth
: 0;
2590 int32_t chromeOffsetHeight
= aSetOuterHeight
? aChromeHeight
: 0;
2591 int32_t resultWidth
= 0, resultHeight
= 0;
2593 // if the original size is greater than the maximum available size, we set
2594 // it to the maximum size. And if the original value is less than the
2595 // minimum rounded size, we set it to the minimum 200x100.
2596 if (aInputWidth
> (availContentWidth
+ chromeOffsetWidth
)) {
2597 resultWidth
= availContentWidth
+ chromeOffsetWidth
;
2598 } else if (aInputWidth
< (200 + chromeOffsetWidth
)) {
2599 resultWidth
= 200 + chromeOffsetWidth
;
2601 // Otherwise, we round the window to the nearest upper rounded 200x100.
2602 resultWidth
= NSToIntCeil((aInputWidth
- chromeOffsetWidth
) / 200.0) * 200 +
2606 if (aInputHeight
> (availContentHeight
+ chromeOffsetHeight
)) {
2607 resultHeight
= availContentHeight
+ chromeOffsetHeight
;
2608 } else if (aInputHeight
< (100 + chromeOffsetHeight
)) {
2609 resultHeight
= 100 + chromeOffsetHeight
;
2612 NSToIntCeil((aInputHeight
- chromeOffsetHeight
) / 100.0) * 100 +
2616 *aOutputWidth
= resultWidth
;
2617 *aOutputHeight
= resultHeight
;
2620 bool nsContentUtils::ThreadsafeIsCallerChrome() {
2621 return NS_IsMainThread() ? IsCallerChrome()
2622 : IsCurrentThreadRunningChromeWorker();
2625 bool nsContentUtils::IsCallerUAWidget() {
2626 JSContext
* cx
= GetCurrentJSContext();
2631 JS::Realm
* realm
= JS::GetCurrentRealmOrNull(cx
);
2636 return xpc::IsUAWidgetScope(realm
);
2639 bool nsContentUtils::IsSystemCaller(JSContext
* aCx
) {
2640 // Note that SubjectPrincipal() assumes we are in a compartment here.
2641 return SubjectPrincipal(aCx
) == sSystemPrincipal
;
2644 bool nsContentUtils::ThreadsafeIsSystemCaller(JSContext
* aCx
) {
2645 CycleCollectedJSContext
* ccjscx
= CycleCollectedJSContext::Get();
2646 MOZ_ASSERT(ccjscx
->Context() == aCx
);
2648 return ccjscx
->IsSystemCaller();
2652 bool nsContentUtils::LookupBindingMember(
2653 JSContext
* aCx
, nsIContent
* aContent
, JS::Handle
<jsid
> aId
,
2654 JS::MutableHandle
<JS::PropertyDescriptor
> aDesc
) {
2658 nsINode
* nsContentUtils::GetNearestInProcessCrossDocParentNode(
2660 if (aChild
->IsDocument()) {
2661 for (BrowsingContext
* bc
= aChild
->AsDocument()->GetBrowsingContext(); bc
;
2662 bc
= bc
->GetParent()) {
2663 if (bc
->GetEmbedderElement()) {
2664 return bc
->GetEmbedderElement();
2670 nsINode
* parent
= aChild
->GetParentNode();
2671 if (parent
&& parent
->IsContent() && aChild
->IsContent()) {
2672 parent
= aChild
->AsContent()->GetFlattenedTreeParent();
2678 bool nsContentUtils::ContentIsHostIncludingDescendantOf(
2679 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2680 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2681 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2684 if (aPossibleDescendant
== aPossibleAncestor
) return true;
2685 if (aPossibleDescendant
->IsDocumentFragment()) {
2686 aPossibleDescendant
=
2687 aPossibleDescendant
->AsDocumentFragment()->GetHost();
2689 aPossibleDescendant
= aPossibleDescendant
->GetParentNode();
2691 } while (aPossibleDescendant
);
2697 bool nsContentUtils::ContentIsCrossDocDescendantOf(nsINode
* aPossibleDescendant
,
2698 nsINode
* aPossibleAncestor
) {
2699 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2700 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2703 if (aPossibleDescendant
== aPossibleAncestor
) {
2707 aPossibleDescendant
=
2708 GetNearestInProcessCrossDocParentNode(aPossibleDescendant
);
2709 } while (aPossibleDescendant
);
2715 bool nsContentUtils::ContentIsFlattenedTreeDescendantOf(
2716 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2717 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2718 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2721 if (aPossibleDescendant
== aPossibleAncestor
) {
2724 aPossibleDescendant
= aPossibleDescendant
->GetFlattenedTreeParentNode();
2725 } while (aPossibleDescendant
);
2731 bool nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle(
2732 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2733 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2734 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2737 if (aPossibleDescendant
== aPossibleAncestor
) {
2740 aPossibleDescendant
=
2741 aPossibleDescendant
->GetFlattenedTreeParentNodeForStyle();
2742 } while (aPossibleDescendant
);
2748 nsINode
* nsContentUtils::Retarget(nsINode
* aTargetA
, nsINode
* aTargetB
) {
2749 while (true && aTargetA
) {
2750 // If A's root is not a shadow root...
2751 nsINode
* root
= aTargetA
->SubtreeRoot();
2752 if (!root
->IsShadowRoot()) {
2753 // ...then return A.
2757 // or A's root is a shadow-including inclusive ancestor of B...
2758 if (aTargetB
->IsShadowIncludingInclusiveDescendantOf(root
)) {
2759 // ...then return A.
2763 aTargetA
= ShadowRoot::FromNode(root
)->GetHost();
2770 Element
* nsContentUtils::GetAnElementForTiming(Element
* aTarget
,
2771 const Document
* aDocument
,
2772 nsIGlobalObject
* aGlobal
) {
2773 if (!aTarget
->IsInComposedDoc()) {
2778 nsCOMPtr
<nsPIDOMWindowInner
> inner
= do_QueryInterface(aGlobal
);
2782 aDocument
= inner
->GetExtantDoc();
2785 MOZ_ASSERT(aDocument
);
2787 if (aTarget
->GetUncomposedDocOrConnectedShadowRoot() != aDocument
||
2788 !aDocument
->IsCurrentActiveDocument()) {
2796 nsresult
nsContentUtils::GetInclusiveAncestors(nsINode
* aNode
,
2797 nsTArray
<nsINode
*>& aArray
) {
2799 aArray
.AppendElement(aNode
);
2800 aNode
= aNode
->GetParentNode();
2806 nsresult
nsContentUtils::GetInclusiveAncestorsAndOffsets(
2807 nsINode
* aNode
, uint32_t aOffset
, nsTArray
<nsIContent
*>* aAncestorNodes
,
2808 nsTArray
<Maybe
<uint32_t>>* aAncestorOffsets
) {
2809 NS_ENSURE_ARG_POINTER(aNode
);
2811 if (!aNode
->IsContent()) {
2812 return NS_ERROR_FAILURE
;
2814 nsIContent
* content
= aNode
->AsContent();
2816 if (!aAncestorNodes
->IsEmpty()) {
2817 NS_WARNING("aAncestorNodes is not empty");
2818 aAncestorNodes
->Clear();
2821 if (!aAncestorOffsets
->IsEmpty()) {
2822 NS_WARNING("aAncestorOffsets is not empty");
2823 aAncestorOffsets
->Clear();
2826 // insert the node itself
2827 aAncestorNodes
->AppendElement(content
);
2828 aAncestorOffsets
->AppendElement(Some(aOffset
));
2830 // insert all the ancestors
2831 nsIContent
* child
= content
;
2832 nsIContent
* parent
= child
->GetParent();
2834 aAncestorNodes
->AppendElement(parent
);
2835 aAncestorOffsets
->AppendElement(parent
->ComputeIndexOf(child
));
2837 parent
= parent
->GetParent();
2843 template <typename Node
, typename GetParentFunc
>
2844 static Node
* GetCommonAncestorInternal(Node
* aNode1
, Node
* aNode2
,
2845 GetParentFunc aGetParentFunc
) {
2846 MOZ_ASSERT(aNode1
!= aNode2
);
2848 // Build the chain of parents
2849 AutoTArray
<Node
*, 30> parents1
, parents2
;
2851 parents1
.AppendElement(aNode1
);
2852 aNode1
= aGetParentFunc(aNode1
);
2855 parents2
.AppendElement(aNode2
);
2856 aNode2
= aGetParentFunc(aNode2
);
2859 // Find where the parent chain differs
2860 uint32_t pos1
= parents1
.Length();
2861 uint32_t pos2
= parents2
.Length();
2862 Node
** data1
= parents1
.Elements();
2863 Node
** data2
= parents2
.Elements();
2864 Node
* parent
= nullptr;
2866 for (len
= std::min(pos1
, pos2
); len
> 0; --len
) {
2867 Node
* child1
= data1
[--pos1
];
2868 Node
* child2
= data2
[--pos2
];
2869 if (child1
!= child2
) {
2879 nsINode
* nsContentUtils::GetCommonAncestorHelper(nsINode
* aNode1
,
2881 return GetCommonAncestorInternal(
2882 aNode1
, aNode2
, [](nsINode
* aNode
) { return aNode
->GetParentNode(); });
2886 nsIContent
* nsContentUtils::GetCommonFlattenedTreeAncestorHelper(
2887 nsIContent
* aContent1
, nsIContent
* aContent2
) {
2888 return GetCommonAncestorInternal(
2889 aContent1
, aContent2
,
2890 [](nsIContent
* aContent
) { return aContent
->GetFlattenedTreeParent(); });
2894 Element
* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(
2895 Element
* aElement1
, Element
* aElement2
) {
2896 return GetCommonAncestorInternal(aElement1
, aElement2
, [](Element
* aElement
) {
2897 return aElement
->GetFlattenedTreeParentElementForStyle();
2902 bool nsContentUtils::PositionIsBefore(nsINode
* aNode1
, nsINode
* aNode2
,
2903 Maybe
<uint32_t>* aNode1Index
,
2904 Maybe
<uint32_t>* aNode2Index
) {
2905 // Note, CompareDocumentPosition takes the latter params in different order.
2906 return (aNode2
->CompareDocumentPosition(*aNode1
, aNode2Index
, aNode1Index
) &
2907 (Node_Binding::DOCUMENT_POSITION_PRECEDING
|
2908 Node_Binding::DOCUMENT_POSITION_DISCONNECTED
)) ==
2909 Node_Binding::DOCUMENT_POSITION_PRECEDING
;
2913 Maybe
<int32_t> nsContentUtils::ComparePoints(
2914 const nsINode
* aParent1
, uint32_t aOffset1
, const nsINode
* aParent2
,
2915 uint32_t aOffset2
, ComparePointsCache
* aParent1Cache
) {
2916 bool disconnected
{false};
2918 const int32_t order
= ComparePoints_Deprecated(
2919 aParent1
, aOffset1
, aParent2
, aOffset2
, &disconnected
, aParent1Cache
);
2928 int32_t nsContentUtils::ComparePoints_Deprecated(
2929 const nsINode
* aParent1
, uint32_t aOffset1
, const nsINode
* aParent2
,
2930 uint32_t aOffset2
, bool* aDisconnected
, ComparePointsCache
* aParent1Cache
) {
2931 if (aParent1
== aParent2
) {
2932 return aOffset1
< aOffset2
? -1 : aOffset1
> aOffset2
? 1 : 0;
2935 AutoTArray
<const nsINode
*, 32> parents1
, parents2
;
2936 const nsINode
* node1
= aParent1
;
2937 const nsINode
* node2
= aParent2
;
2939 parents1
.AppendElement(node1
);
2940 node1
= node1
->GetParentOrShadowHostNode();
2943 parents2
.AppendElement(node2
);
2944 node2
= node2
->GetParentOrShadowHostNode();
2947 uint32_t pos1
= parents1
.Length() - 1;
2948 uint32_t pos2
= parents2
.Length() - 1;
2950 bool disconnected
= parents1
.ElementAt(pos1
) != parents2
.ElementAt(pos2
);
2951 if (aDisconnected
) {
2952 *aDisconnected
= disconnected
;
2955 NS_ASSERTION(aDisconnected
, "unexpected disconnected nodes");
2959 // Find where the parent chains differ
2960 const nsINode
* parent
= parents1
.ElementAt(pos1
);
2962 for (len
= std::min(pos1
, pos2
); len
> 0; --len
) {
2963 const nsINode
* child1
= parents1
.ElementAt(--pos1
);
2964 const nsINode
* child2
= parents2
.ElementAt(--pos2
);
2965 if (child1
!= child2
) {
2966 if (MOZ_UNLIKELY(child1
->IsShadowRoot())) {
2967 // Shadow roots come before light DOM per
2968 // https://dom.spec.whatwg.org/#concept-shadow-including-tree-order
2969 MOZ_ASSERT(!child2
->IsShadowRoot(), "Two shadow roots?");
2972 if (MOZ_UNLIKELY(child2
->IsShadowRoot())) {
2975 const Maybe
<uint32_t> child1Index
=
2976 aParent1Cache
? aParent1Cache
->ComputeIndexOf(parent
, child1
)
2977 : parent
->ComputeIndexOf(child1
);
2978 const Maybe
<uint32_t> child2Index
= parent
->ComputeIndexOf(child2
);
2979 if (MOZ_LIKELY(child1Index
.isSome() && child2Index
.isSome())) {
2980 return *child1Index
< *child2Index
? -1 : 1;
2982 // XXX Keep the odd traditional behavior for now.
2983 return child1Index
.isNothing() && child2Index
.isSome() ? -1 : 1;
2988 // The parent chains never differed, so one of the nodes is an ancestor of
2991 NS_ASSERTION(!pos1
|| !pos2
,
2992 "should have run out of parent chain for one of the nodes");
2995 const nsINode
* child2
= parents2
.ElementAt(--pos2
);
2996 const Maybe
<uint32_t> child2Index
= parent
->ComputeIndexOf(child2
);
2997 if (MOZ_UNLIKELY(NS_WARN_IF(child2Index
.isNothing()))) {
3000 return aOffset1
<= *child2Index
? -1 : 1;
3003 const nsINode
* child1
= parents1
.ElementAt(--pos1
);
3004 const Maybe
<uint32_t> child1Index
=
3005 aParent1Cache
? aParent1Cache
->ComputeIndexOf(parent
, child1
)
3006 : parent
->ComputeIndexOf(child1
);
3007 if (MOZ_UNLIKELY(NS_WARN_IF(child1Index
.isNothing()))) {
3010 return *child1Index
< aOffset2
? -1 : 1;
3014 BrowserParent
* nsContentUtils::GetCommonBrowserParentAncestor(
3015 BrowserParent
* aBrowserParent1
, BrowserParent
* aBrowserParent2
) {
3016 return GetCommonAncestorInternal(
3017 aBrowserParent1
, aBrowserParent2
, [](BrowserParent
* aBrowserParent
) {
3018 return aBrowserParent
->GetBrowserBridgeParent()
3019 ? aBrowserParent
->GetBrowserBridgeParent()->Manager()
3025 Element
* nsContentUtils::GetTargetElement(Document
* aDocument
,
3026 const nsAString
& aAnchorName
) {
3027 MOZ_ASSERT(aDocument
);
3029 if (aAnchorName
.IsEmpty()) {
3032 // 1. If there is an element in the document tree that has an ID equal to
3033 // fragment, then return the first such element in tree order.
3034 if (Element
* el
= aDocument
->GetElementById(aAnchorName
)) {
3038 // 2. If there is an a element in the document tree that has a name
3039 // attribute whose value is equal to fragment, then return the first such
3040 // element in tree order.
3042 // FIXME(emilio): Why the different code-paths for HTML and non-HTML docs?
3043 if (aDocument
->IsHTMLDocument()) {
3044 nsCOMPtr
<nsINodeList
> list
= aDocument
->GetElementsByName(aAnchorName
);
3045 // Loop through the named nodes looking for the first anchor
3046 uint32_t length
= list
->Length();
3047 for (uint32_t i
= 0; i
< length
; i
++) {
3048 nsIContent
* node
= list
->Item(i
);
3049 if (node
->IsHTMLElement(nsGkAtoms::a
)) {
3050 return node
->AsElement();
3054 constexpr auto nameSpace
= u
"http://www.w3.org/1999/xhtml"_ns
;
3055 // Get the list of anchor elements
3056 nsCOMPtr
<nsINodeList
> list
=
3057 aDocument
->GetElementsByTagNameNS(nameSpace
, u
"a"_ns
);
3058 // Loop through the anchors looking for the first one with the given name.
3059 for (uint32_t i
= 0; true; i
++) {
3060 nsIContent
* node
= list
->Item(i
);
3061 if (!node
) { // End of list
3065 // Compare the name attribute
3066 if (node
->AsElement()->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::name
,
3067 aAnchorName
, eCaseMatters
)) {
3068 return node
->AsElement();
3078 template <typename FPT
, typename FRT
, typename SPT
, typename SRT
>
3079 Maybe
<int32_t> nsContentUtils::ComparePoints(
3080 const RangeBoundaryBase
<FPT
, FRT
>& aFirstBoundary
,
3081 const RangeBoundaryBase
<SPT
, SRT
>& aSecondBoundary
) {
3082 if (!aFirstBoundary
.IsSet() || !aSecondBoundary
.IsSet()) {
3086 bool disconnected
{false};
3087 const int32_t order
=
3088 ComparePoints_Deprecated(aFirstBoundary
, aSecondBoundary
, &disconnected
);
3098 template <typename FPT
, typename FRT
, typename SPT
, typename SRT
>
3099 int32_t nsContentUtils::ComparePoints_Deprecated(
3100 const RangeBoundaryBase
<FPT
, FRT
>& aFirstBoundary
,
3101 const RangeBoundaryBase
<SPT
, SRT
>& aSecondBoundary
, bool* aDisconnected
) {
3102 if (NS_WARN_IF(!aFirstBoundary
.IsSet()) ||
3103 NS_WARN_IF(!aSecondBoundary
.IsSet())) {
3106 // XXX Re-implement this without calling `Offset()` as far as possible,
3107 // and the other overload should be an alias of this.
3108 return ComparePoints_Deprecated(
3109 aFirstBoundary
.Container(),
3110 *aFirstBoundary
.Offset(
3111 RangeBoundaryBase
<FPT
, FRT
>::OffsetFilter::kValidOrInvalidOffsets
),
3112 aSecondBoundary
.Container(),
3113 *aSecondBoundary
.Offset(
3114 RangeBoundaryBase
<SPT
, SRT
>::OffsetFilter::kValidOrInvalidOffsets
),
3118 inline bool IsCharInSet(const char* aSet
, const char16_t aChar
) {
3120 while ((ch
= *aSet
)) {
3121 if (aChar
== char16_t(ch
)) {
3130 * This method strips leading/trailing chars, in given set, from string.
3134 const nsDependentSubstring
nsContentUtils::TrimCharsInSet(
3135 const char* aSet
, const nsAString
& aValue
) {
3136 nsAString::const_iterator valueCurrent
, valueEnd
;
3138 aValue
.BeginReading(valueCurrent
);
3139 aValue
.EndReading(valueEnd
);
3141 // Skip characters in the beginning
3142 while (valueCurrent
!= valueEnd
) {
3143 if (!IsCharInSet(aSet
, *valueCurrent
)) {
3149 if (valueCurrent
!= valueEnd
) {
3152 if (!IsCharInSet(aSet
, *valueEnd
)) {
3156 ++valueEnd
; // Step beyond the last character we want in the value.
3159 // valueEnd should point to the char after the last to copy
3160 return Substring(valueCurrent
, valueEnd
);
3164 * This method strips leading and trailing whitespace from a string.
3168 template <bool IsWhitespace(char16_t
)>
3169 const nsDependentSubstring
nsContentUtils::TrimWhitespace(const nsAString
& aStr
,
3170 bool aTrimTrailing
) {
3171 nsAString::const_iterator start
, end
;
3173 aStr
.BeginReading(start
);
3174 aStr
.EndReading(end
);
3176 // Skip whitespace characters in the beginning
3177 while (start
!= end
&& IsWhitespace(*start
)) {
3181 if (aTrimTrailing
) {
3182 // Skip whitespace characters in the end.
3183 while (end
!= start
) {
3186 if (!IsWhitespace(*end
)) {
3187 // Step back to the last non-whitespace character.
3195 // Return a substring for the string w/o leading and/or trailing
3198 return Substring(start
, end
);
3201 // Declaring the templates we are going to use avoid linking issues without
3202 // inlining the method. Considering there is not so much spaces checking
3203 // methods we can consider this to be better than inlining.
3204 template const nsDependentSubstring
3205 nsContentUtils::TrimWhitespace
<nsCRT::IsAsciiSpace
>(const nsAString
&, bool);
3206 template const nsDependentSubstring
nsContentUtils::TrimWhitespace
<
3207 nsContentUtils::IsHTMLWhitespace
>(const nsAString
&, bool);
3208 template const nsDependentSubstring
nsContentUtils::TrimWhitespace
<
3209 nsContentUtils::IsHTMLWhitespaceOrNBSP
>(const nsAString
&, bool);
3211 static inline void KeyAppendSep(nsACString
& aKey
) {
3212 if (!aKey
.IsEmpty()) {
3217 static inline void KeyAppendString(const nsAString
& aString
, nsACString
& aKey
) {
3220 // Could escape separator here if collisions happen. > is not a legal char
3221 // for a name or type attribute, so we should be safe avoiding that extra
3224 AppendUTF16toUTF8(aString
, aKey
);
3227 static inline void KeyAppendString(const nsACString
& aString
,
3231 // Could escape separator here if collisions happen. > is not a legal char
3232 // for a name or type attribute, so we should be safe avoiding that extra
3235 aKey
.Append(aString
);
3238 static inline void KeyAppendInt(int32_t aInt
, nsACString
& aKey
) {
3241 aKey
.AppendInt(aInt
);
3244 static inline bool IsAutocompleteOff(const nsIContent
* aContent
) {
3245 return aContent
->IsElement() &&
3246 aContent
->AsElement()->AttrValueIs(kNameSpaceID_None
,
3247 nsGkAtoms::autocomplete
, u
"off"_ns
,
3252 void nsContentUtils::GenerateStateKey(nsIContent
* aContent
, Document
* aDocument
,
3254 MOZ_ASSERT(aContent
);
3258 uint32_t partID
= aDocument
? aDocument
->GetPartID() : 0;
3260 // Don't capture state for anonymous content
3261 if (aContent
->IsInNativeAnonymousSubtree()) {
3265 if (IsAutocompleteOff(aContent
)) {
3269 RefPtr
<Document
> doc
= aContent
->GetUncomposedDoc();
3271 KeyAppendInt(partID
, aKey
); // first append a partID
3272 bool generatedUniqueKey
= false;
3274 if (doc
&& doc
->IsHTMLOrXHTML()) {
3275 nsHTMLDocument
* htmlDoc
= doc
->AsHTMLDocument();
3277 // If we have a form control and can calculate form information, use that
3278 // as the key - it is more reliable than just recording position in the
3280 // XXXbz Is it, really? We have bugs on this, I think...
3281 // Important to have a unique key, and tag/type/name may not be.
3283 // The format of the key depends on whether the control has a form,
3284 // and whether the element was parser inserted:
3286 // [Has Form, Parser Inserted]:
3287 // fp>type>FormNum>IndOfControlInForm>FormName>name
3289 // [No Form, Parser Inserted]:
3290 // dp>type>ControlNum>name
3292 // [Has Form, Not Parser Inserted]:
3293 // fn>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
3295 // [No Form, Not Parser Inserted]:
3296 // dn>type>IndOfControlInDoc>name
3298 // XXX We don't need to use index if name is there
3299 // XXXbz We don't? Why not? I don't follow.
3301 nsCOMPtr
<nsIFormControl
> control(do_QueryInterface(aContent
));
3303 // Get the control number if this was a parser inserted element from the
3305 int32_t controlNumber
=
3306 control
->GetParserInsertedControlNumberForStateKey();
3307 bool parserInserted
= controlNumber
!= -1;
3309 RefPtr
<nsContentList
> htmlForms
;
3310 RefPtr
<nsContentList
> htmlFormControls
;
3311 if (!parserInserted
) {
3312 // Getting these lists is expensive, as we need to keep them up to date
3313 // as the document loads, so we avoid it if we don't need them.
3314 htmlDoc
->GetFormsAndFormControls(getter_AddRefs(htmlForms
),
3315 getter_AddRefs(htmlFormControls
));
3318 // Append the control type
3319 KeyAppendInt(int32_t(control
->ControlType()), aKey
);
3321 // If in a form, add form name / index of form / index in form
3322 HTMLFormElement
* formElement
= control
->GetForm();
3324 if (IsAutocompleteOff(formElement
)) {
3329 // Append the form number, if this is a parser inserted control, or
3330 // the index of the form in the document otherwise.
3331 bool appendedForm
= false;
3332 if (parserInserted
) {
3333 MOZ_ASSERT(formElement
->GetFormNumberForStateKey() != -1,
3334 "when generating a state key for a parser inserted form "
3335 "control we should have a parser inserted <form> element");
3336 KeyAppendString("fp"_ns
, aKey
);
3337 KeyAppendInt(formElement
->GetFormNumberForStateKey(), aKey
);
3338 appendedForm
= true;
3340 KeyAppendString("fn"_ns
, aKey
);
3341 int32_t index
= htmlForms
->IndexOf(formElement
, false);
3344 // XXX HACK this uses some state that was dumped into the document
3345 // specifically to fix bug 138892. What we are trying to do is
3346 // *guess* which form this control's state is found in, with the
3347 // highly likely guess that the highest form parsed so far is the
3348 // one. This code should not be on trunk, only branch.
3350 index
= htmlDoc
->GetNumFormsSynchronous() - 1;
3353 KeyAppendInt(index
, aKey
);
3354 appendedForm
= true;
3359 // Append the index of the control in the form
3360 int32_t index
= formElement
->IndexOfContent(aContent
);
3363 KeyAppendInt(index
, aKey
);
3364 generatedUniqueKey
= true;
3368 // Append the form name
3369 nsAutoString formName
;
3370 formElement
->GetAttr(nsGkAtoms::name
, formName
);
3371 KeyAppendString(formName
, aKey
);
3373 // Not in a form. Append the control number, if this is a parser
3374 // inserted control, or the index of the control in the document
3376 if (parserInserted
) {
3377 KeyAppendString("dp"_ns
, aKey
);
3378 KeyAppendInt(control
->GetParserInsertedControlNumberForStateKey(),
3380 generatedUniqueKey
= true;
3382 KeyAppendString("dn"_ns
, aKey
);
3383 int32_t index
= htmlFormControls
->IndexOf(aContent
, true);
3385 KeyAppendInt(index
, aKey
);
3386 generatedUniqueKey
= true;
3390 // Append the control name
3392 aContent
->AsElement()->GetAttr(nsGkAtoms::name
, name
);
3393 KeyAppendString(name
, aKey
);
3398 if (!generatedUniqueKey
) {
3399 // Either we didn't have a form control or we aren't in an HTML document so
3400 // we can't figure out form info. Append the tag name if it's an element
3401 // to avoid restoring state for one type of element on another type.
3402 if (aContent
->IsElement()) {
3403 KeyAppendString(nsDependentAtomString(aContent
->NodeInfo()->NameAtom()),
3406 // Append a character that is not "d" or "f" to disambiguate from
3407 // the case when we were a form control in an HTML document.
3408 KeyAppendString("o"_ns
, aKey
);
3411 // Now start at aContent and append the indices of it and all its ancestors
3412 // in their containers. That should at least pin down its position in the
3414 nsINode
* parent
= aContent
->GetParentNode();
3415 nsINode
* content
= aContent
;
3417 KeyAppendInt(parent
->ComputeIndexOf_Deprecated(content
), aKey
);
3419 parent
= content
->GetParentNode();
3425 nsIPrincipal
* nsContentUtils::SubjectPrincipal(JSContext
* aCx
) {
3426 MOZ_ASSERT(NS_IsMainThread());
3428 // As opposed to SubjectPrincipal(), we do in fact assume that
3429 // we're in a realm here; anyone who calls this function in
3430 // situations where that's not the case is doing it wrong.
3431 JS::Realm
* realm
= js::GetContextRealm(aCx
);
3434 JSPrincipals
* principals
= JS::GetRealmPrincipals(realm
);
3435 return nsJSPrincipals::get(principals
);
3439 nsIPrincipal
* nsContentUtils::SubjectPrincipal() {
3440 MOZ_ASSERT(IsInitialized());
3441 MOZ_ASSERT(NS_IsMainThread());
3442 JSContext
* cx
= GetCurrentJSContext();
3445 "Accessing the Subject Principal without an AutoJSAPI on the stack is "
3449 JS::Realm
* realm
= js::GetContextRealm(cx
);
3451 // When an AutoJSAPI is instantiated, we are in a null realm until the
3452 // first JSAutoRealm, which is kind of a purgatory as far as permissions
3453 // go. It would be nice to just hard-abort if somebody does a security check
3454 // in this purgatory zone, but that would be too fragile, since it could be
3455 // triggered by random IsCallerChrome() checks 20-levels deep.
3457 // So we want to return _something_ here - and definitely not the System
3458 // Principal, since that would make an AutoJSAPI a very dangerous thing to
3461 // The natural thing to return is a null principal. Ideally, we'd return a
3462 // different null principal each time, to avoid any unexpected interactions
3463 // when the principal accidentally gets inherited somewhere. But
3464 // SubjectPrincipal doesn't return strong references, so there's no way to
3465 // sanely manage the lifetime of multiple null principals.
3467 // So we use a singleton null principal. To avoid it being accidentally
3468 // inherited and becoming a "real" subject or object principal, we do a
3469 // release-mode assert during realm creation against using this principal on
3470 // an actual global.
3472 return sNullSubjectPrincipal
;
3475 return SubjectPrincipal(cx
);
3479 nsIPrincipal
* nsContentUtils::ObjectPrincipal(JSObject
* aObj
) {
3481 JS::AssertObjectBelongsToCurrentThread(aObj
);
3484 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(aObj
));
3486 JS::Realm
* realm
= js::GetNonCCWObjectRealm(aObj
);
3487 JSPrincipals
* principals
= JS::GetRealmPrincipals(realm
);
3488 return nsJSPrincipals::get(principals
);
3492 nsresult
nsContentUtils::NewURIWithDocumentCharset(nsIURI
** aResult
,
3493 const nsAString
& aSpec
,
3494 Document
* aDocument
,
3497 return NS_NewURI(aResult
, aSpec
, aDocument
->GetDocumentCharacterSet(),
3500 return NS_NewURI(aResult
, aSpec
, nullptr, aBaseURI
);
3504 bool nsContentUtils::IsNameWithDash(nsAtom
* aName
) {
3505 // A valid custom element name is a sequence of characters name which
3506 // must match the PotentialCustomElementName production:
3507 // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
3508 const char16_t
* name
= aName
->GetUTF16String();
3509 uint32_t len
= aName
->GetLength();
3510 bool hasDash
= false;
3512 if (!len
|| name
[0] < 'a' || name
[0] > 'z') {
3518 if (i
+ 1 < len
&& NS_IS_SURROGATE_PAIR(name
[i
], name
[i
+ 1])) {
3519 // Merged two 16-bit surrogate pairs into code point.
3520 char32_t code
= SURROGATE_TO_UCS4(name
[i
], name
[i
+ 1]);
3522 if (code
< 0x10000 || code
> 0xEFFFF) {
3528 if (name
[i
] == '-') {
3532 if (name
[i
] != '-' && name
[i
] != '.' && name
[i
] != '_' &&
3533 name
[i
] != 0xB7 && (name
[i
] < '0' || name
[i
] > '9') &&
3534 (name
[i
] < 'a' || name
[i
] > 'z') &&
3535 (name
[i
] < 0xC0 || name
[i
] > 0xD6) &&
3536 (name
[i
] < 0xF8 || name
[i
] > 0x37D) &&
3537 (name
[i
] < 0x37F || name
[i
] > 0x1FFF) &&
3538 (name
[i
] < 0x200C || name
[i
] > 0x200D) &&
3539 (name
[i
] < 0x203F || name
[i
] > 0x2040) &&
3540 (name
[i
] < 0x2070 || name
[i
] > 0x218F) &&
3541 (name
[i
] < 0x2C00 || name
[i
] > 0x2FEF) &&
3542 (name
[i
] < 0x3001 || name
[i
] > 0xD7FF) &&
3543 (name
[i
] < 0xF900 || name
[i
] > 0xFDCF) &&
3544 (name
[i
] < 0xFDF0 || name
[i
] > 0xFFFD)) {
3556 bool nsContentUtils::IsCustomElementName(nsAtom
* aName
, uint32_t aNameSpaceID
) {
3557 // Allow non-dashed names in XUL for XBL to Custom Element migrations.
3558 if (aNameSpaceID
== kNameSpaceID_XUL
) {
3562 bool hasDash
= IsNameWithDash(aName
);
3567 // The custom element name must not be one of the following values:
3576 return aName
!= nsGkAtoms::annotation_xml_
&&
3577 aName
!= nsGkAtoms::colorProfile
&& aName
!= nsGkAtoms::font_face
&&
3578 aName
!= nsGkAtoms::font_face_src
&&
3579 aName
!= nsGkAtoms::font_face_uri
&&
3580 aName
!= nsGkAtoms::font_face_format
&&
3581 aName
!= nsGkAtoms::font_face_name
&& aName
!= nsGkAtoms::missingGlyph
;
3585 nsresult
nsContentUtils::CheckQName(const nsAString
& aQualifiedName
,
3586 bool aNamespaceAware
,
3587 const char16_t
** aColon
) {
3588 const char* colon
= nullptr;
3589 const char16_t
* begin
= aQualifiedName
.BeginReading();
3590 const char16_t
* end
= aQualifiedName
.EndReading();
3592 int result
= MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin
),
3593 reinterpret_cast<const char*>(end
),
3594 aNamespaceAware
, &colon
);
3598 *aColon
= reinterpret_cast<const char16_t
*>(colon
);
3604 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
3608 nsresult
nsContentUtils::SplitQName(const nsIContent
* aNamespaceResolver
,
3609 const nsString
& aQName
, int32_t* aNamespace
,
3610 nsAtom
** aLocalName
) {
3611 const char16_t
* colon
;
3612 nsresult rv
= nsContentUtils::CheckQName(aQName
, true, &colon
);
3613 NS_ENSURE_SUCCESS(rv
, rv
);
3616 const char16_t
* end
;
3617 aQName
.EndReading(end
);
3618 nsAutoString nameSpace
;
3619 rv
= aNamespaceResolver
->LookupNamespaceURIInternal(
3620 Substring(aQName
.get(), colon
), nameSpace
);
3621 NS_ENSURE_SUCCESS(rv
, rv
);
3623 *aNamespace
= nsNameSpaceManager::GetInstance()->GetNameSpaceID(
3624 nameSpace
, nsContentUtils::IsChromeDoc(aNamespaceResolver
->OwnerDoc()));
3625 if (*aNamespace
== kNameSpaceID_Unknown
) return NS_ERROR_FAILURE
;
3627 *aLocalName
= NS_AtomizeMainThread(Substring(colon
+ 1, end
)).take();
3629 *aNamespace
= kNameSpaceID_None
;
3630 *aLocalName
= NS_AtomizeMainThread(aQName
).take();
3632 NS_ENSURE_TRUE(aLocalName
, NS_ERROR_OUT_OF_MEMORY
);
3637 nsresult
nsContentUtils::GetNodeInfoFromQName(
3638 const nsAString
& aNamespaceURI
, const nsAString
& aQualifiedName
,
3639 nsNodeInfoManager
* aNodeInfoManager
, uint16_t aNodeType
,
3640 mozilla::dom::NodeInfo
** aNodeInfo
) {
3641 const nsString
& qName
= PromiseFlatString(aQualifiedName
);
3642 const char16_t
* colon
;
3643 nsresult rv
= nsContentUtils::CheckQName(qName
, true, &colon
);
3644 NS_ENSURE_SUCCESS(rv
, rv
);
3647 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI
, nsID
);
3649 const char16_t
* end
;
3650 qName
.EndReading(end
);
3652 RefPtr
<nsAtom
> prefix
= NS_AtomizeMainThread(Substring(qName
.get(), colon
));
3654 rv
= aNodeInfoManager
->GetNodeInfo(Substring(colon
+ 1, end
), prefix
, nsID
,
3655 aNodeType
, aNodeInfo
);
3657 rv
= aNodeInfoManager
->GetNodeInfo(aQualifiedName
, nullptr, nsID
, aNodeType
,
3660 NS_ENSURE_SUCCESS(rv
, rv
);
3662 return nsContentUtils::IsValidNodeName((*aNodeInfo
)->NameAtom(),
3663 (*aNodeInfo
)->GetPrefixAtom(),
3664 (*aNodeInfo
)->NamespaceID())
3666 : NS_ERROR_DOM_NAMESPACE_ERR
;
3670 void nsContentUtils::SplitExpatName(const char16_t
* aExpatName
,
3671 nsAtom
** aPrefix
, nsAtom
** aLocalName
,
3672 int32_t* aNameSpaceID
) {
3674 * Expat can send the following:
3676 * namespaceURI<separator>localName
3677 * namespaceURI<separator>localName<separator>prefix
3679 * and we use 0xFFFF for the <separator>.
3683 const char16_t
* uriEnd
= nullptr;
3684 const char16_t
* nameEnd
= nullptr;
3685 const char16_t
* pos
;
3686 for (pos
= aExpatName
; *pos
; ++pos
) {
3687 if (*pos
== 0xFFFF) {
3696 const char16_t
* nameStart
;
3698 nsNameSpaceManager::GetInstance()->RegisterNameSpace(
3699 nsDependentSubstring(aExpatName
, uriEnd
), *aNameSpaceID
);
3701 nameStart
= (uriEnd
+ 1);
3703 const char16_t
* prefixStart
= nameEnd
+ 1;
3704 *aPrefix
= NS_AtomizeMainThread(Substring(prefixStart
, pos
)).take();
3710 *aNameSpaceID
= kNameSpaceID_None
;
3711 nameStart
= aExpatName
;
3715 *aLocalName
= NS_AtomizeMainThread(Substring(nameStart
, nameEnd
)).take();
3719 PresShell
* nsContentUtils::GetPresShellForContent(const nsIContent
* aContent
) {
3720 Document
* doc
= aContent
->GetComposedDoc();
3724 return doc
->GetPresShell();
3728 nsPresContext
* nsContentUtils::GetContextForContent(
3729 const nsIContent
* aContent
) {
3730 PresShell
* presShell
= GetPresShellForContent(aContent
);
3734 return presShell
->GetPresContext();
3738 bool nsContentUtils::CanLoadImage(nsIURI
* aURI
, nsINode
* aNode
,
3739 Document
* aLoadingDocument
,
3740 nsIPrincipal
* aLoadingPrincipal
) {
3741 MOZ_ASSERT(aURI
, "Must have a URI");
3742 MOZ_ASSERT(aLoadingDocument
, "Must have a document");
3743 MOZ_ASSERT(aLoadingPrincipal
, "Must have a loading principal");
3747 auto appType
= nsIDocShell::APP_TYPE_UNKNOWN
;
3750 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
=
3751 aLoadingDocument
->GetDocShell();
3752 if (docShellTreeItem
) {
3753 nsCOMPtr
<nsIDocShellTreeItem
> root
;
3754 docShellTreeItem
->GetInProcessRootTreeItem(getter_AddRefs(root
));
3756 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(root
));
3759 appType
= docShell
->GetAppType();
3764 if (appType
!= nsIDocShell::APP_TYPE_EDITOR
) {
3765 // Editor apps get special treatment here, editors can load images
3766 // from anywhere. This allows editor to insert images from file://
3767 // into documents that are being edited.
3768 rv
= sSecurityManager
->CheckLoadURIWithPrincipal(
3769 aLoadingPrincipal
, aURI
, nsIScriptSecurityManager::ALLOW_CHROME
,
3770 aLoadingDocument
->InnerWindowID());
3771 if (NS_FAILED(rv
)) {
3776 nsCOMPtr
<nsILoadInfo
> secCheckLoadInfo
= new mozilla::net::LoadInfo(
3778 aLoadingPrincipal
, // triggering principal
3779 aNode
, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
,
3780 nsIContentPolicy::TYPE_INTERNAL_IMAGE
);
3782 int16_t decision
= nsIContentPolicy::ACCEPT
;
3784 rv
= NS_CheckContentLoadPolicy(aURI
, secCheckLoadInfo
,
3785 ""_ns
, // mime guess
3786 &decision
, GetContentPolicy());
3788 return NS_SUCCEEDED(rv
) && NS_CP_ACCEPTED(decision
);
3792 bool nsContentUtils::IsInPrivateBrowsing(Document
* aDoc
) {
3797 nsCOMPtr
<nsILoadGroup
> loadGroup
= aDoc
->GetDocumentLoadGroup();
3799 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
3800 loadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
3802 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
3804 return loadContext
->UsePrivateBrowsing();
3809 nsCOMPtr
<nsIChannel
> channel
= aDoc
->GetChannel();
3810 return channel
&& NS_UsePrivateBrowsing(channel
);
3814 bool nsContentUtils::IsInPrivateBrowsing(nsILoadGroup
* aLoadGroup
) {
3818 bool isPrivate
= false;
3819 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
3820 aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
3822 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
3823 isPrivate
= loadContext
&& loadContext
->UsePrivateBrowsing();
3828 // FIXME(emilio): This is (effectively) almost but not quite the same as
3829 // Document::ShouldLoadImages(), which one is right?
3830 bool nsContentUtils::DocumentInactiveForImageLoads(Document
* aDocument
) {
3834 if (IsChromeDoc(aDocument
) || aDocument
->IsResourceDoc() ||
3835 aDocument
->IsStaticDocument()) {
3838 nsCOMPtr
<nsPIDOMWindowInner
> win
=
3839 do_QueryInterface(aDocument
->GetScopeObject());
3840 return !win
|| !win
->GetDocShell();
3843 imgLoader
* nsContentUtils::GetImgLoaderForDocument(Document
* aDoc
) {
3844 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc
), nullptr);
3847 return imgLoader::NormalLoader();
3849 bool isPrivate
= IsInPrivateBrowsing(aDoc
);
3850 return isPrivate
? imgLoader::PrivateBrowsingLoader()
3851 : imgLoader::NormalLoader();
3855 imgLoader
* nsContentUtils::GetImgLoaderForChannel(nsIChannel
* aChannel
,
3856 Document
* aContext
) {
3857 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext
), nullptr);
3860 return imgLoader::NormalLoader();
3862 nsCOMPtr
<nsILoadContext
> context
;
3863 NS_QueryNotificationCallbacks(aChannel
, context
);
3864 return context
&& context
->UsePrivateBrowsing()
3865 ? imgLoader::PrivateBrowsingLoader()
3866 : imgLoader::NormalLoader();
3870 int32_t nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode
) {
3872 case CORS_ANONYMOUS
:
3873 return imgILoader::LOAD_CORS_ANONYMOUS
;
3874 case CORS_USE_CREDENTIALS
:
3875 return imgILoader::LOAD_CORS_USE_CREDENTIALS
;
3882 nsresult
nsContentUtils::LoadImage(
3883 nsIURI
* aURI
, nsINode
* aContext
, Document
* aLoadingDocument
,
3884 nsIPrincipal
* aLoadingPrincipal
, uint64_t aRequestContextID
,
3885 nsIReferrerInfo
* aReferrerInfo
, imgINotificationObserver
* aObserver
,
3886 int32_t aLoadFlags
, const nsAString
& initiatorType
,
3887 imgRequestProxy
** aRequest
, nsContentPolicyType aContentPolicyType
,
3888 bool aUseUrgentStartForChannel
, bool aLinkPreload
,
3889 uint64_t aEarlyHintPreloaderId
) {
3890 MOZ_ASSERT(aURI
, "Must have a URI");
3891 MOZ_ASSERT(aContext
, "Must have a context");
3892 MOZ_ASSERT(aLoadingDocument
, "Must have a document");
3893 MOZ_ASSERT(aLoadingPrincipal
, "Must have a principal");
3894 MOZ_ASSERT(aRequest
, "Null out param");
3896 imgLoader
* imgLoader
= GetImgLoaderForDocument(aLoadingDocument
);
3898 // nothing we can do here
3899 return NS_ERROR_FAILURE
;
3902 nsCOMPtr
<nsILoadGroup
> loadGroup
= aLoadingDocument
->GetDocumentLoadGroup();
3904 nsIURI
* documentURI
= aLoadingDocument
->GetDocumentURI();
3906 NS_ASSERTION(loadGroup
|| aLoadingDocument
->IsSVGGlyphsDocument(),
3907 "Could not get loadgroup; onload may fire too early");
3909 // XXXbz using "documentURI" for the initialDocumentURI is not quite
3910 // right, but the best we can do here...
3911 return imgLoader
->LoadImage(aURI
, /* uri to load */
3912 documentURI
, /* initialDocumentURI */
3913 aReferrerInfo
, /* referrerInfo */
3914 aLoadingPrincipal
, /* loading principal */
3915 aRequestContextID
, /* request context ID */
3916 loadGroup
, /* loadgroup */
3917 aObserver
, /* imgINotificationObserver */
3918 aContext
, /* loading context */
3919 aLoadingDocument
, /* uniquification key */
3920 aLoadFlags
, /* load flags */
3921 nullptr, /* cache key */
3922 aContentPolicyType
, /* content policy type */
3923 initiatorType
, /* the load initiator */
3924 aUseUrgentStartForChannel
, /* urgent-start flag */
3925 aLinkPreload
, /* <link preload> initiator */
3926 aEarlyHintPreloaderId
, aRequest
);
3930 already_AddRefed
<imgIContainer
> nsContentUtils::GetImageFromContent(
3931 nsIImageLoadingContent
* aContent
, imgIRequest
** aRequest
) {
3933 *aRequest
= nullptr;
3936 NS_ENSURE_TRUE(aContent
, nullptr);
3938 nsCOMPtr
<imgIRequest
> imgRequest
;
3939 aContent
->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST
,
3940 getter_AddRefs(imgRequest
));
3945 nsCOMPtr
<imgIContainer
> imgContainer
;
3946 imgRequest
->GetImage(getter_AddRefs(imgContainer
));
3948 if (!imgContainer
) {
3953 // If the consumer wants the request, verify it has actually loaded
3956 imgRequest
->GetImageStatus(&imgStatus
);
3957 if (imgStatus
& imgIRequest::STATUS_FRAME_COMPLETE
&&
3958 !(imgStatus
& imgIRequest::STATUS_ERROR
)) {
3959 imgRequest
.swap(*aRequest
);
3963 return imgContainer
.forget();
3966 static bool IsLinkWithURI(const nsIContent
& aContent
) {
3967 const auto* element
= Element::FromNode(aContent
);
3968 if (!element
|| !element
->IsLink()) {
3971 nsCOMPtr
<nsIURI
> absURI
= element
->GetHrefURI();
3975 static bool HasImageRequest(nsIContent
& aContent
) {
3976 nsCOMPtr
<nsIImageLoadingContent
> imageContent(do_QueryInterface(&aContent
));
3977 if (!imageContent
) {
3981 nsCOMPtr
<imgIRequest
> imgRequest
;
3982 imageContent
->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST
,
3983 getter_AddRefs(imgRequest
));
3985 // XXXbz It may be draggable even if the request resulted in an error. Why?
3986 // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
3987 return !!imgRequest
;
3990 static Maybe
<bool> DraggableOverride(const nsIContent
& aContent
) {
3991 if (auto* el
= nsGenericHTMLElement::FromNode(aContent
)) {
3992 if (el
->Draggable()) {
3996 if (el
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::draggable
,
3997 nsGkAtoms::_false
, eIgnoreCase
)) {
4001 if (aContent
.IsSVGElement()) {
4008 bool nsContentUtils::ContentIsDraggable(nsIContent
* aContent
) {
4009 MOZ_ASSERT(aContent
);
4011 if (auto draggable
= DraggableOverride(*aContent
)) {
4015 // special handling for content area image and link dragging
4016 return HasImageRequest(*aContent
) || IsLinkWithURI(*aContent
);
4020 bool nsContentUtils::IsDraggableImage(nsIContent
* aContent
) {
4021 MOZ_ASSERT(aContent
);
4022 return HasImageRequest(*aContent
) &&
4023 DraggableOverride(*aContent
).valueOr(true);
4027 bool nsContentUtils::IsDraggableLink(const nsIContent
* aContent
) {
4028 MOZ_ASSERT(aContent
);
4029 return IsLinkWithURI(*aContent
) && DraggableOverride(*aContent
).valueOr(true);
4033 nsresult
nsContentUtils::QNameChanged(mozilla::dom::NodeInfo
* aNodeInfo
,
4035 mozilla::dom::NodeInfo
** aResult
) {
4036 nsNodeInfoManager
* niMgr
= aNodeInfo
->NodeInfoManager();
4039 ->GetNodeInfo(aName
, nullptr, aNodeInfo
->NamespaceID(),
4040 aNodeInfo
->NodeType(), aNodeInfo
->GetExtraName())
4045 static bool TestSitePerm(nsIPrincipal
* aPrincipal
, const nsACString
& aType
,
4046 uint32_t aPerm
, bool aExactHostMatch
) {
4048 // We always deny (i.e. don't allow) the permission if we don't have a
4050 return aPerm
!= nsIPermissionManager::ALLOW_ACTION
;
4053 nsCOMPtr
<nsIPermissionManager
> permMgr
=
4054 components::PermissionManager::Service();
4055 NS_ENSURE_TRUE(permMgr
, false);
4059 if (aExactHostMatch
) {
4060 rv
= permMgr
->TestExactPermissionFromPrincipal(aPrincipal
, aType
, &perm
);
4062 rv
= permMgr
->TestPermissionFromPrincipal(aPrincipal
, aType
, &perm
);
4064 NS_ENSURE_SUCCESS(rv
, false);
4066 return perm
== aPerm
;
4069 bool nsContentUtils::IsSitePermAllow(nsIPrincipal
* aPrincipal
,
4070 const nsACString
& aType
) {
4071 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::ALLOW_ACTION
,
4075 bool nsContentUtils::IsSitePermDeny(nsIPrincipal
* aPrincipal
,
4076 const nsACString
& aType
) {
4077 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::DENY_ACTION
,
4081 bool nsContentUtils::IsExactSitePermAllow(nsIPrincipal
* aPrincipal
,
4082 const nsACString
& aType
) {
4083 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::ALLOW_ACTION
,
4087 bool nsContentUtils::IsExactSitePermDeny(nsIPrincipal
* aPrincipal
,
4088 const nsACString
& aType
) {
4089 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::DENY_ACTION
,
4093 bool nsContentUtils::HasSitePerm(nsIPrincipal
* aPrincipal
,
4094 const nsACString
& aType
) {
4099 nsCOMPtr
<nsIPermissionManager
> permMgr
=
4100 components::PermissionManager::Service();
4101 NS_ENSURE_TRUE(permMgr
, false);
4104 nsresult rv
= permMgr
->TestPermissionFromPrincipal(aPrincipal
, aType
, &perm
);
4105 NS_ENSURE_SUCCESS(rv
, false);
4107 return perm
!= nsIPermissionManager::UNKNOWN_ACTION
;
4110 static const char* gEventNames
[] = {"event"};
4111 static const char* gSVGEventNames
[] = {"evt"};
4112 // for b/w compat, the first name to onerror is still 'event', even though it
4113 // is actually the error message
4114 static const char* gOnErrorNames
[] = {"event", "source", "lineno", "colno",
4118 void nsContentUtils::GetEventArgNames(int32_t aNameSpaceID
, nsAtom
* aEventName
,
4119 bool aIsForWindow
, uint32_t* aArgCount
,
4120 const char*** aArgArray
) {
4121 #define SET_EVENT_ARG_NAMES(names) \
4122 *aArgCount = sizeof(names) / sizeof(names[0]); \
4125 // JSEventHandler is what does the arg magic for onerror, and it does
4126 // not seem to take the namespace into account. So we let onerror in all
4127 // namespaces get the 3 arg names.
4128 if (aEventName
== nsGkAtoms::onerror
&& aIsForWindow
) {
4129 SET_EVENT_ARG_NAMES(gOnErrorNames
);
4130 } else if (aNameSpaceID
== kNameSpaceID_SVG
) {
4131 SET_EVENT_ARG_NAMES(gSVGEventNames
);
4133 SET_EVENT_ARG_NAMES(gEventNames
);
4137 // Note: The list of content bundles in nsStringBundle.cpp should be updated
4138 // whenever entries are added or removed from this list.
4139 static const char* gPropertiesFiles
[nsContentUtils::PropertiesFile_COUNT
] = {
4140 // Must line up with the enum values in |PropertiesFile| enum.
4141 "chrome://global/locale/css.properties",
4142 "chrome://global/locale/xul.properties",
4143 "chrome://global/locale/layout_errors.properties",
4144 "chrome://global/locale/layout/HtmlForm.properties",
4145 "chrome://global/locale/printing.properties",
4146 "chrome://global/locale/dom/dom.properties",
4147 "chrome://global/locale/layout/htmlparser.properties",
4148 "chrome://global/locale/svg/svg.properties",
4149 "chrome://branding/locale/brand.properties",
4150 "chrome://global/locale/commonDialogs.properties",
4151 "chrome://global/locale/mathml/mathml.properties",
4152 "chrome://global/locale/security/security.properties",
4153 "chrome://necko/locale/necko.properties",
4154 "resource://gre/res/locale/layout/HtmlForm.properties",
4155 "resource://gre/res/locale/dom/dom.properties"};
4158 nsresult
nsContentUtils::EnsureStringBundle(PropertiesFile aFile
) {
4159 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
4160 "Should not create bundles off main thread.");
4161 if (!sStringBundles
[aFile
]) {
4162 if (!sStringBundleService
) {
4164 CallGetService(NS_STRINGBUNDLE_CONTRACTID
, &sStringBundleService
);
4165 NS_ENSURE_SUCCESS(rv
, rv
);
4167 RefPtr
<nsIStringBundle
> bundle
;
4168 MOZ_TRY(sStringBundleService
->CreateBundle(gPropertiesFiles
[aFile
],
4169 getter_AddRefs(bundle
)));
4170 sStringBundles
[aFile
] = bundle
.forget();
4176 void nsContentUtils::AsyncPrecreateStringBundles() {
4177 // We only ever want to pre-create bundles in the parent process.
4179 // All nsContentUtils bundles are shared between the parent and child
4180 // precesses, and the shared memory regions that back them *must* be created
4181 // in the parent, and then sent to all children.
4183 // If we attempt to create a bundle in the child before its memory region is
4184 // available, we need to create a temporary non-shared bundle, and later
4185 // replace that with the shared memory copy. So attempting to pre-load in the
4186 // child is wasteful and unnecessary.
4187 MOZ_ASSERT(XRE_IsParentProcess());
4189 for (uint32_t bundleIndex
= 0; bundleIndex
< PropertiesFile_COUNT
;
4191 nsresult rv
= NS_DispatchToCurrentThreadQueue(
4192 NS_NewRunnableFunction("AsyncPrecreateStringBundles",
4194 PropertiesFile file
=
4195 static_cast<PropertiesFile
>(bundleIndex
);
4196 EnsureStringBundle(file
);
4197 nsIStringBundle
* bundle
= sStringBundles
[file
];
4198 bundle
->AsyncPreload();
4200 EventQueuePriority::Idle
);
4201 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
4206 bool nsContentUtils::SpoofLocaleEnglish() {
4210 return StaticPrefs::privacy_spoof_english() == 2;
4213 static nsContentUtils::PropertiesFile
GetMaybeSpoofedPropertiesFile(
4214 nsContentUtils::PropertiesFile aFile
, const char* aKey
,
4215 Document
* aDocument
) {
4216 // When we spoof English, use en-US properties in strings that are accessible
4218 bool spoofLocale
= nsContentUtils::SpoofLocaleEnglish() &&
4219 (!aDocument
|| !aDocument
->AllowsL10n());
4222 case nsContentUtils::eFORMS_PROPERTIES
:
4223 return nsContentUtils::eFORMS_PROPERTIES_en_US
;
4224 case nsContentUtils::eDOM_PROPERTIES
:
4225 return nsContentUtils::eDOM_PROPERTIES_en_US
;
4234 nsresult
nsContentUtils::GetMaybeLocalizedString(PropertiesFile aFile
,
4236 Document
* aDocument
,
4237 nsAString
& aResult
) {
4238 return GetLocalizedString(
4239 GetMaybeSpoofedPropertiesFile(aFile
, aKey
, aDocument
), aKey
, aResult
);
4243 nsresult
nsContentUtils::GetLocalizedString(PropertiesFile aFile
,
4245 nsAString
& aResult
) {
4246 return FormatLocalizedString(aFile
, aKey
, {}, aResult
);
4250 nsresult
nsContentUtils::FormatMaybeLocalizedString(
4251 PropertiesFile aFile
, const char* aKey
, Document
* aDocument
,
4252 const nsTArray
<nsString
>& aParams
, nsAString
& aResult
) {
4253 return FormatLocalizedString(
4254 GetMaybeSpoofedPropertiesFile(aFile
, aKey
, aDocument
), aKey
, aParams
,
4258 class FormatLocalizedStringRunnable final
: public WorkerMainThreadRunnable
{
4260 FormatLocalizedStringRunnable(WorkerPrivate
* aWorkerPrivate
,
4261 nsContentUtils::PropertiesFile aFile
,
4263 const nsTArray
<nsString
>& aParams
,
4264 nsAString
& aLocalizedString
)
4265 : WorkerMainThreadRunnable(aWorkerPrivate
,
4266 "FormatLocalizedStringRunnable"_ns
),
4270 mLocalizedString(aLocalizedString
) {
4271 MOZ_ASSERT(aWorkerPrivate
);
4272 aWorkerPrivate
->AssertIsOnWorkerThread();
4275 bool MainThreadRun() override
{
4276 AssertIsOnMainThread();
4278 mResult
= nsContentUtils::FormatLocalizedString(mFile
, mKey
, mParams
,
4280 Unused
<< NS_WARN_IF(NS_FAILED(mResult
));
4284 nsresult
GetResult() const { return mResult
; }
4287 const nsContentUtils::PropertiesFile mFile
;
4289 const nsTArray
<nsString
>& mParams
;
4290 nsresult mResult
= NS_ERROR_FAILURE
;
4291 nsAString
& mLocalizedString
;
4295 nsresult
nsContentUtils::FormatLocalizedString(
4296 PropertiesFile aFile
, const char* aKey
, const nsTArray
<nsString
>& aParams
,
4297 nsAString
& aResult
) {
4298 if (!NS_IsMainThread()) {
4299 // nsIStringBundle is thread-safe but its creation is not, and in particular
4300 // we don't create and store nsIStringBundle objects in a thread-safe way.
4302 // TODO(emilio): Maybe if we already have the right bundle created we could
4303 // just call into it, but we should make sure that Shutdown() doesn't get
4304 // called on the main thread when that happens which is a bit tricky to
4306 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
4307 if (NS_WARN_IF(!workerPrivate
)) {
4308 return NS_ERROR_UNEXPECTED
;
4311 auto runnable
= MakeRefPtr
<FormatLocalizedStringRunnable
>(
4312 workerPrivate
, aFile
, aKey
, aParams
, aResult
);
4314 runnable
->Dispatch(Canceling
, IgnoreErrors());
4315 return runnable
->GetResult();
4318 MOZ_TRY(EnsureStringBundle(aFile
));
4319 nsIStringBundle
* bundle
= sStringBundles
[aFile
];
4320 if (aParams
.IsEmpty()) {
4321 return bundle
->GetStringFromName(aKey
, aResult
);
4323 return bundle
->FormatStringFromName(aKey
, aParams
, aResult
);
4327 void nsContentUtils::LogSimpleConsoleError(const nsAString
& aErrorText
,
4328 const nsACString
& aCategory
,
4329 bool aFromPrivateWindow
,
4330 bool aFromChromeContext
,
4331 uint32_t aErrorFlags
) {
4332 nsCOMPtr
<nsIScriptError
> scriptError
=
4333 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
);
4335 nsCOMPtr
<nsIConsoleService
> console
=
4336 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
4337 if (console
&& NS_SUCCEEDED(scriptError
->Init(
4338 aErrorText
, u
""_ns
, u
""_ns
, 0, 0, aErrorFlags
, aCategory
,
4339 aFromPrivateWindow
, aFromChromeContext
))) {
4340 console
->LogMessage(scriptError
);
4346 nsresult
nsContentUtils::ReportToConsole(
4347 uint32_t aErrorFlags
, const nsACString
& aCategory
,
4348 const Document
* aDocument
, PropertiesFile aFile
, const char* aMessageName
,
4349 const nsTArray
<nsString
>& aParams
, nsIURI
* aURI
,
4350 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
) {
4352 nsAutoString errorText
;
4353 if (!aParams
.IsEmpty()) {
4354 rv
= FormatLocalizedString(aFile
, aMessageName
, aParams
, errorText
);
4356 rv
= GetLocalizedString(aFile
, aMessageName
, errorText
);
4358 NS_ENSURE_SUCCESS(rv
, rv
);
4360 return ReportToConsoleNonLocalized(errorText
, aErrorFlags
, aCategory
,
4361 aDocument
, aURI
, aSourceLine
, aLineNumber
,
4366 void nsContentUtils::ReportEmptyGetElementByIdArg(const Document
* aDoc
) {
4367 ReportToConsole(nsIScriptError::warningFlag
, "DOM"_ns
, aDoc
,
4368 nsContentUtils::eDOM_PROPERTIES
, "EmptyGetElementByIdParam");
4372 nsresult
nsContentUtils::ReportToConsoleNonLocalized(
4373 const nsAString
& aErrorText
, uint32_t aErrorFlags
,
4374 const nsACString
& aCategory
, const Document
* aDocument
, nsIURI
* aURI
,
4375 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
,
4376 MissingErrorLocationMode aLocationMode
) {
4377 uint64_t innerWindowID
= 0;
4380 aURI
= aDocument
->GetDocumentURI();
4382 innerWindowID
= aDocument
->InnerWindowID();
4385 return ReportToConsoleByWindowID(aErrorText
, aErrorFlags
, aCategory
,
4386 innerWindowID
, aURI
, aSourceLine
,
4387 aLineNumber
, aColumnNumber
, aLocationMode
);
4391 nsresult
nsContentUtils::ReportToConsoleByWindowID(
4392 const nsAString
& aErrorText
, uint32_t aErrorFlags
,
4393 const nsACString
& aCategory
, uint64_t aInnerWindowID
, nsIURI
* aURI
,
4394 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
,
4395 MissingErrorLocationMode aLocationMode
) {
4397 if (!sConsoleService
) { // only need to bother null-checking here
4398 rv
= CallGetService(NS_CONSOLESERVICE_CONTRACTID
, &sConsoleService
);
4399 NS_ENSURE_SUCCESS(rv
, rv
);
4403 if (!aLineNumber
&& aLocationMode
== eUSE_CALLING_LOCATION
) {
4404 JSContext
* cx
= GetCurrentJSContext();
4406 nsJSUtils::GetCallingLocation(cx
, spec
, &aLineNumber
, &aColumnNumber
);
4410 nsCOMPtr
<nsIScriptError
> errorObject
=
4411 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
, &rv
);
4412 NS_ENSURE_SUCCESS(rv
, rv
);
4414 if (!spec
.IsEmpty()) {
4415 rv
= errorObject
->InitWithWindowID(aErrorText
,
4417 aSourceLine
, aLineNumber
, aColumnNumber
,
4418 aErrorFlags
, aCategory
, aInnerWindowID
);
4420 rv
= errorObject
->InitWithSourceURI(aErrorText
, aURI
, aSourceLine
,
4421 aLineNumber
, aColumnNumber
, aErrorFlags
,
4422 aCategory
, aInnerWindowID
);
4424 NS_ENSURE_SUCCESS(rv
, rv
);
4426 return sConsoleService
->LogMessage(errorObject
);
4429 void nsContentUtils::LogMessageToConsole(const char* aMsg
) {
4430 if (!sConsoleService
) { // only need to bother null-checking here
4431 CallGetService(NS_CONSOLESERVICE_CONTRACTID
, &sConsoleService
);
4432 if (!sConsoleService
) {
4436 sConsoleService
->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg
).get());
4439 bool nsContentUtils::IsChromeDoc(const Document
* aDocument
) {
4440 return aDocument
&& aDocument
->NodePrincipal() == sSystemPrincipal
;
4443 bool nsContentUtils::IsChildOfSameType(Document
* aDoc
) {
4444 if (BrowsingContext
* bc
= aDoc
->GetBrowsingContext()) {
4445 return bc
->GetParent();
4450 bool nsContentUtils::IsPlainTextType(const nsACString
& aContentType
) {
4451 // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
4452 // define in nsContentDLF.h as well.
4453 return aContentType
.EqualsLiteral(TEXT_PLAIN
) ||
4454 aContentType
.EqualsLiteral(TEXT_CSS
) ||
4455 aContentType
.EqualsLiteral(TEXT_CACHE_MANIFEST
) ||
4456 aContentType
.EqualsLiteral(TEXT_VTT
) ||
4457 aContentType
.EqualsLiteral(APPLICATION_JAVASCRIPT
) ||
4458 aContentType
.EqualsLiteral(APPLICATION_XJAVASCRIPT
) ||
4459 aContentType
.EqualsLiteral(TEXT_ECMASCRIPT
) ||
4460 aContentType
.EqualsLiteral(APPLICATION_ECMASCRIPT
) ||
4461 aContentType
.EqualsLiteral(TEXT_JAVASCRIPT
) ||
4462 aContentType
.EqualsLiteral(APPLICATION_JSON
) ||
4463 aContentType
.EqualsLiteral(TEXT_JSON
);
4466 bool nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString
& aContentType
) {
4467 // NOTE: This must be a subset of the list in IsPlainTextType().
4468 return aContentType
.EqualsLiteral(TEXT_CACHE_MANIFEST
) ||
4469 aContentType
.EqualsLiteral(APPLICATION_JSON
) ||
4470 aContentType
.EqualsLiteral(TEXT_JSON
) ||
4471 aContentType
.EqualsLiteral(TEXT_VTT
);
4474 bool nsContentUtils::IsInChromeDocshell(const Document
* aDocument
) {
4475 return aDocument
&& aDocument
->IsInChromeDocShell();
4479 nsIContentPolicy
* nsContentUtils::GetContentPolicy() {
4480 if (!sTriedToGetContentPolicy
) {
4481 CallGetService(NS_CONTENTPOLICY_CONTRACTID
, &sContentPolicyService
);
4482 // It's OK to not have a content policy service
4483 sTriedToGetContentPolicy
= true;
4486 return sContentPolicyService
;
4490 bool nsContentUtils::IsEventAttributeName(nsAtom
* aName
, int32_t aType
) {
4491 const char16_t
* name
= aName
->GetUTF16String();
4492 if (name
[0] != 'o' || name
[1] != 'n') {
4496 EventNameMapping mapping
;
4497 return (sAtomEventTable
->Get(aName
, &mapping
) && mapping
.mType
& aType
);
4501 EventMessage
nsContentUtils::GetEventMessage(nsAtom
* aName
) {
4502 MOZ_ASSERT(NS_IsMainThread(), "sAtomEventTable is not threadsafe");
4504 EventNameMapping mapping
;
4505 if (sAtomEventTable
->Get(aName
, &mapping
)) {
4506 return mapping
.mMessage
;
4510 return eUnidentifiedEvent
;
4514 mozilla::EventClassID
nsContentUtils::GetEventClassID(const nsAString
& aName
) {
4515 EventNameMapping mapping
;
4516 if (sStringEventTable
->Get(aName
, &mapping
)) return mapping
.mEventClassID
;
4518 return eBasicEventClass
;
4521 nsAtom
* nsContentUtils::GetEventMessageAndAtom(
4522 const nsAString
& aName
, mozilla::EventClassID aEventClassID
,
4523 EventMessage
* aEventMessage
) {
4524 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe");
4525 EventNameMapping mapping
;
4526 if (sStringEventTable
->Get(aName
, &mapping
)) {
4527 *aEventMessage
= mapping
.mEventClassID
== aEventClassID
4529 : eUnidentifiedEvent
;
4530 return mapping
.mAtom
;
4533 // If we have cached lots of user defined event names, clear some of them.
4534 if (sUserDefinedEvents
->Length() > 127) {
4535 while (sUserDefinedEvents
->Length() > 64) {
4536 nsAtom
* first
= sUserDefinedEvents
->ElementAt(0);
4537 sStringEventTable
->Remove(Substring(nsDependentAtomString(first
), 2));
4538 sUserDefinedEvents
->RemoveElementAt(0);
4542 *aEventMessage
= eUnidentifiedEvent
;
4543 RefPtr
<nsAtom
> atom
= NS_AtomizeMainThread(u
"on"_ns
+ aName
);
4544 sUserDefinedEvents
->AppendElement(atom
);
4545 mapping
.mAtom
= atom
;
4546 mapping
.mMessage
= eUnidentifiedEvent
;
4547 mapping
.mType
= EventNameType_None
;
4548 mapping
.mEventClassID
= eBasicEventClass
;
4549 sStringEventTable
->InsertOrUpdate(aName
, mapping
);
4550 return mapping
.mAtom
;
4554 EventMessage
nsContentUtils::GetEventMessageAndAtomForListener(
4555 const nsAString
& aName
, nsAtom
** aOnName
) {
4556 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe");
4558 // Check sStringEventTable for a matching entry. This will only fail for
4559 // user-defined event types.
4560 EventNameMapping mapping
;
4561 if (sStringEventTable
->Get(aName
, &mapping
)) {
4562 RefPtr
<nsAtom
> atom
= mapping
.mAtom
;
4563 atom
.forget(aOnName
);
4564 return mapping
.mMessage
;
4567 // sStringEventTable did not contain an entry for this event type string.
4568 // Call GetEventMessageAndAtom, which will create an event type atom and
4569 // cache it in sStringEventTable for future calls.
4570 EventMessage msg
= eUnidentifiedEvent
;
4571 RefPtr
<nsAtom
> atom
= GetEventMessageAndAtom(aName
, eBasicEventClass
, &msg
);
4572 atom
.forget(aOnName
);
4576 static already_AddRefed
<Event
> GetEventWithTarget(
4577 Document
* aDoc
, EventTarget
* aTarget
, const nsAString
& aEventName
,
4578 CanBubble aCanBubble
, Cancelable aCancelable
, Composed aComposed
,
4579 Trusted aTrusted
, ErrorResult
& aErrorResult
) {
4580 RefPtr
<Event
> event
=
4581 aDoc
->CreateEvent(u
"Events"_ns
, CallerType::System
, aErrorResult
);
4582 if (aErrorResult
.Failed()) {
4586 event
->InitEvent(aEventName
, aCanBubble
, aCancelable
, aComposed
);
4587 event
->SetTrusted(aTrusted
== Trusted::eYes
);
4589 event
->SetTarget(aTarget
);
4591 return event
.forget();
4595 nsresult
nsContentUtils::DispatchTrustedEvent(
4596 Document
* aDoc
, EventTarget
* aTarget
, const nsAString
& aEventName
,
4597 CanBubble aCanBubble
, Cancelable aCancelable
, Composed aComposed
,
4598 bool* aDefaultAction
) {
4599 MOZ_ASSERT(!aEventName
.EqualsLiteral("input") &&
4600 !aEventName
.EqualsLiteral("beforeinput"),
4601 "Use DispatchInputEvent() instead");
4602 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4603 aComposed
, Trusted::eYes
, aDefaultAction
);
4607 nsresult
nsContentUtils::DispatchUntrustedEvent(
4608 Document
* aDoc
, EventTarget
* aTarget
, const nsAString
& aEventName
,
4609 CanBubble aCanBubble
, Cancelable aCancelable
, bool* aDefaultAction
) {
4610 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4611 Composed::eDefault
, Trusted::eNo
, aDefaultAction
);
4615 nsresult
nsContentUtils::DispatchEvent(Document
* aDoc
, EventTarget
* aTarget
,
4616 const nsAString
& aEventName
,
4617 CanBubble aCanBubble
,
4618 Cancelable aCancelable
,
4619 Composed aComposed
, Trusted aTrusted
,
4620 bool* aDefaultAction
,
4621 ChromeOnlyDispatch aOnlyChromeDispatch
) {
4622 if (!aDoc
|| !aTarget
) {
4623 return NS_ERROR_INVALID_ARG
;
4627 RefPtr
<Event
> event
=
4628 GetEventWithTarget(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4629 aComposed
, aTrusted
, err
);
4631 return err
.StealNSResult();
4633 event
->WidgetEventPtr()->mFlags
.mOnlyChromeDispatch
=
4634 aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
;
4636 bool doDefault
= aTarget
->DispatchEvent(*event
, CallerType::System
, err
);
4637 if (aDefaultAction
) {
4638 *aDefaultAction
= doDefault
;
4640 return err
.StealNSResult();
4644 nsresult
nsContentUtils::DispatchEvent(Document
* aDoc
, EventTarget
* aTarget
,
4645 WidgetEvent
& aEvent
,
4646 EventMessage aEventMessage
,
4647 CanBubble aCanBubble
,
4648 Cancelable aCancelable
, Trusted aTrusted
,
4649 bool* aDefaultAction
,
4650 ChromeOnlyDispatch aOnlyChromeDispatch
) {
4651 MOZ_ASSERT_IF(aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
,
4652 aTrusted
== Trusted::eYes
);
4654 aEvent
.mSpecifiedEventType
= GetEventTypeFromMessage(aEventMessage
);
4655 aEvent
.SetDefaultComposed();
4656 aEvent
.SetDefaultComposedInNativeAnonymousContent();
4658 aEvent
.mFlags
.mBubbles
= aCanBubble
== CanBubble::eYes
;
4659 aEvent
.mFlags
.mCancelable
= aCancelable
== Cancelable::eYes
;
4660 aEvent
.mFlags
.mOnlyChromeDispatch
=
4661 aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
;
4663 aEvent
.mTarget
= aTarget
;
4665 nsEventStatus status
= nsEventStatus_eIgnore
;
4666 nsresult rv
= EventDispatcher::DispatchDOMEvent(aTarget
, &aEvent
, nullptr,
4668 if (aDefaultAction
) {
4669 *aDefaultAction
= (status
!= nsEventStatus_eConsumeNoDefault
);
4675 nsresult
nsContentUtils::DispatchInputEvent(Element
* aEventTarget
) {
4676 return DispatchInputEvent(aEventTarget
, mozilla::eEditorInput
,
4677 mozilla::EditorInputType::eUnknown
, nullptr,
4678 InputEventOptions());
4682 nsresult
nsContentUtils::DispatchInputEvent(
4683 Element
* aEventTargetElement
, EventMessage aEventMessage
,
4684 EditorInputType aEditorInputType
, EditorBase
* aEditorBase
,
4685 InputEventOptions
&& aOptions
, nsEventStatus
* aEventStatus
/* = nullptr */) {
4686 MOZ_ASSERT(aEventMessage
== eEditorInput
||
4687 aEventMessage
== eEditorBeforeInput
);
4689 if (NS_WARN_IF(!aEventTargetElement
)) {
4690 return NS_ERROR_INVALID_ARG
;
4693 // If this is called from editor, the instance should be set to aEditorBase.
4694 // Otherwise, we need to look for an editor for aEventTargetElement.
4695 // However, we don't need to do it for HTMLEditor since nobody shouldn't
4696 // dispatch "beforeinput" nor "input" event for HTMLEditor except HTMLEditor
4698 bool useInputEvent
= false;
4700 useInputEvent
= true;
4701 } else if (HTMLTextAreaElement
* textAreaElement
=
4702 HTMLTextAreaElement::FromNode(aEventTargetElement
)) {
4703 aEditorBase
= textAreaElement
->GetTextEditorWithoutCreation();
4704 useInputEvent
= true;
4705 } else if (HTMLInputElement
* inputElement
=
4706 HTMLInputElement::FromNode(aEventTargetElement
)) {
4707 if (inputElement
->IsInputEventTarget()) {
4708 aEditorBase
= inputElement
->GetTextEditorWithoutCreation();
4709 useInputEvent
= true;
4714 MOZ_ASSERT(!aEventTargetElement
->IsTextControlElement(),
4715 "The event target may have editor, but we've not known it yet.");
4717 #endif // #ifdef DEBUG
4719 if (!useInputEvent
) {
4720 MOZ_ASSERT(aEventMessage
== eEditorInput
);
4721 MOZ_ASSERT(aEditorInputType
== EditorInputType::eUnknown
);
4722 MOZ_ASSERT(!aOptions
.mNeverCancelable
);
4723 // Dispatch "input" event with Event instance.
4724 WidgetEvent
widgetEvent(true, eUnidentifiedEvent
);
4725 widgetEvent
.mSpecifiedEventType
= nsGkAtoms::oninput
;
4726 widgetEvent
.mFlags
.mCancelable
= false;
4727 widgetEvent
.mFlags
.mComposed
= true;
4728 return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement
,
4729 widgetEvent
, aEventStatus
);
4732 MOZ_ASSERT_IF(aEventMessage
!= eEditorBeforeInput
,
4733 !aOptions
.mNeverCancelable
);
4735 aEventMessage
== eEditorBeforeInput
&& aOptions
.mNeverCancelable
,
4736 aEditorInputType
== EditorInputType::eInsertReplacementText
);
4738 nsCOMPtr
<nsIWidget
> widget
;
4740 widget
= aEditorBase
->GetWidget();
4741 if (NS_WARN_IF(!widget
)) {
4742 return NS_ERROR_FAILURE
;
4745 Document
* document
= aEventTargetElement
->OwnerDoc();
4746 if (NS_WARN_IF(!document
)) {
4747 return NS_ERROR_FAILURE
;
4749 // If we're running xpcshell tests, we fail to get presShell here.
4750 // Even in such case, we need to dispatch "input" event without widget.
4751 PresShell
* presShell
= document
->GetPresShell();
4753 nsPresContext
* presContext
= presShell
->GetPresContext();
4754 if (NS_WARN_IF(!presContext
)) {
4755 return NS_ERROR_FAILURE
;
4757 widget
= presContext
->GetRootWidget();
4758 if (NS_WARN_IF(!widget
)) {
4759 return NS_ERROR_FAILURE
;
4764 // Dispatch "input" event with InputEvent instance.
4765 InternalEditorInputEvent
inputEvent(true, aEventMessage
, widget
);
4767 inputEvent
.mFlags
.mCancelable
=
4768 !aOptions
.mNeverCancelable
&& aEventMessage
== eEditorBeforeInput
&&
4769 IsCancelableBeforeInputEvent(aEditorInputType
);
4770 MOZ_ASSERT(!inputEvent
.mFlags
.mCancelable
|| aEventStatus
);
4772 // If there is an editor, set isComposing to true when it has composition.
4773 // Note that EditorBase::IsIMEComposing() may return false even when we
4774 // need to set it to true.
4775 // Otherwise, i.e., editor hasn't been created for the element yet,
4776 // we should set isComposing to false since the element can never has
4777 // composition without editor.
4778 inputEvent
.mIsComposing
= aEditorBase
&& aEditorBase
->GetComposition();
4780 if (!aEditorBase
|| aEditorBase
->IsTextEditor()) {
4781 if (IsDataAvailableOnTextEditor(aEditorInputType
)) {
4782 inputEvent
.mData
= std::move(aOptions
.mData
);
4783 MOZ_ASSERT(!inputEvent
.mData
.IsVoid(),
4784 "inputEvent.mData shouldn't be void");
4788 MOZ_ASSERT(inputEvent
.mData
.IsVoid(), "inputEvent.mData should be void");
4790 #endif // #ifdef DEBUG
4792 aOptions
.mTargetRanges
.IsEmpty(),
4793 "Target ranges for <input> and <textarea> should always be empty");
4795 MOZ_ASSERT(aEditorBase
->IsHTMLEditor());
4796 if (IsDataAvailableOnHTMLEditor(aEditorInputType
)) {
4797 inputEvent
.mData
= std::move(aOptions
.mData
);
4798 MOZ_ASSERT(!inputEvent
.mData
.IsVoid(),
4799 "inputEvent.mData shouldn't be void");
4801 MOZ_ASSERT(inputEvent
.mData
.IsVoid(), "inputEvent.mData should be void");
4802 if (IsDataTransferAvailableOnHTMLEditor(aEditorInputType
)) {
4803 inputEvent
.mDataTransfer
= std::move(aOptions
.mDataTransfer
);
4804 MOZ_ASSERT(inputEvent
.mDataTransfer
,
4805 "inputEvent.mDataTransfer shouldn't be nullptr");
4806 MOZ_ASSERT(inputEvent
.mDataTransfer
->IsReadOnly(),
4807 "inputEvent.mDataTransfer should be read only");
4811 MOZ_ASSERT(!inputEvent
.mDataTransfer
,
4812 "inputEvent.mDataTransfer should be nullptr");
4814 #endif // #ifdef DEBUG
4816 if (aEventMessage
== eEditorBeforeInput
&&
4817 MayHaveTargetRangesOnHTMLEditor(aEditorInputType
)) {
4818 inputEvent
.mTargetRanges
= std::move(aOptions
.mTargetRanges
);
4822 MOZ_ASSERT(aOptions
.mTargetRanges
.IsEmpty(),
4823 "Target ranges shouldn't be set for the dispatching event");
4825 #endif // #ifdef DEBUG
4828 inputEvent
.mInputType
= aEditorInputType
;
4830 // If we cannot dispatch an event right now, we cannot make it cancelable.
4831 if (!nsContentUtils::IsSafeToRunScript()) {
4833 !inputEvent
.mFlags
.mCancelable
,
4834 "Cancelable beforeinput event dispatcher should run when it's safe");
4835 inputEvent
.mFlags
.mCancelable
= false;
4837 return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement
,
4838 inputEvent
, aEventStatus
);
4841 nsresult
nsContentUtils::DispatchChromeEvent(
4842 Document
* aDoc
, EventTarget
* aTarget
, const nsAString
& aEventName
,
4843 CanBubble aCanBubble
, Cancelable aCancelable
, bool* aDefaultAction
) {
4844 if (!aDoc
|| !aTarget
) {
4845 return NS_ERROR_INVALID_ARG
;
4848 if (!aDoc
->GetWindow()) {
4849 return NS_ERROR_INVALID_ARG
;
4852 EventTarget
* piTarget
= aDoc
->GetWindow()->GetParentTarget();
4854 return NS_ERROR_INVALID_ARG
;
4858 RefPtr
<Event
> event
=
4859 GetEventWithTarget(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4860 Composed::eDefault
, Trusted::eYes
, err
);
4862 return err
.StealNSResult();
4865 bool defaultActionEnabled
=
4866 piTarget
->DispatchEvent(*event
, CallerType::System
, err
);
4867 if (aDefaultAction
) {
4868 *aDefaultAction
= defaultActionEnabled
;
4870 return err
.StealNSResult();
4873 void nsContentUtils::RequestFrameFocus(Element
& aFrameElement
, bool aCanRaise
,
4874 CallerType aCallerType
) {
4875 RefPtr
<Element
> target
= &aFrameElement
;
4876 bool defaultAction
= true;
4878 DispatchEventOnlyToChrome(target
->OwnerDoc(), target
,
4879 u
"framefocusrequested"_ns
, CanBubble::eYes
,
4880 Cancelable::eYes
, &defaultAction
);
4882 if (!defaultAction
) {
4886 RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager();
4891 uint32_t flags
= nsIFocusManager::FLAG_NOSCROLL
;
4893 flags
|= nsIFocusManager::FLAG_RAISE
;
4896 if (aCallerType
== CallerType::NonSystem
) {
4897 flags
|= nsIFocusManager::FLAG_NONSYSTEMCALLER
;
4900 fm
->SetFocus(target
, flags
);
4903 nsresult
nsContentUtils::DispatchEventOnlyToChrome(
4904 Document
* aDoc
, EventTarget
* aTarget
, const nsAString
& aEventName
,
4905 CanBubble aCanBubble
, Cancelable aCancelable
, Composed aComposed
,
4906 bool* aDefaultAction
) {
4907 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4908 aComposed
, Trusted::eYes
, aDefaultAction
,
4909 ChromeOnlyDispatch::eYes
);
4913 Element
* nsContentUtils::MatchElementId(nsIContent
* aContent
,
4914 const nsAtom
* aId
) {
4915 for (nsIContent
* cur
= aContent
; cur
; cur
= cur
->GetNextNode(aContent
)) {
4916 if (aId
== cur
->GetID()) {
4917 return cur
->AsElement();
4925 Element
* nsContentUtils::MatchElementId(nsIContent
* aContent
,
4926 const nsAString
& aId
) {
4927 MOZ_ASSERT(!aId
.IsEmpty(), "Will match random elements");
4929 // ID attrs are generally stored as atoms, so just atomize this up front
4930 RefPtr
<nsAtom
> id(NS_Atomize(aId
));
4932 // OOM, so just bail
4936 return MatchElementId(aContent
, id
);
4940 void nsContentUtils::RegisterShutdownObserver(nsIObserver
* aObserver
) {
4941 nsCOMPtr
<nsIObserverService
> observerService
=
4942 mozilla::services::GetObserverService();
4943 if (observerService
) {
4944 observerService
->AddObserver(aObserver
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
,
4950 void nsContentUtils::UnregisterShutdownObserver(nsIObserver
* aObserver
) {
4951 nsCOMPtr
<nsIObserverService
> observerService
=
4952 mozilla::services::GetObserverService();
4953 if (observerService
) {
4954 observerService
->RemoveObserver(aObserver
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
);
4959 bool nsContentUtils::HasNonEmptyAttr(const nsIContent
* aContent
,
4960 int32_t aNameSpaceID
, nsAtom
* aName
) {
4961 static AttrArray::AttrValuesArray strings
[] = {nsGkAtoms::_empty
, nullptr};
4962 return aContent
->IsElement() &&
4963 aContent
->AsElement()->FindAttrValueIn(aNameSpaceID
, aName
, strings
,
4965 AttrArray::ATTR_VALUE_NO_MATCH
;
4969 bool nsContentUtils::HasMutationListeners(nsINode
* aNode
, uint32_t aType
,
4970 nsINode
* aTargetForSubtreeModified
) {
4971 Document
* doc
= aNode
->OwnerDoc();
4973 // global object will be null for documents that don't have windows.
4974 nsPIDOMWindowInner
* window
= doc
->GetInnerWindow();
4975 // This relies on EventListenerManager::AddEventListener, which sets
4976 // all mutation bits when there is a listener for DOMSubtreeModified event.
4977 if (window
&& !window
->HasMutationListeners(aType
)) {
4981 if (aNode
->ChromeOnlyAccess() || aNode
->IsInShadowTree()) {
4985 doc
->MayDispatchMutationEvent(aTargetForSubtreeModified
);
4987 // If we have a window, we can check it for mutation listeners now.
4988 if (aNode
->IsInUncomposedDoc()) {
4989 nsCOMPtr
<EventTarget
> piTarget(do_QueryInterface(window
));
4991 EventListenerManager
* manager
= piTarget
->GetExistingListenerManager();
4992 if (manager
&& manager
->HasMutationListeners()) {
4998 // If we have a window, we know a mutation listener is registered, but it
4999 // might not be in our chain. If we don't have a window, we might have a
5000 // mutation listener. Check quickly to see.
5002 EventListenerManager
* manager
= aNode
->GetExistingListenerManager();
5003 if (manager
&& manager
->HasMutationListeners()) {
5007 aNode
= aNode
->GetParentNode();
5014 bool nsContentUtils::HasMutationListeners(Document
* aDocument
, uint32_t aType
) {
5015 nsPIDOMWindowInner
* window
=
5016 aDocument
? aDocument
->GetInnerWindow() : nullptr;
5018 // This relies on EventListenerManager::AddEventListener, which sets
5019 // all mutation bits when there is a listener for DOMSubtreeModified event.
5020 return !window
|| window
->HasMutationListeners(aType
);
5023 void nsContentUtils::MaybeFireNodeRemoved(nsINode
* aChild
, nsINode
* aParent
) {
5024 MOZ_ASSERT(aChild
, "Missing child");
5025 MOZ_ASSERT(aChild
->GetParentNode() == aParent
, "Wrong parent");
5026 MOZ_ASSERT(aChild
->OwnerDoc() == aParent
->OwnerDoc(), "Wrong owner-doc");
5028 // Having an explicit check here since it's an easy mistake to fall into,
5029 // and there might be existing code with problems. We'd rather be safe
5030 // than fire DOMNodeRemoved in all corner cases. We also rely on it for
5031 // nsAutoScriptBlockerSuppressNodeRemoved.
5032 if (!IsSafeToRunScript()) {
5033 // This checks that IsSafeToRunScript is true since we don't want to fire
5034 // events when that is false. We can't rely on EventDispatcher to assert
5035 // this in this situation since most of the time there are no mutation
5036 // event listeners, in which case we won't even attempt to dispatch events.
5037 // However this also allows for two exceptions. First off, we don't assert
5038 // if the mutation happens to native anonymous content since we never fire
5039 // mutation events on such content anyway.
5040 // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
5041 // that is a know case when we'd normally fire a mutation event, but can't
5042 // make that safe and so we suppress it at this time. Ideally this should
5043 // go away eventually.
5044 if (!aChild
->IsInNativeAnonymousSubtree() &&
5045 !sDOMNodeRemovedSuppressCount
) {
5046 NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe");
5047 WarnScriptWasIgnored(aChild
->OwnerDoc());
5053 Document
* doc
= aParent
->OwnerDoc();
5054 if (MOZ_UNLIKELY(doc
->DevToolsWatchingDOMMutations()) &&
5055 aChild
->IsInComposedDoc() && !aChild
->ChromeOnlyAccess()) {
5056 DispatchChromeEvent(doc
, aChild
, u
"devtoolschildremoved"_ns
,
5057 CanBubble::eNo
, Cancelable::eNo
);
5061 if (HasMutationListeners(aChild
, NS_EVENT_BITS_MUTATION_NODEREMOVED
,
5063 InternalMutationEvent
mutation(true, eLegacyNodeRemoved
);
5064 mutation
.mRelatedNode
= aParent
;
5066 mozAutoSubtreeModified
subtree(aParent
->OwnerDoc(), aParent
);
5067 EventDispatcher::Dispatch(aChild
, nullptr, &mutation
);
5071 void nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() {
5072 if (!sEventListenerManagersHash
) {
5076 for (auto i
= sEventListenerManagersHash
->Iter(); !i
.Done(); i
.Next()) {
5077 auto entry
= static_cast<EventListenerManagerMapEntry
*>(i
.Get());
5078 nsINode
* n
= static_cast<nsINode
*>(entry
->mListenerManager
->GetTarget());
5079 if (n
&& n
->IsInComposedDoc() &&
5080 nsCCUncollectableMarker::InGeneration(
5081 n
->OwnerDoc()->GetMarkedCCGeneration())) {
5082 entry
->mListenerManager
->MarkForCC();
5088 void nsContentUtils::TraverseListenerManager(
5089 nsINode
* aNode
, nsCycleCollectionTraversalCallback
& cb
) {
5090 if (!sEventListenerManagersHash
) {
5091 // We're already shut down, just return.
5095 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
5096 sEventListenerManagersHash
->Search(aNode
));
5098 CycleCollectionNoteChild(cb
, entry
->mListenerManager
.get(),
5099 "[via hash] mListenerManager");
5103 EventListenerManager
* nsContentUtils::GetListenerManagerForNode(
5105 if (!sEventListenerManagersHash
) {
5106 // We're already shut down, don't bother creating an event listener
5112 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
5113 sEventListenerManagersHash
->Add(aNode
, fallible
));
5119 if (!entry
->mListenerManager
) {
5120 entry
->mListenerManager
= new EventListenerManager(aNode
);
5122 aNode
->SetFlags(NODE_HAS_LISTENERMANAGER
);
5125 return entry
->mListenerManager
;
5128 EventListenerManager
* nsContentUtils::GetExistingListenerManagerForNode(
5129 const nsINode
* aNode
) {
5130 if (!aNode
->HasFlag(NODE_HAS_LISTENERMANAGER
)) {
5134 if (!sEventListenerManagersHash
) {
5135 // We're already shut down, don't bother creating an event listener
5141 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
5142 sEventListenerManagersHash
->Search(aNode
));
5144 return entry
->mListenerManager
;
5150 void nsContentUtils::AddEntryToDOMArenaTable(nsINode
* aNode
,
5151 DOMArena
* aDOMArena
) {
5152 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
5153 MOZ_ASSERT_IF(sDOMArenaHashtable
, !sDOMArenaHashtable
->Contains(aNode
));
5154 MOZ_ASSERT(!aNode
->HasFlag(NODE_KEEPS_DOMARENA
));
5155 if (!sDOMArenaHashtable
) {
5156 sDOMArenaHashtable
=
5157 new nsRefPtrHashtable
<nsPtrHashKey
<const nsINode
>, dom::DOMArena
>();
5159 aNode
->SetFlags(NODE_KEEPS_DOMARENA
);
5160 sDOMArenaHashtable
->InsertOrUpdate(aNode
, RefPtr
<DOMArena
>(aDOMArena
));
5163 already_AddRefed
<DOMArena
> nsContentUtils::TakeEntryFromDOMArenaTable(
5164 const nsINode
* aNode
) {
5165 MOZ_ASSERT(sDOMArenaHashtable
->Contains(aNode
));
5166 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
5167 RefPtr
<DOMArena
> arena
;
5168 sDOMArenaHashtable
->Remove(aNode
, getter_AddRefs(arena
));
5169 return arena
.forget();
5173 void nsContentUtils::RemoveListenerManager(nsINode
* aNode
) {
5174 if (sEventListenerManagersHash
) {
5175 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
5176 sEventListenerManagersHash
->Search(aNode
));
5178 RefPtr
<EventListenerManager
> listenerManager
;
5179 listenerManager
.swap(entry
->mListenerManager
);
5180 // Remove the entry and *then* do operations that could cause further
5181 // modification of sEventListenerManagersHash. See bug 334177.
5182 sEventListenerManagersHash
->RawRemove(entry
);
5183 if (listenerManager
) {
5184 listenerManager
->Disconnect();
5191 bool nsContentUtils::IsValidNodeName(nsAtom
* aLocalName
, nsAtom
* aPrefix
,
5192 int32_t aNamespaceID
) {
5193 if (aNamespaceID
== kNameSpaceID_Unknown
) {
5198 // If the prefix is null, then either the QName must be xmlns or the
5199 // namespace must not be XMLNS.
5200 return (aLocalName
== nsGkAtoms::xmlns
) ==
5201 (aNamespaceID
== kNameSpaceID_XMLNS
);
5204 // If the prefix is non-null then the namespace must not be null.
5205 if (aNamespaceID
== kNameSpaceID_None
) {
5209 // If the namespace is the XMLNS namespace then the prefix must be xmlns,
5210 // but the localname must not be xmlns.
5211 if (aNamespaceID
== kNameSpaceID_XMLNS
) {
5212 return aPrefix
== nsGkAtoms::xmlns
&& aLocalName
!= nsGkAtoms::xmlns
;
5215 // If the namespace is not the XMLNS namespace then the prefix must not be
5217 // If the namespace is the XML namespace then the prefix can be anything.
5218 // If the namespace is not the XML namespace then the prefix must not be xml.
5219 return aPrefix
!= nsGkAtoms::xmlns
&&
5220 (aNamespaceID
== kNameSpaceID_XML
|| aPrefix
!= nsGkAtoms::xml
);
5223 already_AddRefed
<DocumentFragment
> nsContentUtils::CreateContextualFragment(
5224 nsINode
* aContextNode
, const nsAString
& aFragment
,
5225 bool aPreventScriptExecution
, ErrorResult
& aRv
) {
5226 if (!aContextNode
) {
5227 aRv
.Throw(NS_ERROR_INVALID_ARG
);
5231 // If we don't have a document here, we can't get the right security context
5232 // for compiling event handlers... so just bail out.
5233 RefPtr
<Document
> document
= aContextNode
->OwnerDoc();
5234 bool isHTML
= document
->IsHTMLDocument();
5237 RefPtr
<DocumentFragment
> frag
= new (document
->NodeInfoManager())
5238 DocumentFragment(document
->NodeInfoManager());
5240 Element
* element
= aContextNode
->GetAsElementOrParentElement();
5241 if (element
&& !element
->IsHTMLElement(nsGkAtoms::html
)) {
5242 aRv
= ParseFragmentHTML(
5243 aFragment
, frag
, element
->NodeInfo()->NameAtom(),
5244 element
->GetNameSpaceID(),
5245 (document
->GetCompatibilityMode() == eCompatibility_NavQuirks
),
5246 aPreventScriptExecution
);
5248 aRv
= ParseFragmentHTML(
5249 aFragment
, frag
, nsGkAtoms::body
, kNameSpaceID_XHTML
,
5250 (document
->GetCompatibilityMode() == eCompatibility_NavQuirks
),
5251 aPreventScriptExecution
);
5254 return frag
.forget();
5257 AutoTArray
<nsString
, 32> tagStack
;
5258 nsAutoString uriStr
, nameStr
;
5259 for (Element
* element
: aContextNode
->InclusiveAncestorsOfType
<Element
>()) {
5260 nsString
& tagName
= *tagStack
.AppendElement();
5261 // It mostly doesn't actually matter what tag name we use here: XML doesn't
5262 // have parsing that depends on the open tag stack, apart from namespace
5263 // declarations. So this whole tagStack bit is just there to get the right
5264 // namespace declarations to the XML parser. That said, the parser _is_
5265 // going to create elements with the tag names we provide here, so we need
5266 // to make sure they are not names that can trigger custom element
5267 // constructors. Just make up a name that is never going to be a valid
5268 // custom element name.
5270 // The principled way to do this would probably be to add a new FromParser
5271 // value and make sure we use it when creating the context elements, then
5272 // make sure we teach all FromParser consumers (and in particular the custom
5273 // element code) about it as needed. But right now the XML parser never
5274 // actually uses FromParser values other than NOT_FROM_PARSER, and changing
5275 // that is pretty complicated.
5276 tagName
.AssignLiteral("notacustomelement");
5278 // see if we need to add xmlns declarations
5279 uint32_t count
= element
->GetAttrCount();
5280 bool setDefaultNamespace
= false;
5284 for (index
= 0; index
< count
; index
++) {
5285 const BorrowedAttrInfo info
= element
->GetAttrInfoAt(index
);
5286 const nsAttrName
* name
= info
.mName
;
5287 if (name
->NamespaceEquals(kNameSpaceID_XMLNS
)) {
5288 info
.mValue
->ToString(uriStr
);
5290 // really want something like nsXMLContentSerializer::SerializeAttr
5291 tagName
.AppendLiteral(" xmlns"); // space important
5292 if (name
->GetPrefix()) {
5293 tagName
.Append(char16_t(':'));
5294 name
->LocalName()->ToString(nameStr
);
5295 tagName
.Append(nameStr
);
5297 setDefaultNamespace
= true;
5299 tagName
.AppendLiteral(R
"(=")");
5300 tagName.Append(uriStr);
5301 tagName.Append('"');
5306 if (!setDefaultNamespace) {
5307 mozilla::dom::NodeInfo* info = element->NodeInfo();
5308 if (!info->GetPrefixAtom() && info->NamespaceID() != kNameSpaceID_None) {
5309 // We have no namespace prefix, but have a namespace ID. Push
5310 // default namespace attr in, so that our kids will be in our
5312 info->GetNamespaceURI(uriStr);
5313 tagName.AppendLiteral(R"( xmlns=")");
5314 tagName.Append(uriStr);
5315 tagName.Append('"');
5320 RefPtr<DocumentFragment> frag;
5321 aRv = ParseFragmentXML(aFragment, document, tagStack, aPreventScriptExecution,
5322 -1, getter_AddRefs(frag));
5323 return frag.forget();
5327 void nsContentUtils::DropFragmentParsers() {
5328 NS_IF_RELEASE(sHTMLFragmentParser);
5329 NS_IF_RELEASE(sXMLFragmentParser);
5330 NS_IF_RELEASE(sXMLFragmentSink);
5334 void nsContentUtils::XPCOMShutdown() { nsContentUtils::DropFragmentParsers(); }
5336 /* Helper function to compuate Sanitization Flags for ParseFramentHTML/XML */
5337 uint32_t computeSanitizationFlags(nsIPrincipal* aPrincipal, int32_t aFlags) {
5338 uint32_t sanitizationFlags = 0;
5339 if (aPrincipal->IsSystemPrincipal()) {
5341 // if this is a chrome-privileged document and no explicit flags
5342 // were passed, then use this sanitization flags.
5343 sanitizationFlags = nsIParserUtils::SanitizerAllowStyle |
5344 nsIParserUtils::SanitizerAllowComments |
5345 nsIParserUtils::SanitizerDropForms |
5346 nsIParserUtils::SanitizerLogRemovals;
5348 // if the caller explicitly passes flags, then we use those
5349 // flags but additionally drop forms.
5350 sanitizationFlags = aFlags | nsIParserUtils::SanitizerDropForms;
5352 } else if (aFlags >= 0) {
5353 // aFlags by default is -1 and is only ever non equal to -1 if the
5354 // caller of ParseFragmentHTML/ParseFragmentXML is
5355 // ParserUtils::ParseFragment(). Only in that case we should use
5356 // the sanitization flags passed within aFlags.
5357 sanitizationFlags = aFlags;
5359 return sanitizationFlags;
5363 bool AllowsUnsanitizedContentForAboutNewTab(nsIPrincipal* aPrincipal) {
5364 if (StaticPrefs::dom_about_newtab_sanitization_enabled() ||
5365 !aPrincipal->SchemeIs("about
")) {
5368 uint32_t aboutModuleFlags = 0;
5369 aPrincipal->GetAboutModuleFlags(&aboutModuleFlags);
5370 return aboutModuleFlags & nsIAboutModule::ALLOW_UNSANITIZED_CONTENT;
5374 nsresult nsContentUtils::ParseFragmentHTML(
5375 const nsAString& aSourceBuffer, nsIContent* aTargetNode,
5376 nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks,
5377 bool aPreventScriptExecution, int32_t aFlags) {
5378 AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML
");
5380 if (nsContentUtils::sFragmentParsingActive) {
5381 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
5382 return NS_ERROR_DOM_INVALID_STATE_ERR;
5384 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5385 nsContentUtils::sFragmentParsingActive = true;
5386 if (!sHTMLFragmentParser) {
5387 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
5388 // Now sHTMLFragmentParser owns the object
5391 nsCOMPtr<nsIPrincipal> nodePrincipal = aTargetNode->NodePrincipal();
5394 // aFlags should always be -1 unless the caller of ParseFragmentHTML
5395 // is ParserUtils::ParseFragment() which is the only caller that intends
5396 // sanitization. For all other callers we need to ensure to call
5397 // AuditParsingOfHTMLXMLFragments.
5399 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
5404 nsIContent* target = aTargetNode;
5406 RefPtr<Document> doc = aTargetNode->OwnerDoc();
5407 RefPtr<DocumentFragment> fragment;
5408 // We sanitize if the fragment occurs in a system privileged
5409 // context, an about: page, or if there are explicit sanitization flags.
5410 // Please note that about:blank and about:srcdoc inherit the security
5411 // context from the embedding context and hence are not loaded using
5412 // an about: scheme principal.
5413 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
5414 nodePrincipal->SchemeIs("about
") || aFlags >= 0;
5415 if (shouldSanitize &&
5416 !AllowsUnsanitizedContentForAboutNewTab(nodePrincipal)) {
5417 if (!doc->IsLoadedAsData()) {
5418 doc = nsContentUtils::CreateInertHTMLDocument(doc);
5420 return NS_ERROR_FAILURE;
5424 new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager());
5428 nsresult rv = sHTMLFragmentParser->ParseFragment(
5429 aSourceBuffer, target, aContextLocalName, aContextNamespace, aQuirks,
5430 aPreventScriptExecution);
5431 NS_ENSURE_SUCCESS(rv, rv);
5434 uint32_t sanitizationFlags =
5435 computeSanitizationFlags(nodePrincipal, aFlags);
5436 // Don't fire mutation events for nodes removed by the sanitizer.
5437 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
5438 nsTreeSanitizer sanitizer(sanitizationFlags);
5439 sanitizer.Sanitize(fragment);
5442 aTargetNode->AppendChild(*fragment, error);
5443 rv = error.StealNSResult();
5450 nsresult nsContentUtils::ParseDocumentHTML(
5451 const nsAString& aSourceBuffer, Document* aTargetDocument,
5452 bool aScriptingEnabledForNoscriptParsing) {
5453 AutoTimelineMarker m(aTargetDocument->GetDocShell(), "Parse HTML
");
5455 if (nsContentUtils::sFragmentParsingActive) {
5456 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
5457 return NS_ERROR_DOM_INVALID_STATE_ERR;
5459 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5460 nsContentUtils::sFragmentParsingActive = true;
5461 if (!sHTMLFragmentParser) {
5462 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
5463 // Now sHTMLFragmentParser owns the object
5465 nsresult rv = sHTMLFragmentParser->ParseDocument(
5466 aSourceBuffer, aTargetDocument, aScriptingEnabledForNoscriptParsing);
5471 nsresult nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
5472 Document* aDocument,
5473 nsTArray<nsString>& aTagStack,
5474 bool aPreventScriptExecution,
5476 DocumentFragment** aReturn) {
5477 AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML
");
5479 if (nsContentUtils::sFragmentParsingActive) {
5480 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
5481 return NS_ERROR_DOM_INVALID_STATE_ERR;
5483 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5484 nsContentUtils::sFragmentParsingActive = true;
5485 if (!sXMLFragmentParser) {
5486 RefPtr<nsParser> parser = new nsParser();
5487 parser.forget(&sXMLFragmentParser);
5488 // sXMLFragmentParser now owns the parser
5490 if (!sXMLFragmentSink) {
5491 NS_NewXMLFragmentContentSink(&sXMLFragmentSink);
5492 // sXMLFragmentSink now owns the sink
5494 nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink);
5495 MOZ_ASSERT(contentsink, "Sink doesn
't QI to nsIContentSink!");
5496 sXMLFragmentParser->SetContentSink(contentsink);
5498 RefPtr<Document> doc;
5499 nsCOMPtr<nsIPrincipal> nodePrincipal = aDocument->NodePrincipal();
5502 // aFlags should always be -1 unless the caller of ParseFragmentXML
5503 // is ParserUtils::ParseFragment() which is the only caller that intends
5504 // sanitization. For all other callers we need to ensure to call
5505 // AuditParsingOfHTMLXMLFragments.
5507 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
5512 // We sanitize if the fragment occurs in a system privileged
5513 // context, an about: page, or if there are explicit sanitization flags.
5514 // Please note that about:blank and about:srcdoc inherit the security
5515 // context from the embedding context and hence are not loaded using
5516 // an about: scheme principal.
5517 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
5518 nodePrincipal->SchemeIs("about") || aFlags >= 0;
5519 if (shouldSanitize && !aDocument->IsLoadedAsData()) {
5520 doc = nsContentUtils::CreateInertXMLDocument(aDocument);
5525 sXMLFragmentSink->SetTargetDocument(doc);
5526 sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution);
5528 nsresult rv = sXMLFragmentParser->ParseFragment(aSourceBuffer, aTagStack);
5529 if (NS_FAILED(rv)) {
5530 // Drop the fragment parser and sink that might be in an inconsistent state
5531 NS_IF_RELEASE(sXMLFragmentParser);
5532 NS_IF_RELEASE(sXMLFragmentSink);
5536 rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
5538 sXMLFragmentParser->Reset();
5539 NS_ENSURE_SUCCESS(rv, rv);
5541 if (shouldSanitize) {
5542 uint32_t sanitizationFlags =
5543 computeSanitizationFlags(nodePrincipal, aFlags);
5544 // Don't fire mutation events
for nodes removed by the sanitizer
.
5545 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker
;
5546 nsTreeSanitizer
sanitizer(sanitizationFlags
);
5547 sanitizer
.Sanitize(*aReturn
);
5554 nsresult
nsContentUtils::ConvertToPlainText(const nsAString
& aSourceBuffer
,
5555 nsAString
& aResultBuffer
,
5557 uint32_t aWrapCol
) {
5558 RefPtr
<Document
> document
= nsContentUtils::CreateInertHTMLDocument(nullptr);
5560 return NS_ERROR_FAILURE
;
5563 nsresult rv
= nsContentUtils::ParseDocumentHTML(
5564 aSourceBuffer
, document
,
5565 !(aFlags
& nsIDocumentEncoder::OutputNoScriptContent
));
5566 NS_ENSURE_SUCCESS(rv
, rv
);
5568 nsCOMPtr
<nsIDocumentEncoder
> encoder
= do_createDocumentEncoder("text/plain");
5570 rv
= encoder
->Init(document
, u
"text/plain"_ns
, aFlags
);
5571 NS_ENSURE_SUCCESS(rv
, rv
);
5573 encoder
->SetWrapColumn(aWrapCol
);
5575 return encoder
->EncodeToString(aResultBuffer
);
5578 static already_AddRefed
<Document
> CreateInertDocument(const Document
* aTemplate
,
5579 DocumentFlavor aFlavor
) {
5582 nsIScriptGlobalObject
* sgo
= aTemplate
->GetScriptHandlingObject(hasHad
);
5583 NS_ENSURE_TRUE(sgo
|| !hasHad
, nullptr);
5585 nsCOMPtr
<Document
> doc
;
5586 nsresult rv
= NS_NewDOMDocument(
5587 getter_AddRefs(doc
), u
""_ns
, u
""_ns
, nullptr,
5588 aTemplate
->GetDocumentURI(), aTemplate
->GetDocBaseURI(),
5589 aTemplate
->NodePrincipal(), true, sgo
, aFlavor
);
5590 if (NS_FAILED(rv
)) {
5593 return doc
.forget();
5595 nsCOMPtr
<nsIURI
> uri
;
5596 NS_NewURI(getter_AddRefs(uri
), "about:blank"_ns
);
5601 RefPtr
<NullPrincipal
> nullPrincipal
=
5602 NullPrincipal::CreateWithoutOriginAttributes();
5603 if (!nullPrincipal
) {
5607 nsCOMPtr
<Document
> doc
;
5609 NS_NewDOMDocument(getter_AddRefs(doc
), u
""_ns
, u
""_ns
, nullptr, uri
, uri
,
5610 nullPrincipal
, true, nullptr, aFlavor
);
5611 if (NS_FAILED(rv
)) {
5614 return doc
.forget();
5618 already_AddRefed
<Document
> nsContentUtils::CreateInertXMLDocument(
5619 const Document
* aTemplate
) {
5620 return CreateInertDocument(aTemplate
, DocumentFlavorXML
);
5624 already_AddRefed
<Document
> nsContentUtils::CreateInertHTMLDocument(
5625 const Document
* aTemplate
) {
5626 return CreateInertDocument(aTemplate
, DocumentFlavorHTML
);
5630 nsresult
nsContentUtils::SetNodeTextContent(nsIContent
* aContent
,
5631 const nsAString
& aValue
,
5633 // Fire DOMNodeRemoved mutation events before we do anything else.
5634 nsCOMPtr
<nsIContent
> owningContent
;
5636 // Batch possible DOMSubtreeModified events.
5637 mozAutoSubtreeModified
subtree(nullptr, nullptr);
5639 // Scope firing mutation events so that we don't carry any state that
5642 // We're relying on mozAutoSubtreeModified to keep a strong reference if
5644 Document
* doc
= aContent
->OwnerDoc();
5646 // Optimize the common case of there being no observers
5647 if (HasMutationListeners(doc
, NS_EVENT_BITS_MUTATION_NODEREMOVED
)) {
5648 subtree
.UpdateTarget(doc
, nullptr);
5649 owningContent
= aContent
;
5650 nsCOMPtr
<nsINode
> child
;
5651 bool skipFirst
= aTryReuse
;
5652 for (child
= aContent
->GetFirstChild();
5653 child
&& child
->GetParentNode() == aContent
;
5654 child
= child
->GetNextSibling()) {
5655 if (skipFirst
&& child
->IsText()) {
5659 nsContentUtils::MaybeFireNodeRemoved(child
, aContent
);
5664 // Might as well stick a batch around this since we're performing several
5666 mozAutoDocUpdate
updateBatch(aContent
->GetComposedDoc(), true);
5667 nsAutoMutationBatch mb
;
5669 if (aTryReuse
&& !aValue
.IsEmpty()) {
5670 // Let's remove nodes until we find a eTEXT.
5671 while (aContent
->HasChildren()) {
5672 nsIContent
* child
= aContent
->GetFirstChild();
5673 if (child
->IsText()) {
5676 aContent
->RemoveChildNode(child
, true);
5679 // If we have a node, it must be a eTEXT and we reuse it.
5680 if (aContent
->HasChildren()) {
5681 nsIContent
* child
= aContent
->GetFirstChild();
5682 nsresult rv
= child
->AsText()->SetText(aValue
, true);
5683 NS_ENSURE_SUCCESS(rv
, rv
);
5685 // All the following nodes, if they exist, must be deleted.
5686 while (nsIContent
* nextChild
= child
->GetNextSibling()) {
5687 aContent
->RemoveChildNode(nextChild
, true);
5691 if (aContent
->HasChildren()) {
5695 mb
.Init(aContent
, true, false);
5696 while (aContent
->HasChildren()) {
5697 aContent
->RemoveChildNode(aContent
->GetFirstChild(), true);
5702 if (aValue
.IsEmpty()) {
5706 RefPtr
<nsTextNode
> textContent
= new (aContent
->NodeInfo()->NodeInfoManager())
5707 nsTextNode(aContent
->NodeInfo()->NodeInfoManager());
5709 textContent
->SetText(aValue
, true);
5712 aContent
->AppendChildTo(textContent
, true, rv
);
5714 return rv
.StealNSResult();
5717 static bool AppendNodeTextContentsRecurse(const nsINode
* aNode
,
5719 const fallible_t
& aFallible
) {
5720 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5721 child
= child
->GetNextSibling()) {
5722 if (child
->IsElement()) {
5723 bool ok
= AppendNodeTextContentsRecurse(child
, aResult
, aFallible
);
5727 } else if (Text
* text
= child
->GetAsText()) {
5728 bool ok
= text
->AppendTextTo(aResult
, aFallible
);
5739 bool nsContentUtils::AppendNodeTextContent(const nsINode
* aNode
, bool aDeep
,
5741 const fallible_t
& aFallible
) {
5742 if (const Text
* text
= aNode
->GetAsText()) {
5743 return text
->AppendTextTo(aResult
, aFallible
);
5746 return AppendNodeTextContentsRecurse(aNode
, aResult
, aFallible
);
5749 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5750 child
= child
->GetNextSibling()) {
5751 if (Text
* text
= child
->GetAsText()) {
5752 bool ok
= text
->AppendTextTo(aResult
, fallible
);
5761 bool nsContentUtils::HasNonEmptyTextContent(
5762 nsINode
* aNode
, TextContentDiscoverMode aDiscoverMode
) {
5763 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5764 child
= child
->GetNextSibling()) {
5765 if (child
->IsText() && child
->TextLength() > 0) {
5769 if (aDiscoverMode
== eRecurseIntoChildren
&&
5770 HasNonEmptyTextContent(child
, aDiscoverMode
)) {
5779 bool nsContentUtils::IsInSameAnonymousTree(const nsINode
* aNode
,
5780 const nsINode
* aOtherNode
) {
5781 MOZ_ASSERT(aNode
, "Must have a node to work with");
5782 MOZ_ASSERT(aOtherNode
, "Must have a content to work with");
5784 const bool anon
= aNode
->IsInNativeAnonymousSubtree();
5785 if (anon
!= aOtherNode
->IsInNativeAnonymousSubtree()) {
5790 return aOtherNode
->GetClosestNativeAnonymousSubtreeRoot() ==
5791 aNode
->GetClosestNativeAnonymousSubtreeRoot();
5794 // FIXME: This doesn't deal with disconnected nodes whatsoever, but it didn't
5795 // use to either. Maybe that's fine.
5796 return aNode
->GetContainingShadow() == aOtherNode
->GetContainingShadow();
5800 bool nsContentUtils::IsInInteractiveHTMLContent(const Element
* aElement
,
5801 const Element
* aStop
) {
5802 const Element
* element
= aElement
;
5803 while (element
&& element
!= aStop
) {
5804 if (element
->IsInteractiveHTMLContent()) {
5807 element
= element
->GetFlattenedTreeParentElement();
5813 void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling
) {
5814 IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling
);
5818 bool nsContentUtils::SchemeIs(nsIURI
* aURI
, const char* aScheme
) {
5819 nsCOMPtr
<nsIURI
> baseURI
= NS_GetInnermostURI(aURI
);
5820 NS_ENSURE_TRUE(baseURI
, false);
5821 return baseURI
->SchemeIs(aScheme
);
5824 bool nsContentUtils::IsExpandedPrincipal(nsIPrincipal
* aPrincipal
) {
5825 return aPrincipal
&& aPrincipal
->GetIsExpandedPrincipal();
5828 bool nsContentUtils::IsSystemOrExpandedPrincipal(nsIPrincipal
* aPrincipal
) {
5829 return (aPrincipal
&& aPrincipal
->IsSystemPrincipal()) ||
5830 IsExpandedPrincipal(aPrincipal
);
5833 nsIPrincipal
* nsContentUtils::GetSystemPrincipal() {
5834 MOZ_ASSERT(IsInitialized());
5835 return sSystemPrincipal
;
5838 bool nsContentUtils::CombineResourcePrincipals(
5839 nsCOMPtr
<nsIPrincipal
>* aResourcePrincipal
, nsIPrincipal
* aExtraPrincipal
) {
5840 if (!aExtraPrincipal
) {
5843 if (!*aResourcePrincipal
) {
5844 *aResourcePrincipal
= aExtraPrincipal
;
5847 if (*aResourcePrincipal
== aExtraPrincipal
) {
5852 (*aResourcePrincipal
)->Subsumes(aExtraPrincipal
, &subsumes
)) &&
5856 *aResourcePrincipal
= sSystemPrincipal
;
5861 void nsContentUtils::TriggerLink(nsIContent
* aContent
, nsIURI
* aLinkURI
,
5862 const nsString
& aTargetSpec
, bool aClick
,
5864 MOZ_ASSERT(aLinkURI
, "No link URI");
5866 if (aContent
->IsEditable() || !aContent
->OwnerDoc()->LinkHandlingEnabled()) {
5870 nsCOMPtr
<nsIDocShell
> docShell
= aContent
->OwnerDoc()->GetDocShell();
5876 nsDocShell::Cast(docShell
)->OnOverLink(aContent
, aLinkURI
, aTargetSpec
);
5880 // Check that this page is allowed to load this URI.
5881 nsresult proceed
= NS_OK
;
5883 if (sSecurityManager
) {
5884 uint32_t flag
= static_cast<uint32_t>(nsIScriptSecurityManager::STANDARD
);
5885 proceed
= sSecurityManager
->CheckLoadURIWithPrincipal(
5886 aContent
->NodePrincipal(), aLinkURI
, flag
,
5887 aContent
->OwnerDoc()->InnerWindowID());
5890 // Only pass off the click event if the script security manager says it's ok.
5891 // We need to rest aTargetSpec for forced downloads.
5892 if (NS_SUCCEEDED(proceed
)) {
5893 // A link/area element with a download attribute is allowed to set
5894 // a pseudo Content-Disposition header.
5895 // For security reasons we only allow websites to declare same-origin
5896 // resources as downloadable. If this check fails we will just do the normal
5897 // thing (i.e. navigate to the resource).
5898 nsAutoString fileName
;
5899 if ((!aContent
->IsHTMLElement(nsGkAtoms::a
) &&
5900 !aContent
->IsHTMLElement(nsGkAtoms::area
) &&
5901 !aContent
->IsSVGElement(nsGkAtoms::a
)) ||
5902 !aContent
->AsElement()->GetAttr(nsGkAtoms::download
, fileName
) ||
5903 NS_FAILED(aContent
->NodePrincipal()->CheckMayLoad(aLinkURI
, true))) {
5904 fileName
.SetIsVoid(true); // No actionable download attribute was found.
5907 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
= aContent
->NodePrincipal();
5908 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= aContent
->GetCsp();
5910 // Sanitize fileNames containing null characters by replacing them with
5912 if (!fileName
.IsVoid()) {
5913 fileName
.ReplaceChar(char16_t(0), '_');
5915 nsDocShell::Cast(docShell
)->OnLinkClick(
5916 aContent
, aLinkURI
, fileName
.IsVoid() ? aTargetSpec
: u
""_ns
, fileName
,
5917 nullptr, nullptr, UserActivation::IsHandlingUserInput(), aIsTrusted
,
5918 triggeringPrincipal
, csp
);
5923 void nsContentUtils::GetLinkLocation(Element
* aElement
,
5924 nsString
& aLocationString
) {
5925 nsCOMPtr
<nsIURI
> hrefURI
= aElement
->GetHrefURI();
5927 nsAutoCString specUTF8
;
5928 nsresult rv
= hrefURI
->GetSpec(specUTF8
);
5929 if (NS_SUCCEEDED(rv
)) CopyUTF8toUTF16(specUTF8
, aLocationString
);
5934 nsIWidget
* nsContentUtils::GetTopLevelWidget(nsIWidget
* aWidget
) {
5935 if (!aWidget
) return nullptr;
5937 return aWidget
->GetTopLevelWidget();
5941 const nsDependentString
nsContentUtils::GetLocalizedEllipsis() {
5942 static char16_t sBuf
[4] = {0, 0, 0, 0};
5944 if (!SpoofLocaleEnglish()) {
5946 Preferences::GetLocalizedString("intl.ellipsis", tmp
);
5948 std::min(uint32_t(tmp
.Length()), uint32_t(ArrayLength(sBuf
) - 1));
5949 CopyUnicodeTo(tmp
, 0, sBuf
, len
);
5951 if (!sBuf
[0]) sBuf
[0] = char16_t(0x2026);
5953 return nsDependentString(sBuf
);
5957 void nsContentUtils::AddScriptBlocker() {
5958 MOZ_ASSERT(NS_IsMainThread());
5959 if (!sScriptBlockerCount
) {
5960 MOZ_ASSERT(sRunnersCountAtFirstBlocker
== 0,
5961 "Should not already have a count");
5962 sRunnersCountAtFirstBlocker
=
5963 sBlockedScriptRunners
? sBlockedScriptRunners
->Length() : 0;
5965 ++sScriptBlockerCount
;
5969 static bool sRemovingScriptBlockers
= false;
5973 void nsContentUtils::RemoveScriptBlocker() {
5974 MOZ_ASSERT(NS_IsMainThread());
5975 MOZ_ASSERT(!sRemovingScriptBlockers
);
5976 NS_ASSERTION(sScriptBlockerCount
!= 0, "Negative script blockers");
5977 --sScriptBlockerCount
;
5978 if (sScriptBlockerCount
) {
5982 if (!sBlockedScriptRunners
) {
5986 uint32_t firstBlocker
= sRunnersCountAtFirstBlocker
;
5987 uint32_t lastBlocker
= sBlockedScriptRunners
->Length();
5988 uint32_t originalFirstBlocker
= firstBlocker
;
5989 uint32_t blockersCount
= lastBlocker
- firstBlocker
;
5990 sRunnersCountAtFirstBlocker
= 0;
5991 NS_ASSERTION(firstBlocker
<= lastBlocker
, "bad sRunnersCountAtFirstBlocker");
5993 while (firstBlocker
< lastBlocker
) {
5994 nsCOMPtr
<nsIRunnable
> runnable
;
5995 runnable
.swap((*sBlockedScriptRunners
)[firstBlocker
]);
5998 // Calling the runnable can reenter us
6000 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable
);
6003 // So can dropping the reference to the runnable
6006 NS_ASSERTION(sRunnersCountAtFirstBlocker
== 0, "Bad count");
6007 NS_ASSERTION(!sScriptBlockerCount
, "This is really bad");
6010 AutoRestore
<bool> removingScriptBlockers(sRemovingScriptBlockers
);
6011 sRemovingScriptBlockers
= true;
6013 sBlockedScriptRunners
->RemoveElementsAt(originalFirstBlocker
, blockersCount
);
6017 already_AddRefed
<nsPIDOMWindowOuter
>
6018 nsContentUtils::GetMostRecentNonPBWindow() {
6019 nsCOMPtr
<nsIWindowMediator
> wm
= do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
);
6021 nsCOMPtr
<mozIDOMWindowProxy
> window
;
6022 wm
->GetMostRecentNonPBWindow(u
"navigator:browser", getter_AddRefs(window
));
6023 nsCOMPtr
<nsPIDOMWindowOuter
> pwindow
;
6024 pwindow
= do_QueryInterface(window
);
6026 return pwindow
.forget();
6030 void nsContentUtils::WarnScriptWasIgnored(Document
* aDocument
) {
6032 bool privateBrowsing
= false;
6033 bool chromeContext
= false;
6036 nsCOMPtr
<nsIURI
> uri
= aDocument
->GetDocumentURI();
6038 msg
.Append(NS_ConvertUTF8toUTF16(uri
->GetSpecOrDefault()));
6039 msg
.AppendLiteral(" : ");
6042 !!aDocument
->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId
;
6043 chromeContext
= aDocument
->NodePrincipal()->IsSystemPrincipal();
6047 "Unable to run script because scripts are blocked internally.");
6048 LogSimpleConsoleError(msg
, "DOM"_ns
, privateBrowsing
, chromeContext
);
6052 void nsContentUtils::AddScriptRunner(already_AddRefed
<nsIRunnable
> aRunnable
) {
6053 nsCOMPtr
<nsIRunnable
> runnable
= aRunnable
;
6058 if (sScriptBlockerCount
) {
6059 sBlockedScriptRunners
->AppendElement(runnable
.forget());
6063 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable
);
6068 void nsContentUtils::AddScriptRunner(nsIRunnable
* aRunnable
) {
6069 nsCOMPtr
<nsIRunnable
> runnable
= aRunnable
;
6070 AddScriptRunner(runnable
.forget());
6073 /* static */ bool nsContentUtils::IsSafeToRunScript() {
6074 MOZ_ASSERT(NS_IsMainThread(),
6075 "This static variable only makes sense on the main thread!");
6076 return sScriptBlockerCount
== 0;
6080 void nsContentUtils::RunInStableState(already_AddRefed
<nsIRunnable
> aRunnable
) {
6081 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
6082 CycleCollectedJSContext::Get()->RunInStableState(std::move(aRunnable
));
6086 void nsContentUtils::AddPendingIDBTransaction(
6087 already_AddRefed
<nsIRunnable
> aTransaction
) {
6088 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
6089 CycleCollectedJSContext::Get()->AddPendingIDBTransaction(
6090 std::move(aTransaction
));
6094 bool nsContentUtils::IsInStableOrMetaStableState() {
6095 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
6096 return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState();
6100 void nsContentUtils::HidePopupsInDocument(Document
* aDocument
) {
6101 RefPtr
<nsXULPopupManager
> pm
= nsXULPopupManager::GetInstance();
6102 if (!pm
|| !aDocument
) {
6105 nsCOMPtr
<nsIDocShellTreeItem
> docShellToHide
= aDocument
->GetDocShell();
6106 if (docShellToHide
) {
6107 pm
->HidePopupsInDocShell(docShellToHide
);
6112 already_AddRefed
<nsIDragSession
> nsContentUtils::GetDragSession() {
6113 nsCOMPtr
<nsIDragSession
> dragSession
;
6114 nsCOMPtr
<nsIDragService
> dragService
=
6115 do_GetService("@mozilla.org/widget/dragservice;1");
6116 if (dragService
) dragService
->GetCurrentSession(getter_AddRefs(dragSession
));
6117 return dragSession
.forget();
6121 nsresult
nsContentUtils::SetDataTransferInEvent(WidgetDragEvent
* aDragEvent
) {
6122 if (aDragEvent
->mDataTransfer
|| !aDragEvent
->IsTrusted()) {
6126 // For dragstart events, the data transfer object is
6127 // created before the event fires, so it should already be set. For other
6128 // drag events, get the object from the drag session.
6129 NS_ASSERTION(aDragEvent
->mMessage
!= eDragStart
,
6130 "draggesture event created without a dataTransfer");
6132 nsCOMPtr
<nsIDragSession
> dragSession
= GetDragSession();
6133 NS_ENSURE_TRUE(dragSession
, NS_OK
); // no drag in progress
6135 RefPtr
<DataTransfer
> initialDataTransfer
= dragSession
->GetDataTransfer();
6136 if (!initialDataTransfer
) {
6137 // A dataTransfer won't exist when a drag was started by some other
6138 // means, for instance calling the drag service directly, or a drag
6139 // from another application. In either case, a new dataTransfer should
6140 // be created that reflects the data.
6141 initialDataTransfer
=
6142 new DataTransfer(aDragEvent
->mTarget
, aDragEvent
->mMessage
, true, -1);
6144 // now set it in the drag session so we don't need to create it again
6145 dragSession
->SetDataTransfer(initialDataTransfer
);
6148 bool isCrossDomainSubFrameDrop
= false;
6149 if (aDragEvent
->mMessage
== eDrop
) {
6150 isCrossDomainSubFrameDrop
= CheckForSubFrameDrop(dragSession
, aDragEvent
);
6153 // each event should use a clone of the original dataTransfer.
6154 initialDataTransfer
->Clone(
6155 aDragEvent
->mTarget
, aDragEvent
->mMessage
, aDragEvent
->mUserCancelled
,
6156 isCrossDomainSubFrameDrop
, getter_AddRefs(aDragEvent
->mDataTransfer
));
6157 if (NS_WARN_IF(!aDragEvent
->mDataTransfer
)) {
6158 return NS_ERROR_OUT_OF_MEMORY
;
6161 // for the dragenter and dragover events, initialize the drop effect
6162 // from the drop action, which platform specific widget code sets before
6163 // the event is fired based on the keyboard state.
6164 if (aDragEvent
->mMessage
== eDragEnter
|| aDragEvent
->mMessage
== eDragOver
) {
6166 dragSession
->GetDragAction(&action
);
6167 uint32_t effectAllowed
= aDragEvent
->mDataTransfer
->EffectAllowedInt();
6168 aDragEvent
->mDataTransfer
->SetDropEffectInt(
6169 FilterDropEffect(action
, effectAllowed
));
6170 } else if (aDragEvent
->mMessage
== eDrop
||
6171 aDragEvent
->mMessage
== eDragEnd
) {
6172 // For the drop and dragend events, set the drop effect based on the
6173 // last value that the dropEffect had. This will have been set in
6174 // EventStateManager::PostHandleEvent for the last dragenter or
6176 aDragEvent
->mDataTransfer
->SetDropEffectInt(
6177 initialDataTransfer
->DropEffectInt());
6184 uint32_t nsContentUtils::FilterDropEffect(uint32_t aAction
,
6185 uint32_t aEffectAllowed
) {
6186 // It is possible for the drag action to include more than one action, but
6187 // the widget code which sets the action from the keyboard state should only
6188 // be including one. If multiple actions were set, we just consider them in
6189 // the following order:
6191 if (aAction
& nsIDragService::DRAGDROP_ACTION_COPY
)
6192 aAction
= nsIDragService::DRAGDROP_ACTION_COPY
;
6193 else if (aAction
& nsIDragService::DRAGDROP_ACTION_LINK
)
6194 aAction
= nsIDragService::DRAGDROP_ACTION_LINK
;
6195 else if (aAction
& nsIDragService::DRAGDROP_ACTION_MOVE
)
6196 aAction
= nsIDragService::DRAGDROP_ACTION_MOVE
;
6198 // Filter the action based on the effectAllowed. If the effectAllowed
6199 // doesn't include the action, then that action cannot be done, so adjust
6200 // the action to something that is allowed. For a copy, adjust to move or
6201 // link. For a move, adjust to copy or link. For a link, adjust to move or
6202 // link. Otherwise, use none.
6203 if (aAction
& aEffectAllowed
||
6204 aEffectAllowed
== nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
)
6206 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_MOVE
)
6207 return nsIDragService::DRAGDROP_ACTION_MOVE
;
6208 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_COPY
)
6209 return nsIDragService::DRAGDROP_ACTION_COPY
;
6210 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_LINK
)
6211 return nsIDragService::DRAGDROP_ACTION_LINK
;
6212 return nsIDragService::DRAGDROP_ACTION_NONE
;
6216 bool nsContentUtils::CheckForSubFrameDrop(nsIDragSession
* aDragSession
,
6217 WidgetDragEvent
* aDropEvent
) {
6218 nsCOMPtr
<nsIContent
> target
=
6219 nsIContent::FromEventTargetOrNull(aDropEvent
->mOriginalTarget
);
6224 // Always allow dropping onto chrome shells.
6225 BrowsingContext
* targetBC
= target
->OwnerDoc()->GetBrowsingContext();
6226 if (targetBC
->IsChrome()) {
6230 WindowContext
* targetWC
= target
->OwnerDoc()->GetWindowContext();
6232 // If there is no source browsing context, then this is a drag from another
6233 // application, which should be allowed.
6234 RefPtr
<WindowContext
> sourceWC
;
6235 aDragSession
->GetSourceWindowContext(getter_AddRefs(sourceWC
));
6237 // Get each successive parent of the source document and compare it to
6238 // the drop document. If they match, then this is a drag from a child frame.
6239 for (sourceWC
= sourceWC
->GetParentWindowContext(); sourceWC
;
6240 sourceWC
= sourceWC
->GetParentWindowContext()) {
6241 // If the source and the target match, then the drag started in a
6242 // descendant frame. If the source is discarded, err on the side of
6243 // caution and treat it as a subframe drag.
6244 if (sourceWC
== targetWC
|| sourceWC
->IsDiscarded()) {
6254 bool nsContentUtils::URIIsLocalFile(nsIURI
* aURI
) {
6256 nsCOMPtr
<nsINetUtil
> util
= mozilla::components::IO::Service();
6258 // Important: we do NOT test the entire URI chain here!
6260 NS_SUCCEEDED(util
->ProtocolHasFlags(
6261 aURI
, nsIProtocolHandler::URI_IS_LOCAL_FILE
, &isFile
)) &&
6266 JSContext
* nsContentUtils::GetCurrentJSContext() {
6267 MOZ_ASSERT(IsInitialized());
6268 if (!IsJSAPIActive()) {
6271 return danger::GetJSContext();
6274 template <typename StringType
, typename CharType
>
6275 void _ASCIIToLowerInSitu(StringType
& aStr
) {
6276 CharType
* iter
= aStr
.BeginWriting();
6277 CharType
* end
= aStr
.EndWriting();
6278 MOZ_ASSERT(iter
&& end
);
6280 while (iter
!= end
) {
6282 if (c
>= 'A' && c
<= 'Z') {
6283 *iter
= c
+ ('a' - 'A');
6290 void nsContentUtils::ASCIIToLower(nsAString
& aStr
) {
6291 return _ASCIIToLowerInSitu
<nsAString
, char16_t
>(aStr
);
6295 void nsContentUtils::ASCIIToLower(nsACString
& aStr
) {
6296 return _ASCIIToLowerInSitu
<nsACString
, char>(aStr
);
6299 template <typename StringType
, typename CharType
>
6300 void _ASCIIToLowerCopy(const StringType
& aSource
, StringType
& aDest
) {
6301 uint32_t len
= aSource
.Length();
6302 aDest
.SetLength(len
);
6303 MOZ_ASSERT(aDest
.Length() == len
);
6305 CharType
* dest
= aDest
.BeginWriting();
6308 const CharType
* iter
= aSource
.BeginReading();
6309 const CharType
* end
= aSource
.EndReading();
6310 while (iter
!= end
) {
6312 *dest
= (c
>= 'A' && c
<= 'Z') ? c
+ ('a' - 'A') : c
;
6319 void nsContentUtils::ASCIIToLower(const nsAString
& aSource
, nsAString
& aDest
) {
6320 return _ASCIIToLowerCopy
<nsAString
, char16_t
>(aSource
, aDest
);
6324 void nsContentUtils::ASCIIToLower(const nsACString
& aSource
,
6325 nsACString
& aDest
) {
6326 return _ASCIIToLowerCopy
<nsACString
, char>(aSource
, aDest
);
6329 template <typename StringType
, typename CharType
>
6330 void _ASCIIToUpperInSitu(StringType
& aStr
) {
6331 CharType
* iter
= aStr
.BeginWriting();
6332 CharType
* end
= aStr
.EndWriting();
6333 MOZ_ASSERT(iter
&& end
);
6335 while (iter
!= end
) {
6337 if (c
>= 'a' && c
<= 'z') {
6338 *iter
= c
+ ('A' - 'a');
6345 void nsContentUtils::ASCIIToUpper(nsAString
& aStr
) {
6346 return _ASCIIToUpperInSitu
<nsAString
, char16_t
>(aStr
);
6350 void nsContentUtils::ASCIIToUpper(nsACString
& aStr
) {
6351 return _ASCIIToUpperInSitu
<nsACString
, char>(aStr
);
6354 template <typename StringType
, typename CharType
>
6355 void _ASCIIToUpperCopy(const StringType
& aSource
, StringType
& aDest
) {
6356 uint32_t len
= aSource
.Length();
6357 aDest
.SetLength(len
);
6358 MOZ_ASSERT(aDest
.Length() == len
);
6360 CharType
* dest
= aDest
.BeginWriting();
6363 const CharType
* iter
= aSource
.BeginReading();
6364 const CharType
* end
= aSource
.EndReading();
6365 while (iter
!= end
) {
6367 *dest
= (c
>= 'a' && c
<= 'z') ? c
+ ('A' - 'a') : c
;
6374 void nsContentUtils::ASCIIToUpper(const nsAString
& aSource
, nsAString
& aDest
) {
6375 return _ASCIIToUpperCopy
<nsAString
, char16_t
>(aSource
, aDest
);
6379 void nsContentUtils::ASCIIToUpper(const nsACString
& aSource
,
6380 nsACString
& aDest
) {
6381 return _ASCIIToUpperCopy
<nsACString
, char>(aSource
, aDest
);
6385 bool nsContentUtils::EqualsIgnoreASCIICase(nsAtom
* aAtom1
, nsAtom
* aAtom2
) {
6386 if (aAtom1
== aAtom2
) {
6390 // If both are ascii lowercase already, we know that the slow comparison
6391 // below is going to return false.
6392 if (aAtom1
->IsAsciiLowercase() && aAtom2
->IsAsciiLowercase()) {
6396 return EqualsIgnoreASCIICase(nsDependentAtomString(aAtom1
),
6397 nsDependentAtomString(aAtom2
));
6401 bool nsContentUtils::EqualsIgnoreASCIICase(const nsAString
& aStr1
,
6402 const nsAString
& aStr2
) {
6403 uint32_t len
= aStr1
.Length();
6404 if (len
!= aStr2
.Length()) {
6408 const char16_t
* str1
= aStr1
.BeginReading();
6409 const char16_t
* str2
= aStr2
.BeginReading();
6410 const char16_t
* end
= str1
+ len
;
6412 while (str1
< end
) {
6413 char16_t c1
= *str1
++;
6414 char16_t c2
= *str2
++;
6416 // First check if any bits other than the 0x0020 differs
6417 if ((c1
^ c2
) & 0xffdf) {
6421 // We know they can only differ in the 0x0020 bit.
6422 // Likely the two chars are the same, so check that first
6424 // They do differ, but since it's only in the 0x0020 bit, check if it's
6425 // the same ascii char, but just differing in case
6426 char16_t c1Upper
= c1
& 0xffdf;
6427 if (!('A' <= c1Upper
&& c1Upper
<= 'Z')) {
6437 bool nsContentUtils::StringContainsASCIIUpper(const nsAString
& aStr
) {
6438 const char16_t
* iter
= aStr
.BeginReading();
6439 const char16_t
* end
= aStr
.EndReading();
6440 while (iter
!= end
) {
6442 if (c
>= 'A' && c
<= 'Z') {
6452 nsIInterfaceRequestor
* nsContentUtils::SameOriginChecker() {
6453 if (!sSameOriginChecker
) {
6454 sSameOriginChecker
= new SameOriginCheckerImpl();
6455 NS_ADDREF(sSameOriginChecker
);
6457 return sSameOriginChecker
;
6461 nsresult
nsContentUtils::CheckSameOrigin(nsIChannel
* aOldChannel
,
6462 nsIChannel
* aNewChannel
) {
6463 if (!nsContentUtils::GetSecurityManager()) return NS_ERROR_NOT_AVAILABLE
;
6465 nsCOMPtr
<nsIPrincipal
> oldPrincipal
;
6466 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
6467 aOldChannel
, getter_AddRefs(oldPrincipal
));
6469 nsCOMPtr
<nsIURI
> newURI
;
6470 aNewChannel
->GetURI(getter_AddRefs(newURI
));
6471 nsCOMPtr
<nsIURI
> newOriginalURI
;
6472 aNewChannel
->GetOriginalURI(getter_AddRefs(newOriginalURI
));
6474 NS_ENSURE_STATE(oldPrincipal
&& newURI
&& newOriginalURI
);
6476 nsresult rv
= oldPrincipal
->CheckMayLoad(newURI
, false);
6477 if (NS_SUCCEEDED(rv
) && newOriginalURI
!= newURI
) {
6478 rv
= oldPrincipal
->CheckMayLoad(newOriginalURI
, false);
6484 NS_IMPL_ISUPPORTS(SameOriginCheckerImpl
, nsIChannelEventSink
,
6485 nsIInterfaceRequestor
)
6488 SameOriginCheckerImpl::AsyncOnChannelRedirect(
6489 nsIChannel
* aOldChannel
, nsIChannel
* aNewChannel
, uint32_t aFlags
,
6490 nsIAsyncVerifyRedirectCallback
* cb
) {
6491 MOZ_ASSERT(aNewChannel
, "Redirecting to null channel?");
6493 nsresult rv
= nsContentUtils::CheckSameOrigin(aOldChannel
, aNewChannel
);
6494 if (NS_SUCCEEDED(rv
)) {
6495 cb
->OnRedirectVerifyCallback(NS_OK
);
6502 SameOriginCheckerImpl::GetInterface(const nsIID
& aIID
, void** aResult
) {
6503 return QueryInterface(aIID
, aResult
);
6507 nsresult
nsContentUtils::GetWebExposedOriginSerialization(nsIURI
* aURI
,
6508 nsACString
& aOrigin
) {
6510 MOZ_ASSERT(aURI
, "missing uri");
6512 // For Blob URI, the path is the URL of the owning page.
6513 if (aURI
->SchemeIs(BLOBURI_SCHEME
)) {
6515 rv
= aURI
->GetPathQueryRef(path
);
6516 NS_ENSURE_SUCCESS(rv
, rv
);
6518 nsCOMPtr
<nsIURI
> uri
;
6519 rv
= NS_NewURI(getter_AddRefs(uri
), path
);
6520 if (NS_FAILED(rv
)) {
6521 aOrigin
.AssignLiteral("null");
6525 return GetWebExposedOriginSerialization(uri
, aOrigin
);
6528 nsAutoCString scheme
;
6529 aURI
->GetScheme(scheme
);
6531 // If the protocol doesn't have URI_HAS_WEB_EXPOSED_ORIGIN, then
6532 // return "null" as the origin serialization.
6533 // We make an exception for "ftp" since we don't have a protocol handler
6536 nsCOMPtr
<nsIIOService
> io
= mozilla::components::IO::Service(&rv
);
6537 if (!scheme
.Equals("ftp") && NS_SUCCEEDED(rv
) &&
6538 NS_SUCCEEDED(io
->GetProtocolFlags(scheme
.get(), &flags
))) {
6539 if (!(flags
& nsIProtocolHandler::URI_HAS_WEB_EXPOSED_ORIGIN
)) {
6540 aOrigin
.AssignLiteral("null");
6547 nsCOMPtr
<nsIURI
> uri
= NS_GetInnermostURI(aURI
);
6548 NS_ENSURE_TRUE(uri
, NS_ERROR_UNEXPECTED
);
6551 rv
= uri
->GetAsciiHost(host
);
6553 if (NS_SUCCEEDED(rv
) && !host
.IsEmpty()) {
6554 nsAutoCString userPass
;
6555 uri
->GetUserPass(userPass
);
6557 nsAutoCString prePath
;
6558 if (!userPass
.IsEmpty()) {
6559 rv
= NS_MutateURI(uri
).SetUserPass(""_ns
).Finalize(uri
);
6560 NS_ENSURE_SUCCESS(rv
, rv
);
6563 rv
= uri
->GetPrePath(prePath
);
6564 NS_ENSURE_SUCCESS(rv
, rv
);
6568 aOrigin
.AssignLiteral("null");
6575 nsresult
nsContentUtils::GetWebExposedOriginSerialization(
6576 nsIPrincipal
* aPrincipal
, nsAString
& aOrigin
) {
6577 MOZ_ASSERT(aPrincipal
, "missing principal");
6580 nsAutoCString webExposedOriginSerialization
;
6582 nsresult rv
= aPrincipal
->GetWebExposedOriginSerialization(
6583 webExposedOriginSerialization
);
6584 if (NS_FAILED(rv
)) {
6585 webExposedOriginSerialization
.AssignLiteral("null");
6588 CopyUTF8toUTF16(webExposedOriginSerialization
, aOrigin
);
6593 nsresult
nsContentUtils::GetWebExposedOriginSerialization(nsIURI
* aURI
,
6594 nsAString
& aOrigin
) {
6595 MOZ_ASSERT(aURI
, "missing uri");
6598 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
6599 // Check if either URI has a special origin.
6600 nsCOMPtr
<nsIURIWithSpecialOrigin
> uriWithSpecialOrigin
=
6601 do_QueryInterface(aURI
);
6602 if (uriWithSpecialOrigin
) {
6603 nsCOMPtr
<nsIURI
> origin
;
6604 rv
= uriWithSpecialOrigin
->GetOrigin(getter_AddRefs(origin
));
6605 NS_ENSURE_SUCCESS(rv
, rv
);
6607 return GetWebExposedOriginSerialization(origin
, aOrigin
);
6611 nsAutoCString webExposedOriginSerialization
;
6612 rv
= GetWebExposedOriginSerialization(aURI
, webExposedOriginSerialization
);
6613 NS_ENSURE_SUCCESS(rv
, rv
);
6615 CopyUTF8toUTF16(webExposedOriginSerialization
, aOrigin
);
6620 bool nsContentUtils::CheckMayLoad(nsIPrincipal
* aPrincipal
,
6621 nsIChannel
* aChannel
,
6622 bool aAllowIfInheritsPrincipal
) {
6623 nsCOMPtr
<nsIURI
> channelURI
;
6624 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
6625 NS_ENSURE_SUCCESS(rv
, false);
6627 return NS_SUCCEEDED(
6628 aPrincipal
->CheckMayLoad(channelURI
, aAllowIfInheritsPrincipal
));
6632 bool nsContentUtils::CanAccessNativeAnon() {
6633 return LegacyIsCallerChromeOrNativeCode();
6637 nsresult
nsContentUtils::DispatchXULCommand(nsIContent
* aTarget
, bool aTrusted
,
6638 Event
* aSourceEvent
,
6639 PresShell
* aPresShell
, bool aCtrl
,
6640 bool aAlt
, bool aShift
, bool aMeta
,
6641 uint16_t aInputSource
,
6643 NS_ENSURE_STATE(aTarget
);
6644 Document
* doc
= aTarget
->OwnerDoc();
6645 nsPresContext
* presContext
= doc
->GetPresContext();
6647 RefPtr
<XULCommandEvent
> xulCommand
=
6648 new XULCommandEvent(doc
, presContext
, nullptr);
6649 xulCommand
->InitCommandEvent(u
"command"_ns
, true, true,
6650 nsGlobalWindowInner::Cast(doc
->GetInnerWindow()),
6651 0, aCtrl
, aAlt
, aShift
, aMeta
, aButton
,
6652 aSourceEvent
, aInputSource
, IgnoreErrors());
6655 nsEventStatus status
= nsEventStatus_eIgnore
;
6656 return aPresShell
->HandleDOMEventWithTarget(aTarget
, xulCommand
, &status
);
6660 aTarget
->DispatchEvent(*xulCommand
, rv
);
6661 return rv
.StealNSResult();
6665 nsresult
nsContentUtils::WrapNative(JSContext
* cx
, nsISupports
* native
,
6666 nsWrapperCache
* cache
, const nsIID
* aIID
,
6667 JS::MutableHandle
<JS::Value
> vp
,
6668 bool aAllowWrapping
) {
6669 MOZ_ASSERT(cx
== GetCurrentJSContext());
6677 JSObject
* wrapper
= xpc_FastGetCachedWrapper(cx
, cache
, vp
);
6682 NS_ENSURE_TRUE(sXPConnect
, NS_ERROR_UNEXPECTED
);
6684 if (!NS_IsMainThread()) {
6688 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
6689 nsresult rv
= sXPConnect
->WrapNativeToJSVal(cx
, scope
, native
, cache
, aIID
,
6690 aAllowWrapping
, vp
);
6694 nsresult
nsContentUtils::CreateArrayBuffer(JSContext
* aCx
,
6695 const nsACString
& aData
,
6696 JSObject
** aResult
) {
6698 return NS_ERROR_FAILURE
;
6701 size_t dataLen
= aData
.Length();
6702 *aResult
= JS::NewArrayBuffer(aCx
, dataLen
);
6704 return NS_ERROR_FAILURE
;
6708 NS_ASSERTION(JS::IsArrayBufferObject(*aResult
), "What happened?");
6709 JS::AutoCheckCannotGC nogc
;
6711 memcpy(JS::GetArrayBufferData(*aResult
, &isShared
, nogc
),
6712 aData
.BeginReading(), dataLen
);
6713 MOZ_ASSERT(!isShared
);
6719 void nsContentUtils::StripNullChars(const nsAString
& aInStr
,
6720 nsAString
& aOutStr
) {
6721 // In common cases where we don't have nulls in the
6722 // string we can simple simply bypass the checking code.
6723 int32_t firstNullPos
= aInStr
.FindChar('\0');
6724 if (firstNullPos
== kNotFound
) {
6725 aOutStr
.Assign(aInStr
);
6729 aOutStr
.SetCapacity(aInStr
.Length() - 1);
6730 nsAString::const_iterator start
, end
;
6731 aInStr
.BeginReading(start
);
6732 aInStr
.EndReading(end
);
6733 while (start
!= end
) {
6734 if (*start
!= '\0') aOutStr
.Append(*start
);
6739 struct ClassMatchingInfo
{
6741 nsCaseTreatment mCaseTreatment
;
6745 bool nsContentUtils::MatchClassNames(Element
* aElement
, int32_t aNamespaceID
,
6746 nsAtom
* aAtom
, void* aData
) {
6747 // We can't match if there are no class names
6748 const nsAttrValue
* classAttr
= aElement
->GetClasses();
6753 // need to match *all* of the classes
6754 ClassMatchingInfo
* info
= static_cast<ClassMatchingInfo
*>(aData
);
6755 uint32_t length
= info
->mClasses
.Length();
6757 // If we actually had no classes, don't match.
6761 for (i
= 0; i
< length
; ++i
) {
6762 if (!classAttr
->Contains(info
->mClasses
[i
], info
->mCaseTreatment
)) {
6771 void nsContentUtils::DestroyClassNameArray(void* aData
) {
6772 ClassMatchingInfo
* info
= static_cast<ClassMatchingInfo
*>(aData
);
6777 void* nsContentUtils::AllocClassMatchingInfo(nsINode
* aRootNode
,
6778 const nsString
* aClasses
) {
6779 nsAttrValue attrValue
;
6780 attrValue
.ParseAtomArray(*aClasses
);
6781 // nsAttrValue::Equals is sensitive to order, so we'll send an array
6782 auto* info
= new ClassMatchingInfo
;
6783 if (attrValue
.Type() == nsAttrValue::eAtomArray
) {
6784 info
->mClasses
= attrValue
.GetAtomArrayValue()->mArray
.Clone();
6785 } else if (attrValue
.Type() == nsAttrValue::eAtom
) {
6786 info
->mClasses
.AppendElement(attrValue
.GetAtomValue());
6789 info
->mCaseTreatment
=
6790 aRootNode
->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks
6797 bool nsContentUtils::IsFocusedContent(const nsIContent
* aContent
) {
6798 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
6800 return fm
&& fm
->GetFocusedElement() == aContent
;
6803 bool nsContentUtils::HasScrollgrab(nsIContent
* aContent
) {
6804 // If we ever standardize this feature we'll want to hook this up properly
6805 // again. For now we're removing all the DOM-side code related to it but
6806 // leaving the layout and APZ handling for it in place.
6810 void nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter
* aWindow
) {
6815 // Note that because FlushPendingNotifications flushes parents, this
6816 // is O(N^2) in docshell tree depth. However, the docshell tree is
6817 // usually pretty shallow.
6819 if (RefPtr
<Document
> doc
= aWindow
->GetDoc()) {
6820 doc
->FlushPendingNotifications(FlushType::Layout
);
6823 if (nsCOMPtr
<nsIDocShell
> docShell
= aWindow
->GetDocShell()) {
6824 int32_t i
= 0, i_end
;
6825 docShell
->GetInProcessChildCount(&i_end
);
6826 for (; i
< i_end
; ++i
) {
6827 nsCOMPtr
<nsIDocShellTreeItem
> item
;
6828 if (docShell
->GetInProcessChildAt(i
, getter_AddRefs(item
)) == NS_OK
&&
6830 if (nsCOMPtr
<nsPIDOMWindowOuter
> win
= item
->GetWindow()) {
6831 FlushLayoutForTree(win
);
6838 void nsContentUtils::RemoveNewlines(nsString
& aString
) { aString
.StripCRLF(); }
6840 void nsContentUtils::PlatformToDOMLineBreaks(nsString
& aString
) {
6841 if (!PlatformToDOMLineBreaks(aString
, fallible
)) {
6842 aString
.AllocFailed(aString
.Length());
6846 bool nsContentUtils::PlatformToDOMLineBreaks(nsString
& aString
,
6847 const fallible_t
& aFallible
) {
6848 if (aString
.FindChar(char16_t('\r')) != -1) {
6849 // Windows linebreaks: Map CRLF to LF:
6850 if (!aString
.ReplaceSubstring(u
"\r\n", u
"\n", aFallible
)) {
6854 // Mac linebreaks: Map any remaining CR to LF:
6855 if (!aString
.ReplaceSubstring(u
"\r", u
"\n", aFallible
)) {
6863 void nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer
* aBuf
,
6864 nsAString
& aResultString
) {
6865 MOZ_ASSERT(aBuf
, "Expecting a non-null string buffer");
6867 uint32_t stringLen
= NS_strlen(static_cast<char16_t
*>(aBuf
->Data()));
6869 // SANITY CHECK: In case the nsStringBuffer isn't correctly
6870 // null-terminated, let's clamp its length using the allocated size, to be
6871 // sure the resulting string doesn't sample past the end of the the buffer.
6872 // (Note that StorageSize() is in units of bytes, so we have to convert that
6873 // to units of PRUnichars, and subtract 1 for the null-terminator.)
6874 uint32_t allocStringLen
= (aBuf
->StorageSize() / sizeof(char16_t
)) - 1;
6875 MOZ_ASSERT(stringLen
<= allocStringLen
,
6876 "string buffer lacks null terminator!");
6877 stringLen
= std::min(stringLen
, allocStringLen
);
6879 aBuf
->ToString(stringLen
, aResultString
);
6882 already_AddRefed
<nsContentList
> nsContentUtils::GetElementsByClassName(
6883 nsINode
* aRootNode
, const nsAString
& aClasses
) {
6884 MOZ_ASSERT(aRootNode
, "Must have root node");
6886 return GetFuncStringContentList
<nsCacheableFuncStringHTMLCollection
>(
6887 aRootNode
, MatchClassNames
, DestroyClassNameArray
, AllocClassMatchingInfo
,
6891 PresShell
* nsContentUtils::FindPresShellForDocument(const Document
* aDocument
) {
6892 const Document
* doc
= aDocument
;
6893 Document
* displayDoc
= doc
->GetDisplayDocument();
6898 PresShell
* presShell
= doc
->GetPresShell();
6903 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= doc
->GetDocShell();
6904 while (docShellTreeItem
) {
6905 // We may be in a display:none subdocument, or we may not have a presshell
6907 // Walk the docshell tree to find the nearest container that has a
6908 // presshell, and return that.
6909 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(docShellTreeItem
);
6910 if (PresShell
* presShell
= docShell
->GetPresShell()) {
6913 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
6914 docShellTreeItem
->GetInProcessParent(getter_AddRefs(parent
));
6915 docShellTreeItem
= parent
;
6922 nsPresContext
* nsContentUtils::FindPresContextForDocument(
6923 const Document
* aDocument
) {
6924 if (PresShell
* presShell
= FindPresShellForDocument(aDocument
)) {
6925 return presShell
->GetPresContext();
6930 nsIWidget
* nsContentUtils::WidgetForDocument(const Document
* aDocument
) {
6931 PresShell
* presShell
= FindPresShellForDocument(aDocument
);
6935 nsViewManager
* vm
= presShell
->GetViewManager();
6939 nsView
* rootView
= vm
->GetRootView();
6943 nsView
* displayRoot
= nsViewManager::GetDisplayRootFor(rootView
);
6947 return displayRoot
->GetNearestWidget(nullptr);
6950 nsIWidget
* nsContentUtils::WidgetForContent(const nsIContent
* aContent
) {
6951 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
6953 frame
= nsLayoutUtils::GetDisplayRootFrame(frame
);
6955 nsView
* view
= frame
->GetView();
6957 return view
->GetWidget();
6964 WindowRenderer
* nsContentUtils::WindowRendererForContent(
6965 const nsIContent
* aContent
) {
6966 nsIWidget
* widget
= nsContentUtils::WidgetForContent(aContent
);
6968 return widget
->GetWindowRenderer();
6974 WindowRenderer
* nsContentUtils::WindowRendererForDocument(
6975 const Document
* aDoc
) {
6976 nsIWidget
* widget
= nsContentUtils::WidgetForDocument(aDoc
);
6978 return widget
->GetWindowRenderer();
6984 bool nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal
* aPrincipal
) {
6989 if (aPrincipal
->IsSystemPrincipal()) {
6993 return xpc::IsInAutomation() && IsSitePermAllow(aPrincipal
, "allowXULXBL"_ns
);
6996 bool nsContentUtils::IsPDFJSEnabled() {
6997 nsCOMPtr
<nsIStreamConverter
> conv
= do_CreateInstance(
6998 "@mozilla.org/streamconv;1?from=application/pdf&to=text/html");
7002 bool nsContentUtils::IsPDFJS(nsIPrincipal
* aPrincipal
) {
7003 if (!aPrincipal
|| !aPrincipal
->SchemeIs("resource")) {
7007 nsresult rv
= aPrincipal
->GetAsciiSpec(spec
);
7008 NS_ENSURE_SUCCESS(rv
, false);
7009 return spec
.EqualsLiteral("resource://pdf.js/web/viewer.html");
7012 bool nsContentUtils::IsSystemOrPDFJS(JSContext
* aCx
, JSObject
*) {
7013 nsIPrincipal
* principal
= SubjectPrincipal(aCx
);
7014 return principal
&& (principal
->IsSystemPrincipal() || IsPDFJS(principal
));
7017 already_AddRefed
<nsIDocumentLoaderFactory
>
7018 nsContentUtils::FindInternalContentViewer(const nsACString
& aType
,
7019 ContentViewerType
* aLoaderType
) {
7021 *aLoaderType
= TYPE_UNSUPPORTED
;
7024 // one helper factory, please
7025 nsCOMPtr
<nsICategoryManager
> catMan(
7026 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
));
7027 if (!catMan
) return nullptr;
7029 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory
;
7031 nsCString contractID
;
7033 catMan
->GetCategoryEntry("Gecko-Content-Viewers", aType
, contractID
);
7034 if (NS_SUCCEEDED(rv
)) {
7035 docFactory
= do_GetService(contractID
.get());
7036 if (docFactory
&& aLoaderType
) {
7037 if (contractID
.EqualsLiteral(CONTENT_DLF_CONTRACTID
))
7038 *aLoaderType
= TYPE_CONTENT
;
7039 else if (contractID
.EqualsLiteral(PLUGIN_DLF_CONTRACTID
))
7040 *aLoaderType
= TYPE_FALLBACK
;
7042 *aLoaderType
= TYPE_UNKNOWN
;
7044 return docFactory
.forget();
7047 if (DecoderTraits::IsSupportedInVideoDocument(aType
)) {
7049 do_GetService("@mozilla.org/content/document-loader-factory;1");
7050 if (docFactory
&& aLoaderType
) {
7051 *aLoaderType
= TYPE_CONTENT
;
7053 return docFactory
.forget();
7059 static void ReportPatternCompileFailure(nsAString
& aPattern
,
7060 const Document
* aDocument
,
7061 JS::MutableHandle
<JS::Value
> error
,
7063 JS::AutoSaveExceptionState
savedExc(cx
);
7064 JS::Rooted
<JSObject
*> exnObj(cx
, &error
.toObject());
7065 JS::Rooted
<JS::Value
> messageVal(cx
);
7066 if (!JS_GetProperty(cx
, exnObj
, "message", &messageVal
)) {
7069 JS::Rooted
<JSString
*> messageStr(cx
, messageVal
.toString());
7070 MOZ_ASSERT(messageStr
);
7072 AutoTArray
<nsString
, 2> strings
;
7073 strings
.AppendElement(aPattern
);
7074 if (!AssignJSString(cx
, *strings
.AppendElement(), messageStr
)) {
7078 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "DOM"_ns
,
7079 aDocument
, nsContentUtils::eDOM_PROPERTIES
,
7080 "PatternAttributeCompileFailure", strings
);
7085 Maybe
<bool> nsContentUtils::IsPatternMatching(const nsAString
& aValue
,
7086 nsString
&& aPattern
,
7087 const Document
* aDocument
,
7089 JS::RegExpFlags aFlags
) {
7090 NS_ASSERTION(aDocument
, "aDocument should be a valid pointer (not null)");
7092 // The fact that we're using a JS regexp under the hood should not be visible
7093 // to things like window onerror handlers, so we don't initialize our JSAPI
7094 // with the document's window (which may not exist anyway).
7097 JSContext
* cx
= jsapi
.cx();
7098 AutoDisableJSInterruptCallback
disabler(cx
);
7100 // We can use the junk scope here, because we're just using it for regexp
7101 // evaluation, not actual script execution, and we disable statics so that the
7102 // evaluation does not interact with the execution global.
7103 JSAutoRealm
ar(cx
, xpc::PrivilegedJunkScope());
7105 // Check if the pattern by itself is valid first, and not that it only becomes
7106 // valid once we add ^(?: and )$.
7107 JS::Rooted
<JS::Value
> error(cx
);
7108 if (!JS::CheckRegExpSyntax(cx
, aPattern
.BeginReading(), aPattern
.Length(),
7113 if (!error
.isUndefined()) {
7114 ReportPatternCompileFailure(aPattern
, aDocument
, &error
, cx
);
7118 // The pattern has to match the entire value.
7119 aPattern
.InsertLiteral(u
"^(?:", 0);
7120 aPattern
.AppendLiteral(")$");
7122 JS::Rooted
<JSObject
*> re(
7123 cx
, JS::NewUCRegExpObject(cx
, aPattern
.BeginReading(), aPattern
.Length(),
7129 JS::Rooted
<JS::Value
> rval(cx
, JS::NullValue());
7130 if (!aHasMultiple
) {
7132 if (!JS::ExecuteRegExpNoStatics(cx
, re
, aValue
.BeginReading(),
7133 aValue
.Length(), &idx
, true, &rval
)) {
7136 return Some(!rval
.isNull());
7139 HTMLSplitOnSpacesTokenizer
tokenizer(aValue
, ',');
7140 while (tokenizer
.hasMoreTokens()) {
7141 const nsAString
& value
= tokenizer
.nextToken();
7143 if (!JS::ExecuteRegExpNoStatics(cx
, re
, value
.BeginReading(),
7144 value
.Length(), &idx
, true, &rval
)) {
7147 if (rval
.isNull()) {
7155 nsresult
nsContentUtils::URIInheritsSecurityContext(nsIURI
* aURI
,
7157 // Note: about:blank URIs do NOT inherit the security context from the
7158 // current document, which is what this function tests for...
7159 return NS_URIChainHasFlags(
7160 aURI
, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
, aResult
);
7164 bool nsContentUtils::ChannelShouldInheritPrincipal(
7165 nsIPrincipal
* aLoadingPrincipal
, nsIURI
* aURI
, bool aInheritForAboutBlank
,
7166 bool aForceInherit
) {
7167 MOZ_ASSERT(aLoadingPrincipal
,
7168 "Can not check inheritance without a principal");
7170 // Only tell the channel to inherit if it can't provide its own security
7173 // XXX: If this is ever changed, check all callers for what owners
7174 // they're passing in. In particular, see the code and
7175 // comments in nsDocShell::LoadURI where we fall back on
7176 // inheriting the owner if called from chrome. That would be
7177 // very wrong if this code changed anything but channels that
7178 // can't provide their own security context!
7180 // If aForceInherit is true, we will inherit, even for a channel that
7181 // can provide its own security context. This is used for srcdoc loads.
7182 bool inherit
= aForceInherit
;
7185 // We expect URIInheritsSecurityContext to return success for an
7186 // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
7187 // This condition needs to match the one in nsDocShell::InternalLoad where
7188 // we're checking for things that will use the owner.
7190 (NS_SUCCEEDED(URIInheritsSecurityContext(aURI
, &uriInherits
)) &&
7191 (uriInherits
|| (aInheritForAboutBlank
&& NS_IsAboutBlank(aURI
)))) ||
7193 // file: uri special-casing
7195 // If this is a file: load opened from another file: then it may need
7196 // to inherit the owner from the referrer so they can script each other.
7197 // If we don't set the owner explicitly then each file: gets an owner
7198 // based on its own codebase later.
7200 (URIIsLocalFile(aURI
) &&
7201 NS_SUCCEEDED(aLoadingPrincipal
->CheckMayLoad(aURI
, false)) &&
7202 // One more check here. CheckMayLoad will always return true for the
7203 // system principal, but we do NOT want to inherit in that case.
7204 !aLoadingPrincipal
->IsSystemPrincipal());
7210 bool nsContentUtils::IsCutCopyAllowed(Document
* aDocument
,
7211 nsIPrincipal
& aSubjectPrincipal
) {
7212 if (StaticPrefs::dom_allow_cut_copy() && aDocument
&&
7213 aDocument
->HasValidTransientUserGestureActivation()) {
7217 return PrincipalHasPermission(aSubjectPrincipal
, nsGkAtoms::clipboardWrite
);
7221 bool nsContentUtils::HaveEqualPrincipals(Document
* aDoc1
, Document
* aDoc2
) {
7222 if (!aDoc1
|| !aDoc2
) {
7225 bool principalsEqual
= false;
7226 aDoc1
->NodePrincipal()->Equals(aDoc2
->NodePrincipal(), &principalsEqual
);
7227 return principalsEqual
;
7231 void nsContentUtils::FireMutationEventsForDirectParsing(
7232 Document
* aDoc
, nsIContent
* aDest
, int32_t aOldChildCount
) {
7233 // Fire mutation events. Optimize for the case when there are no listeners
7234 int32_t newChildCount
= aDest
->GetChildCount();
7235 if (newChildCount
&& nsContentUtils::HasMutationListeners(
7236 aDoc
, NS_EVENT_BITS_MUTATION_NODEINSERTED
)) {
7237 AutoTArray
<nsCOMPtr
<nsIContent
>, 50> childNodes
;
7238 NS_ASSERTION(newChildCount
- aOldChildCount
>= 0,
7239 "What, some unexpected dom mutation has happened?");
7240 childNodes
.SetCapacity(newChildCount
- aOldChildCount
);
7241 for (nsIContent
* child
= aDest
->GetFirstChild(); child
;
7242 child
= child
->GetNextSibling()) {
7243 childNodes
.AppendElement(child
);
7245 FragmentOrElement::FireNodeInserted(aDoc
, aDest
, childNodes
);
7250 const Document
* nsContentUtils::GetInProcessSubtreeRootDocument(
7251 const Document
* aDoc
) {
7255 const Document
* doc
= aDoc
;
7256 while (doc
->GetInProcessParentDocument()) {
7257 doc
= doc
->GetInProcessParentDocument();
7263 int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame
* aOffsetFrame
,
7265 // The structure of the anonymous frames within a text control frame is
7266 // an optional block frame, followed by an optional br frame.
7268 // If the offset frame has a child, then this frame is the block which
7269 // has the text frames (containing the content) as its children. This will
7270 // be the case if we click to the right of any of the text frames, or at the
7271 // bottom of the text area.
7272 nsIFrame
* firstChild
= aOffsetFrame
->PrincipalChildList().FirstChild();
7274 // In this case, the passed-in offset is incorrect, and we want the length
7275 // of the entire content in the text control frame.
7276 return firstChild
->GetContent()->Length();
7279 if (aOffsetFrame
->GetPrevSibling() && !aOffsetFrame
->GetNextSibling()) {
7280 // In this case, we're actually within the last frame, which is a br
7281 // frame. Our offset should therefore be the length of the first child of
7283 int32_t aOutOffset
= aOffsetFrame
->GetParent()
7284 ->PrincipalChildList()
7291 // Otherwise, we're within one of the text frames, in which case our offset
7292 // has already been correctly calculated.
7297 void nsContentUtils::GetSelectionInTextControl(Selection
* aSelection
,
7299 uint32_t& aOutStartOffset
,
7300 uint32_t& aOutEndOffset
) {
7301 MOZ_ASSERT(aSelection
&& aRoot
);
7303 // We don't care which end of this selection is anchor and which is focus. In
7304 // fact, we explicitly want to know which is the _start_ and which is the
7305 // _end_, not anchor vs focus.
7306 const nsRange
* range
= aSelection
->GetAnchorFocusRange();
7309 aOutStartOffset
= aOutEndOffset
= 0;
7313 // All the node pointers here are raw pointers for performance. We shouldn't
7314 // be doing anything in this function that invalidates the node tree.
7315 nsINode
* startContainer
= range
->GetStartContainer();
7316 uint32_t startOffset
= range
->StartOffset();
7317 nsINode
* endContainer
= range
->GetEndContainer();
7318 uint32_t endOffset
= range
->EndOffset();
7320 // We have at most two children, consisting of an optional text node followed
7321 // by an optional <br>.
7322 NS_ASSERTION(aRoot
->GetChildCount() <= 2, "Unexpected children");
7323 nsIContent
* firstChild
= aRoot
->GetFirstChild();
7325 nsCOMPtr
<nsIContent
> lastChild
= aRoot
->GetLastChild();
7326 NS_ASSERTION(startContainer
== aRoot
|| startContainer
== firstChild
||
7327 startContainer
== lastChild
,
7328 "Unexpected startContainer");
7329 NS_ASSERTION(endContainer
== aRoot
|| endContainer
== firstChild
||
7330 endContainer
== lastChild
,
7331 "Unexpected endContainer");
7332 // firstChild is either text or a <br> (hence an element).
7333 MOZ_ASSERT_IF(firstChild
, firstChild
->IsText() || firstChild
->IsElement());
7335 if (!firstChild
|| firstChild
->IsElement()) {
7336 // No text node, so everything is 0
7337 startOffset
= endOffset
= 0;
7339 // First child is text. If the start/end is already in the text node,
7340 // or the start of the root node, no change needed. If it's in the root
7341 // node but not the start, or in the trailing <br>, we need to set the
7342 // offset to the end.
7343 if ((startContainer
== aRoot
&& startOffset
!= 0) ||
7344 (startContainer
!= aRoot
&& startContainer
!= firstChild
)) {
7345 startOffset
= firstChild
->Length();
7347 if ((endContainer
== aRoot
&& endOffset
!= 0) ||
7348 (endContainer
!= aRoot
&& endContainer
!= firstChild
)) {
7349 endOffset
= firstChild
->Length();
7353 MOZ_ASSERT(startOffset
<= endOffset
);
7354 aOutStartOffset
= startOffset
;
7355 aOutEndOffset
= endOffset
;
7359 HTMLEditor
* nsContentUtils::GetHTMLEditor(nsPresContext
* aPresContext
) {
7360 if (!aPresContext
) {
7363 return GetHTMLEditor(aPresContext
->GetDocShell());
7367 HTMLEditor
* nsContentUtils::GetHTMLEditor(nsDocShell
* aDocShell
) {
7369 if (!aDocShell
|| NS_FAILED(aDocShell
->GetEditable(&isEditable
)) ||
7373 return aDocShell
->GetHTMLEditor();
7377 EditorBase
* nsContentUtils::GetActiveEditor(nsPresContext
* aPresContext
) {
7378 if (!aPresContext
) {
7382 return GetActiveEditor(aPresContext
->Document()->GetWindow());
7386 EditorBase
* nsContentUtils::GetActiveEditor(nsPIDOMWindowOuter
* aWindow
) {
7387 if (!aWindow
|| !aWindow
->GetExtantDoc()) {
7391 // If it's in designMode, nobody can have focus. Therefore, the HTMLEditor
7392 // handles all events. I.e., it's focused editor in this case.
7393 if (aWindow
->GetExtantDoc()->IsInDesignMode()) {
7394 return GetHTMLEditor(nsDocShell::Cast(aWindow
->GetDocShell()));
7397 // If focused element is associated with TextEditor, it must be <input>
7398 // element or <textarea> element. Let's return it even if it's in a
7399 // contenteditable element.
7400 nsCOMPtr
<nsPIDOMWindowOuter
> focusedWindow
;
7401 if (Element
* focusedElement
= nsFocusManager::GetFocusedDescendant(
7402 aWindow
, nsFocusManager::SearchRange::eOnlyCurrentWindow
,
7403 getter_AddRefs(focusedWindow
))) {
7404 if (TextEditor
* textEditor
= focusedElement
->GetTextEditorInternal()) {
7409 // Otherwise, HTMLEditor may handle inputs even non-editable element has
7410 // focus or nobody has focus.
7411 return GetHTMLEditor(nsDocShell::Cast(aWindow
->GetDocShell()));
7415 TextEditor
* nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
7416 const nsIContent
* aAnonymousContent
) {
7417 if (!aAnonymousContent
) {
7420 nsIContent
* parent
= aAnonymousContent
->FindFirstNonChromeOnlyAccessContent();
7421 if (!parent
|| parent
== aAnonymousContent
) {
7424 if (HTMLInputElement
* inputElement
=
7425 HTMLInputElement::FromNodeOrNull(parent
)) {
7426 return inputElement
->GetTextEditorWithoutCreation();
7428 if (HTMLTextAreaElement
* textareaElement
=
7429 HTMLTextAreaElement::FromNodeOrNull(parent
)) {
7430 return textareaElement
->GetTextEditorWithoutCreation();
7436 bool nsContentUtils::IsNodeInEditableRegion(nsINode
* aNode
) {
7438 if (aNode
->IsEditable()) {
7441 aNode
= aNode
->GetParent();
7447 bool nsContentUtils::IsForbiddenRequestHeader(const nsACString
& aHeader
,
7448 const nsACString
& aValue
) {
7449 if (IsForbiddenSystemRequestHeader(aHeader
)) {
7453 if ((nsContentUtils::IsOverrideMethodHeader(aHeader
) &&
7454 nsContentUtils::ContainsForbiddenMethod(aValue
))) {
7458 if (StringBeginsWith(aHeader
, "proxy-"_ns
,
7459 nsCaseInsensitiveCStringComparator
) ||
7460 StringBeginsWith(aHeader
, "sec-"_ns
,
7461 nsCaseInsensitiveCStringComparator
)) {
7469 bool nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString
& aHeader
) {
7470 static const char* kInvalidHeaders
[] = {"accept-charset",
7472 "access-control-request-headers",
7473 "access-control-request-method",
7488 "transfer-encoding",
7491 for (auto& kInvalidHeader
: kInvalidHeaders
) {
7492 if (aHeader
.LowerCaseEqualsASCII(kInvalidHeader
)) {
7500 bool nsContentUtils::IsForbiddenResponseHeader(const nsACString
& aHeader
) {
7501 return (aHeader
.LowerCaseEqualsASCII("set-cookie") ||
7502 aHeader
.LowerCaseEqualsASCII("set-cookie2"));
7506 bool nsContentUtils::IsOverrideMethodHeader(const nsACString
& headerName
) {
7507 return headerName
.EqualsIgnoreCase("x-http-method-override") ||
7508 headerName
.EqualsIgnoreCase("x-http-method") ||
7509 headerName
.EqualsIgnoreCase("x-method-override");
7513 bool nsContentUtils::ContainsForbiddenMethod(const nsACString
& headerValue
) {
7514 bool hasInsecureMethod
= false;
7515 nsCCharSeparatedTokenizer
tokenizer(headerValue
, ',');
7517 while (tokenizer
.hasMoreTokens()) {
7518 const nsDependentCSubstring
& value
= tokenizer
.nextToken();
7520 if (value
.EqualsIgnoreCase("connect") || value
.EqualsIgnoreCase("trace") ||
7521 value
.EqualsIgnoreCase("track")) {
7522 hasInsecureMethod
= true;
7527 return hasInsecureMethod
;
7530 Maybe
<nsContentUtils::ParsedRange
> nsContentUtils::ParseSingleRangeRequest(
7531 const nsACString
& aHeaderValue
, bool aAllowWhitespace
) {
7532 // See https://fetch.spec.whatwg.org/#simple-range-header-value
7533 mozilla::Tokenizer
p(aHeaderValue
);
7534 Maybe
<uint64_t> rangeStart
;
7535 Maybe
<uint64_t> rangeEnd
;
7538 if (!p
.CheckWord("bytes")) {
7543 if (aAllowWhitespace
) {
7548 if (!p
.CheckChar('=')) {
7553 if (aAllowWhitespace
) {
7559 if (p
.ReadInteger(&res
)) {
7560 rangeStart
= Some(res
);
7564 if (aAllowWhitespace
) {
7569 if (!p
.CheckChar('-')) {
7574 if (aAllowWhitespace
) {
7579 if (p
.ReadInteger(&res
)) {
7580 rangeEnd
= Some(res
);
7584 if (!p
.CheckEOF()) {
7589 if (!rangeStart
&& !rangeEnd
) {
7594 if (rangeStart
&& rangeEnd
&& *rangeStart
> *rangeEnd
) {
7598 return Some(ParsedRange(rangeStart
, rangeEnd
));
7602 bool nsContentUtils::IsCorsUnsafeRequestHeaderValue(
7603 const nsACString
& aHeaderValue
) {
7604 const char* cur
= aHeaderValue
.BeginReading();
7605 const char* end
= aHeaderValue
.EndReading();
7607 while (cur
!= end
) {
7608 // Implementation of
7609 // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less
7610 // than a space but not a horizontal tab
7611 if ((*cur
< ' ' && *cur
!= '\t') || *cur
== '"' || *cur
== '(' ||
7612 *cur
== ')' || *cur
== ':' || *cur
== '<' || *cur
== '>' ||
7613 *cur
== '?' || *cur
== '@' || *cur
== '[' || *cur
== '\\' ||
7614 *cur
== ']' || *cur
== '{' || *cur
== '}' ||
7615 *cur
== 0x7F) { // 0x75 is DEL
7624 bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString
& aHeaderValue
) {
7625 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue
)) {
7632 bool nsContentUtils::IsAllowedNonCorsContentType(
7633 const nsACString
& aHeaderValue
) {
7634 nsAutoCString contentType
;
7635 nsAutoCString unused
;
7637 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue
)) {
7641 nsresult rv
= NS_ParseRequestContentType(aHeaderValue
, contentType
, unused
);
7642 if (NS_FAILED(rv
)) {
7646 return contentType
.LowerCaseEqualsLiteral("text/plain") ||
7647 contentType
.LowerCaseEqualsLiteral(
7648 "application/x-www-form-urlencoded") ||
7649 contentType
.LowerCaseEqualsLiteral("multipart/form-data");
7653 bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString
& aHeaderValue
) {
7654 const char* cur
= aHeaderValue
.BeginReading();
7655 const char* end
= aHeaderValue
.EndReading();
7657 while (cur
!= end
) {
7658 if ((*cur
>= '0' && *cur
<= '9') || (*cur
>= 'A' && *cur
<= 'Z') ||
7659 (*cur
>= 'a' && *cur
<= 'z') || *cur
== ' ' || *cur
== '*' ||
7660 *cur
== ',' || *cur
== '-' || *cur
== '.' || *cur
== ';' ||
7670 bool nsContentUtils::IsAllowedNonCorsRange(const nsACString
& aHeaderValue
) {
7671 Maybe
<ParsedRange
> parsedRange
= ParseSingleRangeRequest(aHeaderValue
, false);
7676 if (!parsedRange
->Start()) {
7684 bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString
& aName
,
7685 const nsACString
& aValue
) {
7686 // see https://fetch.spec.whatwg.org/#cors-safelisted-request-header
7687 if (aValue
.Length() > 128) {
7690 return (aName
.LowerCaseEqualsLiteral("accept") &&
7691 nsContentUtils::IsAllowedNonCorsAccept(aValue
)) ||
7692 (aName
.LowerCaseEqualsLiteral("accept-language") &&
7693 nsContentUtils::IsAllowedNonCorsLanguage(aValue
)) ||
7694 (aName
.LowerCaseEqualsLiteral("content-language") &&
7695 nsContentUtils::IsAllowedNonCorsLanguage(aValue
)) ||
7696 (aName
.LowerCaseEqualsLiteral("content-type") &&
7697 nsContentUtils::IsAllowedNonCorsContentType(aValue
)) ||
7698 (aName
.LowerCaseEqualsLiteral("range") &&
7699 nsContentUtils::IsAllowedNonCorsRange(aValue
));
7702 mozilla::LogModule
* nsContentUtils::ResistFingerprintingLog() {
7703 return gResistFingerprintingLog
;
7705 mozilla::LogModule
* nsContentUtils::DOMDumpLog() { return sDOMDumpLog
; }
7707 bool nsContentUtils::GetNodeTextContent(const nsINode
* aNode
, bool aDeep
,
7709 const fallible_t
& aFallible
) {
7711 return AppendNodeTextContent(aNode
, aDeep
, aResult
, aFallible
);
7714 void nsContentUtils::GetNodeTextContent(const nsINode
* aNode
, bool aDeep
,
7715 nsAString
& aResult
) {
7716 if (!GetNodeTextContent(aNode
, aDeep
, aResult
, fallible
)) {
7717 NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size
7721 void nsContentUtils::DestroyMatchString(void* aData
) {
7723 nsString
* matchString
= static_cast<nsString
*>(aData
);
7728 bool nsContentUtils::IsJavascriptMIMEType(const nsAString
& aMIMEType
) {
7729 // Table ordered from most to least likely JS MIME types.
7730 static const char* jsTypes
[] = {"text/javascript",
7732 "application/javascript",
7733 "application/ecmascript",
7734 "application/x-javascript",
7735 "application/x-ecmascript",
7736 "text/javascript1.0",
7737 "text/javascript1.1",
7738 "text/javascript1.2",
7739 "text/javascript1.3",
7740 "text/javascript1.4",
7741 "text/javascript1.5",
7744 "text/x-ecmascript",
7745 "text/x-javascript",
7748 for (uint32_t i
= 0; jsTypes
[i
]; ++i
) {
7749 if (aMIMEType
.LowerCaseEqualsASCII(jsTypes
[i
])) {
7757 bool nsContentUtils::PrefetchPreloadEnabled(nsIDocShell
* aDocShell
) {
7759 // SECURITY CHECK: disable prefetching and preloading from mailnews!
7761 // walk up the docshell tree to see if any containing
7762 // docshell are of type MAIL.
7769 nsCOMPtr
<nsIDocShell
> docshell
= aDocShell
;
7770 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
7773 auto appType
= docshell
->GetAppType();
7774 if (appType
== nsIDocShell::APP_TYPE_MAIL
) {
7775 return false; // do not prefetch, preload, preconnect from mailnews
7778 docshell
->GetInProcessParent(getter_AddRefs(parentItem
));
7780 docshell
= do_QueryInterface(parentItem
);
7782 NS_ERROR("cannot get a docshell from a treeItem!");
7786 } while (parentItem
);
7791 uint64_t nsContentUtils::GetInnerWindowID(nsIRequest
* aRequest
) {
7792 // can't do anything if there's no nsIRequest!
7797 nsCOMPtr
<nsILoadGroup
> loadGroup
;
7798 nsresult rv
= aRequest
->GetLoadGroup(getter_AddRefs(loadGroup
));
7800 if (NS_FAILED(rv
) || !loadGroup
) {
7804 return GetInnerWindowID(loadGroup
);
7807 uint64_t nsContentUtils::GetInnerWindowID(nsILoadGroup
* aLoadGroup
) {
7812 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
7813 nsresult rv
= aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
7814 if (NS_FAILED(rv
) || !callbacks
) {
7818 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
7823 nsCOMPtr
<mozIDOMWindowProxy
> window
;
7824 rv
= loadContext
->GetAssociatedWindow(getter_AddRefs(window
));
7825 if (NS_FAILED(rv
) || !window
) {
7829 auto* pwindow
= nsPIDOMWindowOuter::From(window
);
7834 nsPIDOMWindowInner
* inner
= pwindow
->GetCurrentInnerWindow();
7835 return inner
? inner
->WindowID() : 0;
7839 void nsContentUtils::MaybeFixIPv6Host(nsACString
& aHost
) {
7840 if (aHost
.FindChar(':') != -1) { // Escape IPv6 address
7841 MOZ_ASSERT(!aHost
.Length() ||
7842 (aHost
[0] != '[' && aHost
[aHost
.Length() - 1] != ']'));
7843 aHost
.Insert('[', 0);
7848 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI
* aURI
,
7849 nsACString
& aHost
) {
7851 nsresult rv
= aURI
->GetHost(aHost
);
7852 if (NS_FAILED(rv
)) { // Some URIs do not have a host
7856 MaybeFixIPv6Host(aHost
);
7861 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI
* aURI
,
7863 nsAutoCString hostname
;
7864 nsresult rv
= GetHostOrIPv6WithBrackets(aURI
, hostname
);
7865 if (NS_FAILED(rv
)) {
7868 CopyUTF8toUTF16(hostname
, aHost
);
7872 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIPrincipal
* aPrincipal
,
7873 nsACString
& aHost
) {
7874 nsresult rv
= aPrincipal
->GetAsciiHost(aHost
);
7875 if (NS_FAILED(rv
)) { // Some URIs do not have a host
7879 MaybeFixIPv6Host(aHost
);
7883 CallState
nsContentUtils::CallOnAllRemoteChildren(
7884 MessageBroadcaster
* aManager
,
7885 const std::function
<CallState(BrowserParent
*)>& aCallback
) {
7886 uint32_t browserChildCount
= aManager
->ChildCount();
7887 for (uint32_t j
= 0; j
< browserChildCount
; ++j
) {
7888 RefPtr
<MessageListenerManager
> childMM
= aManager
->GetChildAt(j
);
7893 RefPtr
<MessageBroadcaster
> nonLeafMM
= MessageBroadcaster::From(childMM
);
7895 if (CallOnAllRemoteChildren(nonLeafMM
, aCallback
) == CallState::Stop
) {
7896 return CallState::Stop
;
7901 mozilla::dom::ipc::MessageManagerCallback
* cb
= childMM
->GetCallback();
7903 nsFrameLoader
* fl
= static_cast<nsFrameLoader
*>(cb
);
7904 BrowserParent
* remote
= BrowserParent::GetFrom(fl
);
7905 if (remote
&& aCallback
) {
7906 if (aCallback(remote
) == CallState::Stop
) {
7907 return CallState::Stop
;
7913 return CallState::Continue
;
7916 void nsContentUtils::CallOnAllRemoteChildren(
7917 nsPIDOMWindowOuter
* aWindow
,
7918 const std::function
<CallState(BrowserParent
*)>& aCallback
) {
7919 nsGlobalWindowOuter
* window
= nsGlobalWindowOuter::Cast(aWindow
);
7920 if (window
->IsChromeWindow()) {
7921 RefPtr
<MessageBroadcaster
> windowMM
= window
->GetMessageManager();
7923 CallOnAllRemoteChildren(windowMM
, aCallback
);
7928 bool nsContentUtils::IPCTransferableDataItemHasKnownFlavor(
7929 const IPCTransferableDataItem
& aItem
) {
7930 // Unknown types are converted to kCustomTypesMime.
7931 if (aItem
.flavor().EqualsASCII(kCustomTypesMime
)) {
7935 for (const char* format
: DataTransfer::kKnownFormats
) {
7936 if (aItem
.flavor().EqualsASCII(format
)) {
7944 nsresult
nsContentUtils::IPCTransferableDataToTransferable(
7945 const IPCTransferableData
& aTransferableData
, bool aAddDataFlavor
,
7946 nsITransferable
* aTransferable
, const bool aFilterUnknownFlavors
) {
7948 const nsTArray
<IPCTransferableDataItem
>& items
= aTransferableData
.items();
7949 for (const auto& item
: items
) {
7950 if (aFilterUnknownFlavors
&& !IPCTransferableDataItemHasKnownFlavor(item
)) {
7952 "Ignoring unknown flavor in "
7953 "nsContentUtils::IPCTransferableDataToTransferable");
7957 if (aAddDataFlavor
) {
7958 aTransferable
->AddDataFlavor(item
.flavor().get());
7961 nsCOMPtr
<nsISupports
> transferData
;
7962 switch (item
.data().type()) {
7963 case IPCTransferableDataType::TIPCTransferableDataString
: {
7964 const auto& data
= item
.data().get_IPCTransferableDataString();
7965 nsCOMPtr
<nsISupportsString
> dataWrapper
=
7966 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
7967 NS_ENSURE_SUCCESS(rv
, rv
);
7968 rv
= dataWrapper
->SetData(nsDependentSubstring(
7969 reinterpret_cast<const char16_t
*>(data
.data().Data()),
7970 data
.data().Size() / sizeof(char16_t
)));
7971 NS_ENSURE_SUCCESS(rv
, rv
);
7972 transferData
= dataWrapper
;
7975 case IPCTransferableDataType::TIPCTransferableDataCString
: {
7976 const auto& data
= item
.data().get_IPCTransferableDataCString();
7977 nsCOMPtr
<nsISupportsCString
> dataWrapper
=
7978 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID
, &rv
);
7979 NS_ENSURE_SUCCESS(rv
, rv
);
7980 rv
= dataWrapper
->SetData(nsDependentCSubstring(
7981 reinterpret_cast<const char*>(data
.data().Data()),
7982 data
.data().Size()));
7983 NS_ENSURE_SUCCESS(rv
, rv
);
7984 transferData
= dataWrapper
;
7987 case IPCTransferableDataType::TIPCTransferableDataInputStream
: {
7988 const auto& data
= item
.data().get_IPCTransferableDataInputStream();
7989 nsCOMPtr
<nsIInputStream
> stream
;
7990 rv
= NS_NewByteInputStream(getter_AddRefs(stream
),
7991 AsChars(data
.data().AsSpan()),
7992 NS_ASSIGNMENT_COPY
);
7993 NS_ENSURE_SUCCESS(rv
, rv
);
7994 transferData
= stream
.forget();
7997 case IPCTransferableDataType::TIPCTransferableDataImageContainer
: {
7998 const auto& data
= item
.data().get_IPCTransferableDataImageContainer();
7999 nsCOMPtr
<imgIContainer
> container
;
8000 rv
= DeserializeTransferableDataImageContainer(
8001 data
, getter_AddRefs(container
));
8002 NS_ENSURE_SUCCESS(rv
, rv
);
8003 transferData
= container
;
8006 case IPCTransferableDataType::TIPCTransferableDataBlob
: {
8007 const auto& data
= item
.data().get_IPCTransferableDataBlob();
8008 transferData
= IPCBlobUtils::Deserialize(data
.blob());
8011 case IPCTransferableDataType::T__None
:
8012 MOZ_ASSERT_UNREACHABLE();
8013 return NS_ERROR_FAILURE
;
8016 rv
= aTransferable
->SetTransferData(item
.flavor().get(), transferData
);
8017 NS_ENSURE_SUCCESS(rv
, rv
);
8022 nsresult
nsContentUtils::IPCTransferableDataToTransferable(
8023 const IPCTransferableData
& aTransferableData
, const bool& aIsPrivateData
,
8024 nsIPrincipal
* aRequestingPrincipal
,
8025 const nsContentPolicyType
& aContentPolicyType
, bool aAddDataFlavor
,
8026 nsITransferable
* aTransferable
, const bool aFilterUnknownFlavors
) {
8027 // Note that we need to set privacy status of transferable before adding any
8029 aTransferable
->SetIsPrivateData(aIsPrivateData
);
8031 nsresult rv
= IPCTransferableDataToTransferable(
8032 aTransferableData
, aAddDataFlavor
, aTransferable
, aFilterUnknownFlavors
);
8033 NS_ENSURE_SUCCESS(rv
, rv
);
8035 aTransferable
->SetRequestingPrincipal(aRequestingPrincipal
);
8036 aTransferable
->SetContentPolicyType(aContentPolicyType
);
8040 nsresult
nsContentUtils::IPCTransferableToTransferable(
8041 const IPCTransferable
& aIPCTransferable
, bool aAddDataFlavor
,
8042 nsITransferable
* aTransferable
, const bool aFilterUnknownFlavors
) {
8043 nsresult rv
= IPCTransferableDataToTransferable(
8044 aIPCTransferable
.data(), aIPCTransferable
.isPrivateData(),
8045 aIPCTransferable
.requestingPrincipal(),
8046 aIPCTransferable
.contentPolicyType(), aAddDataFlavor
, aTransferable
,
8047 aFilterUnknownFlavors
);
8048 NS_ENSURE_SUCCESS(rv
, rv
);
8050 if (aIPCTransferable
.cookieJarSettings().isSome()) {
8051 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
8052 net::CookieJarSettings::Deserialize(
8053 aIPCTransferable
.cookieJarSettings().ref(),
8054 getter_AddRefs(cookieJarSettings
));
8055 aTransferable
->SetCookieJarSettings(cookieJarSettings
);
8057 aTransferable
->SetReferrerInfo(aIPCTransferable
.referrerInfo());
8061 nsresult
nsContentUtils::IPCTransferableDataItemToVariant(
8062 const IPCTransferableDataItem
& aItem
, nsIWritableVariant
* aVariant
) {
8063 MOZ_ASSERT(aVariant
);
8065 switch (aItem
.data().type()) {
8066 case IPCTransferableDataType::TIPCTransferableDataString
: {
8067 const auto& data
= aItem
.data().get_IPCTransferableDataString();
8068 return aVariant
->SetAsAString(nsDependentSubstring(
8069 reinterpret_cast<const char16_t
*>(data
.data().Data()),
8070 data
.data().Size() / sizeof(char16_t
)));
8072 case IPCTransferableDataType::TIPCTransferableDataCString
: {
8073 const auto& data
= aItem
.data().get_IPCTransferableDataCString();
8074 return aVariant
->SetAsACString(nsDependentCSubstring(
8075 reinterpret_cast<const char*>(data
.data().Data()),
8076 data
.data().Size()));
8078 case IPCTransferableDataType::TIPCTransferableDataInputStream
: {
8079 const auto& data
= aItem
.data().get_IPCTransferableDataInputStream();
8080 nsCOMPtr
<nsIInputStream
> stream
;
8081 nsresult rv
= NS_NewByteInputStream(getter_AddRefs(stream
),
8082 AsChars(data
.data().AsSpan()),
8083 NS_ASSIGNMENT_COPY
);
8084 NS_ENSURE_SUCCESS(rv
, rv
);
8085 return aVariant
->SetAsISupports(stream
);
8087 case IPCTransferableDataType::TIPCTransferableDataImageContainer
: {
8088 const auto& data
= aItem
.data().get_IPCTransferableDataImageContainer();
8089 nsCOMPtr
<imgIContainer
> container
;
8090 nsresult rv
= DeserializeTransferableDataImageContainer(
8091 data
, getter_AddRefs(container
));
8092 NS_ENSURE_SUCCESS(rv
, rv
);
8093 return aVariant
->SetAsISupports(container
);
8095 case IPCTransferableDataType::TIPCTransferableDataBlob
: {
8096 const auto& data
= aItem
.data().get_IPCTransferableDataBlob();
8097 RefPtr
<BlobImpl
> blobImpl
= IPCBlobUtils::Deserialize(data
.blob());
8098 return aVariant
->SetAsISupports(blobImpl
);
8100 case IPCTransferableDataType::T__None
:
8104 MOZ_ASSERT_UNREACHABLE();
8105 return NS_ERROR_UNEXPECTED
;
8108 void nsContentUtils::TransferablesToIPCTransferableDatas(
8109 nsIArray
* aTransferables
, nsTArray
<IPCTransferableData
>& aIPC
,
8110 bool aInSyncMessage
, mozilla::dom::ContentParent
* aParent
) {
8112 if (aTransferables
) {
8113 uint32_t transferableCount
= 0;
8114 aTransferables
->GetLength(&transferableCount
);
8115 for (uint32_t i
= 0; i
< transferableCount
; ++i
) {
8116 IPCTransferableData
* dt
= aIPC
.AppendElement();
8117 nsCOMPtr
<nsITransferable
> transferable
=
8118 do_QueryElementAt(aTransferables
, i
);
8119 TransferableToIPCTransferableData(transferable
, dt
, aInSyncMessage
,
8125 nsresult
nsContentUtils::CalculateBufferSizeForImage(
8126 const uint32_t& aStride
, const IntSize
& aImageSize
,
8127 const SurfaceFormat
& aFormat
, size_t* aMaxBufferSize
,
8128 size_t* aUsedBufferSize
) {
8129 CheckedInt32 requiredBytes
=
8130 CheckedInt32(aStride
) * CheckedInt32(aImageSize
.height
);
8132 CheckedInt32 usedBytes
=
8133 requiredBytes
- aStride
+
8134 (CheckedInt32(aImageSize
.width
) * BytesPerPixel(aFormat
));
8135 if (!usedBytes
.isValid()) {
8136 return NS_ERROR_FAILURE
;
8139 MOZ_ASSERT(requiredBytes
.isValid(), "usedBytes valid but not required?");
8140 *aMaxBufferSize
= requiredBytes
.value();
8141 *aUsedBufferSize
= usedBytes
.value();
8145 static already_AddRefed
<DataSourceSurface
> BigBufferToDataSurface(
8146 BigBuffer
& aData
, uint32_t aStride
, const IntSize
& aImageSize
,
8147 SurfaceFormat aFormat
) {
8148 if (!aData
.Size() || !aImageSize
.width
|| !aImageSize
.height
) {
8152 // Validate shared memory buffer size
8153 size_t imageBufLen
= 0;
8154 size_t maxBufLen
= 0;
8155 if (NS_FAILED(nsContentUtils::CalculateBufferSizeForImage(
8156 aStride
, aImageSize
, aFormat
, &maxBufLen
, &imageBufLen
))) {
8159 if (imageBufLen
> aData
.Size()) {
8162 return CreateDataSourceSurfaceFromData(aImageSize
, aFormat
, aData
.Data(),
8166 nsresult
nsContentUtils::DeserializeTransferableDataImageContainer(
8167 const IPCTransferableDataImageContainer
& aData
,
8168 imgIContainer
** aContainer
) {
8169 const IntSize
size(aData
.width(), aData
.height());
8170 size_t maxBufferSize
= 0;
8171 size_t usedBufferSize
= 0;
8172 nsresult rv
= CalculateBufferSizeForImage(
8173 aData
.stride(), size
, aData
.format(), &maxBufferSize
, &usedBufferSize
);
8174 NS_ENSURE_SUCCESS(rv
, rv
);
8175 if (usedBufferSize
> aData
.data().Size()) {
8176 return NS_ERROR_FAILURE
;
8178 RefPtr
<DataSourceSurface
> surface
=
8179 CreateDataSourceSurfaceFromData(size
, aData
.format(), aData
.data().Data(),
8180 static_cast<int32_t>(aData
.stride()));
8182 return NS_ERROR_FAILURE
;
8184 RefPtr
<gfxDrawable
> drawable
= new gfxSurfaceDrawable(surface
, size
);
8185 nsCOMPtr
<imgIContainer
> imageContainer
=
8186 image::ImageOps::CreateFromDrawable(drawable
);
8187 imageContainer
.forget(aContainer
);
8192 bool nsContentUtils::IsFlavorImage(const nsACString
& aFlavor
) {
8193 return aFlavor
.EqualsLiteral(kNativeImageMime
) ||
8194 aFlavor
.EqualsLiteral(kJPEGImageMime
) ||
8195 aFlavor
.EqualsLiteral(kJPGImageMime
) ||
8196 aFlavor
.EqualsLiteral(kPNGImageMime
) ||
8197 aFlavor
.EqualsLiteral(kGIFImageMime
);
8200 // FIXME: This can probably be removed once bug 1783240 lands, as `nsString`
8201 // will be implicitly serialized in shmem when sent over IPDL directly.
8202 static IPCTransferableDataString
AsIPCTransferableDataString(
8203 Span
<const char16_t
> aInput
) {
8204 return IPCTransferableDataString
{BigBuffer(AsBytes(aInput
))};
8207 // FIXME: This can probably be removed once bug 1783240 lands, as `nsCString`
8208 // will be implicitly serialized in shmem when sent over IPDL directly.
8209 static IPCTransferableDataCString
AsIPCTransferableDataCString(
8210 Span
<const char> aInput
) {
8211 return IPCTransferableDataCString
{BigBuffer(AsBytes(aInput
))};
8214 void nsContentUtils::TransferableToIPCTransferableData(
8215 nsITransferable
* aTransferable
, IPCTransferableData
* aTransferableData
,
8216 bool aInSyncMessage
, mozilla::dom::ContentParent
* aParent
) {
8217 MOZ_ASSERT_IF(XRE_IsParentProcess(), aParent
);
8219 if (aTransferable
) {
8220 nsTArray
<nsCString
> flavorList
;
8221 aTransferable
->FlavorsTransferableCanExport(flavorList
);
8223 for (uint32_t j
= 0; j
< flavorList
.Length(); ++j
) {
8224 nsCString
& flavorStr
= flavorList
[j
];
8225 if (!flavorStr
.Length()) {
8229 nsCOMPtr
<nsISupports
> data
;
8231 aTransferable
->GetTransferData(flavorStr
.get(), getter_AddRefs(data
));
8233 if (NS_FAILED(rv
) || !data
) {
8234 if (aInSyncMessage
) {
8235 // Can't do anything.
8236 // FIXME: This shouldn't be the case anymore!
8240 // This is a hack to support kFilePromiseMime.
8241 // On Windows there just needs to be an entry for it,
8242 // and for OSX we need to create
8243 // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
8244 if (flavorStr
.EqualsLiteral(kFilePromiseMime
)) {
8245 IPCTransferableDataItem
* item
=
8246 aTransferableData
->items().AppendElement();
8247 item
->flavor() = flavorStr
;
8249 AsIPCTransferableDataString(NS_ConvertUTF8toUTF16(flavorStr
));
8253 // Empty element, transfer only the flavor
8254 IPCTransferableDataItem
* item
=
8255 aTransferableData
->items().AppendElement();
8256 item
->flavor() = flavorStr
;
8257 item
->data() = AsIPCTransferableDataString(EmptyString());
8261 // We need to handle nsIInputStream before nsISupportsCString, otherwise
8262 // nsStringInputStream would be converted into a wrong type.
8263 if (nsCOMPtr
<nsIInputStream
> stream
= do_QueryInterface(data
)) {
8264 IPCTransferableDataItem
* item
=
8265 aTransferableData
->items().AppendElement();
8266 item
->flavor() = flavorStr
;
8267 nsCString imageData
;
8268 DebugOnly
<nsresult
> rv
=
8269 NS_ConsumeStream(stream
, UINT32_MAX
, imageData
);
8271 rv
!= NS_BASE_STREAM_WOULD_BLOCK
,
8272 "cannot use async input streams in nsITransferable right now");
8273 // FIXME: This can probably be simplified once bug 1783240 lands, as
8274 // `nsCString` will be implicitly serialized in shmem when sent over
8277 IPCTransferableDataInputStream(BigBuffer(AsBytes(Span(imageData
))));
8281 if (nsCOMPtr
<nsISupportsString
> text
= do_QueryInterface(data
)) {
8282 nsAutoString dataAsString
;
8283 MOZ_ALWAYS_SUCCEEDS(text
->GetData(dataAsString
));
8285 IPCTransferableDataItem
* item
=
8286 aTransferableData
->items().AppendElement();
8287 item
->flavor() = flavorStr
;
8288 item
->data() = AsIPCTransferableDataString(dataAsString
);
8292 if (nsCOMPtr
<nsISupportsCString
> ctext
= do_QueryInterface(data
)) {
8293 nsAutoCString dataAsString
;
8294 MOZ_ALWAYS_SUCCEEDS(ctext
->GetData(dataAsString
));
8296 IPCTransferableDataItem
* item
=
8297 aTransferableData
->items().AppendElement();
8298 item
->flavor() = flavorStr
;
8299 item
->data() = AsIPCTransferableDataCString(dataAsString
);
8303 if (nsCOMPtr
<imgIContainer
> image
= do_QueryInterface(data
)) {
8304 // Images to be placed on the clipboard are imgIContainers.
8305 RefPtr
<mozilla::gfx::SourceSurface
> surface
= image
->GetFrame(
8306 imgIContainer::FRAME_CURRENT
,
8307 imgIContainer::FLAG_SYNC_DECODE
| imgIContainer::FLAG_ASYNC_NOTIFY
);
8311 RefPtr
<mozilla::gfx::DataSourceSurface
> dataSurface
=
8312 surface
->GetDataSurface();
8318 Maybe
<BigBuffer
> surfaceData
=
8319 GetSurfaceData(*dataSurface
, &length
, &stride
);
8321 if (surfaceData
.isNothing()) {
8325 IPCTransferableDataItem
* item
=
8326 aTransferableData
->items().AppendElement();
8327 item
->flavor() = flavorStr
;
8329 mozilla::gfx::IntSize size
= dataSurface
->GetSize();
8330 item
->data() = IPCTransferableDataImageContainer(
8331 std::move(*surfaceData
), size
.width
, size
.height
, stride
,
8332 dataSurface
->GetFormat());
8336 // Otherwise, handle this as a file.
8337 nsCOMPtr
<BlobImpl
> blobImpl
;
8338 if (nsCOMPtr
<nsIFile
> file
= do_QueryInterface(data
)) {
8341 if (NS_SUCCEEDED(file
->IsDirectory(&isDir
)) && isDir
) {
8343 if (NS_WARN_IF(NS_FAILED(file
->GetPath(path
)))) {
8347 RefPtr
<FileSystemSecurity
> fss
= FileSystemSecurity::GetOrCreate();
8348 fss
->GrantAccessToContentProcess(aParent
->ChildID(), path
);
8352 blobImpl
= new FileBlobImpl(file
);
8354 IgnoredErrorResult rv
;
8356 // Ensure that file data is cached no that the content process
8357 // has this data available to it when passed over:
8358 blobImpl
->GetSize(rv
);
8359 if (NS_WARN_IF(rv
.Failed())) {
8363 blobImpl
->GetLastModified(rv
);
8364 if (NS_WARN_IF(rv
.Failed())) {
8368 if (aInSyncMessage
) {
8369 // Can't do anything.
8370 // FIXME: This shouldn't be the case anymore!
8374 blobImpl
= do_QueryInterface(data
);
8378 // If we failed to create the blob actor, then this blob probably
8379 // can't get the file size for the underlying file, ignore it for
8380 // now. TODO pass this through anyway.
8382 nsresult rv
= IPCBlobUtils::Serialize(blobImpl
, ipcBlob
);
8383 if (NS_WARN_IF(NS_FAILED(rv
))) {
8387 IPCTransferableDataItem
* item
=
8388 aTransferableData
->items().AppendElement();
8389 item
->flavor() = flavorStr
;
8390 item
->data() = IPCTransferableDataBlob(ipcBlob
);
8396 void nsContentUtils::TransferableToIPCTransferable(
8397 nsITransferable
* aTransferable
, IPCTransferable
* aIPCTransferable
,
8398 bool aInSyncMessage
, mozilla::dom::ContentParent
* aParent
) {
8399 IPCTransferableData ipcTransferableData
;
8400 TransferableToIPCTransferableData(aTransferable
, &ipcTransferableData
,
8401 aInSyncMessage
, aParent
);
8403 Maybe
<net::CookieJarSettingsArgs
> cookieJarSettingsArgs
;
8404 if (nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
=
8405 aTransferable
->GetCookieJarSettings()) {
8406 net::CookieJarSettingsArgs args
;
8407 net::CookieJarSettings::Cast(cookieJarSettings
)->Serialize(args
);
8408 cookieJarSettingsArgs
= Some(std::move(args
));
8411 aIPCTransferable
->data() = std::move(ipcTransferableData
);
8412 aIPCTransferable
->isPrivateData() = aTransferable
->GetIsPrivateData();
8413 aIPCTransferable
->requestingPrincipal() =
8414 aTransferable
->GetRequestingPrincipal();
8415 aIPCTransferable
->cookieJarSettings() = std::move(cookieJarSettingsArgs
);
8416 aIPCTransferable
->contentPolicyType() = aTransferable
->GetContentPolicyType();
8417 aIPCTransferable
->referrerInfo() = aTransferable
->GetReferrerInfo();
8420 Maybe
<BigBuffer
> nsContentUtils::GetSurfaceData(DataSourceSurface
& aSurface
,
8423 mozilla::gfx::DataSourceSurface::MappedSurface map
;
8424 if (!aSurface
.Map(mozilla::gfx::DataSourceSurface::MapType::READ
, &map
)) {
8429 size_t maxBufLen
= 0;
8430 nsresult rv
= nsContentUtils::CalculateBufferSizeForImage(
8431 map
.mStride
, aSurface
.GetSize(), aSurface
.GetFormat(), &maxBufLen
,
8433 if (NS_FAILED(rv
)) {
8438 BigBuffer
surfaceData(maxBufLen
);
8439 memcpy(surfaceData
.Data(), map
.mData
, bufLen
);
8440 memset(surfaceData
.Data() + bufLen
, 0, maxBufLen
- bufLen
);
8442 *aLength
= maxBufLen
;
8443 *aStride
= map
.mStride
;
8446 return Some(std::move(surfaceData
));
8449 Maybe
<IPCImage
> nsContentUtils::SurfaceToIPCImage(DataSourceSurface
& aSurface
) {
8452 auto mem
= GetSurfaceData(aSurface
, &len
, &stride
);
8456 return Some(IPCImage
{std::move(*mem
), uint32_t(stride
), aSurface
.GetFormat(),
8457 ImageIntSize::FromUnknownSize(aSurface
.GetSize())});
8460 already_AddRefed
<DataSourceSurface
> nsContentUtils::IPCImageToSurface(
8461 IPCImage
&& aImage
) {
8462 return BigBufferToDataSurface(aImage
.data(), aImage
.stride(),
8463 aImage
.size().ToUnknownSize(), aImage
.format());
8466 Modifiers
nsContentUtils::GetWidgetModifiers(int32_t aModifiers
) {
8467 Modifiers result
= 0;
8468 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SHIFT
) {
8469 result
|= mozilla::MODIFIER_SHIFT
;
8471 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_CONTROL
) {
8472 result
|= mozilla::MODIFIER_CONTROL
;
8474 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_ALT
) {
8475 result
|= mozilla::MODIFIER_ALT
;
8477 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_META
) {
8478 result
|= mozilla::MODIFIER_META
;
8480 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_ALTGRAPH
) {
8481 result
|= mozilla::MODIFIER_ALTGRAPH
;
8483 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_CAPSLOCK
) {
8484 result
|= mozilla::MODIFIER_CAPSLOCK
;
8486 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_FN
) {
8487 result
|= mozilla::MODIFIER_FN
;
8489 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_FNLOCK
) {
8490 result
|= mozilla::MODIFIER_FNLOCK
;
8492 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_NUMLOCK
) {
8493 result
|= mozilla::MODIFIER_NUMLOCK
;
8495 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SCROLLLOCK
) {
8496 result
|= mozilla::MODIFIER_SCROLLLOCK
;
8498 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SYMBOL
) {
8499 result
|= mozilla::MODIFIER_SYMBOL
;
8501 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK
) {
8502 result
|= mozilla::MODIFIER_SYMBOLLOCK
;
8507 nsIWidget
* nsContentUtils::GetWidget(PresShell
* aPresShell
, nsPoint
* aOffset
) {
8511 nsIFrame
* frame
= aPresShell
->GetRootFrame();
8515 return frame
->GetView()->GetNearestWidget(aOffset
);
8518 int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton
) {
8521 return MouseButtonsFlag::eNoButtons
;
8522 case MouseButton::ePrimary
:
8523 return MouseButtonsFlag::ePrimaryFlag
;
8524 case MouseButton::eMiddle
:
8525 return MouseButtonsFlag::eMiddleFlag
;
8526 case MouseButton::eSecondary
:
8527 return MouseButtonsFlag::eSecondaryFlag
;
8529 return MouseButtonsFlag::e4thFlag
;
8531 return MouseButtonsFlag::e5thFlag
;
8532 case MouseButton::eEraser
:
8533 return MouseButtonsFlag::eEraserFlag
;
8535 NS_ERROR("Button not known.");
8540 LayoutDeviceIntPoint
nsContentUtils::ToWidgetPoint(
8541 const CSSPoint
& aPoint
, const nsPoint
& aOffset
,
8542 nsPresContext
* aPresContext
) {
8543 nsPoint layoutRelative
= CSSPoint::ToAppUnits(aPoint
) + aOffset
;
8544 nsPoint visualRelative
=
8545 ViewportUtils::LayoutToVisual(layoutRelative
, aPresContext
->PresShell());
8546 return LayoutDeviceIntPoint::FromAppUnitsRounded(
8547 visualRelative
, aPresContext
->AppUnitsPerDevPixel());
8550 nsView
* nsContentUtils::GetViewToDispatchEvent(nsPresContext
* aPresContext
,
8551 PresShell
** aPresShell
) {
8552 if (!aPresContext
|| !aPresShell
) {
8555 RefPtr
<PresShell
> presShell
= aPresContext
->PresShell();
8556 if (NS_WARN_IF(!presShell
)) {
8557 *aPresShell
= nullptr;
8560 nsViewManager
* viewManager
= presShell
->GetViewManager();
8562 presShell
.forget(aPresShell
); // XXX Is this intentional?
8565 presShell
.forget(aPresShell
);
8566 return viewManager
->GetRootView();
8569 nsresult
nsContentUtils::SendMouseEvent(
8570 mozilla::PresShell
* aPresShell
, const nsAString
& aType
, float aX
, float aY
,
8571 int32_t aButton
, int32_t aButtons
, int32_t aClickCount
, int32_t aModifiers
,
8572 bool aIgnoreRootScrollFrame
, float aPressure
,
8573 unsigned short aInputSourceArg
, uint32_t aIdentifier
, bool aToWindow
,
8574 PreventDefaultResult
* aPreventDefault
, bool aIsDOMEventSynthesized
,
8575 bool aIsWidgetEventSynthesized
) {
8577 nsCOMPtr
<nsIWidget
> widget
= GetWidget(aPresShell
, &offset
);
8578 if (!widget
) return NS_ERROR_FAILURE
;
8581 Maybe
<WidgetMouseEvent::ExitFrom
> exitFrom
;
8582 bool contextMenuKey
= false;
8583 if (aType
.EqualsLiteral("mousedown")) {
8585 } else if (aType
.EqualsLiteral("mouseup")) {
8587 } else if (aType
.EqualsLiteral("mousemove")) {
8589 } else if (aType
.EqualsLiteral("mouseover")) {
8590 msg
= eMouseEnterIntoWidget
;
8591 } else if (aType
.EqualsLiteral("mouseout")) {
8592 msg
= eMouseExitFromWidget
;
8593 exitFrom
= Some(WidgetMouseEvent::ePlatformChild
);
8594 } else if (aType
.EqualsLiteral("mousecancel")) {
8595 msg
= eMouseExitFromWidget
;
8596 exitFrom
= Some(XRE_IsParentProcess() ? WidgetMouseEvent::ePlatformTopLevel
8597 : WidgetMouseEvent::ePuppet
);
8598 } else if (aType
.EqualsLiteral("mouselongtap")) {
8599 msg
= eMouseLongTap
;
8600 } else if (aType
.EqualsLiteral("contextmenu")) {
8602 contextMenuKey
= (aButton
== 0);
8603 } else if (aType
.EqualsLiteral("MozMouseHittest")) {
8604 msg
= eMouseHitTest
;
8605 } else if (aType
.EqualsLiteral("MozMouseExploreByTouch")) {
8606 msg
= eMouseExploreByTouch
;
8608 return NS_ERROR_FAILURE
;
8611 if (aInputSourceArg
== MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
) {
8612 aInputSourceArg
= MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
8615 WidgetMouseEvent
event(true, msg
, widget
,
8616 aIsWidgetEventSynthesized
8617 ? WidgetMouseEvent::eSynthesized
8618 : WidgetMouseEvent::eReal
,
8619 contextMenuKey
? WidgetMouseEvent::eContextMenuKey
8620 : WidgetMouseEvent::eNormal
);
8621 event
.pointerId
= aIdentifier
;
8622 event
.mModifiers
= GetWidgetModifiers(aModifiers
);
8623 event
.mButton
= aButton
;
8624 event
.mButtons
= aButtons
!= nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED
8626 : msg
== eMouseUp
? 0
8627 : GetButtonsFlagForButton(aButton
);
8628 event
.mPressure
= aPressure
;
8629 event
.mInputSource
= aInputSourceArg
;
8630 event
.mClickCount
= aClickCount
;
8631 event
.mFlags
.mIsSynthesizedForTests
= aIsDOMEventSynthesized
;
8632 event
.mExitFrom
= exitFrom
;
8634 nsPresContext
* presContext
= aPresShell
->GetPresContext();
8635 if (!presContext
) return NS_ERROR_FAILURE
;
8637 event
.mRefPoint
= ToWidgetPoint(CSSPoint(aX
, aY
), offset
, presContext
);
8638 event
.mIgnoreRootScrollFrame
= aIgnoreRootScrollFrame
;
8640 nsEventStatus status
= nsEventStatus_eIgnore
;
8642 RefPtr
<PresShell
> presShell
;
8644 GetViewToDispatchEvent(presContext
, getter_AddRefs(presShell
));
8645 if (!presShell
|| !view
) {
8646 return NS_ERROR_FAILURE
;
8648 return presShell
->HandleEvent(view
->GetFrame(), &event
, false, &status
);
8650 if (StaticPrefs::test_events_async_enabled() &&
8651 StaticPrefs::test_events_async_mouse_enabled()) {
8652 status
= widget
->DispatchInputEvent(&event
).mContentStatus
;
8654 nsresult rv
= widget
->DispatchEvent(&event
, status
);
8655 NS_ENSURE_SUCCESS(rv
, rv
);
8657 if (aPreventDefault
) {
8658 if (status
== nsEventStatus_eConsumeNoDefault
) {
8659 if (event
.mFlags
.mDefaultPreventedByContent
) {
8660 *aPreventDefault
= PreventDefaultResult::ByContent
;
8662 *aPreventDefault
= PreventDefaultResult::ByChrome
;
8665 *aPreventDefault
= PreventDefaultResult::No
;
8673 void nsContentUtils::FirePageHideEventForFrameLoaderSwap(
8674 nsIDocShellTreeItem
* aItem
, EventTarget
* aChromeEventHandler
,
8675 bool aOnlySystemGroup
) {
8676 MOZ_DIAGNOSTIC_ASSERT(aItem
);
8677 MOZ_DIAGNOSTIC_ASSERT(aChromeEventHandler
);
8679 RefPtr
<Document
> doc
= aItem
->GetDocument();
8680 NS_ASSERTION(doc
, "What happened here?");
8681 doc
->OnPageHide(true, aChromeEventHandler
, aOnlySystemGroup
);
8683 int32_t childCount
= 0;
8684 aItem
->GetInProcessChildCount(&childCount
);
8685 AutoTArray
<nsCOMPtr
<nsIDocShellTreeItem
>, 8> kids
;
8686 kids
.AppendElements(childCount
);
8687 for (int32_t i
= 0; i
< childCount
; ++i
) {
8688 aItem
->GetInProcessChildAt(i
, getter_AddRefs(kids
[i
]));
8691 for (uint32_t i
= 0; i
< kids
.Length(); ++i
) {
8693 FirePageHideEventForFrameLoaderSwap(kids
[i
], aChromeEventHandler
,
8699 // The pageshow event is fired for a given document only if IsShowing() returns
8700 // the same thing as aFireIfShowing. This gives us a way to fire pageshow only
8701 // on documents that are still loading or only on documents that are already
8704 void nsContentUtils::FirePageShowEventForFrameLoaderSwap(
8705 nsIDocShellTreeItem
* aItem
, EventTarget
* aChromeEventHandler
,
8706 bool aFireIfShowing
, bool aOnlySystemGroup
) {
8707 int32_t childCount
= 0;
8708 aItem
->GetInProcessChildCount(&childCount
);
8709 AutoTArray
<nsCOMPtr
<nsIDocShellTreeItem
>, 8> kids
;
8710 kids
.AppendElements(childCount
);
8711 for (int32_t i
= 0; i
< childCount
; ++i
) {
8712 aItem
->GetInProcessChildAt(i
, getter_AddRefs(kids
[i
]));
8715 for (uint32_t i
= 0; i
< kids
.Length(); ++i
) {
8717 FirePageShowEventForFrameLoaderSwap(kids
[i
], aChromeEventHandler
,
8718 aFireIfShowing
, aOnlySystemGroup
);
8722 RefPtr
<Document
> doc
= aItem
->GetDocument();
8723 if (doc
&& doc
->IsShowing() == aFireIfShowing
) {
8724 doc
->OnPageShow(true, aChromeEventHandler
, aOnlySystemGroup
);
8729 already_AddRefed
<nsPIWindowRoot
> nsContentUtils::GetWindowRoot(Document
* aDoc
) {
8731 if (nsPIDOMWindowOuter
* win
= aDoc
->GetWindow()) {
8732 return win
->GetTopWindowRoot();
8739 bool nsContentUtils::LinkContextIsURI(const nsAString
& aAnchor
,
8741 if (aAnchor
.IsEmpty()) {
8742 // anchor parameter not present or empty -> same document reference
8746 // the document URI might contain a fragment identifier ("#...')
8747 // we want to ignore that because it's invisible to the server
8748 // and just affects the local interpretation in the recipient
8749 nsCOMPtr
<nsIURI
> contextUri
;
8750 nsresult rv
= NS_GetURIWithoutRef(aDocURI
, getter_AddRefs(contextUri
));
8752 if (NS_FAILED(rv
)) {
8757 // resolve anchor against context
8758 nsCOMPtr
<nsIURI
> resolvedUri
;
8759 rv
= NS_NewURI(getter_AddRefs(resolvedUri
), aAnchor
, nullptr, contextUri
);
8761 if (NS_FAILED(rv
)) {
8767 rv
= contextUri
->Equals(resolvedUri
, &same
);
8768 if (NS_FAILED(rv
)) {
8769 // comparison failed
8777 bool nsContentUtils::IsPreloadType(nsContentPolicyType aType
) {
8778 return (aType
== nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD
||
8779 aType
== nsIContentPolicy::TYPE_INTERNAL_MODULE_PRELOAD
||
8780 aType
== nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD
||
8781 aType
== nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
||
8782 aType
== nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD
||
8783 aType
== nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD
);
8787 ReferrerPolicy
nsContentUtils::GetReferrerPolicyFromChannel(
8788 nsIChannel
* aChannel
) {
8789 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
8791 return ReferrerPolicy::_empty
;
8795 nsAutoCString headerValue
;
8796 rv
= httpChannel
->GetResponseHeader("referrer-policy"_ns
, headerValue
);
8797 if (NS_FAILED(rv
) || headerValue
.IsEmpty()) {
8798 return ReferrerPolicy::_empty
;
8801 return ReferrerInfo::ReferrerPolicyFromHeaderString(
8802 NS_ConvertUTF8toUTF16(headerValue
));
8806 bool nsContentUtils::IsNonSubresourceRequest(nsIChannel
* aChannel
) {
8807 nsLoadFlags loadFlags
= 0;
8808 aChannel
->GetLoadFlags(&loadFlags
);
8809 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
) {
8813 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
8814 nsContentPolicyType type
= loadInfo
->InternalContentPolicyType();
8815 return IsNonSubresourceInternalPolicyType(type
);
8819 bool nsContentUtils::IsNonSubresourceInternalPolicyType(
8820 nsContentPolicyType aType
) {
8821 return aType
== nsIContentPolicy::TYPE_DOCUMENT
||
8822 aType
== nsIContentPolicy::TYPE_INTERNAL_IFRAME
||
8823 aType
== nsIContentPolicy::TYPE_INTERNAL_FRAME
||
8824 aType
== nsIContentPolicy::TYPE_INTERNAL_WORKER
||
8825 aType
== nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
8829 bool nsContentUtils::IsThirdPartyTrackingResourceWindow(
8830 nsPIDOMWindowInner
* aWindow
) {
8831 MOZ_ASSERT(aWindow
);
8833 Document
* document
= aWindow
->GetExtantDoc();
8838 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
8839 do_QueryInterface(document
->GetChannel());
8840 if (!classifiedChannel
) {
8844 return classifiedChannel
->IsThirdPartyTrackingResource();
8848 bool nsContentUtils::IsFirstPartyTrackingResourceWindow(
8849 nsPIDOMWindowInner
* aWindow
) {
8850 MOZ_ASSERT(aWindow
);
8852 Document
* document
= aWindow
->GetExtantDoc();
8857 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
8858 do_QueryInterface(document
->GetChannel());
8859 if (!classifiedChannel
) {
8863 uint32_t classificationFlags
=
8864 classifiedChannel
->GetFirstPartyClassificationFlags();
8866 return mozilla::net::UrlClassifierCommon::IsTrackingClassificationFlag(
8867 classificationFlags
, NS_UsePrivateBrowsing(document
->GetChannel()));
8872 // We put StringBuilder in the anonymous namespace to prevent anything outside
8873 // this file from accidentally being linked against it.
8874 class BulkAppender
{
8875 using size_type
= typename
nsAString::size_type
;
8878 explicit BulkAppender(BulkWriteHandle
<char16_t
>&& aHandle
)
8879 : mHandle(std::move(aHandle
)), mPosition(0) {}
8880 ~BulkAppender() = default;
8883 void AppendLiteral(const char16_t (&aStr
)[N
]) {
8885 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8886 memcpy(mHandle
.Elements() + mPosition
, aStr
, len
* sizeof(char16_t
));
8890 void Append(Span
<const char16_t
> aStr
) {
8891 size_t len
= aStr
.Length();
8892 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8893 // Both mHandle.Elements() and aStr.Elements() are guaranteed
8894 // to be non-null (by the string implementation and by Span,
8895 // respectively), so not checking the pointers for null before
8896 // memcpy does not lead to UB even if len was zero.
8897 memcpy(mHandle
.Elements() + mPosition
, aStr
.Elements(),
8898 len
* sizeof(char16_t
));
8902 void Append(Span
<const char> aStr
) {
8903 size_t len
= aStr
.Length();
8904 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8905 ConvertLatin1toUtf16(aStr
, mHandle
.AsSpan().From(mPosition
));
8909 void Finish() { mHandle
.Finish(mPosition
, false); }
8912 BulkWriteHandle
<char16_t
> mHandle
;
8913 size_type mPosition
;
8916 class StringBuilder
{
8920 Unit() : mAtom(nullptr) { MOZ_COUNT_CTOR(StringBuilder::Unit
); }
8922 if (mType
== Type::String
|| mType
== Type::StringWithEncode
) {
8923 mString
.~nsString();
8925 MOZ_COUNT_DTOR(StringBuilder::Unit
);
8928 enum class Type
: uint8_t {
8935 TextFragmentWithEncode
,
8940 const char16_t
* mLiteral
;
8942 const nsTextFragment
* mTextFragment
;
8944 uint32_t mLength
= 0;
8945 Type mType
= Type::Unknown
;
8948 static_assert(sizeof(void*) != 8 || sizeof(Unit
) <= 3 * sizeof(void*),
8949 "Unit should remain small");
8952 // Try to keep the size of StringBuilder close to a jemalloc bucket size (the
8953 // 16kb one in this case).
8954 static constexpr uint32_t TARGET_SIZE
= 16 * 1024;
8956 // The number of units we need to remove from the inline buffer so that the
8957 // rest of the builder members fit. A more precise approach would be to
8958 // calculate that extra size and use (TARGET_SIZE - OTHER_SIZE) / sizeof(Unit)
8959 // or so, but this is simpler.
8960 static constexpr uint32_t PADDING_UNITS
= sizeof(void*) == 8 ? 1 : 2;
8962 static constexpr uint32_t STRING_BUFFER_UNITS
=
8963 TARGET_SIZE
/ sizeof(Unit
) - PADDING_UNITS
;
8965 StringBuilder() : mLast(this), mLength(0) { MOZ_COUNT_CTOR(StringBuilder
); }
8967 MOZ_COUNTED_DTOR(StringBuilder
)
8969 void Append(nsAtom
* aAtom
) {
8970 Unit
* u
= AddUnit();
8972 u
->mType
= Unit::Type::Atom
;
8973 uint32_t len
= aAtom
->GetLength();
8979 void Append(const char16_t (&aLiteral
)[N
]) {
8980 Unit
* u
= AddUnit();
8981 u
->mLiteral
= aLiteral
;
8982 u
->mType
= Unit::Type::Literal
;
8983 uint32_t len
= N
- 1;
8988 void Append(nsString
&& aString
) {
8989 Unit
* u
= AddUnit();
8990 uint32_t len
= aString
.Length();
8991 new (&u
->mString
) nsString(std::move(aString
));
8992 u
->mType
= Unit::Type::String
;
8997 void AppendWithAttrEncode(nsString
&& aString
, uint32_t aLen
) {
8998 Unit
* u
= AddUnit();
8999 new (&u
->mString
) nsString(std::move(aString
));
9000 u
->mType
= Unit::Type::StringWithEncode
;
9005 void Append(const nsTextFragment
* aTextFragment
) {
9006 Unit
* u
= AddUnit();
9007 u
->mTextFragment
= aTextFragment
;
9008 u
->mType
= Unit::Type::TextFragment
;
9009 uint32_t len
= aTextFragment
->GetLength();
9014 void AppendWithEncode(const nsTextFragment
* aTextFragment
, uint32_t aLen
) {
9015 Unit
* u
= AddUnit();
9016 u
->mTextFragment
= aTextFragment
;
9017 u
->mType
= Unit::Type::TextFragmentWithEncode
;
9022 bool ToString(nsAString
& aOut
) {
9023 if (!mLength
.isValid()) {
9026 auto appenderOrErr
= aOut
.BulkWrite(mLength
.value(), 0, true);
9027 if (appenderOrErr
.isErr()) {
9031 BulkAppender appender
{appenderOrErr
.unwrap()};
9033 for (StringBuilder
* current
= this; current
;
9034 current
= current
->mNext
.get()) {
9035 uint32_t len
= current
->mUnits
.Length();
9036 for (uint32_t i
= 0; i
< len
; ++i
) {
9037 Unit
& u
= current
->mUnits
[i
];
9039 case Unit::Type::Atom
:
9040 appender
.Append(*(u
.mAtom
));
9042 case Unit::Type::String
:
9043 appender
.Append(u
.mString
);
9045 case Unit::Type::StringWithEncode
:
9046 EncodeAttrString(u
.mString
, appender
);
9048 case Unit::Type::Literal
:
9049 appender
.Append(Span(u
.mLiteral
, u
.mLength
));
9051 case Unit::Type::TextFragment
:
9052 if (u
.mTextFragment
->Is2b()) {
9054 Span(u
.mTextFragment
->Get2b(), u
.mTextFragment
->GetLength()));
9057 Span(u
.mTextFragment
->Get1b(), u
.mTextFragment
->GetLength()));
9060 case Unit::Type::TextFragmentWithEncode
:
9061 if (u
.mTextFragment
->Is2b()) {
9063 Span(u
.mTextFragment
->Get2b(), u
.mTextFragment
->GetLength()),
9067 Span(u
.mTextFragment
->Get1b(), u
.mTextFragment
->GetLength()),
9072 MOZ_CRASH("Unknown unit type?");
9082 if (mLast
->mUnits
.Length() == STRING_BUFFER_UNITS
) {
9083 new StringBuilder(this);
9085 return mLast
->mUnits
.AppendElement();
9088 explicit StringBuilder(StringBuilder
* aFirst
) : mLast(nullptr), mLength(0) {
9089 MOZ_COUNT_CTOR(StringBuilder
);
9090 aFirst
->mLast
->mNext
= WrapUnique(this);
9091 aFirst
->mLast
= this;
9094 void EncodeAttrString(Span
<const char16_t
> aStr
, BulkAppender
& aAppender
) {
9095 size_t flushedUntil
= 0;
9096 size_t currentPosition
= 0;
9097 for (char16_t c
: aStr
) {
9100 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9101 aAppender
.AppendLiteral(u
""");
9102 flushedUntil
= currentPosition
+ 1;
9105 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9106 aAppender
.AppendLiteral(u
"&");
9107 flushedUntil
= currentPosition
+ 1;
9110 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9111 aAppender
.AppendLiteral(u
" ");
9112 flushedUntil
= currentPosition
+ 1;
9119 if (currentPosition
> flushedUntil
) {
9120 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9125 void EncodeTextFragment(Span
<const T
> aStr
, BulkAppender
& aAppender
) {
9126 size_t flushedUntil
= 0;
9127 size_t currentPosition
= 0;
9131 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9132 aAppender
.AppendLiteral(u
"<");
9133 flushedUntil
= currentPosition
+ 1;
9136 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9137 aAppender
.AppendLiteral(u
">");
9138 flushedUntil
= currentPosition
+ 1;
9141 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9142 aAppender
.AppendLiteral(u
"&");
9143 flushedUntil
= currentPosition
+ 1;
9146 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9147 aAppender
.AppendLiteral(u
" ");
9148 flushedUntil
= currentPosition
+ 1;
9155 if (currentPosition
> flushedUntil
) {
9156 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
9160 AutoTArray
<Unit
, STRING_BUFFER_UNITS
> mUnits
;
9161 UniquePtr
<StringBuilder
> mNext
;
9162 StringBuilder
* mLast
;
9163 // mLength is used only in the first StringBuilder object in the linked list.
9164 CheckedInt
<uint32_t> mLength
;
9167 static_assert(sizeof(StringBuilder
) <= StringBuilder::TARGET_SIZE
,
9168 "StringBuilder should fit in the target bucket");
9172 static void AppendEncodedCharacters(const nsTextFragment
* aText
,
9173 StringBuilder
& aBuilder
) {
9174 uint32_t extraSpaceNeeded
= 0;
9175 uint32_t len
= aText
->GetLength();
9176 if (aText
->Is2b()) {
9177 const char16_t
* data
= aText
->Get2b();
9178 for (uint32_t i
= 0; i
< len
; ++i
) {
9179 const char16_t c
= data
[i
];
9182 extraSpaceNeeded
+= ArrayLength("<") - 2;
9185 extraSpaceNeeded
+= ArrayLength(">") - 2;
9188 extraSpaceNeeded
+= ArrayLength("&") - 2;
9191 extraSpaceNeeded
+= ArrayLength(" ") - 2;
9198 const char* data
= aText
->Get1b();
9199 for (uint32_t i
= 0; i
< len
; ++i
) {
9200 const unsigned char c
= data
[i
];
9203 extraSpaceNeeded
+= ArrayLength("<") - 2;
9206 extraSpaceNeeded
+= ArrayLength(">") - 2;
9209 extraSpaceNeeded
+= ArrayLength("&") - 2;
9212 extraSpaceNeeded
+= ArrayLength(" ") - 2;
9220 if (extraSpaceNeeded
) {
9221 aBuilder
.AppendWithEncode(aText
, len
+ extraSpaceNeeded
);
9223 aBuilder
.Append(aText
);
9227 static uint32_t ExtraSpaceNeededForAttrEncoding(const nsAString
& aValue
) {
9228 const char16_t
* c
= aValue
.BeginReading();
9229 const char16_t
* end
= aValue
.EndReading();
9231 uint32_t extraSpaceNeeded
= 0;
9235 extraSpaceNeeded
+= ArrayLength(""") - 2;
9238 extraSpaceNeeded
+= ArrayLength("&") - 2;
9241 extraSpaceNeeded
+= ArrayLength(" ") - 2;
9249 return extraSpaceNeeded
;
9252 static void AppendEncodedAttributeValue(const nsAttrValue
& aValue
,
9253 StringBuilder
& aBuilder
) {
9254 if (nsAtom
* atom
= aValue
.GetStoredAtom()) {
9255 nsDependentAtomString
atomStr(atom
);
9256 uint32_t space
= ExtraSpaceNeededForAttrEncoding(atomStr
);
9258 aBuilder
.Append(atom
);
9260 aBuilder
.AppendWithAttrEncode(nsString(atomStr
),
9261 atomStr
.Length() + space
);
9265 // NOTE(emilio): In most cases this will just be a reference to the stored
9268 aValue
.ToString(str
);
9269 uint32_t space
= ExtraSpaceNeededForAttrEncoding(str
);
9271 aBuilder
.AppendWithAttrEncode(std::move(str
), str
.Length() + space
);
9273 aBuilder
.Append(std::move(str
));
9277 static void StartElement(Element
* aElement
, StringBuilder
& aBuilder
) {
9278 nsAtom
* localName
= aElement
->NodeInfo()->NameAtom();
9279 const int32_t tagNS
= aElement
->GetNameSpaceID();
9281 aBuilder
.Append(u
"<");
9282 if (tagNS
== kNameSpaceID_XHTML
|| tagNS
== kNameSpaceID_SVG
||
9283 tagNS
== kNameSpaceID_MathML
) {
9284 aBuilder
.Append(localName
);
9286 aBuilder
.Append(nsString(aElement
->NodeName()));
9289 if (CustomElementData
* ceData
= aElement
->GetCustomElementData()) {
9290 nsAtom
* isAttr
= ceData
->GetIs(aElement
);
9291 if (isAttr
&& !aElement
->HasAttr(nsGkAtoms::is
)) {
9292 aBuilder
.Append(uR
"( is=")");
9293 aBuilder.Append(isAttr);
9294 aBuilder.Append(uR"(")");
9299 while (BorrowedAttrInfo info
= aElement
->GetAttrInfoAt(i
++)) {
9300 const nsAttrName
* name
= info
.mName
;
9302 int32_t attNs
= name
->NamespaceID();
9303 nsAtom
* attName
= name
->LocalName();
9305 // Filter out any attribute starting with [-|_]moz
9306 // FIXME(emilio): Do we still need this?
9307 nsDependentAtomString
attrNameStr(attName
);
9308 if (StringBeginsWith(attrNameStr
, u
"_moz"_ns
) ||
9309 StringBeginsWith(attrNameStr
, u
"-moz"_ns
)) {
9313 aBuilder
.Append(u
" ");
9315 if (MOZ_LIKELY(attNs
== kNameSpaceID_None
) ||
9316 (attNs
== kNameSpaceID_XMLNS
&& attName
== nsGkAtoms::xmlns
)) {
9317 // Nothing else required
9318 } else if (attNs
== kNameSpaceID_XML
) {
9319 aBuilder
.Append(u
"xml:");
9320 } else if (attNs
== kNameSpaceID_XMLNS
) {
9321 aBuilder
.Append(u
"xmlns:");
9322 } else if (attNs
== kNameSpaceID_XLink
) {
9323 aBuilder
.Append(u
"xlink:");
9324 } else if (nsAtom
* prefix
= name
->GetPrefix()) {
9325 aBuilder
.Append(prefix
);
9326 aBuilder
.Append(u
":");
9329 aBuilder
.Append(attName
);
9330 aBuilder
.Append(uR
"(=")");
9331 AppendEncodedAttributeValue(*info.mValue, aBuilder);
9332 aBuilder.Append(uR"(")");
9335 aBuilder
.Append(u
">");
9338 // Per HTML spec we should append one \n if the first child of
9339 // pre/textarea/listing is a textnode and starts with a \n.
9340 // But because browsers haven't traditionally had that behavior,
9341 // we're not changing our behavior either - yet.
9342 if (aContent->IsHTMLElement()) {
9343 if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
9344 localName == nsGkAtoms::listing) {
9345 nsIContent* fc = aContent->GetFirstChild();
9347 (fc->NodeType() == nsINode::TEXT_NODE ||
9348 fc->NodeType() == nsINode::CDATA_SECTION_NODE)) {
9349 const nsTextFragment* text = fc->GetText();
9350 if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
9351 aBuilder.Append("\n");
9358 static inline bool ShouldEscape(nsIContent
* aParent
) {
9359 if (!aParent
|| !aParent
->IsHTMLElement()) {
9363 static const nsAtom
* nonEscapingElements
[] = {
9364 nsGkAtoms::style
, nsGkAtoms::script
, nsGkAtoms::xmp
,
9365 nsGkAtoms::iframe
, nsGkAtoms::noembed
, nsGkAtoms::noframes
,
9366 nsGkAtoms::plaintext
, nsGkAtoms::noscript
};
9367 static mozilla::BitBloomFilter
<12, nsAtom
> sFilter
;
9368 static bool sInitialized
= false;
9369 if (!sInitialized
) {
9370 sInitialized
= true;
9371 for (auto& nonEscapingElement
: nonEscapingElements
) {
9372 sFilter
.add(nonEscapingElement
);
9376 nsAtom
* tag
= aParent
->NodeInfo()->NameAtom();
9377 if (sFilter
.mightContain(tag
)) {
9378 for (auto& nonEscapingElement
: nonEscapingElements
) {
9379 if (tag
== nonEscapingElement
) {
9380 if (MOZ_UNLIKELY(tag
== nsGkAtoms::noscript
) &&
9381 MOZ_UNLIKELY(!aParent
->OwnerDoc()->IsScriptEnabled())) {
9391 static inline bool IsVoidTag(Element
* aElement
) {
9392 if (!aElement
->IsHTMLElement()) {
9395 return FragmentOrElement::IsHTMLVoid(aElement
->NodeInfo()->NameAtom());
9398 bool nsContentUtils::SerializeNodeToMarkup(nsINode
* aRoot
,
9399 bool aDescendantsOnly
,
9401 // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true
9402 MOZ_ASSERT(aDescendantsOnly
|| aRoot
->NodeType() != nsINode::DOCUMENT_NODE
);
9405 aDescendantsOnly
? aRoot
->GetFirstChildOfTemplateOrNode() : aRoot
;
9411 StringBuilder builder
;
9414 bool isVoid
= false;
9415 switch (current
->NodeType()) {
9416 case nsINode::ELEMENT_NODE
: {
9417 Element
* elem
= current
->AsElement();
9418 StartElement(elem
, builder
);
9419 isVoid
= IsVoidTag(elem
);
9420 if (!isVoid
&& (next
= current
->GetFirstChildOfTemplateOrNode())) {
9427 case nsINode::TEXT_NODE
:
9428 case nsINode::CDATA_SECTION_NODE
: {
9429 const nsTextFragment
* text
= ¤t
->AsText()->TextFragment();
9430 nsIContent
* parent
= current
->GetParent();
9431 if (ShouldEscape(parent
)) {
9432 AppendEncodedCharacters(text
, builder
);
9434 builder
.Append(text
);
9439 case nsINode::COMMENT_NODE
: {
9440 builder
.Append(u
"<!--");
9441 builder
.Append(static_cast<nsIContent
*>(current
)->GetText());
9442 builder
.Append(u
"-->");
9446 case nsINode::DOCUMENT_TYPE_NODE
: {
9447 builder
.Append(u
"<!DOCTYPE ");
9448 builder
.Append(nsString(current
->NodeName()));
9449 builder
.Append(u
">");
9453 case nsINode::PROCESSING_INSTRUCTION_NODE
: {
9454 builder
.Append(u
"<?");
9455 builder
.Append(nsString(current
->NodeName()));
9456 builder
.Append(u
" ");
9457 builder
.Append(static_cast<nsIContent
*>(current
)->GetText());
9458 builder
.Append(u
">");
9464 if (!isVoid
&& current
->NodeType() == nsINode::ELEMENT_NODE
) {
9465 builder
.Append(u
"</");
9466 nsIContent
* elem
= static_cast<nsIContent
*>(current
);
9467 if (elem
->IsHTMLElement() || elem
->IsSVGElement() ||
9468 elem
->IsMathMLElement()) {
9469 builder
.Append(elem
->NodeInfo()->NameAtom());
9471 builder
.Append(nsString(current
->NodeName()));
9473 builder
.Append(u
">");
9477 if (current
== aRoot
) {
9478 return builder
.ToString(aOut
);
9481 if ((next
= current
->GetNextSibling())) {
9486 current
= current
->GetParentNode();
9488 // Handle template element. If the parent is a template's content,
9489 // then adjust the parent to be the template element.
9490 if (current
!= aRoot
&&
9491 current
->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE
) {
9492 DocumentFragment
* frag
= static_cast<DocumentFragment
*>(current
);
9493 nsIContent
* fragHost
= frag
->GetHost();
9494 if (fragHost
&& fragHost
->IsTemplateElement()) {
9499 if (aDescendantsOnly
&& current
== aRoot
) {
9500 return builder
.ToString(aOut
);
9506 bool nsContentUtils::IsSpecificAboutPage(JSObject
* aGlobal
, const char* aUri
) {
9507 // aUri must start with about: or this isn't the right function to be using.
9508 MOZ_ASSERT(strncmp(aUri
, "about:", 6) == 0);
9510 // Make sure the global is a window
9511 MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal
));
9512 nsGlobalWindowInner
* win
= xpc::WindowOrNull(aGlobal
);
9517 nsCOMPtr
<nsIPrincipal
> principal
= win
->GetPrincipal();
9518 NS_ENSURE_TRUE(principal
, false);
9520 // First check the scheme to avoid getting long specs in the common case.
9521 if (!principal
->SchemeIs("about")) {
9526 principal
->GetAsciiSpec(spec
);
9528 return spec
.EqualsASCII(aUri
);
9532 void nsContentUtils::SetScrollbarsVisibility(nsIDocShell
* aDocShell
,
9537 auto pref
= aVisible
? ScrollbarPreference::Auto
: ScrollbarPreference::Never
;
9538 nsDocShell::Cast(aDocShell
)->SetScrollbarPreference(pref
);
9542 nsIDocShell
* nsContentUtils::GetDocShellForEventTarget(EventTarget
* aTarget
) {
9547 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
;
9548 if (nsCOMPtr
<nsINode
> node
= nsINode::FromEventTarget(aTarget
)) {
9551 do_QueryInterface(node
->OwnerDoc()->GetScriptHandlingObject(ignore
));
9552 } else if ((innerWindow
= nsPIDOMWindowInner::FromEventTarget(aTarget
))) {
9553 // Nothing else to do
9555 nsCOMPtr
<DOMEventTargetHelper
> helper
= do_QueryInterface(aTarget
);
9557 innerWindow
= helper
->GetOwner();
9562 return innerWindow
->GetDocShell();
9569 * Note: this function only relates to figuring out HTTPS state, which is an
9570 * input to the Secure Context algorithm. We are not actually implementing any
9571 * part of the Secure Context algorithm itself here.
9573 * This is a bit of a hack. Ideally we'd propagate HTTPS state through
9574 * nsIChannel as described in the Fetch and HTML specs, but making channels
9575 * know about whether they should inherit HTTPS state, propagating information
9576 * about who the channel's "client" is, exposing GetHttpsState API on channels
9577 * and modifying the various cache implementations to store and retrieve HTTPS
9578 * state involves a huge amount of code (see bug 1220687). We avoid that for
9579 * now using this function.
9581 * This function takes advantage of the observation that we can return true if
9582 * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for
9583 * the document's origin (e.g. the origin has a scheme of 'https' or host
9584 * 'localhost' etc.). Since we generally propagate a creator document's origin
9585 * onto data:, blob:, etc. documents, this works for them too.
9587 * The scenario where this observation breaks down is sandboxing without the
9588 * 'allow-same-origin' flag, since in this case a document is given a unique
9589 * origin (IsOriginPotentiallyTrustworthy would return false). We handle that
9590 * by using the origin that the document would have had had it not been
9593 * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's
9594 * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of
9595 * sandboxing is limited to the immediate sandbox. In the case that aDocument
9596 * should inherit its origin (e.g. data: URI) but its parent has ended up
9597 * with a unique origin due to sandboxing further up the parent chain we may
9598 * end up returning false when we would ideally return true (since we will
9599 * examine the parent's origin for 'https' and not finding it.) This means
9600 * that we may restrict the privileges of some pages unnecessarily in this
9604 bool nsContentUtils::HttpsStateIsModern(Document
* aDocument
) {
9609 nsCOMPtr
<nsIPrincipal
> principal
= aDocument
->NodePrincipal();
9611 if (principal
->IsSystemPrincipal()) {
9615 // If aDocument is sandboxed, try and get the principal that it would have
9616 // been given had it not been sandboxed:
9617 if (principal
->GetIsNullPrincipal() &&
9618 (aDocument
->GetSandboxFlags() & SANDBOXED_ORIGIN
)) {
9619 nsIChannel
* channel
= aDocument
->GetChannel();
9621 nsCOMPtr
<nsIScriptSecurityManager
> ssm
=
9622 nsContentUtils::GetSecurityManager();
9623 nsresult rv
= ssm
->GetChannelResultPrincipalIfNotSandboxed(
9624 channel
, getter_AddRefs(principal
));
9625 if (NS_FAILED(rv
)) {
9628 if (principal
->IsSystemPrincipal()) {
9629 // If a document with the system principal is sandboxing a subdocument
9630 // that would normally inherit the embedding element's principal (e.g.
9631 // a srcdoc document) then the embedding document does not trust the
9632 // content that is written to the embedded document. Unlike when the
9633 // embedding document is https, in this case we have no indication as
9634 // to whether the embedded document's contents are delivered securely
9635 // or not, and the sandboxing would possibly indicate that they were
9636 // not. To play it safe we return false here. (See bug 1162772
9643 if (principal
->GetIsNullPrincipal()) {
9647 MOZ_ASSERT(principal
->GetIsContentPrincipal());
9649 return principal
->GetIsOriginPotentiallyTrustworthy();
9653 bool nsContentUtils::ComputeIsSecureContext(nsIChannel
* aChannel
) {
9654 MOZ_ASSERT(aChannel
);
9656 nsCOMPtr
<nsIScriptSecurityManager
> ssm
= nsContentUtils::GetSecurityManager();
9657 nsCOMPtr
<nsIPrincipal
> principal
;
9658 nsresult rv
= ssm
->GetChannelResultPrincipalIfNotSandboxed(
9659 aChannel
, getter_AddRefs(principal
));
9660 if (NS_FAILED(rv
)) {
9664 const RefPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
9666 if (principal
->IsSystemPrincipal()) {
9667 // If the load would've been sandboxed, treat this load as an untrusted
9668 // load, as system code considers sandboxed resources insecure.
9669 return !loadInfo
->GetLoadingSandboxed();
9672 if (principal
->GetIsNullPrincipal()) {
9676 if (const RefPtr
<WindowContext
> windowContext
=
9677 WindowContext::GetById(loadInfo
->GetInnerWindowID())) {
9678 if (!windowContext
->GetIsSecureContext()) {
9683 return principal
->GetIsOriginPotentiallyTrustworthy();
9687 void nsContentUtils::TryToUpgradeElement(Element
* aElement
) {
9688 NodeInfo
* nodeInfo
= aElement
->NodeInfo();
9689 RefPtr
<nsAtom
> typeAtom
=
9690 aElement
->GetCustomElementData()->GetCustomElementType();
9692 MOZ_ASSERT(nodeInfo
->NameAtom()->Equals(nodeInfo
->LocalName()));
9693 CustomElementDefinition
* definition
=
9694 nsContentUtils::LookupCustomElementDefinition(
9695 nodeInfo
->GetDocument(), nodeInfo
->NameAtom(),
9696 nodeInfo
->NamespaceID(), typeAtom
);
9698 nsContentUtils::EnqueueUpgradeReaction(aElement
, definition
);
9700 // Add an unresolved custom element that is a candidate for upgrade when a
9701 // custom element is connected to the document.
9702 nsContentUtils::RegisterUnresolvedElement(aElement
, typeAtom
);
9707 static void DoCustomElementCreate(Element
** aElement
, JSContext
* aCx
,
9708 Document
* aDoc
, NodeInfo
* aNodeInfo
,
9709 CustomElementConstructor
* aConstructor
,
9710 ErrorResult
& aRv
, FromParser aFromParser
) {
9711 JS::Rooted
<JS::Value
> constructResult(aCx
);
9712 aConstructor
->Construct(&constructResult
, aRv
, "Custom Element Create",
9713 CallbackFunction::eRethrowExceptions
);
9718 RefPtr
<Element
> element
;
9719 // constructResult is an ObjectValue because construction with a callback
9720 // always forms the return value from a JSObject.
9721 UNWRAP_OBJECT(Element
, &constructResult
, element
);
9722 if (aNodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9723 if (!element
|| !element
->IsHTMLElement()) {
9724 aRv
.ThrowTypeError
<MSG_DOES_NOT_IMPLEMENT_INTERFACE
>("\"this\"",
9729 if (!element
|| !element
->IsXULElement()) {
9730 aRv
.ThrowTypeError
<MSG_DOES_NOT_IMPLEMENT_INTERFACE
>("\"this\"",
9736 nsAtom
* localName
= aNodeInfo
->NameAtom();
9738 if (aDoc
!= element
->OwnerDoc() || element
->GetParentNode() ||
9739 element
->HasChildren() || element
->GetAttrCount() ||
9740 element
->NodeInfo()->NameAtom() != localName
) {
9741 aRv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
9745 if (element
->IsHTMLElement()) {
9746 static_cast<HTMLElement
*>(&*element
)->InhibitRestoration(
9747 !(aFromParser
& FROM_PARSER_NETWORK
));
9750 element
.forget(aElement
);
9754 nsresult
nsContentUtils::NewXULOrHTMLElement(
9755 Element
** aResult
, mozilla::dom::NodeInfo
* aNodeInfo
,
9756 FromParser aFromParser
, nsAtom
* aIsAtom
,
9757 mozilla::dom::CustomElementDefinition
* aDefinition
) {
9758 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
= aNodeInfo
;
9759 MOZ_ASSERT(nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
) ||
9760 nodeInfo
->NamespaceEquals(kNameSpaceID_XUL
),
9761 "Can only create XUL or XHTML elements.");
9763 nsAtom
* name
= nodeInfo
->NameAtom();
9764 int32_t tag
= eHTMLTag_unknown
;
9765 bool isCustomElementName
= false;
9766 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9767 tag
= nsHTMLTags::CaseSensitiveAtomTagToId(name
);
9768 isCustomElementName
=
9769 (tag
== eHTMLTag_userdefined
&&
9770 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XHTML
));
9771 } else { // kNameSpaceID_XUL
9773 // Make sure the customized built-in element to be constructed confirms
9774 // to our naming requirement, i.e. [is] must be a dashed name and
9775 // the tag name must not.
9776 // if so, set isCustomElementName to false to kick off all the logics
9777 // that pick up aIsAtom.
9778 if (nsContentUtils::IsNameWithDash(aIsAtom
) &&
9779 !nsContentUtils::IsNameWithDash(name
)) {
9780 isCustomElementName
= false;
9782 isCustomElementName
=
9783 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XUL
);
9786 isCustomElementName
=
9787 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XUL
);
9791 nsAtom
* tagAtom
= nodeInfo
->NameAtom();
9792 nsAtom
* typeAtom
= nullptr;
9793 bool isCustomElement
= isCustomElementName
|| aIsAtom
;
9794 if (isCustomElement
) {
9795 typeAtom
= isCustomElementName
? tagAtom
: aIsAtom
;
9798 MOZ_ASSERT_IF(aDefinition
, isCustomElement
);
9800 // https://dom.spec.whatwg.org/#concept-create-element
9801 // We only handle the "synchronous custom elements flag is set" now.
9802 // For the unset case (e.g. cloning a node), see bug 1319342 for that.
9804 RefPtr
<CustomElementDefinition
> definition
= aDefinition
;
9805 if (isCustomElement
&& !definition
) {
9806 MOZ_ASSERT(nodeInfo
->NameAtom()->Equals(nodeInfo
->LocalName()));
9807 definition
= nsContentUtils::LookupCustomElementDefinition(
9808 nodeInfo
->GetDocument(), nodeInfo
->NameAtom(), nodeInfo
->NamespaceID(),
9812 // It might be a problem that parser synchronously calls constructor, so filed
9813 // bug 1378079 to figure out what we should do for parser case.
9816 * Synchronous custom elements flag is determined by 3 places in spec,
9817 * 1) create an element for a token, the flag is determined by
9818 * "will execute script" which is not originally created
9819 * for the HTML fragment parsing algorithm.
9820 * 2) createElement and createElementNS, the flag is the same as
9822 * 3) clone a node, our implementation will not go into this function.
9823 * For the unset case which is non-synchronous only applied for
9826 bool synchronousCustomElements
= aFromParser
!= dom::FROM_PARSER_FRAGMENT
;
9827 // Per discussion in https://github.com/w3c/webcomponents/issues/635,
9828 // use entry global in those places that are called from JS APIs and use the
9829 // node document's global object if it is called from parser.
9830 nsIGlobalObject
* global
;
9831 if (aFromParser
== dom::NOT_FROM_PARSER
) {
9832 global
= GetEntryGlobal();
9834 // Documents created from the PrototypeDocumentSink always use
9835 // NOT_FROM_PARSER for non-XUL elements. We can get the global from the
9836 // document in that case.
9838 Document
* doc
= nodeInfo
->GetDocument();
9839 if (doc
&& doc
->LoadedFromPrototype()) {
9840 global
= doc
->GetScopeObject();
9844 global
= nodeInfo
->GetDocument()->GetScopeObject();
9847 // In browser chrome code, one may have access to a document which doesn't
9848 // have scope object anymore.
9849 return NS_ERROR_FAILURE
;
9852 AutoAllowLegacyScriptExecution exemption
;
9853 AutoEntryScript
aes(global
, "create custom elements");
9854 JSContext
* cx
= aes
.cx();
9858 if (definition
->IsCustomBuiltIn()) {
9859 // SetupCustomElement() should be called with an element that don't have
9860 // CustomElementData setup, if not we will hit the assertion in
9861 // SetCustomElementData().
9863 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9865 CreateHTMLElement(tag
, nodeInfo
.forget(), aFromParser
).take();
9867 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9869 (*aResult
)->SetCustomElementData(MakeUnique
<CustomElementData
>(typeAtom
));
9870 if (synchronousCustomElements
) {
9871 CustomElementRegistry::Upgrade(*aResult
, definition
, rv
);
9872 if (rv
.MaybeSetPendingException(cx
)) {
9873 aes
.ReportException();
9876 nsContentUtils::EnqueueUpgradeReaction(*aResult
, definition
);
9883 if (synchronousCustomElements
) {
9884 definition
->mPrefixStack
.AppendElement(nodeInfo
->GetPrefixAtom());
9885 RefPtr
<Document
> doc
= nodeInfo
->GetDocument();
9886 DoCustomElementCreate(aResult
, cx
, doc
, nodeInfo
,
9887 MOZ_KnownLive(definition
->mConstructor
), rv
,
9889 if (rv
.MaybeSetPendingException(cx
)) {
9890 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9891 NS_IF_ADDREF(*aResult
= NS_NewHTMLUnknownElement(nodeInfo
.forget(),
9894 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9896 (*aResult
)->SetDefined(false);
9898 definition
->mPrefixStack
.RemoveLastElement();
9903 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9904 NS_IF_ADDREF(*aResult
=
9905 NS_NewHTMLElement(nodeInfo
.forget(), aFromParser
));
9907 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9909 (*aResult
)->SetCustomElementData(
9910 MakeUnique
<CustomElementData
>(definition
->mType
));
9911 nsContentUtils::EnqueueUpgradeReaction(*aResult
, definition
);
9915 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9916 // Per the Custom Element specification, unknown tags that are valid custom
9917 // element names should be HTMLElement instead of HTMLUnknownElement.
9918 if (isCustomElementName
) {
9919 NS_IF_ADDREF(*aResult
=
9920 NS_NewHTMLElement(nodeInfo
.forget(), aFromParser
));
9922 *aResult
= CreateHTMLElement(tag
, nodeInfo
.forget(), aFromParser
).take();
9925 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9929 return NS_ERROR_OUT_OF_MEMORY
;
9932 if (isCustomElement
) {
9933 (*aResult
)->SetCustomElementData(MakeUnique
<CustomElementData
>(typeAtom
));
9934 nsContentUtils::RegisterCallbackUpgradeElement(*aResult
, typeAtom
);
9940 CustomElementRegistry
* nsContentUtils::GetCustomElementRegistry(
9944 if (!aDoc
->GetDocShell()) {
9948 nsPIDOMWindowInner
* window
= aDoc
->GetInnerWindow();
9953 return window
->CustomElements();
9957 CustomElementDefinition
* nsContentUtils::LookupCustomElementDefinition(
9958 Document
* aDoc
, nsAtom
* aNameAtom
, uint32_t aNameSpaceID
,
9959 nsAtom
* aTypeAtom
) {
9960 if (aNameSpaceID
!= kNameSpaceID_XUL
&& aNameSpaceID
!= kNameSpaceID_XHTML
) {
9964 RefPtr
<CustomElementRegistry
> registry
= GetCustomElementRegistry(aDoc
);
9969 return registry
->LookupCustomElementDefinition(aNameAtom
, aNameSpaceID
,
9974 void nsContentUtils::RegisterCallbackUpgradeElement(Element
* aElement
,
9975 nsAtom
* aTypeName
) {
9976 MOZ_ASSERT(aElement
);
9978 Document
* doc
= aElement
->OwnerDoc();
9979 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
9981 registry
->RegisterCallbackUpgradeElement(aElement
, aTypeName
);
9986 void nsContentUtils::RegisterUnresolvedElement(Element
* aElement
,
9987 nsAtom
* aTypeName
) {
9988 MOZ_ASSERT(aElement
);
9990 Document
* doc
= aElement
->OwnerDoc();
9991 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
9993 registry
->RegisterUnresolvedElement(aElement
, aTypeName
);
9998 void nsContentUtils::UnregisterUnresolvedElement(Element
* aElement
) {
9999 MOZ_ASSERT(aElement
);
10001 nsAtom
* typeAtom
= aElement
->GetCustomElementData()->GetCustomElementType();
10002 Document
* doc
= aElement
->OwnerDoc();
10003 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
10005 registry
->UnregisterUnresolvedElement(aElement
, typeAtom
);
10010 void nsContentUtils::EnqueueUpgradeReaction(
10011 Element
* aElement
, CustomElementDefinition
* aDefinition
) {
10012 MOZ_ASSERT(aElement
);
10014 Document
* doc
= aElement
->OwnerDoc();
10016 // No DocGroup means no custom element reactions stack.
10017 if (!doc
->GetDocGroup()) {
10021 CustomElementReactionsStack
* stack
=
10022 doc
->GetDocGroup()->CustomElementReactionsStack();
10023 stack
->EnqueueUpgradeReaction(aElement
, aDefinition
);
10027 void nsContentUtils::EnqueueLifecycleCallback(
10028 ElementCallbackType aType
, Element
* aCustomElement
,
10029 const LifecycleCallbackArgs
& aArgs
, CustomElementDefinition
* aDefinition
) {
10030 // No DocGroup means no custom element reactions stack.
10031 if (!aCustomElement
->OwnerDoc()->GetDocGroup()) {
10035 CustomElementRegistry::EnqueueLifecycleCallback(aType
, aCustomElement
, aArgs
,
10040 CustomElementFormValue
nsContentUtils::ConvertToCustomElementFormValue(
10041 const Nullable
<OwningFileOrUSVStringOrFormData
>& aState
) {
10042 if (aState
.IsNull()) {
10045 const auto& state
= aState
.Value();
10046 if (state
.IsFile()) {
10047 RefPtr
<BlobImpl
> impl
= state
.GetAsFile()->Impl();
10048 return {std::move(impl
)};
10050 if (state
.IsUSVString()) {
10051 return state
.GetAsUSVString();
10053 return state
.GetAsFormData()->ConvertToCustomElementFormValue();
10057 Nullable
<OwningFileOrUSVStringOrFormData
>
10058 nsContentUtils::ExtractFormAssociatedCustomElementValue(
10059 nsIGlobalObject
* aGlobal
,
10060 const mozilla::dom::CustomElementFormValue
& aCEValue
) {
10061 MOZ_ASSERT(aGlobal
);
10063 OwningFileOrUSVStringOrFormData value
;
10064 switch (aCEValue
.type()) {
10065 case CustomElementFormValue::TBlobImpl
: {
10066 RefPtr
<File
> file
= File::Create(aGlobal
, aCEValue
.get_BlobImpl());
10067 if (NS_WARN_IF(!file
)) {
10070 value
.SetAsFile() = file
;
10073 case CustomElementFormValue::TnsString
:
10074 value
.SetAsUSVString() = aCEValue
.get_nsString();
10077 case CustomElementFormValue::TArrayOfFormDataTuple
: {
10078 const auto& array
= aCEValue
.get_ArrayOfFormDataTuple();
10079 auto formData
= MakeRefPtr
<FormData
>();
10081 for (auto i
= 0ul; i
< array
.Length(); ++i
) {
10082 const auto& item
= array
.ElementAt(i
);
10083 switch (item
.value().type()) {
10084 case FormDataValue::TnsString
:
10085 formData
->AddNameValuePair(item
.name(),
10086 item
.value().get_nsString());
10089 case FormDataValue::TBlobImpl
: {
10090 auto blobImpl
= item
.value().get_BlobImpl();
10091 auto* blob
= Blob::Create(aGlobal
, blobImpl
);
10092 formData
->AddNameBlobPair(item
.name(), blob
);
10100 value
.SetAsFormData() = formData
;
10102 case CustomElementFormValue::Tvoid_t
:
10105 NS_WARNING("Invalid CustomElementContentData type!");
10112 void nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
10113 Document
* aDocument
, nsTArray
<nsIContent
*>& aElements
) {
10114 MOZ_ASSERT(aDocument
);
10116 size_t oldLength
= aElements
.Length();
10119 if (PresShell
* presShell
= aDocument
->GetPresShell()) {
10120 if (nsIFrame
* scrollFrame
= presShell
->GetRootScrollFrame()) {
10121 nsIAnonymousContentCreator
* creator
= do_QueryFrame(scrollFrame
);
10124 "scroll frame should always implement nsIAnonymousContentCreator");
10125 creator
->AppendAnonymousContentTo(aElements
, 0);
10127 if (nsCanvasFrame
* canvasFrame
= presShell
->GetCanvasFrame()) {
10128 canvasFrame
->AppendAnonymousContentTo(aElements
, 0);
10133 for (size_t i
= oldLength
; i
< aElements
.Length(); i
++) {
10135 aElements
[i
]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
),
10136 "Someone here has lied, or missed to flag the node");
10141 static void AppendNativeAnonymousChildrenFromFrame(nsIFrame
* aFrame
,
10142 nsTArray
<nsIContent
*>& aKids
,
10144 if (nsIAnonymousContentCreator
* ac
= do_QueryFrame(aFrame
)) {
10145 ac
->AppendAnonymousContentTo(aKids
, aFlags
);
10150 void nsContentUtils::AppendNativeAnonymousChildren(const nsIContent
* aContent
,
10151 nsTArray
<nsIContent
*>& aKids
,
10153 if (aContent
->MayHaveAnonymousChildren()) {
10154 if (nsIFrame
* primaryFrame
= aContent
->GetPrimaryFrame()) {
10155 // NAC created by the element's primary frame.
10156 AppendNativeAnonymousChildrenFromFrame(primaryFrame
, aKids
, aFlags
);
10158 // NAC created by any other non-primary frames for the element.
10159 AutoTArray
<nsIFrame::OwnedAnonBox
, 8> ownedAnonBoxes
;
10160 primaryFrame
->AppendOwnedAnonBoxes(ownedAnonBoxes
);
10161 for (nsIFrame::OwnedAnonBox
& box
: ownedAnonBoxes
) {
10162 MOZ_ASSERT(box
.mAnonBoxFrame
->GetContent() == aContent
);
10163 AppendNativeAnonymousChildrenFromFrame(box
.mAnonBoxFrame
, aKids
,
10168 // Get manually created NAC (editor resize handles, etc.).
10169 if (auto nac
= static_cast<ManualNACArray
*>(
10170 aContent
->GetProperty(nsGkAtoms::manualNACProperty
))) {
10171 aKids
.AppendElements(*nac
);
10175 // The root scroll frame is not the primary frame of the root element.
10176 // Detect and handle this case.
10177 if (!(aFlags
& nsIContent::eSkipDocumentLevelNativeAnonymousContent
) &&
10178 aContent
== aContent
->OwnerDoc()->GetRootElement()) {
10179 AppendDocumentLevelNativeAnonymousContentTo(aContent
->OwnerDoc(), aKids
);
10183 bool nsContentUtils::IsImageAvailable(nsIContent
* aLoadingNode
, nsIURI
* aURI
,
10184 nsIPrincipal
* aDefaultTriggeringPrincipal
,
10185 CORSMode aCORSMode
) {
10186 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
10187 QueryTriggeringPrincipal(aLoadingNode
, aDefaultTriggeringPrincipal
,
10188 getter_AddRefs(triggeringPrincipal
));
10189 MOZ_ASSERT(triggeringPrincipal
);
10191 Document
* doc
= aLoadingNode
->OwnerDoc();
10192 return IsImageAvailable(aURI
, triggeringPrincipal
, aCORSMode
, doc
);
10195 bool nsContentUtils::IsImageAvailable(nsIURI
* aURI
,
10196 nsIPrincipal
* aTriggeringPrincipal
,
10197 CORSMode aCORSMode
, Document
* aDoc
) {
10198 imgLoader
* imgLoader
= GetImgLoaderForDocument(aDoc
);
10199 return imgLoader
->IsImageAvailable(aURI
, aTriggeringPrincipal
, aCORSMode
,
10204 bool nsContentUtils::QueryTriggeringPrincipal(
10205 nsIContent
* aLoadingNode
, nsIPrincipal
* aDefaultPrincipal
,
10206 nsIPrincipal
** aTriggeringPrincipal
) {
10207 MOZ_ASSERT(aLoadingNode
);
10208 MOZ_ASSERT(aTriggeringPrincipal
);
10210 bool result
= false;
10211 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
= aDefaultPrincipal
;
10212 if (!loadingPrincipal
) {
10213 loadingPrincipal
= aLoadingNode
->NodePrincipal();
10216 // If aLoadingNode is content, bail out early.
10217 if (!aLoadingNode
->NodePrincipal()->IsSystemPrincipal()) {
10218 loadingPrincipal
.forget(aTriggeringPrincipal
);
10222 nsAutoString loadingStr
;
10223 if (aLoadingNode
->IsElement()) {
10224 aLoadingNode
->AsElement()->GetAttr(
10225 kNameSpaceID_None
, nsGkAtoms::triggeringprincipal
, loadingStr
);
10228 // Fall back if 'triggeringprincipal' isn't specified,
10229 if (loadingStr
.IsEmpty()) {
10230 loadingPrincipal
.forget(aTriggeringPrincipal
);
10235 nsCOMPtr
<nsIPrincipal
> serializedPrin
=
10236 BasePrincipal::FromJSON(NS_ConvertUTF16toUTF8(loadingStr
));
10237 if (serializedPrin
) {
10239 serializedPrin
.forget(aTriggeringPrincipal
);
10243 // Fallback if the deserialization is failed.
10244 loadingPrincipal
.forget(aTriggeringPrincipal
);
10251 void nsContentUtils::GetContentPolicyTypeForUIImageLoading(
10252 nsIContent
* aLoadingNode
, nsIPrincipal
** aTriggeringPrincipal
,
10253 nsContentPolicyType
& aContentPolicyType
, uint64_t* aRequestContextID
) {
10254 MOZ_ASSERT(aRequestContextID
);
10256 bool result
= QueryTriggeringPrincipal(aLoadingNode
, aTriggeringPrincipal
);
10258 // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
10259 // indicating it's a favicon loading.
10260 aContentPolicyType
= nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON
;
10262 nsAutoString requestContextID
;
10263 if (aLoadingNode
->IsElement()) {
10264 aLoadingNode
->AsElement()->GetAttr(
10265 kNameSpaceID_None
, nsGkAtoms::requestcontextid
, requestContextID
);
10268 int64_t val
= requestContextID
.ToInteger64(&rv
);
10269 *aRequestContextID
= NS_SUCCEEDED(rv
) ? val
: 0;
10271 aContentPolicyType
= nsIContentPolicy::TYPE_INTERNAL_IMAGE
;
10276 nsresult
nsContentUtils::CreateJSValueFromSequenceOfObject(
10277 JSContext
* aCx
, const Sequence
<JSObject
*>& aTransfer
,
10278 JS::MutableHandle
<JS::Value
> aValue
) {
10279 if (aTransfer
.IsEmpty()) {
10283 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, aTransfer
.Length()));
10285 return NS_ERROR_OUT_OF_MEMORY
;
10288 for (uint32_t i
= 0; i
< aTransfer
.Length(); ++i
) {
10289 JS::Rooted
<JSObject
*> object(aCx
, aTransfer
[i
]);
10295 !JS_DefineElement(aCx
, array
, i
, object
, JSPROP_ENUMERATE
))) {
10296 return NS_ERROR_OUT_OF_MEMORY
;
10300 aValue
.setObject(*array
);
10305 void nsContentUtils::StructuredClone(JSContext
* aCx
, nsIGlobalObject
* aGlobal
,
10306 JS::Handle
<JS::Value
> aValue
,
10307 const StructuredSerializeOptions
& aOptions
,
10308 JS::MutableHandle
<JS::Value
> aRetval
,
10309 ErrorResult
& aError
) {
10310 JS::Rooted
<JS::Value
> transferArray(aCx
, JS::UndefinedValue());
10311 aError
= nsContentUtils::CreateJSValueFromSequenceOfObject(
10312 aCx
, aOptions
.mTransfer
, &transferArray
);
10313 if (NS_WARN_IF(aError
.Failed())) {
10317 JS::CloneDataPolicy clonePolicy
;
10318 // We are definitely staying in the same agent cluster.
10319 clonePolicy
.allowIntraClusterClonableSharedObjects();
10320 if (aGlobal
->IsSharedMemoryAllowed()) {
10321 clonePolicy
.allowSharedMemoryObjects();
10324 StructuredCloneHolder
holder(StructuredCloneHolder::CloningSupported
,
10325 StructuredCloneHolder::TransferringSupported
,
10326 JS::StructuredCloneScope::SameProcess
);
10327 holder
.Write(aCx
, aValue
, transferArray
, clonePolicy
, aError
);
10328 if (NS_WARN_IF(aError
.Failed())) {
10332 holder
.Read(aGlobal
, aCx
, aRetval
, clonePolicy
, aError
);
10333 if (NS_WARN_IF(aError
.Failed())) {
10337 nsTArray
<RefPtr
<MessagePort
>> ports
= holder
.TakeTransferredPorts();
10342 bool nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent
* aKeyEvent
) {
10343 nsCOMPtr
<nsIPrincipal
> principal
;
10344 RefPtr
<Element
> targetElement
=
10345 Element::FromEventTargetOrNull(aKeyEvent
->mOriginalTarget
);
10346 nsCOMPtr
<nsIBrowser
> targetBrowser
;
10347 if (targetElement
) {
10348 targetBrowser
= targetElement
->AsBrowser();
10350 bool isRemoteBrowser
= false;
10351 if (targetBrowser
) {
10352 targetBrowser
->GetIsRemoteBrowser(&isRemoteBrowser
);
10355 if (isRemoteBrowser
) {
10356 targetBrowser
->GetContentPrincipal(getter_AddRefs(principal
));
10357 return principal
? nsContentUtils::IsSitePermDeny(principal
, "shortcuts"_ns
)
10361 if (targetElement
) {
10362 Document
* doc
= targetElement
->GetUncomposedDoc();
10364 RefPtr
<WindowContext
> wc
= doc
->GetWindowContext();
10366 return wc
->TopWindowContext()->GetShortcutsPermission() ==
10367 nsIPermissionManager::DENY_ACTION
;
10376 * Checks whether the given type is a supported document type for
10377 * loading within the nsObjectLoadingContent specified by aContent.
10379 * NOTE Helper method for nsContentUtils::HtmlObjectContentTypeForMIMEType.
10380 * NOTE Does not take content policy or capabilities into account
10382 static bool HtmlObjectContentSupportsDocument(const nsCString
& aMimeType
) {
10383 nsCOMPtr
<nsIWebNavigationInfo
> info(
10384 do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID
));
10389 uint32_t supported
;
10390 nsresult rv
= info
->IsTypeSupported(aMimeType
, &supported
);
10392 if (NS_FAILED(rv
)) {
10396 if (supported
!= nsIWebNavigationInfo::UNSUPPORTED
) {
10397 // Don't want to support plugins as documents
10398 return supported
!= nsIWebNavigationInfo::FALLBACK
;
10401 // Try a stream converter
10402 // NOTE: We treat any type we can convert from as a supported type. If a
10403 // type is not actually supported, the URI loader will detect that and
10404 // return an error, and we'll fallback.
10405 nsCOMPtr
<nsIStreamConverterService
> convServ
=
10406 do_GetService("@mozilla.org/streamConverters;1");
10407 bool canConvert
= false;
10409 rv
= convServ
->CanConvert(aMimeType
.get(), "*/*", &canConvert
);
10411 return NS_SUCCEEDED(rv
) && canConvert
;
10415 already_AddRefed
<nsIPluginTag
> nsContentUtils::PluginTagForType(
10416 const nsCString
& aMIMEType
, bool aNoFakePlugin
) {
10417 RefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
10418 nsCOMPtr
<nsIPluginTag
> tag
;
10419 NS_ENSURE_TRUE(pluginHost
, nullptr);
10421 // ShouldPlay will handle the case where the plugin is disabled
10422 pluginHost
->GetPluginTagForType(
10424 aNoFakePlugin
? nsPluginHost::eExcludeFake
: nsPluginHost::eExcludeNone
,
10425 getter_AddRefs(tag
));
10427 return tag
.forget();
10431 uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType(
10432 const nsCString
& aMIMEType
, bool aNoFakePlugin
) {
10433 if (aMIMEType
.IsEmpty()) {
10434 return nsIObjectLoadingContent::TYPE_NULL
;
10437 if (imgLoader::SupportImageWithMimeType(aMIMEType
)) {
10438 return ResolveObjectType(nsIObjectLoadingContent::TYPE_IMAGE
);
10441 // Faking support of the PDF content as a document for EMBED tags
10442 // when internal PDF viewer is enabled.
10443 if (aMIMEType
.LowerCaseEqualsLiteral("application/pdf") && IsPDFJSEnabled()) {
10444 return nsIObjectLoadingContent::TYPE_DOCUMENT
;
10447 if (HtmlObjectContentSupportsDocument(aMIMEType
)) {
10448 return nsIObjectLoadingContent::TYPE_DOCUMENT
;
10451 bool isSpecialPlugin
= nsPluginHost::GetSpecialType(aMIMEType
) !=
10452 nsPluginHost::eSpecialType_None
;
10453 if (isSpecialPlugin
) {
10454 return nsIObjectLoadingContent::TYPE_FALLBACK
;
10457 return nsIObjectLoadingContent::TYPE_NULL
;
10461 bool nsContentUtils::IsLocalRefURL(const nsAString
& aString
) {
10462 return !aString
.IsEmpty() && aString
[0] == '#';
10465 // We use only 53 bits for the ID so that it can be converted to and from a JS
10466 // value without loss of precision. The upper bits of the ID hold the process
10467 // ID. The lower bits identify the object itself.
10468 static constexpr uint64_t kIdTotalBits
= 53;
10469 static constexpr uint64_t kIdProcessBits
= 22;
10470 static constexpr uint64_t kIdBits
= kIdTotalBits
- kIdProcessBits
;
10473 uint64_t nsContentUtils::GenerateProcessSpecificId(uint64_t aId
) {
10474 uint64_t processId
= 0;
10475 if (XRE_IsContentProcess()) {
10476 ContentChild
* cc
= ContentChild::GetSingleton();
10477 processId
= cc
->GetID();
10480 MOZ_RELEASE_ASSERT(processId
< (uint64_t(1) << kIdProcessBits
));
10481 uint64_t processBits
= processId
& ((uint64_t(1) << kIdProcessBits
) - 1);
10484 MOZ_RELEASE_ASSERT(id
< (uint64_t(1) << kIdBits
));
10485 uint64_t bits
= id
& ((uint64_t(1) << kIdBits
) - 1);
10487 return (processBits
<< kIdBits
) | bits
;
10491 std::tuple
<uint64_t, uint64_t> nsContentUtils::SplitProcessSpecificId(
10493 return {aId
>> kIdBits
, aId
& ((uint64_t(1) << kIdBits
) - 1)};
10496 // Next process-local Tab ID.
10497 static uint64_t gNextTabId
= 0;
10500 uint64_t nsContentUtils::GenerateTabId() {
10501 return GenerateProcessSpecificId(++gNextTabId
);
10504 // Next process-local Browser ID.
10505 static uint64_t gNextBrowserId
= 0;
10508 uint64_t nsContentUtils::GenerateBrowserId() {
10509 return GenerateProcessSpecificId(++gNextBrowserId
);
10512 // Next process-local Browsing Context ID.
10513 static uint64_t gNextBrowsingContextId
= 0;
10516 uint64_t nsContentUtils::GenerateBrowsingContextId() {
10517 return GenerateProcessSpecificId(++gNextBrowsingContextId
);
10520 // Next process-local Window ID.
10521 static uint64_t gNextWindowId
= 0;
10524 uint64_t nsContentUtils::GenerateWindowId() {
10525 return GenerateProcessSpecificId(++gNextWindowId
);
10528 // Next process-local load.
10529 static Atomic
<uint64_t> gNextLoadIdentifier(0);
10532 uint64_t nsContentUtils::GenerateLoadIdentifier() {
10533 return GenerateProcessSpecificId(++gNextLoadIdentifier
);
10537 bool nsContentUtils::GetUserIsInteracting() {
10538 return UserInteractionObserver::sUserActive
;
10542 bool nsContentUtils::GetSourceMapURL(nsIHttpChannel
* aChannel
,
10543 nsACString
& aResult
) {
10544 nsresult rv
= aChannel
->GetResponseHeader("SourceMap"_ns
, aResult
);
10545 if (NS_FAILED(rv
)) {
10546 rv
= aChannel
->GetResponseHeader("X-SourceMap"_ns
, aResult
);
10548 return NS_SUCCEEDED(rv
);
10552 bool nsContentUtils::IsMessageInputEvent(const IPC::Message
& aMsg
) {
10553 if ((aMsg
.type() & mozilla::dom::PBrowser::PBrowserStart
) ==
10554 mozilla::dom::PBrowser::PBrowserStart
) {
10555 switch (aMsg
.type()) {
10556 case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID
:
10557 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID
:
10558 case mozilla::dom::PBrowser::Msg_RealMouseEnterExitWidgetEvent__ID
:
10559 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID
:
10560 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID
:
10561 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID
:
10562 case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID
:
10563 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID
:
10564 case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID
:
10572 bool nsContentUtils::IsMessageCriticalInputEvent(const IPC::Message
& aMsg
) {
10573 if ((aMsg
.type() & mozilla::dom::PBrowser::PBrowserStart
) ==
10574 mozilla::dom::PBrowser::PBrowserStart
) {
10575 switch (aMsg
.type()) {
10576 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID
:
10577 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID
:
10578 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID
:
10579 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID
:
10580 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID
:
10587 static const char* kUserInteractionInactive
= "user-interaction-inactive";
10588 static const char* kUserInteractionActive
= "user-interaction-active";
10590 void nsContentUtils::UserInteractionObserver::Init() {
10591 // Listen for the observer messages from EventStateManager which are telling
10592 // us whether or not the user is interacting.
10593 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
10594 obs
->AddObserver(this, kUserInteractionInactive
, false);
10595 obs
->AddObserver(this, kUserInteractionActive
, false);
10597 // We can't register ourselves as an annotator yet, as the
10598 // BackgroundHangMonitor hasn't started yet. It will have started by the
10599 // time we have the chance to spin the event loop.
10600 RefPtr
<UserInteractionObserver
> self
= this;
10601 NS_DispatchToMainThread(NS_NewRunnableFunction(
10602 "nsContentUtils::UserInteractionObserver::Init",
10603 [=]() { BackgroundHangMonitor::RegisterAnnotator(*self
); }));
10606 void nsContentUtils::UserInteractionObserver::Shutdown() {
10607 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
10609 obs
->RemoveObserver(this, kUserInteractionInactive
);
10610 obs
->RemoveObserver(this, kUserInteractionActive
);
10613 BackgroundHangMonitor::UnregisterAnnotator(*this);
10617 * NB: This function is always called by the BackgroundHangMonitor thread.
10620 void nsContentUtils::UserInteractionObserver::AnnotateHang(
10621 BackgroundHangAnnotations
& aAnnotations
) {
10622 // NOTE: Only annotate the hang report if the user is known to be interacting.
10624 aAnnotations
.AddAnnotation(u
"UserInteracting"_ns
, true);
10629 nsContentUtils::UserInteractionObserver::Observe(nsISupports
* aSubject
,
10630 const char* aTopic
,
10631 const char16_t
* aData
) {
10632 if (!strcmp(aTopic
, kUserInteractionInactive
)) {
10633 if (sUserActive
&& XRE_IsParentProcess()) {
10634 glean::RecordPowerMetrics();
10636 sUserActive
= false;
10637 } else if (!strcmp(aTopic
, kUserInteractionActive
)) {
10638 if (!sUserActive
&& XRE_IsParentProcess()) {
10639 glean::RecordPowerMetrics();
10641 nsCOMPtr
<nsIUserIdleServiceInternal
> idleService
=
10642 do_GetService("@mozilla.org/widget/useridleservice;1");
10644 idleService
->ResetIdleTimeOut(0);
10648 sUserActive
= true;
10650 NS_WARNING("Unexpected observer notification");
10655 Atomic
<bool> nsContentUtils::UserInteractionObserver::sUserActive(false);
10656 NS_IMPL_ISUPPORTS(nsContentUtils::UserInteractionObserver
, nsIObserver
)
10659 bool nsContentUtils::IsSpecialName(const nsAString
& aName
) {
10660 return aName
.LowerCaseEqualsLiteral("_blank") ||
10661 aName
.LowerCaseEqualsLiteral("_top") ||
10662 aName
.LowerCaseEqualsLiteral("_parent") ||
10663 aName
.LowerCaseEqualsLiteral("_self");
10667 bool nsContentUtils::IsOverridingWindowName(const nsAString
& aName
) {
10668 return !aName
.IsEmpty() && !IsSpecialName(aName
);
10671 // Unfortunately, we can't unwrap an IDL object using only a concrete type.
10672 // We need to calculate type data based on the IDL typename. Which means
10673 // wrapping our templated function in a macro.
10674 #define EXTRACT_EXN_VALUES(T, ...) \
10675 ExtractExceptionValues<mozilla::dom::prototypes::id::T, \
10676 T##_Binding::NativeType, T>(__VA_ARGS__) \
10679 template <prototypes::ID PrototypeID
, class NativeType
, typename T
>
10680 static Result
<Ok
, nsresult
> ExtractExceptionValues(
10681 JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
, nsAString
& aSourceSpecOut
,
10682 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10683 AssertStaticUnwrapOK
<PrototypeID
>();
10685 MOZ_TRY((UnwrapObject
<PrototypeID
, NativeType
>(aObj
, exn
, nullptr)));
10687 exn
->GetFilename(aCx
, aSourceSpecOut
);
10688 if (!aSourceSpecOut
.IsEmpty()) {
10689 *aLineOut
= exn
->LineNumber(aCx
);
10690 *aColumnOut
= exn
->ColumnNumber();
10693 exn
->GetName(aMessageOut
);
10694 aMessageOut
.AppendLiteral(": ");
10696 nsAutoString message
;
10697 exn
->GetMessageMoz(message
);
10698 aMessageOut
.Append(message
);
10703 void nsContentUtils::ExtractErrorValues(
10704 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, nsACString
& aSourceSpecOut
,
10705 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10706 nsAutoString sourceSpec
;
10707 ExtractErrorValues(aCx
, aValue
, sourceSpec
, aLineOut
, aColumnOut
,
10709 CopyUTF16toUTF8(sourceSpec
, aSourceSpecOut
);
10713 void nsContentUtils::ExtractErrorValues(
10714 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, nsAString
& aSourceSpecOut
,
10715 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10716 MOZ_ASSERT(aLineOut
);
10717 MOZ_ASSERT(aColumnOut
);
10719 if (aValue
.isObject()) {
10720 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
10722 // Try to process as an Error object. Use the file/line/column values
10723 // from the Error as they will be more specific to the root cause of
10725 JSErrorReport
* err
= obj
? JS_ErrorFromException(aCx
, obj
) : nullptr;
10727 // Use xpc to extract the error message only. We don't actually send
10728 // this report anywhere.
10729 RefPtr
<xpc::ErrorReport
> report
= new xpc::ErrorReport();
10731 nullptr, // toString result
10735 if (!report
->mFileName
.IsEmpty()) {
10736 aSourceSpecOut
= report
->mFileName
;
10737 *aLineOut
= report
->mLineNumber
;
10738 *aColumnOut
= report
->mColumn
;
10740 aMessageOut
.Assign(report
->mErrorMsg
);
10743 // Next, try to unwrap the rejection value as a DOMException.
10744 else if (EXTRACT_EXN_VALUES(DOMException
, aCx
, obj
, aSourceSpecOut
,
10745 aLineOut
, aColumnOut
, aMessageOut
)) {
10749 // Next, try to unwrap the rejection value as an XPC Exception.
10750 else if (EXTRACT_EXN_VALUES(Exception
, aCx
, obj
, aSourceSpecOut
, aLineOut
,
10751 aColumnOut
, aMessageOut
)) {
10756 // If we could not unwrap a specific error type, then perform default safe
10757 // string conversions on primitives. Objects will result in "[Object]"
10759 if (aMessageOut
.IsEmpty()) {
10760 nsAutoJSString jsString
;
10761 if (jsString
.init(aCx
, aValue
)) {
10762 aMessageOut
= jsString
;
10764 JS_ClearPendingException(aCx
);
10769 #undef EXTRACT_EXN_VALUES
10772 bool nsContentUtils::ContentIsLink(nsIContent
* aContent
) {
10773 if (!aContent
|| !aContent
->IsElement()) {
10777 if (aContent
->IsHTMLElement(nsGkAtoms::a
)) {
10781 return aContent
->AsElement()->AttrValueIs(kNameSpaceID_XLink
, nsGkAtoms::type
,
10782 nsGkAtoms::simple
, eCaseMatters
);
10786 already_AddRefed
<ContentFrameMessageManager
>
10787 nsContentUtils::TryGetBrowserChildGlobal(nsISupports
* aFrom
) {
10788 RefPtr
<nsFrameLoaderOwner
> frameLoaderOwner
= do_QueryObject(aFrom
);
10789 if (!frameLoaderOwner
) {
10793 RefPtr
<nsFrameLoader
> frameLoader
= frameLoaderOwner
->GetFrameLoader();
10794 if (!frameLoader
) {
10798 RefPtr
<ContentFrameMessageManager
> manager
=
10799 frameLoader
->GetBrowserChildMessageManager();
10800 return manager
.forget();
10804 uint32_t nsContentUtils::InnerOrOuterWindowCreated() {
10805 MOZ_ASSERT(NS_IsMainThread());
10806 ++sInnerOrOuterWindowCount
;
10807 return ++sInnerOrOuterWindowSerialCounter
;
10811 void nsContentUtils::InnerOrOuterWindowDestroyed() {
10812 MOZ_ASSERT(NS_IsMainThread());
10813 MOZ_ASSERT(sInnerOrOuterWindowCount
> 0);
10814 --sInnerOrOuterWindowCount
;
10818 nsresult
nsContentUtils::AnonymizeURI(nsIURI
* aURI
, nsCString
& aAnonymizedURI
) {
10821 if (aURI
->SchemeIs("data")) {
10822 aAnonymizedURI
.Assign("data:..."_ns
);
10825 // Anonymize the URL.
10826 // Strip the URL of any possible username/password and make it ready to be
10827 // presented in the UI.
10828 nsCOMPtr
<nsIURI
> exposableURI
= net::nsIOService::CreateExposableURI(aURI
);
10829 return exposableURI
->GetSpec(aAnonymizedURI
);
10832 static bool JSONCreator(const char16_t
* aBuf
, uint32_t aLen
, void* aData
) {
10833 nsAString
* result
= static_cast<nsAString
*>(aData
);
10834 result
->Append(aBuf
, aLen
);
10839 bool nsContentUtils::StringifyJSON(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
10840 nsAString
& aOutStr
, JSONBehavior aBehavior
) {
10842 switch (aBehavior
) {
10843 case UndefinedIsNullStringLiteral
: {
10844 aOutStr
.Truncate();
10845 JS::Rooted
<JS::Value
> value(aCx
, aValue
);
10846 nsAutoString serializedValue
;
10847 NS_ENSURE_TRUE(JS_Stringify(aCx
, &value
, nullptr, JS::NullHandleValue
,
10848 JSONCreator
, &serializedValue
),
10850 aOutStr
= serializedValue
;
10853 case UndefinedIsVoidString
: {
10854 aOutStr
.SetIsVoid(true);
10855 return JS::ToJSON(aCx
, aValue
, nullptr, JS::NullHandleValue
, JSONCreator
,
10859 MOZ_ASSERT_UNREACHABLE("Invalid value for aBehavior");
10865 bool nsContentUtils::
10866 HighPriorityEventPendingForTopLevelDocumentBeforeContentfulPaint(
10867 Document
* aDocument
) {
10868 MOZ_ASSERT(XRE_IsContentProcess(),
10869 "This function only makes sense in content processes");
10871 if (aDocument
&& !aDocument
->IsLoadedAsData()) {
10872 if (nsPresContext
* presContext
= FindPresContextForDocument(aDocument
)) {
10873 MOZ_ASSERT(!presContext
->IsChrome(),
10874 "Should never have a chrome PresContext in a content process");
10876 return !presContext
->GetInProcessRootContentDocumentPresContext()
10877 ->HadFirstContentfulPaint() &&
10878 nsThreadManager::MainThreadHasPendingHighPriorityEvents();
10884 static nsGlobalWindowInner
* GetInnerWindowForGlobal(nsIGlobalObject
* aGlobal
) {
10885 NS_ENSURE_TRUE(aGlobal
, nullptr);
10887 if (auto* window
= aGlobal
->GetAsInnerWindow()) {
10888 return nsGlobalWindowInner::Cast(window
);
10891 // When Extensions run content scripts inside a sandbox, it uses
10892 // sandboxPrototype to make them appear as though they're running in the
10893 // scope of the page. So when a content script invokes postMessage, it expects
10894 // the |source| of the received message to be the window set as the
10895 // sandboxPrototype. This used to work incidentally for unrelated reasons, but
10896 // now we need to do some special handling to support it.
10897 JS::Rooted
<JSObject
*> scope(RootingCx(), aGlobal
->GetGlobalJSObject());
10898 NS_ENSURE_TRUE(scope
, nullptr);
10900 if (xpc::IsSandbox(scope
)) {
10902 MOZ_ALWAYS_TRUE(jsapi
.Init(scope
));
10903 JSContext
* cx
= jsapi
.cx();
10904 // Our current Realm on aCx is the sandbox. Using that for unwrapping
10905 // makes sense: if the sandbox can unwrap the window, we can use it.
10906 return xpc::SandboxWindowOrNull(scope
, cx
);
10909 // The calling window must be holding a reference, so we can return a weak
10911 return nsGlobalWindowInner::Cast(aGlobal
->GetAsInnerWindow());
10915 nsGlobalWindowInner
* nsContentUtils::IncumbentInnerWindow() {
10916 return GetInnerWindowForGlobal(GetIncumbentGlobal());
10920 nsGlobalWindowInner
* nsContentUtils::EntryInnerWindow() {
10921 return GetInnerWindowForGlobal(GetEntryGlobal());
10925 bool nsContentUtils::IsURIInPrefList(nsIURI
* aURI
, const char* aPrefName
) {
10926 MOZ_ASSERT(aPrefName
);
10928 nsAutoCString list
;
10929 Preferences::GetCString(aPrefName
, list
);
10931 return IsURIInList(aURI
, list
);
10935 bool nsContentUtils::IsURIInList(nsIURI
* aURI
, const nsCString
& aList
) {
10937 nsAutoCString
listLowerCase(aList
);
10938 ToLowerCase(listLowerCase
);
10939 MOZ_ASSERT(listLowerCase
.Equals(aList
),
10940 "The aList argument should be lower-case");
10947 nsAutoCString scheme
;
10948 aURI
->GetScheme(scheme
);
10949 if (!scheme
.EqualsLiteral("http") && !scheme
.EqualsLiteral("https")) {
10953 if (aList
.IsEmpty()) {
10957 // The list is comma separated domain list. Each item may start with "*.".
10958 // If starts with "*.", it matches any sub-domains.
10960 nsCCharSeparatedTokenizer
tokenizer(aList
, ',');
10961 while (tokenizer
.hasMoreTokens()) {
10962 const nsCString
token(tokenizer
.nextToken());
10964 nsAutoCString host
;
10965 aURI
->GetHost(host
);
10966 if (host
.IsEmpty()) {
10972 int32_t index
= token
.Find(host
);
10974 static_cast<uint32_t>(index
) + host
.Length() <= token
.Length()) {
10975 // If we found a full match, return true.
10976 size_t indexAfterHost
= index
+ host
.Length();
10977 if (index
== 0 && indexAfterHost
== token
.Length()) {
10980 // If next character is '/', we need to check the path too.
10981 // We assume the path in the list means "/foo" + "*".
10982 if (token
[indexAfterHost
] == '/') {
10983 nsDependentCSubstring
pathInList(
10984 token
, indexAfterHost
,
10985 static_cast<nsDependentCSubstring::size_type
>(-1));
10986 nsAutoCString filePath
;
10987 aURI
->GetFilePath(filePath
);
10988 ToLowerCase(filePath
);
10989 if (StringBeginsWith(filePath
, pathInList
) &&
10990 (filePath
.Length() == pathInList
.Length() ||
10991 pathInList
.EqualsLiteral("/") ||
10992 filePath
[pathInList
.Length() - 1] == '/' ||
10993 filePath
[pathInList
.Length() - 1] == '?' ||
10994 filePath
[pathInList
.Length() - 1] == '#')) {
10999 int32_t startIndexOfCurrentLevel
= host
[0] == '*' ? 1 : 0;
11000 int32_t startIndexOfNextLevel
=
11001 host
.Find(".", startIndexOfCurrentLevel
+ 1);
11002 if (startIndexOfNextLevel
<= 0) {
11005 host
= "*"_ns
+ nsDependentCSubstring(host
, startIndexOfNextLevel
);
11013 ScreenIntMargin
nsContentUtils::GetWindowSafeAreaInsets(
11014 nsIScreen
* aScreen
, const ScreenIntMargin
& aSafeAreaInsets
,
11015 const LayoutDeviceIntRect
& aWindowRect
) {
11016 // This calculates safe area insets of window from screen rectangle, window
11017 // rectangle and safe area insets of screen.
11019 // +----------------------------------------+ <-- screen
11020 // | +-------------------------------+ <------- window
11021 // | | window's safe area inset top) | |
11022 // +--+-------------------------------+--+ |
11023 // | | | |<------ safe area rectangle of
11024 // | | | | | screen
11025 // +--+-------------------------------+--+ |
11026 // | |window's safe area inset bottom| |
11027 // | +-------------------------------+ |
11028 // +----------------------------------------+
11030 ScreenIntMargin windowSafeAreaInsets
;
11032 if (windowSafeAreaInsets
== aSafeAreaInsets
) {
11033 // no safe area insets.
11034 return windowSafeAreaInsets
;
11037 int32_t screenLeft
, screenTop
, screenWidth
, screenHeight
;
11039 aScreen
->GetRect(&screenLeft
, &screenTop
, &screenWidth
, &screenHeight
);
11040 if (NS_WARN_IF(NS_FAILED(rv
))) {
11041 return windowSafeAreaInsets
;
11044 const ScreenIntRect
screenRect(screenLeft
, screenTop
, screenWidth
,
11047 ScreenIntRect safeAreaRect
= screenRect
;
11048 safeAreaRect
.Deflate(aSafeAreaInsets
);
11050 ScreenIntRect windowRect
= ViewAs
<ScreenPixel
>(
11051 aWindowRect
, PixelCastJustification::LayoutDeviceIsScreenForTabDims
);
11053 // FIXME(bug 1754323): This can trigger because the screen rect is not
11054 // orientation-aware.
11055 // MOZ_ASSERT(screenRect.Contains(windowRect),
11056 // "Screen doesn't contain window rect? Something seems off");
11058 // window's rect of safe area
11059 safeAreaRect
= safeAreaRect
.Intersect(windowRect
);
11061 windowSafeAreaInsets
.top
= safeAreaRect
.y
- aWindowRect
.y
;
11062 windowSafeAreaInsets
.left
= safeAreaRect
.x
- aWindowRect
.x
;
11063 windowSafeAreaInsets
.right
=
11064 aWindowRect
.x
+ aWindowRect
.width
- (safeAreaRect
.x
+ safeAreaRect
.width
);
11065 windowSafeAreaInsets
.bottom
= aWindowRect
.y
+ aWindowRect
.height
-
11066 (safeAreaRect
.y
+ safeAreaRect
.height
);
11068 windowSafeAreaInsets
.EnsureAtLeast(ScreenIntMargin());
11069 // This shouldn't be needed, but it wallpapers orientation issues, see bug
11071 windowSafeAreaInsets
.EnsureAtMost(aSafeAreaInsets
);
11073 return windowSafeAreaInsets
;
11077 nsContentUtils::SubresourceCacheValidationInfo
11078 nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest
* aRequest
,
11080 SubresourceCacheValidationInfo info
;
11081 if (nsCOMPtr
<nsICacheInfoChannel
> cache
= do_QueryInterface(aRequest
)) {
11082 uint32_t value
= 0;
11083 if (NS_SUCCEEDED(cache
->GetCacheTokenExpirationTime(&value
))) {
11084 info
.mExpirationTime
.emplace(value
);
11088 // Determine whether the cache entry must be revalidated when we try to use
11089 // it. Currently, only HTTP specifies this information...
11090 if (nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aRequest
)) {
11091 Unused
<< httpChannel
->IsNoStoreResponse(&info
.mMustRevalidate
);
11093 if (!info
.mMustRevalidate
) {
11094 Unused
<< httpChannel
->IsNoCacheResponse(&info
.mMustRevalidate
);
11098 // data: URIs are safe to cache across documents under any circumstance, so we
11099 // special-case them here even though the channel itself doesn't have any
11100 // caching policy. Same for chrome:// uris.
11102 // TODO(emilio): Figure out which other schemes that don't have caching
11103 // policies are safe to cache. Blobs should be...
11104 const bool knownCacheable
= [&] {
11108 if (aURI
->SchemeIs("data") || aURI
->SchemeIs("moz-page-thumb") ||
11109 aURI
->SchemeIs("moz-extension")) {
11112 if (aURI
->SchemeIs("chrome") || aURI
->SchemeIs("resource")) {
11113 return !StaticPrefs::nglayout_debug_disable_xul_cache();
11118 if (knownCacheable
) {
11119 MOZ_ASSERT(!info
.mExpirationTime
);
11120 MOZ_ASSERT(!info
.mMustRevalidate
);
11121 info
.mExpirationTime
= Some(0); // 0 means "doesn't expire".
11127 nsCString
nsContentUtils::TruncatedURLForDisplay(nsIURI
* aURL
, size_t aMaxLen
) {
11130 aURL
->GetSpec(spec
);
11131 spec
.Truncate(std::min(aMaxLen
, spec
.Length()));
11137 nsresult
nsContentUtils::AnonymizeId(nsAString
& aId
,
11138 const nsACString
& aOriginKey
,
11139 OriginFormat aFormat
) {
11140 MOZ_ASSERT(NS_IsMainThread());
11144 if (aFormat
== OriginFormat::Base64
) {
11145 rv
= Base64Decode(aOriginKey
, rawKey
);
11146 NS_ENSURE_SUCCESS(rv
, rv
);
11148 rawKey
= aOriginKey
;
11154 Span(reinterpret_cast<const uint8_t*>(rawKey
.get()), rawKey
.Length()));
11155 NS_ENSURE_SUCCESS(rv
, rv
);
11157 NS_ConvertUTF16toUTF8
id(aId
);
11158 rv
= hmac
.Update(reinterpret_cast<const uint8_t*>(id
.get()), id
.Length());
11159 NS_ENSURE_SUCCESS(rv
, rv
);
11161 nsTArray
<uint8_t> macBytes
;
11162 rv
= hmac
.End(macBytes
);
11163 NS_ENSURE_SUCCESS(rv
, rv
);
11165 nsCString macBase64
;
11167 nsDependentCSubstring(reinterpret_cast<const char*>(macBytes
.Elements()),
11168 macBytes
.Length()),
11170 NS_ENSURE_SUCCESS(rv
, rv
);
11172 CopyUTF8toUTF16(macBase64
, aId
);
11177 bool nsContentUtils::ShouldHideObjectOrEmbedImageDocument() {
11178 return StaticPrefs::
11179 browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup() &&
11181 browser_opaqueResponseBlocking_syntheticBrowsingContext_filter_AtStartup_DoNotUseDirectly();
11185 uint32_t nsContentUtils::ResolveObjectType(uint32_t aType
) {
11187 browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup()) {
11191 if (aType
!= nsIObjectLoadingContent::TYPE_IMAGE
) {
11195 return nsIObjectLoadingContent::TYPE_DOCUMENT
;
11198 void nsContentUtils::RequestGeckoTaskBurst() {
11199 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(NS_APPSHELL_CID
);
11201 appShell
->GeckoTaskBurst();
11205 nsIContent
* nsContentUtils::GetClosestLinkInFlatTree(nsIContent
* aContent
) {
11206 for (nsIContent
* content
= aContent
; content
;
11207 content
= content
->GetFlattenedTreeParent()) {
11208 if (nsContentUtils::IsDraggableLink(content
)) {
11217 struct TreePositionComparator
{
11218 Element
* const mChild
;
11219 nsIContent
* const mAncestor
;
11220 TreePositionComparator(Element
* aChild
, nsIContent
* aAncestor
)
11221 : mChild(aChild
), mAncestor(aAncestor
) {}
11222 int operator()(Element
* aElement
) const {
11223 return nsLayoutUtils::CompareTreePosition(mChild
, aElement
, mAncestor
);
11230 int32_t nsContentUtils::CompareTreePosition(nsIContent
* aContent1
,
11231 nsIContent
* aContent2
,
11232 const nsIContent
* aCommonAncestor
) {
11233 NS_ASSERTION(aContent1
!= aContent2
, "Comparing content to itself");
11235 // TODO: remove the prevent asserts fix, see bug 598468.
11237 nsLayoutUtils::gPreventAssertInCompareTreePosition
= true;
11239 nsLayoutUtils::CompareTreePosition(aContent1
, aContent2
, aCommonAncestor
);
11240 nsLayoutUtils::gPreventAssertInCompareTreePosition
= false;
11244 return nsLayoutUtils::CompareTreePosition(aContent1
, aContent2
,
11250 template <typename ElementType
, typename ElementPtr
>
11251 bool nsContentUtils::AddElementToListByTreeOrder(nsTArray
<ElementType
>& aList
,
11253 nsIContent
* aCommonAncestor
) {
11254 NS_ASSERTION(aList
.IndexOf(aChild
) == aList
.NoIndex
,
11255 "aChild already in aList");
11257 const uint32_t count
= aList
.Length();
11258 ElementType element
;
11260 // Optimize most common case where we insert at the end.
11261 int32_t position
= -1;
11263 element
= aList
[count
- 1];
11264 position
= CompareTreePosition(aChild
, element
, aCommonAncestor
);
11267 // If this item comes after the last element, or the elements array is
11268 // empty, we append to the end. Otherwise, we do a binary search to
11269 // determine where the element should go.
11270 if (position
>= 0 || count
== 0) {
11271 aList
.AppendElement(aChild
);
11276 BinarySearchIf(aList
, 0, count
,
11277 TreePositionComparator(aChild
, aCommonAncestor
), &idx
);
11279 aList
.InsertElementAt(idx
, aChild
);
11283 template bool nsContentUtils::AddElementToListByTreeOrder(
11284 nsTArray
<nsGenericHTMLFormElement
*>& aList
,
11285 nsGenericHTMLFormElement
* aChild
, nsIContent
* aAncestor
);
11286 template bool nsContentUtils::AddElementToListByTreeOrder(
11287 nsTArray
<HTMLImageElement
*>& aList
, HTMLImageElement
* aChild
,
11288 nsIContent
* aAncestor
);
11289 template bool nsContentUtils::AddElementToListByTreeOrder(
11290 nsTArray
<RefPtr
<HTMLInputElement
>>& aList
, HTMLInputElement
* aChild
,
11291 nsIContent
* aAncestor
);
11293 namespace mozilla
{
11294 std::ostream
& operator<<(std::ostream
& aOut
,
11295 const PreventDefaultResult aPreventDefaultResult
) {
11296 switch (aPreventDefaultResult
) {
11297 case PreventDefaultResult::No
:
11298 aOut
<< "unhandled";
11300 case PreventDefaultResult::ByContent
:
11301 aOut
<< "handled-by-content";
11303 case PreventDefaultResult::ByChrome
:
11304 aOut
<< "handled-by-chrome";
11309 } // namespace mozilla