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"
23 #include "InProcessBrowserChildMessageManager.h"
25 #include "MainThreadUtils.h"
26 #include "PLDHashTable.h"
27 #include "ReferrerInfo.h"
28 #include "ThirdPartyUtil.h"
30 #include "chrome/common/ipc_message.h"
31 #include "gfxDrawable.h"
32 #include "harfbuzz/hb.h"
33 #include "imgICache.h"
34 #include "imgIContainer.h"
35 #include "imgILoader.h"
36 #include "imgIRequest.h"
37 #include "imgLoader.h"
39 #include "js/ArrayBuffer.h"
40 #include "js/BuildId.h"
44 #include "js/PropertyDescriptor.h"
46 #include "js/RegExp.h"
47 #include "js/RegExpFlags.h"
48 #include "js/RootingAPI.h"
49 #include "js/TypeDecls.h"
51 #include "js/Wrapper.h"
53 #include "jsfriendapi.h"
54 #include "mozAutoDocUpdate.h"
55 #include "mozIDOMWindow.h"
56 #include "mozilla/AlreadyAddRefed.h"
57 #include "mozilla/ArrayIterator.h"
58 #include "mozilla/ArrayUtils.h"
59 #include "mozilla/AsyncEventDispatcher.h"
60 #include "mozilla/AtomArray.h"
61 #include "mozilla/Atomics.h"
62 #include "mozilla/Attributes.h"
63 #include "mozilla/AutoRestore.h"
64 #include "mozilla/AutoTimelineMarker.h"
65 #include "mozilla/BackgroundHangMonitor.h"
66 #include "mozilla/Base64.h"
67 #include "mozilla/BasePrincipal.h"
68 #include "mozilla/BasicEvents.h"
69 #include "mozilla/BloomFilter.h"
70 #include "mozilla/CORSMode.h"
71 #include "mozilla/CallState.h"
72 #include "mozilla/CheckedInt.h"
73 #include "mozilla/Components.h"
74 #include "mozilla/CycleCollectedJSContext.h"
75 #include "mozilla/DOMEventTargetHelper.h"
76 #include "mozilla/DebugOnly.h"
77 #include "mozilla/ErrorResult.h"
78 #include "mozilla/EventDispatcher.h"
79 #include "mozilla/EventListenerManager.h"
80 #include "mozilla/EventQueue.h"
81 #include "mozilla/EventStateManager.h"
82 #include "mozilla/FlushType.h"
83 #include "mozilla/HTMLEditor.h"
84 #include "mozilla/HangAnnotations.h"
85 #include "mozilla/IMEStateManager.h"
86 #include "mozilla/InputEventOptions.h"
87 #include "mozilla/InternalMutationEvent.h"
88 #include "mozilla/Latin1.h"
89 #include "mozilla/Likely.h"
90 #include "mozilla/LoadInfo.h"
91 #include "mozilla/Logging.h"
92 #include "mozilla/MacroForEach.h"
93 #include "mozilla/ManualNAC.h"
94 #include "mozilla/Maybe.h"
95 #include "mozilla/MouseEvents.h"
96 #include "mozilla/NotNull.h"
97 #include "mozilla/NullPrincipal.h"
98 #include "mozilla/OriginAttributes.h"
99 #include "mozilla/Preferences.h"
100 #include "mozilla/PresShell.h"
101 #include "mozilla/RangeBoundary.h"
102 #include "mozilla/RefPtr.h"
103 #include "mozilla/Result.h"
104 #include "mozilla/ResultExtensions.h"
105 #include "mozilla/ScrollbarPreferences.h"
106 #include "mozilla/Span.h"
107 #include "mozilla/StaticAnalysisFunctions.h"
108 #include "mozilla/StaticPrefs_dom.h"
110 # include "mozilla/StaticPrefs_fuzzing.h"
112 #include "mozilla/StaticPrefs_privacy.h"
113 #include "mozilla/StaticPrefs_test.h"
114 #include "mozilla/StaticPrefs_ui.h"
115 #include "mozilla/StaticPtr.h"
116 #include "mozilla/TaskCategory.h"
117 #include "mozilla/TextControlState.h"
118 #include "mozilla/TextEditor.h"
119 #include "mozilla/TextEvents.h"
120 #include "mozilla/UniquePtr.h"
121 #include "mozilla/Unused.h"
122 #include "mozilla/Variant.h"
123 #include "mozilla/ViewportUtils.h"
124 #include "mozilla/dom/AncestorIterator.h"
125 #include "mozilla/dom/AutoEntryScript.h"
126 #include "mozilla/dom/AutocompleteInfoBinding.h"
127 #include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
128 #include "mozilla/dom/BindingDeclarations.h"
129 #include "mozilla/dom/BindingUtils.h"
130 #include "mozilla/dom/BlobImpl.h"
131 #include "mozilla/dom/BlobURLProtocolHandler.h"
132 #include "mozilla/dom/BorrowedAttrInfo.h"
133 #include "mozilla/dom/BrowserBridgeParent.h"
134 #include "mozilla/dom/BrowserParent.h"
135 #include "mozilla/dom/BrowsingContext.h"
136 #include "mozilla/dom/BrowsingContextGroup.h"
137 #include "mozilla/dom/CallbackFunction.h"
138 #include "mozilla/dom/CallbackObject.h"
139 #include "mozilla/dom/ChromeMessageBroadcaster.h"
140 #include "mozilla/dom/ContentChild.h"
141 #include "mozilla/dom/ContentFrameMessageManager.h"
142 #include "mozilla/dom/ContentParent.h"
143 #include "mozilla/dom/CustomElementRegistry.h"
144 #include "mozilla/dom/CustomElementRegistryBinding.h"
145 #include "mozilla/dom/DOMArena.h"
146 #include "mozilla/dom/DOMException.h"
147 #include "mozilla/dom/DOMExceptionBinding.h"
148 #include "mozilla/dom/DOMSecurityMonitor.h"
149 #include "mozilla/dom/DOMTypes.h"
150 #include "mozilla/dom/DataTransfer.h"
151 #include "mozilla/dom/DocGroup.h"
152 #include "mozilla/dom/Document.h"
153 #include "mozilla/dom/DocumentFragment.h"
154 #include "mozilla/dom/DocumentInlines.h"
155 #include "mozilla/dom/Element.h"
156 #include "mozilla/dom/ElementBinding.h"
157 #include "mozilla/dom/ElementInlines.h"
158 #include "mozilla/dom/Event.h"
159 #include "mozilla/dom/EventTarget.h"
160 #include "mozilla/dom/FileBlobImpl.h"
161 #include "mozilla/dom/FileSystemSecurity.h"
162 #include "mozilla/dom/FilteredNodeIterator.h"
163 #include "mozilla/dom/FontTableURIProtocolHandler.h"
164 #include "mozilla/dom/FragmentOrElement.h"
165 #include "mozilla/dom/FromParser.h"
166 #include "mozilla/dom/HTMLFormElement.h"
167 #include "mozilla/dom/HTMLInputElement.h"
168 #include "mozilla/dom/HTMLTextAreaElement.h"
169 #include "mozilla/dom/IPCBlob.h"
170 #include "mozilla/dom/IPCBlobUtils.h"
171 #include "mozilla/dom/MessageBroadcaster.h"
172 #include "mozilla/dom/MessageListenerManager.h"
173 #include "mozilla/dom/MouseEventBinding.h"
174 #include "mozilla/dom/NameSpaceConstants.h"
175 #include "mozilla/dom/NodeBinding.h"
176 #include "mozilla/dom/NodeInfo.h"
177 #include "mozilla/dom/PBrowser.h"
178 #include "mozilla/dom/PContentChild.h"
179 #include "mozilla/dom/PrototypeList.h"
180 #include "mozilla/dom/ReferrerPolicyBinding.h"
181 #include "mozilla/dom/ScriptSettings.h"
182 #include "mozilla/dom/Selection.h"
183 #include "mozilla/dom/ShadowRoot.h"
184 #include "mozilla/dom/Text.h"
185 #include "mozilla/dom/UserActivation.h"
186 #include "mozilla/dom/WindowContext.h"
187 #include "mozilla/dom/WorkerCommon.h"
188 #include "mozilla/dom/WorkerPrivate.h"
189 #include "mozilla/dom/XULCommandEvent.h"
190 #include "mozilla/fallible.h"
191 #include "mozilla/gfx/2D.h"
192 #include "mozilla/gfx/BaseMargin.h"
193 #include "mozilla/gfx/BasePoint.h"
194 #include "mozilla/gfx/BaseSize.h"
195 #include "mozilla/gfx/DataSurfaceHelpers.h"
196 #include "mozilla/gfx/Point.h"
197 #include "mozilla/gfx/Rect.h"
198 #include "mozilla/gfx/Types.h"
199 #include "mozilla/intl/LineBreaker.h"
200 #include "mozilla/intl/WordBreaker.h"
201 #include "mozilla/ipc/ProtocolUtils.h"
202 #include "mozilla/ipc/SharedMemory.h"
203 #include "mozilla/ipc/Shmem.h"
204 #include "mozilla/net/UrlClassifierCommon.h"
205 #include "mozilla/widget/IMEData.h"
206 #include "nsAboutProtocolUtils.h"
207 #include "nsAlgorithm.h"
208 #include "nsArrayUtils.h"
210 #include "nsAttrName.h"
211 #include "nsAttrValue.h"
212 #include "nsAttrValueInlines.h"
213 #include "nsBaseHashtable.h"
214 #include "nsCCUncollectableMarker.h"
215 #include "nsCOMPtr.h"
217 #include "nsCRTGlue.h"
218 #include "nsCanvasFrame.h"
219 #include "nsCaseTreatment.h"
220 #include "nsCharSeparatedTokenizer.h"
221 #include "nsCharTraits.h"
222 #include "nsCompatibility.h"
223 #include "nsComponentManagerUtils.h"
224 #include "nsContainerFrame.h"
225 #include "nsContentCreatorFunctions.h"
226 #include "nsContentDLF.h"
227 #include "nsContentList.h"
228 #include "nsContentListDeclarations.h"
229 #include "nsContentPolicyUtils.h"
231 #include "nsCycleCollectionNoteChild.h"
232 #include "nsDOMMutationObserver.h"
233 #include "nsDOMString.h"
234 #include "nsTHashMap.h"
236 #include "nsDocShell.h"
237 #include "nsDocShellCID.h"
239 #include "nsFocusManager.h"
240 #include "nsFrameList.h"
241 #include "nsFrameLoader.h"
242 #include "nsFrameLoaderOwner.h"
243 #include "nsGenericHTMLElement.h"
244 #include "nsGkAtoms.h"
245 #include "nsGlobalWindowInner.h"
246 #include "nsGlobalWindowOuter.h"
247 #include "nsHTMLDocument.h"
248 #include "nsHTMLTags.h"
249 #include "nsHashKeys.h"
250 #include "nsHtml5StringParser.h"
251 #include "nsIAboutModule.h"
252 #include "nsIAnonymousContentCreator.h"
253 #include "nsIArray.h"
254 #include "nsIAsyncVerifyRedirectCallback.h"
255 #include "nsIBidiKeyboard.h"
256 #include "nsIBrowser.h"
257 #include "nsICacheInfoChannel.h"
258 #include "nsICategoryManager.h"
259 #include "nsIChannel.h"
260 #include "nsIChannelEventSink.h"
261 #include "nsIClassifiedChannel.h"
262 #include "nsIConsoleService.h"
263 #include "nsIContent.h"
264 #include "nsIContentInlines.h"
265 #include "nsIContentPolicy.h"
266 #include "nsIContentSecurityPolicy.h"
267 #include "nsIContentSink.h"
268 #include "nsIContentViewer.h"
270 #include "nsIDOMWindowUtils.h"
271 #include "nsIDocShell.h"
272 #include "nsIDocShellTreeItem.h"
273 #include "nsIDocumentEncoder.h"
274 #include "nsIDocumentLoaderFactory.h"
275 #include "nsIDragService.h"
276 #include "nsIDragSession.h"
278 #include "nsIFocusManager.h"
279 #include "nsIFormControl.h"
280 #include "nsIFragmentContentSink.h"
281 #include "nsIFrame.h"
282 #include "nsIGlobalObject.h"
283 #include "nsIHttpChannel.h"
284 #include "nsIHttpChannelInternal.h"
285 #include "nsIIOService.h"
286 #include "nsIImageLoadingContent.h"
287 #include "nsIInputStream.h"
288 #include "nsIInterfaceRequestor.h"
289 #include "nsIInterfaceRequestorUtils.h"
290 #include "nsILoadContext.h"
291 #include "nsILoadGroup.h"
292 #include "nsILoadInfo.h"
293 #include "nsIMIMEService.h"
294 #include "nsIMemoryReporter.h"
295 #include "nsINetUtil.h"
297 #include "nsIObjectLoadingContent.h"
298 #include "nsIObserver.h"
299 #include "nsIObserverService.h"
300 #include "nsIOfflineCacheUpdate.h"
301 #include "nsIParser.h"
302 #include "nsIParserUtils.h"
303 #include "nsIPermissionManager.h"
304 #include "nsIPluginTag.h"
305 #include "nsIPrincipal.h"
306 #include "nsIProperties.h"
307 #include "nsIProtocolHandler.h"
308 #include "nsIRequest.h"
309 #include "nsIRunnable.h"
310 #include "nsIScreen.h"
311 #include "nsIScriptError.h"
312 #include "nsIScriptGlobalObject.h"
313 #include "nsIScriptObjectPrincipal.h"
314 #include "nsIScriptSecurityManager.h"
315 #include "nsISerialEventTarget.h"
316 #include "nsIStreamConverter.h"
317 #include "nsIStreamConverterService.h"
318 #include "nsIStringBundle.h"
319 #include "nsISupports.h"
320 #include "nsISupportsPrimitives.h"
321 #include "nsISupportsUtils.h"
322 #include "nsITransferable.h"
324 #include "nsIURIMutator.h"
325 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
326 # include "nsIURIWithSpecialOrigin.h"
328 #include "nsIUUIDGenerator.h"
329 #include "nsIUserIdleService.h"
330 #include "nsIWeakReferenceUtils.h"
331 #include "nsIWebNavigation.h"
332 #include "nsIWebNavigationInfo.h"
333 #include "nsIWidget.h"
334 #include "nsIWindowMediator.h"
335 #include "nsIXPConnect.h"
336 #include "nsJSPrincipals.h"
337 #include "nsJSUtils.h"
338 #include "nsLayoutUtils.h"
339 #include "nsLiteralString.h"
340 #include "nsMappedAttributes.h"
341 #include "nsMargin.h"
342 #include "nsMimeTypes.h"
343 #include "nsNameSpaceManager.h"
344 #include "nsNetCID.h"
345 #include "nsNetUtil.h"
346 #include "nsNodeInfoManager.h"
347 #include "nsPIDOMWindow.h"
348 #include "nsPIDOMWindowInlines.h"
349 #include "nsParserCIID.h"
350 #include "nsParserConstants.h"
351 #include "nsPluginHost.h"
353 #include "nsPointerHashKeys.h"
354 #include "nsPresContext.h"
355 #include "nsQueryFrame.h"
356 #include "nsQueryObject.h"
357 #include "nsRFPService.h"
359 #include "nsRefPtrHashtable.h"
360 #include "nsSandboxFlags.h"
361 #include "nsScriptSecurityManager.h"
362 #include "nsServiceManagerUtils.h"
363 #include "nsStreamUtils.h"
364 #include "nsString.h"
365 #include "nsStringBuffer.h"
366 #include "nsStringFlags.h"
367 #include "nsStringFwd.h"
368 #include "nsStringIterator.h"
369 #include "nsTArray.h"
370 #include "nsTLiteralString.h"
371 #include "nsTPromiseFlatString.h"
372 #include "nsTStringRepr.h"
373 #include "nsTextFragment.h"
374 #include "nsTextNode.h"
375 #include "nsThreadManager.h"
376 #include "nsThreadUtils.h"
377 #include "nsTreeSanitizer.h"
378 #include "nsUGenCategory.h"
379 #include "nsURLHelper.h"
380 #include "nsUnicodeProperties.h"
382 #include "nsViewManager.h"
384 #include "nsXPCOMCID.h"
385 #include "nsXULAppAPI.h"
386 #include "nsXULElement.h"
387 #include "nsXULPopupManager.h"
389 #include "prinrval.h"
390 #include "xpcprivate.h"
391 #include "xpcpublic.h"
394 // Undefine LoadImage to prevent naming conflict with Windows.
398 extern "C" int MOZ_XMLTranslateEntity(const char* ptr
, const char* end
,
399 const char** next
, char16_t
* result
);
400 extern "C" int MOZ_XMLCheckQName(const char* ptr
, const char* end
, int ns_aware
,
403 using namespace mozilla::dom
;
404 using namespace mozilla::ipc
;
405 using namespace mozilla::gfx
;
406 using namespace mozilla::layers
;
407 using namespace mozilla::widget
;
408 using namespace mozilla
;
410 const char kLoadAsData
[] = "loadAsData";
412 nsIXPConnect
* nsContentUtils::sXPConnect
;
413 nsIScriptSecurityManager
* nsContentUtils::sSecurityManager
;
414 nsIPrincipal
* nsContentUtils::sSystemPrincipal
;
415 nsIPrincipal
* nsContentUtils::sNullSubjectPrincipal
;
416 nsNameSpaceManager
* nsContentUtils::sNameSpaceManager
;
417 nsIIOService
* nsContentUtils::sIOService
;
418 nsIUUIDGenerator
* nsContentUtils::sUUIDGenerator
;
419 nsIConsoleService
* nsContentUtils::sConsoleService
;
420 nsTHashMap
<nsRefPtrHashKey
<nsAtom
>, EventNameMapping
>*
421 nsContentUtils::sAtomEventTable
= nullptr;
422 nsTHashMap
<nsStringHashKey
, EventNameMapping
>*
423 nsContentUtils::sStringEventTable
= nullptr;
424 nsTArray
<RefPtr
<nsAtom
>>* nsContentUtils::sUserDefinedEvents
= nullptr;
425 nsIStringBundleService
* nsContentUtils::sStringBundleService
;
426 nsIStringBundle
* nsContentUtils::sStringBundles
[PropertiesFile_COUNT
];
427 nsIContentPolicy
* nsContentUtils::sContentPolicyService
;
428 bool nsContentUtils::sTriedToGetContentPolicy
= false;
429 RefPtr
<mozilla::intl::LineBreaker
> nsContentUtils::sLineBreaker
;
430 RefPtr
<mozilla::intl::WordBreaker
> nsContentUtils::sWordBreaker
;
431 StaticRefPtr
<nsIBidiKeyboard
> nsContentUtils::sBidiKeyboard
;
432 uint32_t nsContentUtils::sScriptBlockerCount
= 0;
433 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount
= 0;
434 AutoTArray
<nsCOMPtr
<nsIRunnable
>, 8>* nsContentUtils::sBlockedScriptRunners
=
436 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker
= 0;
437 nsIInterfaceRequestor
* nsContentUtils::sSameOriginChecker
= nullptr;
439 bool nsContentUtils::sIsHandlingKeyBoardEvent
= false;
441 nsString
* nsContentUtils::sShiftText
= nullptr;
442 nsString
* nsContentUtils::sControlText
= nullptr;
443 nsString
* nsContentUtils::sMetaText
= nullptr;
444 nsString
* nsContentUtils::sOSText
= nullptr;
445 nsString
* nsContentUtils::sAltText
= nullptr;
446 nsString
* nsContentUtils::sModifierSeparator
= nullptr;
448 bool nsContentUtils::sInitialized
= false;
449 #ifndef RELEASE_OR_BETA
450 bool nsContentUtils::sBypassCSSOMOriginCheck
= false;
453 nsCString
* nsContentUtils::sJSBytecodeMimeType
= nullptr;
455 nsContentUtils::UserInteractionObserver
*
456 nsContentUtils::sUserInteractionObserver
= nullptr;
458 nsHtml5StringParser
* nsContentUtils::sHTMLFragmentParser
= nullptr;
459 nsIParser
* nsContentUtils::sXMLFragmentParser
= nullptr;
460 nsIFragmentContentSink
* nsContentUtils::sXMLFragmentSink
= nullptr;
461 bool nsContentUtils::sFragmentParsingActive
= false;
463 mozilla::LazyLogModule
nsContentUtils::sDOMDumpLog("Dump");
465 int32_t nsContentUtils::sInnerOrOuterWindowCount
= 0;
466 uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter
= 0;
468 template Maybe
<int32_t> nsContentUtils::ComparePoints(
469 const RangeBoundary
& aFirstBoundary
, const RangeBoundary
& aSecondBoundary
);
470 template Maybe
<int32_t> nsContentUtils::ComparePoints(
471 const RangeBoundary
& aFirstBoundary
,
472 const RawRangeBoundary
& aSecondBoundary
);
473 template Maybe
<int32_t> nsContentUtils::ComparePoints(
474 const RawRangeBoundary
& aFirstBoundary
,
475 const RangeBoundary
& aSecondBoundary
);
476 template Maybe
<int32_t> nsContentUtils::ComparePoints(
477 const RawRangeBoundary
& aFirstBoundary
,
478 const RawRangeBoundary
& aSecondBoundary
);
480 template int32_t nsContentUtils::ComparePoints_Deprecated(
481 const RangeBoundary
& aFirstBoundary
, const RangeBoundary
& aSecondBoundary
,
482 bool* aDisconnected
);
483 template int32_t nsContentUtils::ComparePoints_Deprecated(
484 const RangeBoundary
& aFirstBoundary
,
485 const RawRangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
486 template int32_t nsContentUtils::ComparePoints_Deprecated(
487 const RawRangeBoundary
& aFirstBoundary
,
488 const RangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
489 template int32_t nsContentUtils::ComparePoints_Deprecated(
490 const RawRangeBoundary
& aFirstBoundary
,
491 const RawRangeBoundary
& aSecondBoundary
, bool* aDisconnected
);
494 // http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
495 enum AutocompleteUnsupportedFieldName
: uint8_t {
496 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
497 eAutocompleteUnsupportedFieldName_##name_,
498 #include "AutocompleteFieldList.h"
499 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
502 enum AutocompleteNoPersistFieldName
: uint8_t {
503 #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
504 eAutocompleteNoPersistFieldName_##name_,
505 #include "AutocompleteFieldList.h"
506 #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
509 enum AutocompleteUnsupportFieldContactHint
: uint8_t {
510 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
511 eAutocompleteUnsupportedFieldContactHint_##name_,
512 #include "AutocompleteFieldList.h"
513 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
516 enum AutocompleteFieldName
: uint8_t {
517 #define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_,
518 #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
519 AUTOCOMPLETE_FIELD_NAME(name_, value_)
520 #include "AutocompleteFieldList.h"
521 #undef AUTOCOMPLETE_FIELD_NAME
522 #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
525 enum AutocompleteFieldHint
: uint8_t {
526 #define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_,
527 #include "AutocompleteFieldList.h"
528 #undef AUTOCOMPLETE_FIELD_HINT
531 enum AutocompleteFieldContactHint
: uint8_t {
532 #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
533 eAutocompleteFieldContactHint_##name_,
534 #include "AutocompleteFieldList.h"
535 #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
538 enum AutocompleteCategory
{
539 #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_,
540 #include "AutocompleteFieldList.h"
541 #undef AUTOCOMPLETE_CATEGORY
544 static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable
[] = {
545 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
546 {value_, eAutocompleteUnsupportedFieldName_##name_},
547 #include "AutocompleteFieldList.h"
548 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
551 static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable
[] = {
552 #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
553 {value_, eAutocompleteNoPersistFieldName_##name_},
554 #include "AutocompleteFieldList.h"
555 #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
558 static const nsAttrValue::EnumTable
559 kAutocompleteUnsupportedContactFieldHintTable
[] = {
560 #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
561 {value_, eAutocompleteUnsupportedFieldContactHint_##name_},
562 #include "AutocompleteFieldList.h"
563 #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
566 static const nsAttrValue::EnumTable kAutocompleteFieldNameTable
[] = {
567 #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
568 {value_, eAutocompleteFieldName_##name_},
569 #include "AutocompleteFieldList.h"
570 #undef AUTOCOMPLETE_FIELD_NAME
573 static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable
[] = {
574 #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
575 {value_, eAutocompleteFieldName_##name_},
576 #include "AutocompleteFieldList.h"
577 #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
580 static const nsAttrValue::EnumTable kAutocompleteFieldHintTable
[] = {
581 #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
582 {value_, eAutocompleteFieldHint_##name_},
583 #include "AutocompleteFieldList.h"
584 #undef AUTOCOMPLETE_FIELD_HINT
587 static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable
[] = {
588 #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
589 {value_, eAutocompleteFieldContactHint_##name_},
590 #include "AutocompleteFieldList.h"
591 #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
596 static NS_DEFINE_CID(kCParserCID
, NS_PARSER_CID
);
598 static PLDHashTable
* sEventListenerManagersHash
;
600 // A global hashtable to for keeping the arena alive for cross docGroup node
602 static nsRefPtrHashtable
<nsPtrHashKey
<const nsINode
>, mozilla::dom::DOMArena
>*
605 class DOMEventListenerManagersHashReporter final
: public nsIMemoryReporter
{
606 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf
)
608 ~DOMEventListenerManagersHashReporter() = default;
613 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
614 nsISupports
* aData
, bool aAnonymize
) override
{
615 // We don't measure the |EventListenerManager| objects pointed to by the
616 // entries because those references are non-owning.
618 sEventListenerManagersHash
619 ? sEventListenerManagersHash
->ShallowSizeOfIncludingThis(
624 "explicit/dom/event-listener-managers-hash", KIND_HEAP
, UNITS_BYTES
,
625 amount
, "Memory used by the event listener manager's hash table.");
631 NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter
, nsIMemoryReporter
)
633 class EventListenerManagerMapEntry
: public PLDHashEntryHdr
{
635 explicit EventListenerManagerMapEntry(const void* aKey
) : mKey(aKey
) {}
637 ~EventListenerManagerMapEntry() {
638 NS_ASSERTION(!mListenerManager
, "caller must release and disconnect ELM");
641 protected: // declared protected to silence clang warnings
642 const void* mKey
; // must be first, to look like PLDHashEntryStub
645 RefPtr
<EventListenerManager
> mListenerManager
;
648 static void EventListenerManagerHashInitEntry(PLDHashEntryHdr
* entry
,
650 // Initialize the entry with placement new
651 new (entry
) EventListenerManagerMapEntry(key
);
654 static void EventListenerManagerHashClearEntry(PLDHashTable
* table
,
655 PLDHashEntryHdr
* entry
) {
656 EventListenerManagerMapEntry
* lm
=
657 static_cast<EventListenerManagerMapEntry
*>(entry
);
659 // Let the EventListenerManagerMapEntry clean itself up...
660 lm
->~EventListenerManagerMapEntry();
663 class SameOriginCheckerImpl final
: public nsIChannelEventSink
,
664 public nsIInterfaceRequestor
{
665 ~SameOriginCheckerImpl() = default;
668 NS_DECL_NSICHANNELEVENTSINK
669 NS_DECL_NSIINTERFACEREQUESTOR
674 void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document
* aDoc
) {
675 // Note: Document::SuppressEventHandling will also automatically suppress
676 // event handling for any in-process sub-documents. However, since we need
677 // to deal with cases where remote BrowsingContexts may be interleaved
678 // with in-process ones, we still need to walk the entire tree ourselves.
679 // This may be slightly redundant in some cases, but since event handling
680 // suppressions maintain a count of current blockers, it does not cause
682 aDoc
->SuppressEventHandling();
683 if (nsCOMPtr
<nsPIDOMWindowInner
> win
= aDoc
->GetInnerWindow()) {
685 mWindows
.AppendElement(win
);
689 void AutoSuppressEventHandlingAndSuspend::UnsuppressDocument(Document
* aDoc
) {
690 aDoc
->UnsuppressEventHandlingAndFireEvents(true);
693 AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() {
694 for (const auto& win
: mWindows
) {
697 UnsuppressDocuments();
701 * This class is used to determine whether or not the user is currently
702 * interacting with the browser. It listens to observer events to toggle the
703 * value of the sUserActive static.
705 * This class is an internal implementation detail.
706 * nsContentUtils::GetUserIsInteracting() should be used to access current
707 * user interaction status.
709 class nsContentUtils::UserInteractionObserver final
710 : public nsIObserver
,
711 public BackgroundHangAnnotator
{
718 void AnnotateHang(BackgroundHangAnnotations
& aAnnotations
) override
;
720 static Atomic
<bool> sUserActive
;
723 ~UserInteractionObserver() = default;
727 nsresult
nsContentUtils::Init() {
729 NS_WARNING("Init() called twice");
734 nsHTMLTags::AddRefTable();
736 sNameSpaceManager
= nsNameSpaceManager::GetInstance();
737 NS_ENSURE_TRUE(sNameSpaceManager
, NS_ERROR_OUT_OF_MEMORY
);
739 sXPConnect
= nsXPConnect::XPConnect();
740 // We hold a strong ref to sXPConnect to ensure that it does not go away until
741 // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be
742 // triggered by xpcModuleDtor late in shutdown and cause crashes due to
743 // various stuff already being torn down by then. Note that this means that
744 // we are effectively making sure that if we leak nsLayoutStatics then we also
746 NS_ADDREF(sXPConnect
);
748 sSecurityManager
= nsScriptSecurityManager::GetScriptSecurityManager();
749 if (!sSecurityManager
) return NS_ERROR_FAILURE
;
750 NS_ADDREF(sSecurityManager
);
752 sSecurityManager
->GetSystemPrincipal(&sSystemPrincipal
);
753 MOZ_ASSERT(sSystemPrincipal
);
755 RefPtr
<NullPrincipal
> nullPrincipal
=
756 NullPrincipal::CreateWithoutOriginAttributes();
757 if (!nullPrincipal
) {
758 return NS_ERROR_FAILURE
;
761 nullPrincipal
.forget(&sNullSubjectPrincipal
);
763 nsresult rv
= CallGetService(NS_IOSERVICE_CONTRACTID
, &sIOService
);
765 // This makes life easier, but we can live without it.
767 sIOService
= nullptr;
770 sLineBreaker
= mozilla::intl::LineBreaker::Create();
772 sWordBreaker
= mozilla::intl::WordBreaker::Create();
774 if (!InitializeEventTable()) return NS_ERROR_FAILURE
;
776 if (!sEventListenerManagersHash
) {
777 static const PLDHashTableOps hash_table_ops
= {
778 PLDHashTable::HashVoidPtrKeyStub
, PLDHashTable::MatchEntryStub
,
779 PLDHashTable::MoveEntryStub
, EventListenerManagerHashClearEntry
,
780 EventListenerManagerHashInitEntry
};
782 sEventListenerManagersHash
=
783 new PLDHashTable(&hash_table_ops
, sizeof(EventListenerManagerMapEntry
));
785 RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
788 sBlockedScriptRunners
= new AutoTArray
<nsCOMPtr
<nsIRunnable
>, 8>;
790 #ifndef RELEASE_OR_BETA
791 sBypassCSSOMOriginCheck
= getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
794 Element::InitCCCallbacks();
796 Unused
<< nsRFPService::GetOrCreate();
798 nsCOMPtr
<nsIUUIDGenerator
> uuidGenerator
=
799 do_GetService("@mozilla.org/uuid-generator;1", &rv
);
800 if (NS_WARN_IF(NS_FAILED(rv
))) {
803 uuidGenerator
.forget(&sUUIDGenerator
);
805 if (XRE_IsParentProcess()) {
806 AsyncPrecreateStringBundles();
809 RefPtr
<UserInteractionObserver
> uio
= new UserInteractionObserver();
811 uio
.forget(&sUserInteractionObserver
);
818 bool nsContentUtils::InitJSBytecodeMimeType() {
819 MOZ_ASSERT(NS_IsMainThread());
820 MOZ_ASSERT(!sJSBytecodeMimeType
);
822 JS::BuildIdCharVector jsBuildId
;
823 if (!JS::GetScriptTranscodingBuildId(&jsBuildId
)) {
827 nsDependentCSubstring
jsBuildIdStr(jsBuildId
.begin(), jsBuildId
.length());
828 sJSBytecodeMimeType
=
829 new nsCString("javascript/moz-bytecode-"_ns
+ jsBuildIdStr
);
833 void nsContentUtils::GetShiftText(nsAString
& text
) {
834 if (!sShiftText
) InitializeModifierStrings();
835 text
.Assign(*sShiftText
);
838 void nsContentUtils::GetControlText(nsAString
& text
) {
839 if (!sControlText
) InitializeModifierStrings();
840 text
.Assign(*sControlText
);
843 void nsContentUtils::GetMetaText(nsAString
& text
) {
844 if (!sMetaText
) InitializeModifierStrings();
845 text
.Assign(*sMetaText
);
848 void nsContentUtils::GetOSText(nsAString
& text
) {
850 InitializeModifierStrings();
852 text
.Assign(*sOSText
);
855 void nsContentUtils::GetAltText(nsAString
& text
) {
856 if (!sAltText
) InitializeModifierStrings();
857 text
.Assign(*sAltText
);
860 void nsContentUtils::GetModifierSeparatorText(nsAString
& text
) {
861 if (!sModifierSeparator
) InitializeModifierStrings();
862 text
.Assign(*sModifierSeparator
);
865 void nsContentUtils::InitializeModifierStrings() {
866 // load the display strings for the keyboard accelerators
867 nsCOMPtr
<nsIStringBundleService
> bundleService
=
868 mozilla::components::StringBundle::Service();
869 nsCOMPtr
<nsIStringBundle
> bundle
;
870 DebugOnly
<nsresult
> rv
= NS_OK
;
872 rv
= bundleService
->CreateBundle(
873 "chrome://global-platform/locale/platformKeys.properties",
874 getter_AddRefs(bundle
));
878 NS_SUCCEEDED(rv
) && bundle
,
879 "chrome://global/locale/platformKeys.properties could not be loaded");
880 nsAutoString shiftModifier
;
881 nsAutoString metaModifier
;
882 nsAutoString osModifier
;
883 nsAutoString altModifier
;
884 nsAutoString controlModifier
;
885 nsAutoString modifierSeparator
;
887 // macs use symbols for each modifier key, so fetch each from the bundle,
888 // which also covers i18n
889 bundle
->GetStringFromName("VK_SHIFT", shiftModifier
);
890 bundle
->GetStringFromName("VK_META", metaModifier
);
891 bundle
->GetStringFromName("VK_WIN", osModifier
);
892 bundle
->GetStringFromName("VK_ALT", altModifier
);
893 bundle
->GetStringFromName("VK_CONTROL", controlModifier
);
894 bundle
->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator
);
896 // if any of these don't exist, we get an empty string
897 sShiftText
= new nsString(shiftModifier
);
898 sMetaText
= new nsString(metaModifier
);
899 sOSText
= new nsString(osModifier
);
900 sAltText
= new nsString(altModifier
);
901 sControlText
= new nsString(controlModifier
);
902 sModifierSeparator
= new nsString(modifierSeparator
);
905 mozilla::EventClassID
nsContentUtils::GetEventClassIDFromMessage(
906 EventMessage aEventMessage
) {
907 switch (aEventMessage
) {
908 #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
911 #include "mozilla/EventNameList.h"
912 #undef MESSAGE_TO_EVENT
914 MOZ_ASSERT_UNREACHABLE("Invalid event message?");
915 return eBasicEventClass
;
919 static nsAtom
* GetEventTypeFromMessage(EventMessage aEventMessage
) {
920 switch (aEventMessage
) {
921 #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
923 return nsGkAtoms::on##name_;
924 #include "mozilla/EventNameList.h"
925 #undef MESSAGE_TO_EVENT
931 // Because of SVG/SMIL we have several atoms mapped to the same
932 // id, but we can rely on MESSAGE_TO_EVENT to map id to only one atom.
933 static bool ShouldAddEventToStringEventTable(const EventNameMapping
& aMapping
) {
934 MOZ_ASSERT(aMapping
.mAtom
);
935 return GetEventTypeFromMessage(aMapping
.mMessage
) == aMapping
.mAtom
;
938 bool nsContentUtils::InitializeEventTable() {
939 NS_ASSERTION(!sAtomEventTable
, "EventTable already initialized!");
940 NS_ASSERTION(!sStringEventTable
, "EventTable already initialized!");
942 static const EventNameMapping eventArray
[] = {
943 #define EVENT(name_, _message, _type, _class) \
944 {nsGkAtoms::on##name_, _type, _message, _class, false},
945 #define WINDOW_ONLY_EVENT EVENT
946 #define DOCUMENT_ONLY_EVENT EVENT
947 #define NON_IDL_EVENT EVENT
948 #include "mozilla/EventNameList.h"
949 #undef WINDOW_ONLY_EVENT
954 sAtomEventTable
= new nsTHashMap
<nsRefPtrHashKey
<nsAtom
>, EventNameMapping
>(
955 ArrayLength(eventArray
));
956 sStringEventTable
= new nsTHashMap
<nsStringHashKey
, EventNameMapping
>(
957 ArrayLength(eventArray
));
958 sUserDefinedEvents
= new nsTArray
<RefPtr
<nsAtom
>>(64);
960 // Subtract one from the length because of the trailing null
961 for (uint32_t i
= 0; i
< ArrayLength(eventArray
) - 1; ++i
) {
962 MOZ_ASSERT(!sAtomEventTable
->Contains(eventArray
[i
].mAtom
),
963 "Double-defining event name; fix your EventNameList.h");
964 sAtomEventTable
->InsertOrUpdate(eventArray
[i
].mAtom
, eventArray
[i
]);
965 if (ShouldAddEventToStringEventTable(eventArray
[i
])) {
966 sStringEventTable
->InsertOrUpdate(
967 Substring(nsDependentAtomString(eventArray
[i
].mAtom
), 2),
975 void nsContentUtils::InitializeTouchEventTable() {
976 static bool sEventTableInitialized
= false;
977 if (!sEventTableInitialized
&& sAtomEventTable
&& sStringEventTable
) {
978 sEventTableInitialized
= true;
979 static const EventNameMapping touchEventArray
[] = {
980 #define EVENT(name_, _message, _type, _class)
981 #define TOUCH_EVENT(name_, _message, _type, _class) \
982 {nsGkAtoms::on##name_, _type, _message, _class},
983 #include "mozilla/EventNameList.h"
987 // Subtract one from the length because of the trailing null
988 for (uint32_t i
= 0; i
< ArrayLength(touchEventArray
) - 1; ++i
) {
989 sAtomEventTable
->InsertOrUpdate(touchEventArray
[i
].mAtom
,
991 sStringEventTable
->InsertOrUpdate(
992 Substring(nsDependentAtomString(touchEventArray
[i
].mAtom
), 2),
998 static bool Is8bit(const nsAString
& aString
) {
999 static const char16_t EIGHT_BIT
= char16_t(~0x00FF);
1001 for (nsAString::const_char_iterator start
= aString
.BeginReading(),
1002 end
= aString
.EndReading();
1003 start
!= end
; ++start
) {
1004 if (*start
& EIGHT_BIT
) {
1012 nsresult
nsContentUtils::Btoa(const nsAString
& aBinaryData
,
1013 nsAString
& aAsciiBase64String
) {
1014 if (!Is8bit(aBinaryData
)) {
1015 aAsciiBase64String
.Truncate();
1016 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1019 return Base64Encode(aBinaryData
, aAsciiBase64String
);
1022 nsresult
nsContentUtils::Atob(const nsAString
& aAsciiBase64String
,
1023 nsAString
& aBinaryData
) {
1024 if (!Is8bit(aAsciiBase64String
)) {
1025 aBinaryData
.Truncate();
1026 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1029 const char16_t
* start
= aAsciiBase64String
.BeginReading();
1030 const char16_t
* cur
= start
;
1031 const char16_t
* end
= aAsciiBase64String
.EndReading();
1032 bool hasWhitespace
= false;
1035 if (nsContentUtils::IsHTMLWhitespace(*cur
)) {
1036 hasWhitespace
= true;
1044 if (hasWhitespace
) {
1045 nsString trimmedString
;
1047 if (!trimmedString
.SetCapacity(aAsciiBase64String
.Length(), fallible
)) {
1048 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1051 trimmedString
.Append(start
, cur
- start
);
1054 if (!nsContentUtils::IsHTMLWhitespace(*cur
)) {
1055 trimmedString
.Append(*cur
);
1059 rv
= Base64Decode(trimmedString
, aBinaryData
);
1061 rv
= Base64Decode(aAsciiBase64String
, aBinaryData
);
1064 if (NS_FAILED(rv
) && rv
== NS_ERROR_INVALID_ARG
) {
1065 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
1070 bool nsContentUtils::IsAutocompleteEnabled(
1071 mozilla::dom::HTMLInputElement
* aInput
) {
1072 MOZ_ASSERT(aInput
, "aInput should not be null!");
1074 nsAutoString autocomplete
;
1075 aInput
->GetAutocomplete(autocomplete
);
1077 if (autocomplete
.IsEmpty()) {
1078 auto* form
= aInput
->GetForm();
1083 form
->GetAutocomplete(autocomplete
);
1086 return !autocomplete
.EqualsLiteral("off");
1089 nsContentUtils::AutocompleteAttrState
1090 nsContentUtils::SerializeAutocompleteAttribute(
1091 const nsAttrValue
* aAttr
, nsAString
& aResult
,
1092 AutocompleteAttrState aCachedState
) {
1094 aCachedState
== nsContentUtils::eAutocompleteAttrState_Invalid
) {
1095 return aCachedState
;
1098 if (aCachedState
== nsContentUtils::eAutocompleteAttrState_Valid
) {
1099 uint32_t atomCount
= aAttr
->GetAtomCount();
1100 for (uint32_t i
= 0; i
< atomCount
; i
++) {
1102 aResult
.Append(' ');
1104 aResult
.Append(nsDependentAtomString(aAttr
->AtomAt(i
)));
1106 nsContentUtils::ASCIIToLower(aResult
);
1107 return aCachedState
;
1112 mozilla::dom::AutocompleteInfo info
;
1113 AutocompleteAttrState state
=
1114 InternalSerializeAutocompleteAttribute(aAttr
, info
);
1115 if (state
== eAutocompleteAttrState_Valid
) {
1116 // Concatenate the info fields.
1117 aResult
= info
.mSection
;
1119 if (!info
.mAddressType
.IsEmpty()) {
1120 if (!aResult
.IsEmpty()) {
1123 aResult
+= info
.mAddressType
;
1126 if (!info
.mContactType
.IsEmpty()) {
1127 if (!aResult
.IsEmpty()) {
1130 aResult
+= info
.mContactType
;
1133 if (!info
.mFieldName
.IsEmpty()) {
1134 if (!aResult
.IsEmpty()) {
1137 aResult
+= info
.mFieldName
;
1144 nsContentUtils::AutocompleteAttrState
1145 nsContentUtils::SerializeAutocompleteAttribute(
1146 const nsAttrValue
* aAttr
, mozilla::dom::AutocompleteInfo
& aInfo
,
1147 AutocompleteAttrState aCachedState
, bool aGrantAllValidValue
) {
1149 aCachedState
== nsContentUtils::eAutocompleteAttrState_Invalid
) {
1150 return aCachedState
;
1153 return InternalSerializeAutocompleteAttribute(aAttr
, aInfo
,
1154 aGrantAllValidValue
);
1158 * Helper to validate the @autocomplete tokens.
1160 * @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
1162 nsContentUtils::AutocompleteAttrState
1163 nsContentUtils::InternalSerializeAutocompleteAttribute(
1164 const nsAttrValue
* aAttrVal
, mozilla::dom::AutocompleteInfo
& aInfo
,
1165 bool aGrantAllValidValue
) {
1166 // No autocomplete attribute so we are done
1168 return eAutocompleteAttrState_Invalid
;
1171 uint32_t numTokens
= aAttrVal
->GetAtomCount();
1173 return eAutocompleteAttrState_Invalid
;
1176 uint32_t index
= numTokens
- 1;
1177 nsString tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1178 AutocompleteCategory category
;
1179 nsAttrValue enumValue
;
1181 bool unsupported
= false;
1182 if (!aGrantAllValidValue
) {
1183 unsupported
= enumValue
.ParseEnumValue(
1184 tokenString
, kAutocompleteUnsupportedFieldNameTable
, false);
1186 return eAutocompleteAttrState_Invalid
;
1192 enumValue
.ParseEnumValue(tokenString
, kAutocompleteFieldNameTable
, false);
1194 // Off/Automatic/Normal categories.
1195 if (enumValue
.Equals(u
"off"_ns
, eIgnoreCase
) ||
1196 enumValue
.Equals(u
"on"_ns
, eIgnoreCase
)) {
1197 if (numTokens
> 1) {
1198 return eAutocompleteAttrState_Invalid
;
1200 enumValue
.ToString(str
);
1202 aInfo
.mFieldName
.Assign(str
);
1203 aInfo
.mCanAutomaticallyPersist
=
1204 !enumValue
.Equals(u
"off"_ns
, eIgnoreCase
);
1205 return eAutocompleteAttrState_Valid
;
1208 // Only allow on/off if form autofill @autocomplete values aren't enabled
1209 // and it doesn't grant all valid values.
1210 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1211 !aGrantAllValidValue
) {
1212 return eAutocompleteAttrState_Invalid
;
1216 if (numTokens
> 3) {
1217 return eAutocompleteAttrState_Invalid
;
1219 category
= eAutocompleteCategory_NORMAL
;
1220 } else { // Check if the last token is of the contact category instead.
1221 // Only allow on/off if form autofill @autocomplete values aren't enabled
1222 // and it doesn't grant all valid values.
1223 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1224 !aGrantAllValidValue
) {
1225 return eAutocompleteAttrState_Invalid
;
1228 result
= enumValue
.ParseEnumValue(
1229 tokenString
, kAutocompleteContactFieldNameTable
, false);
1230 if (!result
|| numTokens
> 4) {
1231 return eAutocompleteAttrState_Invalid
;
1234 category
= eAutocompleteCategory_CONTACT
;
1237 enumValue
.ToString(str
);
1239 aInfo
.mFieldName
.Assign(str
);
1241 aInfo
.mCanAutomaticallyPersist
= !enumValue
.ParseEnumValue(
1242 tokenString
, kAutocompleteNoPersistFieldNameTable
, false);
1244 // We are done if this was the only token.
1245 if (numTokens
== 1) {
1246 return eAutocompleteAttrState_Valid
;
1250 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1252 if (category
== eAutocompleteCategory_CONTACT
) {
1253 if (!aGrantAllValidValue
) {
1254 unsupported
= enumValue
.ParseEnumValue(
1255 tokenString
, kAutocompleteUnsupportedContactFieldHintTable
, false);
1257 return eAutocompleteAttrState_Invalid
;
1261 nsAttrValue contactFieldHint
;
1262 result
= contactFieldHint
.ParseEnumValue(
1263 tokenString
, kAutocompleteContactFieldHintTable
, false);
1265 nsAutoString contactFieldHintString
;
1266 contactFieldHint
.ToString(contactFieldHintString
);
1267 ASCIIToLower(contactFieldHintString
);
1268 aInfo
.mContactType
.Assign(contactFieldHintString
);
1270 return eAutocompleteAttrState_Valid
;
1273 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1277 // Check for billing/shipping tokens
1278 nsAttrValue fieldHint
;
1279 if (fieldHint
.ParseEnumValue(tokenString
, kAutocompleteFieldHintTable
,
1281 nsString fieldHintString
;
1282 fieldHint
.ToString(fieldHintString
);
1283 ASCIIToLower(fieldHintString
);
1284 aInfo
.mAddressType
.Assign(fieldHintString
);
1286 return eAutocompleteAttrState_Valid
;
1289 tokenString
= nsDependentAtomString(aAttrVal
->AtomAt(index
));
1292 // Check for section-* token
1293 const nsDependentSubstring
& section
= Substring(tokenString
, 0, 8);
1294 if (section
.LowerCaseEqualsASCII("section-")) {
1295 ASCIIToLower(tokenString
);
1296 aInfo
.mSection
.Assign(tokenString
);
1298 return eAutocompleteAttrState_Valid
;
1302 // Clear the fields as the autocomplete attribute is invalid.
1303 aInfo
.mSection
.Truncate();
1304 aInfo
.mAddressType
.Truncate();
1305 aInfo
.mContactType
.Truncate();
1306 aInfo
.mFieldName
.Truncate();
1308 return eAutocompleteAttrState_Invalid
;
1311 // Parse an integer according to HTML spec
1312 template <class StringT
>
1313 int32_t nsContentUtils::ParseHTMLIntegerImpl(
1314 const StringT
& aValue
, ParseHTMLIntegerResultFlags
* aResult
) {
1315 using CharT
= typename
StringT::char_type
;
1317 int result
= eParseHTMLInteger_NoFlags
;
1319 typename
StringT::const_iterator iter
, end
;
1320 aValue
.BeginReading(iter
);
1321 aValue
.EndReading(end
);
1323 while (iter
!= end
&& nsContentUtils::IsHTMLWhitespace(*iter
)) {
1324 result
|= eParseHTMLInteger_NonStandard
;
1329 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorNoValue
;
1330 *aResult
= (ParseHTMLIntegerResultFlags
)result
;
1335 if (*iter
== CharT('-')) {
1337 result
|= eParseHTMLInteger_Negative
;
1339 } else if (*iter
== CharT('+')) {
1340 result
|= eParseHTMLInteger_NonStandard
;
1344 bool foundValue
= false;
1345 CheckedInt32 value
= 0;
1347 // Check for leading zeros first.
1348 uint64_t leadingZeros
= 0;
1349 while (iter
!= end
) {
1350 if (*iter
!= CharT('0')) {
1359 while (iter
!= end
) {
1360 if (*iter
>= CharT('0') && *iter
<= CharT('9')) {
1361 value
= (value
* 10) + (*iter
- CharT('0')) * sign
;
1363 if (!value
.isValid()) {
1364 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorOverflow
;
1374 result
|= eParseHTMLInteger_Error
| eParseHTMLInteger_ErrorNoValue
;
1377 if (value
.isValid() &&
1378 ((leadingZeros
> 1 || (leadingZeros
== 1 && !(value
== 0))) ||
1379 (sign
== -1 && value
== 0))) {
1380 result
|= eParseHTMLInteger_NonStandard
;
1384 result
|= eParseHTMLInteger_DidNotConsumeAllInput
;
1387 *aResult
= (ParseHTMLIntegerResultFlags
)result
;
1388 return value
.isValid() ? value
.value() : 0;
1391 // Parse an integer according to HTML spec
1392 int32_t nsContentUtils::ParseHTMLInteger(const nsAString
& aValue
,
1393 ParseHTMLIntegerResultFlags
* aResult
) {
1394 return ParseHTMLIntegerImpl(aValue
, aResult
);
1397 int32_t nsContentUtils::ParseHTMLInteger(const nsACString
& aValue
,
1398 ParseHTMLIntegerResultFlags
* aResult
) {
1399 return ParseHTMLIntegerImpl(aValue
, aResult
);
1402 #define SKIP_WHITESPACE(iter, end_iter, end_res) \
1403 while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
1406 if ((iter) == (end_iter)) { \
1410 #define SKIP_ATTR_NAME(iter, end_iter) \
1411 while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
1416 bool nsContentUtils::GetPseudoAttributeValue(const nsString
& aSource
,
1417 nsAtom
* aName
, nsAString
& aValue
) {
1420 const char16_t
* start
= aSource
.get();
1421 const char16_t
* end
= start
+ aSource
.Length();
1422 const char16_t
* iter
;
1424 while (start
!= end
) {
1425 SKIP_WHITESPACE(start
, end
, false)
1427 SKIP_ATTR_NAME(iter
, end
)
1429 if (start
== iter
) {
1433 // Remember the attr name.
1434 const nsDependentSubstring
& attrName
= Substring(start
, iter
);
1436 // Now check whether this is a valid name="value" pair.
1438 SKIP_WHITESPACE(start
, end
, false)
1439 if (*start
!= '=') {
1440 // No '=', so this is not a name="value" pair. We don't know
1441 // what it is, and we have no way to handle it.
1445 // Have to skip the value.
1447 SKIP_WHITESPACE(start
, end
, false)
1448 char16_t q
= *start
;
1449 if (q
!= kQuote
&& q
!= kApostrophe
) {
1450 // Not a valid quoted value, so bail.
1454 ++start
; // Point to the first char of the value.
1457 while (iter
!= end
&& *iter
!= q
) {
1462 // Oops, unterminated quoted string.
1466 // At this point attrName holds the name of the "attribute" and
1467 // the value is between start and iter.
1469 if (aName
->Equals(attrName
)) {
1470 // We'll accumulate as many characters as possible (until we hit either
1471 // the end of the string or the beginning of an entity). Chunks will be
1472 // delimited by start and chunkEnd.
1473 const char16_t
* chunkEnd
= start
;
1474 while (chunkEnd
!= iter
) {
1475 if (*chunkEnd
== kLessThan
) {
1481 if (*chunkEnd
== kAmpersand
) {
1482 aValue
.Append(start
, chunkEnd
- start
);
1484 const char16_t
* afterEntity
= nullptr;
1486 uint32_t count
= MOZ_XMLTranslateEntity(
1487 reinterpret_cast<const char*>(chunkEnd
),
1488 reinterpret_cast<const char*>(iter
),
1489 reinterpret_cast<const char**>(&afterEntity
), result
);
1496 aValue
.Append(result
, count
);
1498 // Advance to after the entity and begin a new chunk.
1499 start
= chunkEnd
= afterEntity
;
1505 // Append remainder.
1506 aValue
.Append(start
, iter
- start
);
1511 // Resume scanning after the end of the attribute value (past the quote
1519 bool nsContentUtils::IsJavaScriptLanguage(const nsString
& aName
) {
1520 return aName
.LowerCaseEqualsLiteral("javascript") ||
1521 aName
.LowerCaseEqualsLiteral("livescript") ||
1522 aName
.LowerCaseEqualsLiteral("mocha") ||
1523 aName
.LowerCaseEqualsLiteral("javascript1.0") ||
1524 aName
.LowerCaseEqualsLiteral("javascript1.1") ||
1525 aName
.LowerCaseEqualsLiteral("javascript1.2") ||
1526 aName
.LowerCaseEqualsLiteral("javascript1.3") ||
1527 aName
.LowerCaseEqualsLiteral("javascript1.4") ||
1528 aName
.LowerCaseEqualsLiteral("javascript1.5");
1531 void nsContentUtils::SplitMimeType(const nsAString
& aValue
, nsString
& aType
,
1532 nsString
& aParams
) {
1535 int32_t semiIndex
= aValue
.FindChar(char16_t(';'));
1536 if (-1 != semiIndex
) {
1537 aType
= Substring(aValue
, 0, semiIndex
);
1539 Substring(aValue
, semiIndex
+ 1, aValue
.Length() - (semiIndex
+ 1));
1540 aParams
.StripWhitespace();
1544 aType
.StripWhitespace();
1547 nsresult
nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS
,
1548 bool* aUserIsIdle
) {
1550 nsCOMPtr
<nsIUserIdleService
> idleService
=
1551 do_GetService("@mozilla.org/widget/useridleservice;1", &rv
);
1552 NS_ENSURE_SUCCESS(rv
, rv
);
1554 uint32_t idleTimeInMS
;
1555 rv
= idleService
->GetIdleTime(&idleTimeInMS
);
1556 NS_ENSURE_SUCCESS(rv
, rv
);
1558 *aUserIsIdle
= idleTimeInMS
>= aRequestedIdleTimeInMS
;
1563 * A helper function that parses a sandbox attribute (of an <iframe> or a CSP
1564 * directive) and converts it to the set of flags used internally.
1566 * @param aSandboxAttr the sandbox attribute
1567 * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is
1570 uint32_t nsContentUtils::ParseSandboxAttributeToFlags(
1571 const nsAttrValue
* aSandboxAttr
) {
1572 if (!aSandboxAttr
) {
1573 return SANDBOXED_NONE
;
1576 uint32_t out
= SANDBOX_ALL_FLAGS
;
1578 #define SANDBOX_KEYWORD(string, atom, flags) \
1579 if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \
1582 #include "IframeSandboxKeywordList.h"
1583 #undef SANDBOX_KEYWORD
1589 * A helper function that checks if a string matches a valid sandbox flag.
1591 * @param aFlag the potential sandbox flag.
1592 * @return true if the flag is a sandbox flag.
1594 bool nsContentUtils::IsValidSandboxFlag(const nsAString
& aFlag
) {
1595 #define SANDBOX_KEYWORD(string, atom, flags) \
1596 if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \
1599 #include "IframeSandboxKeywordList.h"
1600 #undef SANDBOX_KEYWORD
1605 * A helper function that returns a string attribute corresponding to the
1608 * @param aFlags the sandbox flags
1609 * @param aString the attribute corresponding to the flags (null if aFlags
1612 void nsContentUtils::SandboxFlagsToString(uint32_t aFlags
, nsAString
& aString
) {
1614 SetDOMStringToNull(aString
);
1620 #define SANDBOX_KEYWORD(string, atom, flags) \
1621 if (!(aFlags & (flags))) { \
1622 if (!aString.IsEmpty()) { \
1623 aString.AppendLiteral(u" "); \
1625 aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \
1627 #include "IframeSandboxKeywordList.h"
1628 #undef SANDBOX_KEYWORD
1631 nsIBidiKeyboard
* nsContentUtils::GetBidiKeyboard() {
1632 if (!sBidiKeyboard
) {
1633 sBidiKeyboard
= nsIWidget::CreateBidiKeyboard();
1635 return sBidiKeyboard
;
1639 * This is used to determine whether a character is in one of the classes
1640 * which CSS says should be part of the first-letter. Currently, that is
1641 * all punctuation classes (P*). Note that this is a change from CSS2
1642 * which excluded Pc and Pd.
1644 * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo
1645 * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode
1646 * general category [UAX44]) [...]"
1650 bool nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar
) {
1651 switch (mozilla::unicode::GetGeneralCategory(aChar
)) {
1652 case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION
: /* Pc */
1653 case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION
: /* Pd */
1654 case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION
: /* Pe */
1655 case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION
: /* Pf */
1656 case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION
: /* Pi */
1657 case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION
: /* Po */
1658 case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION
: /* Ps */
1666 bool nsContentUtils::IsAlphanumeric(uint32_t aChar
) {
1667 nsUGenCategory cat
= mozilla::unicode::GetGenCategory(aChar
);
1669 return (cat
== nsUGenCategory::kLetter
|| cat
== nsUGenCategory::kNumber
);
1673 bool nsContentUtils::IsAlphanumericOrSymbol(uint32_t aChar
) {
1674 nsUGenCategory cat
= mozilla::unicode::GetGenCategory(aChar
);
1676 return cat
== nsUGenCategory::kLetter
|| cat
== nsUGenCategory::kNumber
||
1677 cat
== nsUGenCategory::kSymbol
;
1681 bool nsContentUtils::IsAlphanumericOrSymbolAt(const nsTextFragment
* aFrag
,
1683 char16_t h
= aFrag
->CharAt(aOffset
);
1684 if (!IS_SURROGATE(h
)) {
1685 return IsAlphanumericOrSymbol(h
);
1687 if (NS_IS_HIGH_SURROGATE(h
) && aOffset
+ 1 < aFrag
->GetLength()) {
1688 char16_t l
= aFrag
->CharAt(aOffset
+ 1);
1689 if (NS_IS_LOW_SURROGATE(l
)) {
1690 return IsAlphanumericOrSymbol(SURROGATE_TO_UCS4(h
, l
));
1697 bool nsContentUtils::IsHTMLWhitespace(char16_t aChar
) {
1698 return aChar
== char16_t(0x0009) || aChar
== char16_t(0x000A) ||
1699 aChar
== char16_t(0x000C) || aChar
== char16_t(0x000D) ||
1700 aChar
== char16_t(0x0020);
1704 bool nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar
) {
1705 return IsHTMLWhitespace(aChar
) || aChar
== char16_t(0xA0);
1709 bool nsContentUtils::IsHTMLBlockLevelElement(nsIContent
* aContent
) {
1710 return aContent
->IsAnyOfHTMLElements(
1711 nsGkAtoms::address
, nsGkAtoms::article
, nsGkAtoms::aside
,
1712 nsGkAtoms::blockquote
, nsGkAtoms::center
, nsGkAtoms::dir
, nsGkAtoms::div
,
1713 nsGkAtoms::dl
, // XXX why not dt and dd?
1714 nsGkAtoms::fieldset
,
1715 nsGkAtoms::figure
, // XXX shouldn't figcaption be on this list
1716 nsGkAtoms::footer
, nsGkAtoms::form
, nsGkAtoms::h1
, nsGkAtoms::h2
,
1717 nsGkAtoms::h3
, nsGkAtoms::h4
, nsGkAtoms::h5
, nsGkAtoms::h6
,
1718 nsGkAtoms::header
, nsGkAtoms::hgroup
, nsGkAtoms::hr
, nsGkAtoms::li
,
1719 nsGkAtoms::listing
, nsGkAtoms::menu
, nsGkAtoms::nav
, nsGkAtoms::ol
,
1720 nsGkAtoms::p
, nsGkAtoms::pre
, nsGkAtoms::section
, nsGkAtoms::table
,
1721 nsGkAtoms::ul
, nsGkAtoms::xmp
);
1725 bool nsContentUtils::ParseIntMarginValue(const nsAString
& aString
,
1726 nsIntMargin
& result
) {
1727 nsAutoString
marginStr(aString
);
1728 marginStr
.CompressWhitespace(true, true);
1729 if (marginStr
.IsEmpty()) {
1733 int32_t start
= 0, end
= 0;
1734 for (int count
= 0; count
< 4; count
++) {
1735 if ((uint32_t)end
>= marginStr
.Length()) return false;
1737 // top, right, bottom, left
1739 end
= Substring(marginStr
, start
).FindChar(',');
1741 end
= Substring(marginStr
, start
).Length();
1743 if (end
<= 0) return false;
1746 int32_t val
= nsString(Substring(marginStr
, start
, end
)).ToInteger(&ec
);
1747 if (NS_FAILED(ec
)) return false;
1757 result
.bottom
= val
;
1769 int32_t nsContentUtils::ParseLegacyFontSize(const nsAString
& aValue
) {
1770 nsAString::const_iterator iter
, end
;
1771 aValue
.BeginReading(iter
);
1772 aValue
.EndReading(end
);
1774 while (iter
!= end
&& nsContentUtils::IsHTMLWhitespace(*iter
)) {
1782 bool relative
= false;
1783 bool negate
= false;
1784 if (*iter
== char16_t('-')) {
1788 } else if (*iter
== char16_t('+')) {
1793 if (iter
== end
|| *iter
< char16_t('0') || *iter
> char16_t('9')) {
1797 // We don't have to worry about overflow, since we can bail out as soon as
1798 // we're bigger than 7.
1800 while (iter
!= end
&& *iter
>= char16_t('0') && *iter
<= char16_t('9')) {
1801 value
= 10 * value
+ (*iter
- char16_t('0'));
1816 return clamped(value
, 1, 7);
1820 void nsContentUtils::GetOfflineAppManifest(Document
* aDocument
, nsIURI
** aURI
) {
1821 MOZ_ASSERT(NS_IsMainThread());
1822 MOZ_ASSERT(aDocument
);
1825 if (aDocument
->GetController().isSome()) {
1829 Element
* docElement
= aDocument
->GetRootElement();
1834 nsAutoString manifestSpec
;
1835 docElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::manifest
, manifestSpec
);
1837 // Manifest URIs can't have fragment identifiers.
1838 if (manifestSpec
.IsEmpty() || manifestSpec
.Contains('#')) {
1842 nsContentUtils::NewURIWithDocumentCharset(aURI
, manifestSpec
, aDocument
,
1843 aDocument
->GetDocBaseURI());
1847 bool nsContentUtils::OfflineAppAllowed(nsIURI
* aURI
) {
1848 nsCOMPtr
<nsIOfflineCacheUpdateService
> updateService
=
1849 components::OfflineCacheUpdate::Service();
1850 if (!updateService
) {
1855 nsresult rv
= updateService
->OfflineAppAllowedForURI(aURI
, &allowed
);
1856 return NS_SUCCEEDED(rv
) && allowed
;
1860 bool nsContentUtils::OfflineAppAllowed(nsIPrincipal
* aPrincipal
) {
1861 nsCOMPtr
<nsIOfflineCacheUpdateService
> updateService
=
1862 components::OfflineCacheUpdate::Service();
1863 if (!updateService
) {
1868 nsresult rv
= updateService
->OfflineAppAllowed(aPrincipal
, &allowed
);
1869 return NS_SUCCEEDED(rv
) && allowed
;
1872 bool nsContentUtils::IsErrorPage(nsIURI
* aURI
) {
1877 if (!aURI
->SchemeIs("about")) {
1882 nsresult rv
= NS_GetAboutModuleName(aURI
, name
);
1883 NS_ENSURE_SUCCESS(rv
, false);
1885 return name
.EqualsLiteral("certerror") || name
.EqualsLiteral("neterror") ||
1886 name
.EqualsLiteral("blocked");
1890 void nsContentUtils::Shutdown() {
1891 sInitialized
= false;
1893 nsHTMLTags::ReleaseTable();
1895 NS_IF_RELEASE(sContentPolicyService
);
1896 sTriedToGetContentPolicy
= false;
1898 for (i
= 0; i
< PropertiesFile_COUNT
; ++i
) NS_IF_RELEASE(sStringBundles
[i
]);
1900 NS_IF_RELEASE(sStringBundleService
);
1901 NS_IF_RELEASE(sConsoleService
);
1902 NS_IF_RELEASE(sXPConnect
);
1903 NS_IF_RELEASE(sSecurityManager
);
1904 NS_IF_RELEASE(sSystemPrincipal
);
1905 NS_IF_RELEASE(sNullSubjectPrincipal
);
1906 NS_IF_RELEASE(sIOService
);
1907 NS_IF_RELEASE(sUUIDGenerator
);
1908 sLineBreaker
= nullptr;
1909 sWordBreaker
= nullptr;
1910 sBidiKeyboard
= nullptr;
1912 delete sAtomEventTable
;
1913 sAtomEventTable
= nullptr;
1914 delete sStringEventTable
;
1915 sStringEventTable
= nullptr;
1916 delete sUserDefinedEvents
;
1917 sUserDefinedEvents
= nullptr;
1919 if (sEventListenerManagersHash
) {
1920 NS_ASSERTION(sEventListenerManagersHash
->EntryCount() == 0,
1921 "Event listener manager hash not empty at shutdown!");
1923 // See comment above.
1925 // However, we have to handle this table differently. If it still
1926 // has entries, we want to leak it too, so that we can keep it alive
1927 // in case any elements are destroyed. Because if they are, we need
1928 // their event listener managers to be destroyed too, or otherwise
1929 // it could leave dangling references in DOMClassInfo's preserved
1932 if (sEventListenerManagersHash
->EntryCount() == 0) {
1933 delete sEventListenerManagersHash
;
1934 sEventListenerManagersHash
= nullptr;
1938 if (sDOMArenaHashtable
) {
1939 MOZ_ASSERT(sDOMArenaHashtable
->Count() == 0);
1940 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
1941 delete sDOMArenaHashtable
;
1942 sDOMArenaHashtable
= nullptr;
1945 NS_ASSERTION(!sBlockedScriptRunners
|| sBlockedScriptRunners
->Length() == 0,
1946 "How'd this happen?");
1947 delete sBlockedScriptRunners
;
1948 sBlockedScriptRunners
= nullptr;
1951 sShiftText
= nullptr;
1952 delete sControlText
;
1953 sControlText
= nullptr;
1955 sMetaText
= nullptr;
1960 delete sModifierSeparator
;
1961 sModifierSeparator
= nullptr;
1963 delete sJSBytecodeMimeType
;
1964 sJSBytecodeMimeType
= nullptr;
1966 NS_IF_RELEASE(sSameOriginChecker
);
1968 if (sUserInteractionObserver
) {
1969 sUserInteractionObserver
->Shutdown();
1970 NS_RELEASE(sUserInteractionObserver
);
1973 TextControlState::Shutdown();
1974 nsMappedAttributes::Shutdown();
1978 * Checks whether two nodes come from the same origin. aTrustedNode is
1979 * considered 'safe' in that a user can operate on it.
1982 nsresult
nsContentUtils::CheckSameOrigin(const nsINode
* aTrustedNode
,
1983 const nsINode
* unTrustedNode
) {
1984 MOZ_ASSERT(aTrustedNode
);
1985 MOZ_ASSERT(unTrustedNode
);
1988 * Get hold of each node's principal
1991 nsIPrincipal
* trustedPrincipal
= aTrustedNode
->NodePrincipal();
1992 nsIPrincipal
* unTrustedPrincipal
= unTrustedNode
->NodePrincipal();
1994 if (trustedPrincipal
== unTrustedPrincipal
) {
1999 // XXXbz should we actually have a Subsumes() check here instead? Or perhaps
2000 // a separate method for that, with callers using one or the other?
2001 if (NS_FAILED(trustedPrincipal
->Equals(unTrustedPrincipal
, &equal
)) ||
2003 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2010 bool nsContentUtils::CanCallerAccess(nsIPrincipal
* aSubjectPrincipal
,
2011 nsIPrincipal
* aPrincipal
) {
2013 nsresult rv
= aSubjectPrincipal
->Subsumes(aPrincipal
, &subsumes
);
2014 NS_ENSURE_SUCCESS(rv
, false);
2020 // The subject doesn't subsume aPrincipal. Allow access only if the subject
2022 return IsCallerChrome();
2026 bool nsContentUtils::CanCallerAccess(const nsINode
* aNode
) {
2027 nsIPrincipal
* subject
= SubjectPrincipal();
2028 if (subject
->IsSystemPrincipal()) {
2032 if (aNode
->ChromeOnlyAccess()) {
2036 return CanCallerAccess(subject
, aNode
->NodePrincipal());
2040 bool nsContentUtils::CanCallerAccess(nsPIDOMWindowInner
* aWindow
) {
2041 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptObject
= do_QueryInterface(aWindow
);
2042 NS_ENSURE_TRUE(scriptObject
, false);
2044 return CanCallerAccess(SubjectPrincipal(), scriptObject
->GetPrincipal());
2048 bool nsContentUtils::PrincipalHasPermission(nsIPrincipal
& aPrincipal
,
2049 const nsAtom
* aPerm
) {
2050 // Chrome gets access by default.
2051 if (aPrincipal
.IsSystemPrincipal()) {
2055 // Otherwise, only allow if caller is an addon with the permission.
2056 return BasePrincipal::Cast(aPrincipal
).AddonHasPermission(aPerm
);
2060 bool nsContentUtils::CallerHasPermission(JSContext
* aCx
, const nsAtom
* aPerm
) {
2061 return PrincipalHasPermission(*SubjectPrincipal(aCx
), aPerm
);
2065 nsIPrincipal
* nsContentUtils::GetAttrTriggeringPrincipal(
2066 nsIContent
* aContent
, const nsAString
& aAttrValue
,
2067 nsIPrincipal
* aSubjectPrincipal
) {
2068 nsIPrincipal
* contentPrin
= aContent
? aContent
->NodePrincipal() : nullptr;
2070 // If the subject principal is the same as the content principal, or no
2071 // explicit subject principal was provided, we don't need to do any further
2072 // checks. Just return the content principal.
2073 if (contentPrin
== aSubjectPrincipal
|| !aSubjectPrincipal
) {
2077 // Only use the subject principal if the URL string we are going to end up
2078 // fetching is under the control of that principal, which is never the case
2079 // for relative URLs.
2080 if (aAttrValue
.IsEmpty() ||
2081 !IsAbsoluteURL(NS_ConvertUTF16toUTF8(aAttrValue
))) {
2085 // Only use the subject principal as the attr triggering principal if it
2086 // should override the CSP of the node's principal.
2087 if (BasePrincipal::Cast(aSubjectPrincipal
)->OverridesCSP(contentPrin
)) {
2088 return aSubjectPrincipal
;
2095 bool nsContentUtils::IsAbsoluteURL(const nsACString
& aURL
) {
2096 nsAutoCString scheme
;
2097 if (NS_FAILED(net_ExtractURLScheme(aURL
, scheme
))) {
2098 // If we can't extract a scheme, it's not an absolute URL.
2102 // If it parses as an absolute StandardURL, it's definitely an absolute URL,
2103 // so no need to check with the IO service.
2104 if (net_IsAbsoluteURL(aURL
)) {
2109 if (NS_SUCCEEDED(sIOService
->GetProtocolFlags(scheme
.get(), &flags
))) {
2110 return flags
& nsIProtocolHandler::URI_NORELATIVE
;
2117 bool nsContentUtils::InProlog(nsINode
* aNode
) {
2118 MOZ_ASSERT(aNode
, "missing node to nsContentUtils::InProlog");
2120 nsINode
* parent
= aNode
->GetParentNode();
2121 if (!parent
|| !parent
->IsDocument()) {
2125 Document
* doc
= parent
->AsDocument();
2126 nsIContent
* root
= doc
->GetRootElement();
2128 return !root
|| doc
->ComputeIndexOf(aNode
) < doc
->ComputeIndexOf(root
);
2131 bool nsContentUtils::IsCallerChrome() {
2132 MOZ_ASSERT(NS_IsMainThread());
2133 return SubjectPrincipal() == sSystemPrincipal
;
2137 bool nsContentUtils::IsFuzzingEnabled() {
2138 return StaticPrefs::fuzzing_enabled();
2143 bool nsContentUtils::IsCallerChromeOrElementTransformGettersEnabled(
2144 JSContext
* aCx
, JSObject
*) {
2145 return ThreadsafeIsSystemCaller(aCx
) ||
2146 StaticPrefs::dom_element_transform_getters_enabled();
2150 bool nsContentUtils::ShouldResistFingerprinting() {
2151 return StaticPrefs::privacy_resistFingerprinting();
2154 bool nsContentUtils::ShouldResistFingerprinting(nsIDocShell
* aDocShell
) {
2156 return ShouldResistFingerprinting();
2158 return ShouldResistFingerprinting(aDocShell
->GetDocument());
2162 bool nsContentUtils::ShouldResistFingerprinting(const Document
* aDoc
) {
2164 return ShouldResistFingerprinting();
2166 bool isChrome
= nsContentUtils::IsChromeDoc(aDoc
);
2167 return !isChrome
&& ShouldResistFingerprinting();
2171 bool nsContentUtils::ShouldResistFingerprinting(nsIPrincipal
* aPrincipal
) {
2173 return ShouldResistFingerprinting();
2175 bool isChrome
= aPrincipal
->IsSystemPrincipal();
2176 return !isChrome
&& ShouldResistFingerprinting();
2180 bool nsContentUtils::ShouldResistFingerprinting(WorkerPrivate
* aWorkerPrivate
) {
2181 if (!aWorkerPrivate
) {
2182 // We may be on a non-worker thread!
2183 return ShouldResistFingerprinting();
2185 bool isChrome
= aWorkerPrivate
->UsesSystemPrincipal();
2186 return !isChrome
&& ShouldResistFingerprinting();
2190 bool nsContentUtils::UseStandinsForNativeColors() {
2191 return ShouldResistFingerprinting() ||
2192 StaticPrefs::ui_use_standins_for_native_colors();
2196 void nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
2197 int32_t aChromeWidth
, int32_t aChromeHeight
, int32_t aScreenWidth
,
2198 int32_t aScreenHeight
, int32_t aInputWidth
, int32_t aInputHeight
,
2199 bool aSetOuterWidth
, bool aSetOuterHeight
, int32_t* aOutputWidth
,
2200 int32_t* aOutputHeight
) {
2201 MOZ_ASSERT(aOutputWidth
);
2202 MOZ_ASSERT(aOutputHeight
);
2204 int32_t availContentWidth
= 0;
2205 int32_t availContentHeight
= 0;
2207 availContentWidth
= std::min(StaticPrefs::privacy_window_maxInnerWidth(),
2208 aScreenWidth
- aChromeWidth
);
2209 #ifdef MOZ_WIDGET_GTK
2210 // In the GTK window, it will not report outside system decorations
2211 // when we get available window size, see Bug 581863. So, we leave a
2212 // 40 pixels space for them when calculating the available content
2213 // height. It is not necessary for the width since the content width
2214 // is usually pretty much the same as the chrome width.
2215 availContentHeight
= std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2216 (-40 + aScreenHeight
) - aChromeHeight
);
2218 availContentHeight
= std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2219 aScreenHeight
- aChromeHeight
);
2222 // Ideally, we'd like to round window size to 1000x1000, but the
2223 // screen space could be too small to accommodate this size in some
2224 // cases. If it happens, we would round the window size to the nearest
2226 availContentWidth
= availContentWidth
- (availContentWidth
% 200);
2227 availContentHeight
= availContentHeight
- (availContentHeight
% 100);
2229 // If aIsOuter is true, we are setting the outer window. So we
2230 // have to consider the chrome UI.
2231 int32_t chromeOffsetWidth
= aSetOuterWidth
? aChromeWidth
: 0;
2232 int32_t chromeOffsetHeight
= aSetOuterHeight
? aChromeHeight
: 0;
2233 int32_t resultWidth
= 0, resultHeight
= 0;
2235 // if the original size is greater than the maximum available size, we set
2236 // it to the maximum size. And if the original value is less than the
2237 // minimum rounded size, we set it to the minimum 200x100.
2238 if (aInputWidth
> (availContentWidth
+ chromeOffsetWidth
)) {
2239 resultWidth
= availContentWidth
+ chromeOffsetWidth
;
2240 } else if (aInputWidth
< (200 + chromeOffsetWidth
)) {
2241 resultWidth
= 200 + chromeOffsetWidth
;
2243 // Otherwise, we round the window to the nearest upper rounded 200x100.
2244 resultWidth
= NSToIntCeil((aInputWidth
- chromeOffsetWidth
) / 200.0) * 200 +
2248 if (aInputHeight
> (availContentHeight
+ chromeOffsetHeight
)) {
2249 resultHeight
= availContentHeight
+ chromeOffsetHeight
;
2250 } else if (aInputHeight
< (100 + chromeOffsetHeight
)) {
2251 resultHeight
= 100 + chromeOffsetHeight
;
2254 NSToIntCeil((aInputHeight
- chromeOffsetHeight
) / 100.0) * 100 +
2258 *aOutputWidth
= resultWidth
;
2259 *aOutputHeight
= resultHeight
;
2262 bool nsContentUtils::ThreadsafeIsCallerChrome() {
2263 return NS_IsMainThread() ? IsCallerChrome()
2264 : IsCurrentThreadRunningChromeWorker();
2267 bool nsContentUtils::IsCallerUAWidget() {
2268 JSContext
* cx
= GetCurrentJSContext();
2273 JS::Realm
* realm
= JS::GetCurrentRealmOrNull(cx
);
2278 return xpc::IsUAWidgetScope(realm
);
2281 bool nsContentUtils::IsSystemCaller(JSContext
* aCx
) {
2282 // Note that SubjectPrincipal() assumes we are in a compartment here.
2283 return SubjectPrincipal(aCx
) == sSystemPrincipal
;
2286 bool nsContentUtils::ThreadsafeIsSystemCaller(JSContext
* aCx
) {
2287 CycleCollectedJSContext
* ccjscx
= CycleCollectedJSContext::Get();
2288 MOZ_ASSERT(ccjscx
->Context() == aCx
);
2290 return ccjscx
->IsSystemCaller();
2294 bool nsContentUtils::LookupBindingMember(
2295 JSContext
* aCx
, nsIContent
* aContent
, JS::Handle
<jsid
> aId
,
2296 JS::MutableHandle
<JS::PropertyDescriptor
> aDesc
) {
2300 nsINode
* nsContentUtils::GetNearestInProcessCrossDocParentNode(
2302 if (aChild
->IsDocument()) {
2303 for (BrowsingContext
* bc
= aChild
->AsDocument()->GetBrowsingContext(); bc
;
2304 bc
= bc
->GetParent()) {
2305 if (bc
->GetEmbedderElement()) {
2306 return bc
->GetEmbedderElement();
2312 nsINode
* parent
= aChild
->GetParentNode();
2313 if (parent
&& parent
->IsContent() && aChild
->IsContent()) {
2314 parent
= aChild
->AsContent()->GetFlattenedTreeParent();
2320 bool nsContentUtils::ContentIsHostIncludingDescendantOf(
2321 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2322 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2323 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2326 if (aPossibleDescendant
== aPossibleAncestor
) return true;
2327 if (aPossibleDescendant
->IsDocumentFragment()) {
2328 aPossibleDescendant
=
2329 aPossibleDescendant
->AsDocumentFragment()->GetHost();
2331 aPossibleDescendant
= aPossibleDescendant
->GetParentNode();
2333 } while (aPossibleDescendant
);
2339 bool nsContentUtils::ContentIsCrossDocDescendantOf(nsINode
* aPossibleDescendant
,
2340 nsINode
* aPossibleAncestor
) {
2341 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2342 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2345 if (aPossibleDescendant
== aPossibleAncestor
) {
2349 aPossibleDescendant
=
2350 GetNearestInProcessCrossDocParentNode(aPossibleDescendant
);
2351 } while (aPossibleDescendant
);
2357 bool nsContentUtils::ContentIsFlattenedTreeDescendantOf(
2358 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2359 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2360 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2363 if (aPossibleDescendant
== aPossibleAncestor
) {
2366 aPossibleDescendant
= aPossibleDescendant
->GetFlattenedTreeParentNode();
2367 } while (aPossibleDescendant
);
2373 bool nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle(
2374 const nsINode
* aPossibleDescendant
, const nsINode
* aPossibleAncestor
) {
2375 MOZ_ASSERT(aPossibleDescendant
, "The possible descendant is null!");
2376 MOZ_ASSERT(aPossibleAncestor
, "The possible ancestor is null!");
2379 if (aPossibleDescendant
== aPossibleAncestor
) {
2382 aPossibleDescendant
=
2383 aPossibleDescendant
->GetFlattenedTreeParentNodeForStyle();
2384 } while (aPossibleDescendant
);
2390 nsINode
* nsContentUtils::Retarget(nsINode
* aTargetA
, nsINode
* aTargetB
) {
2391 while (true && aTargetA
) {
2392 // If A's root is not a shadow root...
2393 nsINode
* root
= aTargetA
->SubtreeRoot();
2394 if (!root
->IsShadowRoot()) {
2395 // ...then return A.
2399 // or A's root is a shadow-including inclusive ancestor of B...
2400 if (aTargetB
->IsShadowIncludingInclusiveDescendantOf(root
)) {
2401 // ...then return A.
2405 aTargetA
= ShadowRoot::FromNode(root
)->GetHost();
2412 nsresult
nsContentUtils::GetInclusiveAncestors(nsINode
* aNode
,
2413 nsTArray
<nsINode
*>& aArray
) {
2415 aArray
.AppendElement(aNode
);
2416 aNode
= aNode
->GetParentNode();
2422 nsresult
nsContentUtils::GetInclusiveAncestorsAndOffsets(
2423 nsINode
* aNode
, int32_t aOffset
, nsTArray
<nsIContent
*>* aAncestorNodes
,
2424 nsTArray
<int32_t>* aAncestorOffsets
) {
2425 NS_ENSURE_ARG_POINTER(aNode
);
2427 if (!aNode
->IsContent()) {
2428 return NS_ERROR_FAILURE
;
2430 nsIContent
* content
= aNode
->AsContent();
2432 if (!aAncestorNodes
->IsEmpty()) {
2433 NS_WARNING("aAncestorNodes is not empty");
2434 aAncestorNodes
->Clear();
2437 if (!aAncestorOffsets
->IsEmpty()) {
2438 NS_WARNING("aAncestorOffsets is not empty");
2439 aAncestorOffsets
->Clear();
2442 // insert the node itself
2443 aAncestorNodes
->AppendElement(content
);
2444 aAncestorOffsets
->AppendElement(aOffset
);
2446 // insert all the ancestors
2447 nsIContent
* child
= content
;
2448 nsIContent
* parent
= child
->GetParent();
2450 aAncestorNodes
->AppendElement(parent
);
2451 aAncestorOffsets
->AppendElement(parent
->ComputeIndexOf(child
));
2453 parent
= parent
->GetParent();
2459 template <typename Node
, typename GetParentFunc
>
2460 static Node
* GetCommonAncestorInternal(Node
* aNode1
, Node
* aNode2
,
2461 GetParentFunc aGetParentFunc
) {
2462 MOZ_ASSERT(aNode1
!= aNode2
);
2464 // Build the chain of parents
2465 AutoTArray
<Node
*, 30> parents1
, parents2
;
2467 parents1
.AppendElement(aNode1
);
2468 aNode1
= aGetParentFunc(aNode1
);
2471 parents2
.AppendElement(aNode2
);
2472 aNode2
= aGetParentFunc(aNode2
);
2475 // Find where the parent chain differs
2476 uint32_t pos1
= parents1
.Length();
2477 uint32_t pos2
= parents2
.Length();
2478 Node
* parent
= nullptr;
2480 for (len
= std::min(pos1
, pos2
); len
> 0; --len
) {
2481 Node
* child1
= parents1
.ElementAt(--pos1
);
2482 Node
* child2
= parents2
.ElementAt(--pos2
);
2483 if (child1
!= child2
) {
2493 nsINode
* nsContentUtils::GetCommonAncestorHelper(nsINode
* aNode1
,
2495 return GetCommonAncestorInternal(
2496 aNode1
, aNode2
, [](nsINode
* aNode
) { return aNode
->GetParentNode(); });
2500 nsIContent
* nsContentUtils::GetCommonFlattenedTreeAncestorHelper(
2501 nsIContent
* aContent1
, nsIContent
* aContent2
) {
2502 return GetCommonAncestorInternal(
2503 aContent1
, aContent2
,
2504 [](nsIContent
* aContent
) { return aContent
->GetFlattenedTreeParent(); });
2508 Element
* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(
2509 Element
* aElement1
, Element
* aElement2
) {
2510 return GetCommonAncestorInternal(aElement1
, aElement2
, [](Element
* aElement
) {
2511 return aElement
->GetFlattenedTreeParentElementForStyle();
2516 bool nsContentUtils::PositionIsBefore(nsINode
* aNode1
, nsINode
* aNode2
,
2517 int32_t* aNode1Index
,
2518 int32_t* aNode2Index
) {
2519 // Note, CompareDocumentPosition takes the latter params in different order.
2520 return (aNode2
->CompareDocumentPosition(*aNode1
, aNode2Index
, aNode1Index
) &
2521 (Node_Binding::DOCUMENT_POSITION_PRECEDING
|
2522 Node_Binding::DOCUMENT_POSITION_DISCONNECTED
)) ==
2523 Node_Binding::DOCUMENT_POSITION_PRECEDING
;
2527 Maybe
<int32_t> nsContentUtils::ComparePoints(
2528 const nsINode
* aParent1
, int32_t aOffset1
, const nsINode
* aParent2
,
2529 int32_t aOffset2
, ComparePointsCache
* aParent1Cache
) {
2530 bool disconnected
{false};
2532 const int32_t order
= ComparePoints_Deprecated(
2533 aParent1
, aOffset1
, aParent2
, aOffset2
, &disconnected
, aParent1Cache
);
2542 int32_t nsContentUtils::ComparePoints_Deprecated(
2543 const nsINode
* aParent1
, int32_t aOffset1
, const nsINode
* aParent2
,
2544 int32_t aOffset2
, bool* aDisconnected
, ComparePointsCache
* aParent1Cache
) {
2545 if (aParent1
== aParent2
) {
2546 // XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
2547 // of nsINode::ComputeIndexOf(), but this compares such invalid
2548 // offset with valid offset.
2549 return aOffset1
< aOffset2
? -1 : aOffset1
> aOffset2
? 1 : 0;
2552 AutoTArray
<const nsINode
*, 32> parents1
, parents2
;
2553 const nsINode
* node1
= aParent1
;
2554 const nsINode
* node2
= aParent2
;
2556 parents1
.AppendElement(node1
);
2557 node1
= node1
->GetParentNode();
2560 parents2
.AppendElement(node2
);
2561 node2
= node2
->GetParentNode();
2564 uint32_t pos1
= parents1
.Length() - 1;
2565 uint32_t pos2
= parents2
.Length() - 1;
2567 bool disconnected
= parents1
.ElementAt(pos1
) != parents2
.ElementAt(pos2
);
2568 if (aDisconnected
) {
2569 *aDisconnected
= disconnected
;
2572 NS_ASSERTION(aDisconnected
, "unexpected disconnected nodes");
2576 // Find where the parent chains differ
2577 const nsINode
* parent
= parents1
.ElementAt(pos1
);
2579 for (len
= std::min(pos1
, pos2
); len
> 0; --len
) {
2580 const nsINode
* child1
= parents1
.ElementAt(--pos1
);
2581 const nsINode
* child2
= parents2
.ElementAt(--pos2
);
2582 if (child1
!= child2
) {
2583 int32_t child1index
= aParent1Cache
2584 ? aParent1Cache
->ComputeIndexOf(parent
, child1
)
2585 : parent
->ComputeIndexOf(child1
);
2586 return child1index
< parent
->ComputeIndexOf(child2
) ? -1 : 1;
2591 // The parent chains never differed, so one of the nodes is an ancestor of
2594 NS_ASSERTION(!pos1
|| !pos2
,
2595 "should have run out of parent chain for one of the nodes");
2598 const nsINode
* child2
= parents2
.ElementAt(--pos2
);
2599 // XXX aOffset1 may be -1 as mentioned above. So, why does this return
2600 // it's *before* of the valid DOM point?
2601 return aOffset1
<= parent
->ComputeIndexOf(child2
) ? -1 : 1;
2604 const nsINode
* child1
= parents1
.ElementAt(--pos1
);
2605 // XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
2606 // *after* of the valid DOM point?
2607 int32_t child1index
= aParent1Cache
2608 ? aParent1Cache
->ComputeIndexOf(parent
, child1
)
2609 : parent
->ComputeIndexOf(child1
);
2610 return child1index
< aOffset2
? -1 : 1;
2614 nsINode
* nsContentUtils::GetCommonAncestorUnderInteractiveContent(
2615 nsINode
* aNode1
, nsINode
* aNode2
) {
2616 if (!aNode1
|| !aNode2
) {
2620 if (aNode1
== aNode2
) {
2624 // Build the chain of parents
2625 AutoTArray
<nsINode
*, 30> parents1
;
2627 parents1
.AppendElement(aNode1
);
2628 if (aNode1
->IsElement() &&
2629 aNode1
->AsElement()->IsInteractiveHTMLContent()) {
2632 aNode1
= aNode1
->GetFlattenedTreeParentNode();
2635 AutoTArray
<nsINode
*, 30> parents2
;
2637 parents2
.AppendElement(aNode2
);
2638 if (aNode2
->IsElement() &&
2639 aNode2
->AsElement()->IsInteractiveHTMLContent()) {
2642 aNode2
= aNode2
->GetFlattenedTreeParentNode();
2645 // Find where the parent chain differs
2646 uint32_t pos1
= parents1
.Length();
2647 uint32_t pos2
= parents2
.Length();
2648 nsINode
* parent
= nullptr;
2649 for (uint32_t len
= std::min(pos1
, pos2
); len
> 0; --len
) {
2650 nsINode
* child1
= parents1
.ElementAt(--pos1
);
2651 nsINode
* child2
= parents2
.ElementAt(--pos2
);
2652 if (child1
!= child2
) {
2662 BrowserParent
* nsContentUtils::GetCommonBrowserParentAncestor(
2663 BrowserParent
* aBrowserParent1
, BrowserParent
* aBrowserParent2
) {
2664 return GetCommonAncestorInternal(
2665 aBrowserParent1
, aBrowserParent2
, [](BrowserParent
* aBrowserParent
) {
2666 return aBrowserParent
->GetBrowserBridgeParent()
2667 ? aBrowserParent
->GetBrowserBridgeParent()->Manager()
2673 template <typename FPT
, typename FRT
, typename SPT
, typename SRT
>
2674 Maybe
<int32_t> nsContentUtils::ComparePoints(
2675 const RangeBoundaryBase
<FPT
, FRT
>& aFirstBoundary
,
2676 const RangeBoundaryBase
<SPT
, SRT
>& aSecondBoundary
) {
2677 if (!aFirstBoundary
.IsSet() || !aSecondBoundary
.IsSet()) {
2681 bool disconnected
{false};
2682 const int32_t order
=
2683 ComparePoints_Deprecated(aFirstBoundary
, aSecondBoundary
, &disconnected
);
2693 template <typename FPT
, typename FRT
, typename SPT
, typename SRT
>
2694 int32_t nsContentUtils::ComparePoints_Deprecated(
2695 const RangeBoundaryBase
<FPT
, FRT
>& aFirstBoundary
,
2696 const RangeBoundaryBase
<SPT
, SRT
>& aSecondBoundary
, bool* aDisconnected
) {
2697 if (NS_WARN_IF(!aFirstBoundary
.IsSet()) ||
2698 NS_WARN_IF(!aSecondBoundary
.IsSet())) {
2701 // XXX Re-implement this without calling `Offset()` as far as possible,
2702 // and the other overload should be an alias of this.
2703 return ComparePoints_Deprecated(
2704 aFirstBoundary
.Container(),
2705 *aFirstBoundary
.Offset(
2706 RangeBoundaryBase
<FPT
, FRT
>::OffsetFilter::kValidOrInvalidOffsets
),
2707 aSecondBoundary
.Container(),
2708 *aSecondBoundary
.Offset(
2709 RangeBoundaryBase
<SPT
, SRT
>::OffsetFilter::kValidOrInvalidOffsets
),
2713 inline bool IsCharInSet(const char* aSet
, const char16_t aChar
) {
2715 while ((ch
= *aSet
)) {
2716 if (aChar
== char16_t(ch
)) {
2725 * This method strips leading/trailing chars, in given set, from string.
2729 const nsDependentSubstring
nsContentUtils::TrimCharsInSet(
2730 const char* aSet
, const nsAString
& aValue
) {
2731 nsAString::const_iterator valueCurrent
, valueEnd
;
2733 aValue
.BeginReading(valueCurrent
);
2734 aValue
.EndReading(valueEnd
);
2736 // Skip characters in the beginning
2737 while (valueCurrent
!= valueEnd
) {
2738 if (!IsCharInSet(aSet
, *valueCurrent
)) {
2744 if (valueCurrent
!= valueEnd
) {
2747 if (!IsCharInSet(aSet
, *valueEnd
)) {
2751 ++valueEnd
; // Step beyond the last character we want in the value.
2754 // valueEnd should point to the char after the last to copy
2755 return Substring(valueCurrent
, valueEnd
);
2759 * This method strips leading and trailing whitespace from a string.
2763 template <bool IsWhitespace(char16_t
)>
2764 const nsDependentSubstring
nsContentUtils::TrimWhitespace(const nsAString
& aStr
,
2765 bool aTrimTrailing
) {
2766 nsAString::const_iterator start
, end
;
2768 aStr
.BeginReading(start
);
2769 aStr
.EndReading(end
);
2771 // Skip whitespace characters in the beginning
2772 while (start
!= end
&& IsWhitespace(*start
)) {
2776 if (aTrimTrailing
) {
2777 // Skip whitespace characters in the end.
2778 while (end
!= start
) {
2781 if (!IsWhitespace(*end
)) {
2782 // Step back to the last non-whitespace character.
2790 // Return a substring for the string w/o leading and/or trailing
2793 return Substring(start
, end
);
2796 // Declaring the templates we are going to use avoid linking issues without
2797 // inlining the method. Considering there is not so much spaces checking
2798 // methods we can consider this to be better than inlining.
2799 template const nsDependentSubstring
2800 nsContentUtils::TrimWhitespace
<nsCRT::IsAsciiSpace
>(const nsAString
&, bool);
2801 template const nsDependentSubstring
nsContentUtils::TrimWhitespace
<
2802 nsContentUtils::IsHTMLWhitespace
>(const nsAString
&, bool);
2803 template const nsDependentSubstring
nsContentUtils::TrimWhitespace
<
2804 nsContentUtils::IsHTMLWhitespaceOrNBSP
>(const nsAString
&, bool);
2806 static inline void KeyAppendSep(nsACString
& aKey
) {
2807 if (!aKey
.IsEmpty()) {
2812 static inline void KeyAppendString(const nsAString
& aString
, nsACString
& aKey
) {
2815 // Could escape separator here if collisions happen. > is not a legal char
2816 // for a name or type attribute, so we should be safe avoiding that extra
2819 AppendUTF16toUTF8(aString
, aKey
);
2822 static inline void KeyAppendString(const nsACString
& aString
,
2826 // Could escape separator here if collisions happen. > is not a legal char
2827 // for a name or type attribute, so we should be safe avoiding that extra
2830 aKey
.Append(aString
);
2833 static inline void KeyAppendInt(int32_t aInt
, nsACString
& aKey
) {
2836 aKey
.AppendInt(aInt
);
2839 static inline bool IsAutocompleteOff(const nsIContent
* aContent
) {
2840 return aContent
->IsElement() &&
2841 aContent
->AsElement()->AttrValueIs(kNameSpaceID_None
,
2842 nsGkAtoms::autocomplete
, u
"off"_ns
,
2847 void nsContentUtils::GenerateStateKey(nsIContent
* aContent
, Document
* aDocument
,
2849 MOZ_ASSERT(aContent
);
2853 uint32_t partID
= aDocument
? aDocument
->GetPartID() : 0;
2855 // Don't capture state for anonymous content
2856 if (aContent
->IsInNativeAnonymousSubtree()) {
2860 if (IsAutocompleteOff(aContent
)) {
2864 RefPtr
<Document
> doc
= aContent
->GetUncomposedDoc();
2866 KeyAppendInt(partID
, aKey
); // first append a partID
2867 bool generatedUniqueKey
= false;
2869 if (doc
&& doc
->IsHTMLOrXHTML()) {
2870 nsHTMLDocument
* htmlDoc
= doc
->AsHTMLDocument();
2872 // If we have a form control and can calculate form information, use that
2873 // as the key - it is more reliable than just recording position in the
2875 // XXXbz Is it, really? We have bugs on this, I think...
2876 // Important to have a unique key, and tag/type/name may not be.
2878 // The format of the key depends on whether the control has a form,
2879 // and whether the element was parser inserted:
2881 // [Has Form, Parser Inserted]:
2882 // fp>type>FormNum>IndOfControlInForm>FormName>name
2884 // [No Form, Parser Inserted]:
2885 // dp>type>ControlNum>name
2887 // [Has Form, Not Parser Inserted]:
2888 // fn>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
2890 // [No Form, Not Parser Inserted]:
2891 // dn>type>IndOfControlInDoc>name
2893 // XXX We don't need to use index if name is there
2894 // XXXbz We don't? Why not? I don't follow.
2896 nsCOMPtr
<nsIFormControl
> control(do_QueryInterface(aContent
));
2898 // Get the control number if this was a parser inserted element from the
2900 int32_t controlNumber
=
2901 control
->GetParserInsertedControlNumberForStateKey();
2902 bool parserInserted
= controlNumber
!= -1;
2904 RefPtr
<nsContentList
> htmlForms
;
2905 RefPtr
<nsContentList
> htmlFormControls
;
2906 if (!parserInserted
) {
2907 // Getting these lists is expensive, as we need to keep them up to date
2908 // as the document loads, so we avoid it if we don't need them.
2909 htmlDoc
->GetFormsAndFormControls(getter_AddRefs(htmlForms
),
2910 getter_AddRefs(htmlFormControls
));
2913 // Append the control type
2914 KeyAppendInt(control
->ControlType(), aKey
);
2916 // If in a form, add form name / index of form / index in form
2917 HTMLFormElement
* formElement
= control
->GetFormElement();
2919 if (IsAutocompleteOff(formElement
)) {
2924 // Append the form number, if this is a parser inserted control, or
2925 // the index of the form in the document otherwise.
2926 bool appendedForm
= false;
2927 if (parserInserted
) {
2928 MOZ_ASSERT(formElement
->GetFormNumberForStateKey() != -1,
2929 "when generating a state key for a parser inserted form "
2930 "control we should have a parser inserted <form> element");
2931 KeyAppendString("fp"_ns
, aKey
);
2932 KeyAppendInt(formElement
->GetFormNumberForStateKey(), aKey
);
2933 appendedForm
= true;
2935 KeyAppendString("fn"_ns
, aKey
);
2936 int32_t index
= htmlForms
->IndexOf(formElement
, false);
2939 // XXX HACK this uses some state that was dumped into the document
2940 // specifically to fix bug 138892. What we are trying to do is
2941 // *guess* which form this control's state is found in, with the
2942 // highly likely guess that the highest form parsed so far is the
2943 // one. This code should not be on trunk, only branch.
2945 index
= htmlDoc
->GetNumFormsSynchronous() - 1;
2948 KeyAppendInt(index
, aKey
);
2949 appendedForm
= true;
2954 // Append the index of the control in the form
2955 int32_t index
= formElement
->IndexOfControl(control
);
2958 KeyAppendInt(index
, aKey
);
2959 generatedUniqueKey
= true;
2963 // Append the form name
2964 nsAutoString formName
;
2965 formElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::name
, formName
);
2966 KeyAppendString(formName
, aKey
);
2968 // Not in a form. Append the control number, if this is a parser
2969 // inserted control, or the index of the control in the document
2971 if (parserInserted
) {
2972 KeyAppendString("dp"_ns
, aKey
);
2973 KeyAppendInt(control
->GetParserInsertedControlNumberForStateKey(),
2975 generatedUniqueKey
= true;
2977 KeyAppendString("dn"_ns
, aKey
);
2978 int32_t index
= htmlFormControls
->IndexOf(aContent
, true);
2980 KeyAppendInt(index
, aKey
);
2981 generatedUniqueKey
= true;
2985 // Append the control name
2987 aContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::name
,
2989 KeyAppendString(name
, aKey
);
2994 if (!generatedUniqueKey
) {
2995 // Either we didn't have a form control or we aren't in an HTML document so
2996 // we can't figure out form info. Append the tag name if it's an element
2997 // to avoid restoring state for one type of element on another type.
2998 if (aContent
->IsElement()) {
2999 KeyAppendString(nsDependentAtomString(aContent
->NodeInfo()->NameAtom()),
3002 // Append a character that is not "d" or "f" to disambiguate from
3003 // the case when we were a form control in an HTML document.
3004 KeyAppendString("o"_ns
, aKey
);
3007 // Now start at aContent and append the indices of it and all its ancestors
3008 // in their containers. That should at least pin down its position in the
3010 nsINode
* parent
= aContent
->GetParentNode();
3011 nsINode
* content
= aContent
;
3013 KeyAppendInt(parent
->ComputeIndexOf(content
), aKey
);
3015 parent
= content
->GetParentNode();
3021 nsIPrincipal
* nsContentUtils::SubjectPrincipal(JSContext
* aCx
) {
3022 MOZ_ASSERT(NS_IsMainThread());
3024 // As opposed to SubjectPrincipal(), we do in fact assume that
3025 // we're in a realm here; anyone who calls this function in
3026 // situations where that's not the case is doing it wrong.
3027 JS::Realm
* realm
= js::GetContextRealm(aCx
);
3030 JSPrincipals
* principals
= JS::GetRealmPrincipals(realm
);
3031 return nsJSPrincipals::get(principals
);
3035 nsIPrincipal
* nsContentUtils::SubjectPrincipal() {
3036 MOZ_ASSERT(IsInitialized());
3037 MOZ_ASSERT(NS_IsMainThread());
3038 JSContext
* cx
= GetCurrentJSContext();
3041 "Accessing the Subject Principal without an AutoJSAPI on the stack is "
3045 JS::Realm
* realm
= js::GetContextRealm(cx
);
3047 // When an AutoJSAPI is instantiated, we are in a null realm until the
3048 // first JSAutoRealm, which is kind of a purgatory as far as permissions
3049 // go. It would be nice to just hard-abort if somebody does a security check
3050 // in this purgatory zone, but that would be too fragile, since it could be
3051 // triggered by random IsCallerChrome() checks 20-levels deep.
3053 // So we want to return _something_ here - and definitely not the System
3054 // Principal, since that would make an AutoJSAPI a very dangerous thing to
3057 // The natural thing to return is a null principal. Ideally, we'd return a
3058 // different null principal each time, to avoid any unexpected interactions
3059 // when the principal accidentally gets inherited somewhere. But
3060 // SubjectPrincipal doesn't return strong references, so there's no way to
3061 // sanely manage the lifetime of multiple null principals.
3063 // So we use a singleton null principal. To avoid it being accidentally
3064 // inherited and becoming a "real" subject or object principal, we do a
3065 // release-mode assert during realm creation against using this principal on
3066 // an actual global.
3068 return sNullSubjectPrincipal
;
3071 return SubjectPrincipal(cx
);
3075 nsIPrincipal
* nsContentUtils::ObjectPrincipal(JSObject
* aObj
) {
3076 MOZ_ASSERT(NS_IsMainThread());
3079 JS::AssertObjectBelongsToCurrentThread(aObj
);
3082 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(aObj
));
3084 JS::Realm
* realm
= js::GetNonCCWObjectRealm(aObj
);
3085 JSPrincipals
* principals
= JS::GetRealmPrincipals(realm
);
3086 return nsJSPrincipals::get(principals
);
3090 nsresult
nsContentUtils::NewURIWithDocumentCharset(nsIURI
** aResult
,
3091 const nsAString
& aSpec
,
3092 Document
* aDocument
,
3095 return NS_NewURI(aResult
, aSpec
, aDocument
->GetDocumentCharacterSet(),
3098 return NS_NewURI(aResult
, aSpec
, nullptr, aBaseURI
);
3102 bool nsContentUtils::IsNameWithDash(nsAtom
* aName
) {
3103 // A valid custom element name is a sequence of characters name which
3104 // must match the PotentialCustomElementName production:
3105 // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
3106 const char16_t
* name
= aName
->GetUTF16String();
3107 uint32_t len
= aName
->GetLength();
3108 bool hasDash
= false;
3110 if (!len
|| name
[0] < 'a' || name
[0] > 'z') {
3116 if (i
+ 1 < len
&& NS_IS_SURROGATE_PAIR(name
[i
], name
[i
+ 1])) {
3117 // Merged two 16-bit surrogate pairs into code point.
3118 char32_t code
= SURROGATE_TO_UCS4(name
[i
], name
[i
+ 1]);
3120 if (code
< 0x10000 || code
> 0xEFFFF) {
3126 if (name
[i
] == '-') {
3130 if (name
[i
] != '-' && name
[i
] != '.' && name
[i
] != '_' &&
3131 name
[i
] != 0xB7 && (name
[i
] < '0' || name
[i
] > '9') &&
3132 (name
[i
] < 'a' || name
[i
] > 'z') &&
3133 (name
[i
] < 0xC0 || name
[i
] > 0xD6) &&
3134 (name
[i
] < 0xF8 || name
[i
] > 0x37D) &&
3135 (name
[i
] < 0x37F || name
[i
] > 0x1FFF) &&
3136 (name
[i
] < 0x200C || name
[i
] > 0x200D) &&
3137 (name
[i
] < 0x203F || name
[i
] > 0x2040) &&
3138 (name
[i
] < 0x2070 || name
[i
] > 0x218F) &&
3139 (name
[i
] < 0x2C00 || name
[i
] > 0x2FEF) &&
3140 (name
[i
] < 0x3001 || name
[i
] > 0xD7FF) &&
3141 (name
[i
] < 0xF900 || name
[i
] > 0xFDCF) &&
3142 (name
[i
] < 0xFDF0 || name
[i
] > 0xFFFD)) {
3154 bool nsContentUtils::IsCustomElementName(nsAtom
* aName
, uint32_t aNameSpaceID
) {
3155 // Allow non-dashed names in XUL for XBL to Custom Element migrations.
3156 if (aNameSpaceID
== kNameSpaceID_XUL
) {
3160 bool hasDash
= IsNameWithDash(aName
);
3165 // The custom element name must not be one of the following values:
3174 return aName
!= nsGkAtoms::annotation_xml_
&&
3175 aName
!= nsGkAtoms::colorProfile
&& aName
!= nsGkAtoms::font_face
&&
3176 aName
!= nsGkAtoms::font_face_src
&&
3177 aName
!= nsGkAtoms::font_face_uri
&&
3178 aName
!= nsGkAtoms::font_face_format
&&
3179 aName
!= nsGkAtoms::font_face_name
&& aName
!= nsGkAtoms::missingGlyph
;
3183 nsresult
nsContentUtils::CheckQName(const nsAString
& aQualifiedName
,
3184 bool aNamespaceAware
,
3185 const char16_t
** aColon
) {
3186 const char* colon
= nullptr;
3187 const char16_t
* begin
= aQualifiedName
.BeginReading();
3188 const char16_t
* end
= aQualifiedName
.EndReading();
3190 int result
= MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin
),
3191 reinterpret_cast<const char*>(end
),
3192 aNamespaceAware
, &colon
);
3196 *aColon
= reinterpret_cast<const char16_t
*>(colon
);
3202 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
3206 nsresult
nsContentUtils::SplitQName(const nsIContent
* aNamespaceResolver
,
3207 const nsString
& aQName
, int32_t* aNamespace
,
3208 nsAtom
** aLocalName
) {
3209 const char16_t
* colon
;
3210 nsresult rv
= nsContentUtils::CheckQName(aQName
, true, &colon
);
3211 NS_ENSURE_SUCCESS(rv
, rv
);
3214 const char16_t
* end
;
3215 aQName
.EndReading(end
);
3216 nsAutoString nameSpace
;
3217 rv
= aNamespaceResolver
->LookupNamespaceURIInternal(
3218 Substring(aQName
.get(), colon
), nameSpace
);
3219 NS_ENSURE_SUCCESS(rv
, rv
);
3221 *aNamespace
= NameSpaceManager()->GetNameSpaceID(
3222 nameSpace
, nsContentUtils::IsChromeDoc(aNamespaceResolver
->OwnerDoc()));
3223 if (*aNamespace
== kNameSpaceID_Unknown
) return NS_ERROR_FAILURE
;
3225 *aLocalName
= NS_AtomizeMainThread(Substring(colon
+ 1, end
)).take();
3227 *aNamespace
= kNameSpaceID_None
;
3228 *aLocalName
= NS_AtomizeMainThread(aQName
).take();
3230 NS_ENSURE_TRUE(aLocalName
, NS_ERROR_OUT_OF_MEMORY
);
3235 nsresult
nsContentUtils::GetNodeInfoFromQName(
3236 const nsAString
& aNamespaceURI
, const nsAString
& aQualifiedName
,
3237 nsNodeInfoManager
* aNodeInfoManager
, uint16_t aNodeType
,
3238 mozilla::dom::NodeInfo
** aNodeInfo
) {
3239 const nsString
& qName
= PromiseFlatString(aQualifiedName
);
3240 const char16_t
* colon
;
3241 nsresult rv
= nsContentUtils::CheckQName(qName
, true, &colon
);
3242 NS_ENSURE_SUCCESS(rv
, rv
);
3245 sNameSpaceManager
->RegisterNameSpace(aNamespaceURI
, nsID
);
3247 const char16_t
* end
;
3248 qName
.EndReading(end
);
3250 RefPtr
<nsAtom
> prefix
= NS_AtomizeMainThread(Substring(qName
.get(), colon
));
3252 rv
= aNodeInfoManager
->GetNodeInfo(Substring(colon
+ 1, end
), prefix
, nsID
,
3253 aNodeType
, aNodeInfo
);
3255 rv
= aNodeInfoManager
->GetNodeInfo(aQualifiedName
, nullptr, nsID
, aNodeType
,
3258 NS_ENSURE_SUCCESS(rv
, rv
);
3260 return nsContentUtils::IsValidNodeName((*aNodeInfo
)->NameAtom(),
3261 (*aNodeInfo
)->GetPrefixAtom(),
3262 (*aNodeInfo
)->NamespaceID())
3264 : NS_ERROR_DOM_NAMESPACE_ERR
;
3268 void nsContentUtils::SplitExpatName(const char16_t
* aExpatName
,
3269 nsAtom
** aPrefix
, nsAtom
** aLocalName
,
3270 int32_t* aNameSpaceID
) {
3272 * Expat can send the following:
3274 * namespaceURI<separator>localName
3275 * namespaceURI<separator>localName<separator>prefix
3277 * and we use 0xFFFF for the <separator>.
3281 const char16_t
* uriEnd
= nullptr;
3282 const char16_t
* nameEnd
= nullptr;
3283 const char16_t
* pos
;
3284 for (pos
= aExpatName
; *pos
; ++pos
) {
3285 if (*pos
== 0xFFFF) {
3294 const char16_t
* nameStart
;
3296 if (sNameSpaceManager
) {
3297 sNameSpaceManager
->RegisterNameSpace(
3298 nsDependentSubstring(aExpatName
, uriEnd
), *aNameSpaceID
);
3300 *aNameSpaceID
= kNameSpaceID_Unknown
;
3303 nameStart
= (uriEnd
+ 1);
3305 const char16_t
* prefixStart
= nameEnd
+ 1;
3306 *aPrefix
= NS_AtomizeMainThread(Substring(prefixStart
, pos
)).take();
3312 *aNameSpaceID
= kNameSpaceID_None
;
3313 nameStart
= aExpatName
;
3317 *aLocalName
= NS_AtomizeMainThread(Substring(nameStart
, nameEnd
)).take();
3321 PresShell
* nsContentUtils::GetPresShellForContent(const nsIContent
* aContent
) {
3322 Document
* doc
= aContent
->GetComposedDoc();
3326 return doc
->GetPresShell();
3330 nsPresContext
* nsContentUtils::GetContextForContent(
3331 const nsIContent
* aContent
) {
3332 PresShell
* presShell
= GetPresShellForContent(aContent
);
3336 return presShell
->GetPresContext();
3340 bool nsContentUtils::CanLoadImage(nsIURI
* aURI
, nsINode
* aNode
,
3341 Document
* aLoadingDocument
,
3342 nsIPrincipal
* aLoadingPrincipal
) {
3343 MOZ_ASSERT(aURI
, "Must have a URI");
3344 MOZ_ASSERT(aLoadingDocument
, "Must have a document");
3345 MOZ_ASSERT(aLoadingPrincipal
, "Must have a loading principal");
3349 auto appType
= nsIDocShell::APP_TYPE_UNKNOWN
;
3352 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
=
3353 aLoadingDocument
->GetDocShell();
3354 if (docShellTreeItem
) {
3355 nsCOMPtr
<nsIDocShellTreeItem
> root
;
3356 docShellTreeItem
->GetInProcessRootTreeItem(getter_AddRefs(root
));
3358 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(root
));
3361 appType
= docShell
->GetAppType();
3366 if (appType
!= nsIDocShell::APP_TYPE_EDITOR
) {
3367 // Editor apps get special treatment here, editors can load images
3368 // from anywhere. This allows editor to insert images from file://
3369 // into documents that are being edited.
3370 rv
= sSecurityManager
->CheckLoadURIWithPrincipal(
3371 aLoadingPrincipal
, aURI
, nsIScriptSecurityManager::ALLOW_CHROME
,
3372 aLoadingDocument
->InnerWindowID());
3373 if (NS_FAILED(rv
)) {
3378 nsCOMPtr
<nsILoadInfo
> secCheckLoadInfo
= new mozilla::net::LoadInfo(
3380 aLoadingPrincipal
, // triggering principal
3381 aNode
, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
,
3382 nsIContentPolicy::TYPE_INTERNAL_IMAGE
);
3384 int16_t decision
= nsIContentPolicy::ACCEPT
;
3386 rv
= NS_CheckContentLoadPolicy(aURI
, secCheckLoadInfo
,
3387 ""_ns
, // mime guess
3388 &decision
, GetContentPolicy());
3390 return NS_SUCCEEDED(rv
) && NS_CP_ACCEPTED(decision
);
3394 bool nsContentUtils::IsInPrivateBrowsing(Document
* aDoc
) {
3399 nsCOMPtr
<nsILoadGroup
> loadGroup
= aDoc
->GetDocumentLoadGroup();
3401 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
3402 loadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
3404 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
3406 return loadContext
->UsePrivateBrowsing();
3411 nsCOMPtr
<nsIChannel
> channel
= aDoc
->GetChannel();
3412 return channel
&& NS_UsePrivateBrowsing(channel
);
3416 bool nsContentUtils::IsInPrivateBrowsing(nsILoadGroup
* aLoadGroup
) {
3420 bool isPrivate
= false;
3421 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
3422 aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
3424 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
3425 isPrivate
= loadContext
&& loadContext
->UsePrivateBrowsing();
3430 // FIXME(emilio): This is (effectively) almost but not quite the same as
3431 // Document::ShouldLoadImages(), which one is right?
3432 bool nsContentUtils::DocumentInactiveForImageLoads(Document
* aDocument
) {
3436 if (IsChromeDoc(aDocument
) || aDocument
->IsResourceDoc() ||
3437 aDocument
->IsStaticDocument()) {
3440 nsCOMPtr
<nsPIDOMWindowInner
> win
=
3441 do_QueryInterface(aDocument
->GetScopeObject());
3442 return !win
|| !win
->GetDocShell();
3445 imgLoader
* nsContentUtils::GetImgLoaderForDocument(Document
* aDoc
) {
3446 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc
), nullptr);
3449 return imgLoader::NormalLoader();
3451 bool isPrivate
= IsInPrivateBrowsing(aDoc
);
3452 return isPrivate
? imgLoader::PrivateBrowsingLoader()
3453 : imgLoader::NormalLoader();
3457 imgLoader
* nsContentUtils::GetImgLoaderForChannel(nsIChannel
* aChannel
,
3458 Document
* aContext
) {
3459 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext
), nullptr);
3462 return imgLoader::NormalLoader();
3464 nsCOMPtr
<nsILoadContext
> context
;
3465 NS_QueryNotificationCallbacks(aChannel
, context
);
3466 return context
&& context
->UsePrivateBrowsing()
3467 ? imgLoader::PrivateBrowsingLoader()
3468 : imgLoader::NormalLoader();
3472 bool nsContentUtils::IsImageInCache(nsIURI
* aURI
, Document
* aDocument
) {
3473 imgILoader
* loader
= GetImgLoaderForDocument(aDocument
);
3474 nsCOMPtr
<imgICache
> cache
= do_QueryInterface(loader
);
3476 // If something unexpected happened we return false, otherwise if props
3477 // is set, the image is cached and we return true
3478 nsCOMPtr
<nsIProperties
> props
;
3480 cache
->FindEntryProperties(aURI
, aDocument
, getter_AddRefs(props
));
3481 return (NS_SUCCEEDED(rv
) && props
);
3485 int32_t nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode
) {
3487 case CORS_ANONYMOUS
:
3488 return imgILoader::LOAD_CORS_ANONYMOUS
;
3489 case CORS_USE_CREDENTIALS
:
3490 return imgILoader::LOAD_CORS_USE_CREDENTIALS
;
3497 nsresult
nsContentUtils::LoadImage(
3498 nsIURI
* aURI
, nsINode
* aContext
, Document
* aLoadingDocument
,
3499 nsIPrincipal
* aLoadingPrincipal
, uint64_t aRequestContextID
,
3500 nsIReferrerInfo
* aReferrerInfo
, imgINotificationObserver
* aObserver
,
3501 int32_t aLoadFlags
, const nsAString
& initiatorType
,
3502 imgRequestProxy
** aRequest
, nsContentPolicyType aContentPolicyType
,
3503 bool aUseUrgentStartForChannel
, bool aLinkPreload
) {
3504 MOZ_ASSERT(aURI
, "Must have a URI");
3505 MOZ_ASSERT(aContext
, "Must have a context");
3506 MOZ_ASSERT(aLoadingDocument
, "Must have a document");
3507 MOZ_ASSERT(aLoadingPrincipal
, "Must have a principal");
3508 MOZ_ASSERT(aRequest
, "Null out param");
3510 imgLoader
* imgLoader
= GetImgLoaderForDocument(aLoadingDocument
);
3512 // nothing we can do here
3513 return NS_ERROR_FAILURE
;
3516 nsCOMPtr
<nsILoadGroup
> loadGroup
= aLoadingDocument
->GetDocumentLoadGroup();
3518 nsIURI
* documentURI
= aLoadingDocument
->GetDocumentURI();
3520 NS_ASSERTION(loadGroup
|| IsFontTableURI(documentURI
),
3521 "Could not get loadgroup; onload may fire too early");
3523 // XXXbz using "documentURI" for the initialDocumentURI is not quite
3524 // right, but the best we can do here...
3525 return imgLoader
->LoadImage(aURI
, /* uri to load */
3526 documentURI
, /* initialDocumentURI */
3527 aReferrerInfo
, /* referrerInfo */
3528 aLoadingPrincipal
, /* loading principal */
3529 aRequestContextID
, /* request context ID */
3530 loadGroup
, /* loadgroup */
3531 aObserver
, /* imgINotificationObserver */
3532 aContext
, /* loading context */
3533 aLoadingDocument
, /* uniquification key */
3534 aLoadFlags
, /* load flags */
3535 nullptr, /* cache key */
3536 aContentPolicyType
, /* content policy type */
3537 initiatorType
, /* the load initiator */
3538 aUseUrgentStartForChannel
, /* urgent-start flag */
3539 aLinkPreload
, /* <link preload> initiator */
3544 already_AddRefed
<imgIContainer
> nsContentUtils::GetImageFromContent(
3545 nsIImageLoadingContent
* aContent
, imgIRequest
** aRequest
) {
3547 *aRequest
= nullptr;
3550 NS_ENSURE_TRUE(aContent
, nullptr);
3552 nsCOMPtr
<imgIRequest
> imgRequest
;
3553 aContent
->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST
,
3554 getter_AddRefs(imgRequest
));
3559 nsCOMPtr
<imgIContainer
> imgContainer
;
3560 imgRequest
->GetImage(getter_AddRefs(imgContainer
));
3562 if (!imgContainer
) {
3567 // If the consumer wants the request, verify it has actually loaded
3570 imgRequest
->GetImageStatus(&imgStatus
);
3571 if (imgStatus
& imgIRequest::STATUS_FRAME_COMPLETE
&&
3572 !(imgStatus
& imgIRequest::STATUS_ERROR
)) {
3573 imgRequest
.swap(*aRequest
);
3577 return imgContainer
.forget();
3581 bool nsContentUtils::ContentIsDraggable(nsIContent
* aContent
) {
3582 MOZ_ASSERT(aContent
);
3584 if (auto htmlElement
= nsGenericHTMLElement::FromNode(aContent
)) {
3585 if (htmlElement
->Draggable()) {
3589 if (htmlElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::draggable
,
3590 nsGkAtoms::_false
, eIgnoreCase
)) {
3594 if (aContent
->IsSVGElement()) {
3598 // special handling for content area image and link dragging
3599 return IsDraggableImage(aContent
) || IsDraggableLink(aContent
);
3603 bool nsContentUtils::IsDraggableImage(nsIContent
* aContent
) {
3604 MOZ_ASSERT(aContent
, "Must have content node to test");
3606 nsCOMPtr
<nsIImageLoadingContent
> imageContent(do_QueryInterface(aContent
));
3607 if (!imageContent
) {
3611 nsCOMPtr
<imgIRequest
> imgRequest
;
3612 imageContent
->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST
,
3613 getter_AddRefs(imgRequest
));
3615 // XXXbz It may be draggable even if the request resulted in an error. Why?
3616 // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
3617 return imgRequest
!= nullptr;
3621 bool nsContentUtils::IsDraggableLink(const nsIContent
* aContent
) {
3622 nsCOMPtr
<nsIURI
> absURI
;
3623 return aContent
->IsLink(getter_AddRefs(absURI
));
3627 nsresult
nsContentUtils::QNameChanged(mozilla::dom::NodeInfo
* aNodeInfo
,
3629 mozilla::dom::NodeInfo
** aResult
) {
3630 nsNodeInfoManager
* niMgr
= aNodeInfo
->NodeInfoManager();
3633 ->GetNodeInfo(aName
, nullptr, aNodeInfo
->NamespaceID(),
3634 aNodeInfo
->NodeType(), aNodeInfo
->GetExtraName())
3639 static bool TestSitePerm(nsIPrincipal
* aPrincipal
, const nsACString
& aType
,
3640 uint32_t aPerm
, bool aExactHostMatch
) {
3642 // We always deny (i.e. don't allow) the permission if we don't have a
3644 return aPerm
!= nsIPermissionManager::ALLOW_ACTION
;
3647 nsCOMPtr
<nsIPermissionManager
> permMgr
=
3648 components::PermissionManager::Service();
3649 NS_ENSURE_TRUE(permMgr
, false);
3653 if (aExactHostMatch
) {
3654 rv
= permMgr
->TestExactPermissionFromPrincipal(aPrincipal
, aType
, &perm
);
3656 rv
= permMgr
->TestPermissionFromPrincipal(aPrincipal
, aType
, &perm
);
3658 NS_ENSURE_SUCCESS(rv
, false);
3660 return perm
== aPerm
;
3663 bool nsContentUtils::IsSitePermAllow(nsIPrincipal
* aPrincipal
,
3664 const nsACString
& aType
) {
3665 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::ALLOW_ACTION
,
3669 bool nsContentUtils::IsSitePermDeny(nsIPrincipal
* aPrincipal
,
3670 const nsACString
& aType
) {
3671 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::DENY_ACTION
,
3675 bool nsContentUtils::IsExactSitePermAllow(nsIPrincipal
* aPrincipal
,
3676 const nsACString
& aType
) {
3677 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::ALLOW_ACTION
,
3681 bool nsContentUtils::IsExactSitePermDeny(nsIPrincipal
* aPrincipal
,
3682 const nsACString
& aType
) {
3683 return TestSitePerm(aPrincipal
, aType
, nsIPermissionManager::DENY_ACTION
,
3687 static const char* gEventNames
[] = {"event"};
3688 static const char* gSVGEventNames
[] = {"evt"};
3689 // for b/w compat, the first name to onerror is still 'event', even though it
3690 // is actually the error message
3691 static const char* gOnErrorNames
[] = {"event", "source", "lineno", "colno",
3695 void nsContentUtils::GetEventArgNames(int32_t aNameSpaceID
, nsAtom
* aEventName
,
3696 bool aIsForWindow
, uint32_t* aArgCount
,
3697 const char*** aArgArray
) {
3698 #define SET_EVENT_ARG_NAMES(names) \
3699 *aArgCount = sizeof(names) / sizeof(names[0]); \
3702 // JSEventHandler is what does the arg magic for onerror, and it does
3703 // not seem to take the namespace into account. So we let onerror in all
3704 // namespaces get the 3 arg names.
3705 if (aEventName
== nsGkAtoms::onerror
&& aIsForWindow
) {
3706 SET_EVENT_ARG_NAMES(gOnErrorNames
);
3707 } else if (aNameSpaceID
== kNameSpaceID_SVG
) {
3708 SET_EVENT_ARG_NAMES(gSVGEventNames
);
3710 SET_EVENT_ARG_NAMES(gEventNames
);
3714 // Note: The list of content bundles in nsStringBundle.cpp should be updated
3715 // whenever entries are added or removed from this list.
3716 static const char* gPropertiesFiles
[nsContentUtils::PropertiesFile_COUNT
] = {
3717 // Must line up with the enum values in |PropertiesFile| enum.
3718 "chrome://global/locale/css.properties",
3719 "chrome://global/locale/xul.properties",
3720 "chrome://global/locale/layout_errors.properties",
3721 "chrome://global/locale/layout/HtmlForm.properties",
3722 "chrome://global/locale/printing.properties",
3723 "chrome://global/locale/dom/dom.properties",
3724 "chrome://global/locale/layout/htmlparser.properties",
3725 "chrome://global/locale/svg/svg.properties",
3726 "chrome://branding/locale/brand.properties",
3727 "chrome://global/locale/commonDialogs.properties",
3728 "chrome://global/locale/mathml/mathml.properties",
3729 "chrome://global/locale/security/security.properties",
3730 "chrome://necko/locale/necko.properties",
3731 "resource://gre/res/locale/layout/HtmlForm.properties",
3732 "resource://gre/res/locale/dom/dom.properties"};
3735 nsresult
nsContentUtils::EnsureStringBundle(PropertiesFile aFile
) {
3736 if (!sStringBundles
[aFile
]) {
3737 if (!sStringBundleService
) {
3739 CallGetService(NS_STRINGBUNDLE_CONTRACTID
, &sStringBundleService
);
3740 NS_ENSURE_SUCCESS(rv
, rv
);
3742 nsIStringBundle
* bundle
;
3744 sStringBundleService
->CreateBundle(gPropertiesFiles
[aFile
], &bundle
);
3745 NS_ENSURE_SUCCESS(rv
, rv
);
3746 sStringBundles
[aFile
] = bundle
; // transfer ownership
3752 void nsContentUtils::AsyncPrecreateStringBundles() {
3753 // We only ever want to pre-create bundles in the parent process.
3755 // All nsContentUtils bundles are shared between the parent and child
3756 // precesses, and the shared memory regions that back them *must* be created
3757 // in the parent, and then sent to all children.
3759 // If we attempt to create a bundle in the child before its memory region is
3760 // available, we need to create a temporary non-shared bundle, and later
3761 // replace that with the shared memory copy. So attempting to pre-load in the
3762 // child is wasteful and unnecessary.
3763 MOZ_ASSERT(XRE_IsParentProcess());
3765 for (uint32_t bundleIndex
= 0; bundleIndex
< PropertiesFile_COUNT
;
3767 nsresult rv
= NS_DispatchToCurrentThreadQueue(
3768 NS_NewRunnableFunction("AsyncPrecreateStringBundles",
3770 PropertiesFile file
=
3771 static_cast<PropertiesFile
>(bundleIndex
);
3772 EnsureStringBundle(file
);
3773 nsIStringBundle
* bundle
= sStringBundles
[file
];
3774 bundle
->AsyncPreload();
3776 EventQueuePriority::Idle
);
3777 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
3782 bool nsContentUtils::SpoofLocaleEnglish() {
3786 return StaticPrefs::privacy_spoof_english() == 2;
3789 static nsContentUtils::PropertiesFile
GetMaybeSpoofedPropertiesFile(
3790 nsContentUtils::PropertiesFile aFile
, const char* aKey
,
3791 Document
* aDocument
) {
3792 // When we spoof English, use en-US properties in strings that are accessible
3794 bool spoofLocale
= nsContentUtils::SpoofLocaleEnglish() &&
3795 (!aDocument
|| !aDocument
->AllowsL10n());
3798 case nsContentUtils::eFORMS_PROPERTIES
:
3799 return nsContentUtils::eFORMS_PROPERTIES_en_US
;
3800 case nsContentUtils::eDOM_PROPERTIES
:
3801 return nsContentUtils::eDOM_PROPERTIES_en_US
;
3810 nsresult
nsContentUtils::GetMaybeLocalizedString(PropertiesFile aFile
,
3812 Document
* aDocument
,
3813 nsAString
& aResult
) {
3814 return GetLocalizedString(
3815 GetMaybeSpoofedPropertiesFile(aFile
, aKey
, aDocument
), aKey
, aResult
);
3819 nsresult
nsContentUtils::GetLocalizedString(PropertiesFile aFile
,
3821 nsAString
& aResult
) {
3822 nsresult rv
= EnsureStringBundle(aFile
);
3823 NS_ENSURE_SUCCESS(rv
, rv
);
3824 nsIStringBundle
* bundle
= sStringBundles
[aFile
];
3825 return bundle
->GetStringFromName(aKey
, aResult
);
3829 nsresult
nsContentUtils::FormatMaybeLocalizedString(
3830 PropertiesFile aFile
, const char* aKey
, Document
* aDocument
,
3831 const nsTArray
<nsString
>& aParams
, nsAString
& aResult
) {
3832 return FormatLocalizedString(
3833 GetMaybeSpoofedPropertiesFile(aFile
, aKey
, aDocument
), aKey
, aParams
,
3838 nsresult
nsContentUtils::FormatLocalizedString(
3839 PropertiesFile aFile
, const char* aKey
, const nsTArray
<nsString
>& aParams
,
3840 nsAString
& aResult
) {
3841 nsresult rv
= EnsureStringBundle(aFile
);
3842 NS_ENSURE_SUCCESS(rv
, rv
);
3843 nsIStringBundle
* bundle
= sStringBundles
[aFile
];
3845 if (aParams
.IsEmpty()) {
3846 return bundle
->GetStringFromName(aKey
, aResult
);
3849 return bundle
->FormatStringFromName(aKey
, aParams
, aResult
);
3853 void nsContentUtils::LogSimpleConsoleError(const nsAString
& aErrorText
,
3854 const char* aCategory
,
3855 bool aFromPrivateWindow
,
3856 bool aFromChromeContext
,
3857 uint32_t aErrorFlags
) {
3858 nsCOMPtr
<nsIScriptError
> scriptError
=
3859 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
);
3861 nsCOMPtr
<nsIConsoleService
> console
=
3862 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
3863 if (console
&& NS_SUCCEEDED(scriptError
->Init(
3864 aErrorText
, u
""_ns
, u
""_ns
, 0, 0, aErrorFlags
, aCategory
,
3865 aFromPrivateWindow
, aFromChromeContext
))) {
3866 console
->LogMessage(scriptError
);
3872 nsresult
nsContentUtils::ReportToConsole(
3873 uint32_t aErrorFlags
, const nsACString
& aCategory
,
3874 const Document
* aDocument
, PropertiesFile aFile
, const char* aMessageName
,
3875 const nsTArray
<nsString
>& aParams
, nsIURI
* aURI
,
3876 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
) {
3878 nsAutoString errorText
;
3879 if (!aParams
.IsEmpty()) {
3880 rv
= FormatLocalizedString(aFile
, aMessageName
, aParams
, errorText
);
3882 rv
= GetLocalizedString(aFile
, aMessageName
, errorText
);
3884 NS_ENSURE_SUCCESS(rv
, rv
);
3886 return ReportToConsoleNonLocalized(errorText
, aErrorFlags
, aCategory
,
3887 aDocument
, aURI
, aSourceLine
, aLineNumber
,
3892 void nsContentUtils::ReportEmptyGetElementByIdArg(const Document
* aDoc
) {
3893 ReportToConsole(nsIScriptError::warningFlag
, "DOM"_ns
, aDoc
,
3894 nsContentUtils::eDOM_PROPERTIES
, "EmptyGetElementByIdParam");
3898 nsresult
nsContentUtils::ReportToConsoleNonLocalized(
3899 const nsAString
& aErrorText
, uint32_t aErrorFlags
,
3900 const nsACString
& aCategory
, const Document
* aDocument
, nsIURI
* aURI
,
3901 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
,
3902 MissingErrorLocationMode aLocationMode
) {
3903 uint64_t innerWindowID
= 0;
3906 aURI
= aDocument
->GetDocumentURI();
3908 innerWindowID
= aDocument
->InnerWindowID();
3911 return ReportToConsoleByWindowID(aErrorText
, aErrorFlags
, aCategory
,
3912 innerWindowID
, aURI
, aSourceLine
,
3913 aLineNumber
, aColumnNumber
, aLocationMode
);
3917 nsresult
nsContentUtils::ReportToConsoleByWindowID(
3918 const nsAString
& aErrorText
, uint32_t aErrorFlags
,
3919 const nsACString
& aCategory
, uint64_t aInnerWindowID
, nsIURI
* aURI
,
3920 const nsString
& aSourceLine
, uint32_t aLineNumber
, uint32_t aColumnNumber
,
3921 MissingErrorLocationMode aLocationMode
) {
3923 if (!sConsoleService
) { // only need to bother null-checking here
3924 rv
= CallGetService(NS_CONSOLESERVICE_CONTRACTID
, &sConsoleService
);
3925 NS_ENSURE_SUCCESS(rv
, rv
);
3929 if (!aLineNumber
&& aLocationMode
== eUSE_CALLING_LOCATION
) {
3930 JSContext
* cx
= GetCurrentJSContext();
3932 nsJSUtils::GetCallingLocation(cx
, spec
, &aLineNumber
, &aColumnNumber
);
3936 nsCOMPtr
<nsIScriptError
> errorObject
=
3937 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
, &rv
);
3938 NS_ENSURE_SUCCESS(rv
, rv
);
3940 if (!spec
.IsEmpty()) {
3941 rv
= errorObject
->InitWithWindowID(aErrorText
,
3943 aSourceLine
, aLineNumber
, aColumnNumber
,
3944 aErrorFlags
, aCategory
, aInnerWindowID
);
3946 rv
= errorObject
->InitWithSourceURI(aErrorText
, aURI
, aSourceLine
,
3947 aLineNumber
, aColumnNumber
, aErrorFlags
,
3948 aCategory
, aInnerWindowID
);
3950 NS_ENSURE_SUCCESS(rv
, rv
);
3952 return sConsoleService
->LogMessage(errorObject
);
3955 void nsContentUtils::LogMessageToConsole(const char* aMsg
) {
3956 if (!sConsoleService
) { // only need to bother null-checking here
3957 CallGetService(NS_CONSOLESERVICE_CONTRACTID
, &sConsoleService
);
3958 if (!sConsoleService
) {
3962 sConsoleService
->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg
).get());
3965 bool nsContentUtils::IsChromeDoc(const Document
* aDocument
) {
3966 return aDocument
&& aDocument
->NodePrincipal() == sSystemPrincipal
;
3969 bool nsContentUtils::IsChildOfSameType(Document
* aDoc
) {
3970 if (BrowsingContext
* bc
= aDoc
->GetBrowsingContext()) {
3971 return bc
->GetParent();
3976 bool nsContentUtils::IsPlainTextType(const nsACString
& aContentType
) {
3977 // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
3978 // define in nsContentDLF.h as well.
3979 return aContentType
.EqualsLiteral(TEXT_PLAIN
) ||
3980 aContentType
.EqualsLiteral(TEXT_CSS
) ||
3981 aContentType
.EqualsLiteral(TEXT_CACHE_MANIFEST
) ||
3982 aContentType
.EqualsLiteral(TEXT_VTT
) ||
3983 aContentType
.EqualsLiteral(APPLICATION_JAVASCRIPT
) ||
3984 aContentType
.EqualsLiteral(APPLICATION_XJAVASCRIPT
) ||
3985 aContentType
.EqualsLiteral(TEXT_ECMASCRIPT
) ||
3986 aContentType
.EqualsLiteral(APPLICATION_ECMASCRIPT
) ||
3987 aContentType
.EqualsLiteral(TEXT_JAVASCRIPT
) ||
3988 aContentType
.EqualsLiteral(APPLICATION_JSON
) ||
3989 aContentType
.EqualsLiteral(TEXT_JSON
);
3992 bool nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString
& aContentType
) {
3993 // NOTE: This must be a subset of the list in IsPlainTextType().
3994 return aContentType
.EqualsLiteral(TEXT_CACHE_MANIFEST
) ||
3995 aContentType
.EqualsLiteral(APPLICATION_JSON
) ||
3996 aContentType
.EqualsLiteral(TEXT_JSON
) ||
3997 aContentType
.EqualsLiteral(TEXT_VTT
);
4000 bool nsContentUtils::IsInChromeDocshell(const Document
* aDocument
) {
4001 return aDocument
&& aDocument
->IsInChromeDocShell();
4005 nsIContentPolicy
* nsContentUtils::GetContentPolicy() {
4006 if (!sTriedToGetContentPolicy
) {
4007 CallGetService(NS_CONTENTPOLICY_CONTRACTID
, &sContentPolicyService
);
4008 // It's OK to not have a content policy service
4009 sTriedToGetContentPolicy
= true;
4012 return sContentPolicyService
;
4016 bool nsContentUtils::IsEventAttributeName(nsAtom
* aName
, int32_t aType
) {
4017 const char16_t
* name
= aName
->GetUTF16String();
4018 if (name
[0] != 'o' || name
[1] != 'n') {
4022 EventNameMapping mapping
;
4023 return (sAtomEventTable
->Get(aName
, &mapping
) && mapping
.mType
& aType
);
4027 EventMessage
nsContentUtils::GetEventMessage(nsAtom
* aName
) {
4028 MOZ_ASSERT(NS_IsMainThread(), "sAtomEventTable is not threadsafe");
4030 EventNameMapping mapping
;
4031 if (sAtomEventTable
->Get(aName
, &mapping
)) {
4032 return mapping
.mMessage
;
4036 return eUnidentifiedEvent
;
4040 mozilla::EventClassID
nsContentUtils::GetEventClassID(const nsAString
& aName
) {
4041 EventNameMapping mapping
;
4042 if (sStringEventTable
->Get(aName
, &mapping
)) return mapping
.mEventClassID
;
4044 return eBasicEventClass
;
4047 nsAtom
* nsContentUtils::GetEventMessageAndAtom(
4048 const nsAString
& aName
, mozilla::EventClassID aEventClassID
,
4049 EventMessage
* aEventMessage
) {
4050 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe");
4051 EventNameMapping mapping
;
4052 if (sStringEventTable
->Get(aName
, &mapping
)) {
4053 *aEventMessage
= mapping
.mEventClassID
== aEventClassID
4055 : eUnidentifiedEvent
;
4056 return mapping
.mAtom
;
4059 // If we have cached lots of user defined event names, clear some of them.
4060 if (sUserDefinedEvents
->Length() > 127) {
4061 while (sUserDefinedEvents
->Length() > 64) {
4062 nsAtom
* first
= sUserDefinedEvents
->ElementAt(0);
4063 sStringEventTable
->Remove(Substring(nsDependentAtomString(first
), 2));
4064 sUserDefinedEvents
->RemoveElementAt(0);
4068 *aEventMessage
= eUnidentifiedEvent
;
4069 RefPtr
<nsAtom
> atom
= NS_AtomizeMainThread(u
"on"_ns
+ aName
);
4070 sUserDefinedEvents
->AppendElement(atom
);
4071 mapping
.mAtom
= atom
;
4072 mapping
.mMessage
= eUnidentifiedEvent
;
4073 mapping
.mType
= EventNameType_None
;
4074 mapping
.mEventClassID
= eBasicEventClass
;
4075 // This is a slow hashtable call, but at least we cache the result for the
4076 // following calls. Because GetEventMessageAndAtomForListener utilizes
4077 // sStringEventTable, it needs to know in which cases sStringEventTable
4078 // doesn't contain the information it needs so that it can use
4079 // sAtomEventTable instead.
4080 mapping
.mMaybeSpecialSVGorSMILEvent
=
4081 GetEventMessage(atom
) != eUnidentifiedEvent
;
4082 sStringEventTable
->InsertOrUpdate(aName
, mapping
);
4083 return mapping
.mAtom
;
4087 EventMessage
nsContentUtils::GetEventMessageAndAtomForListener(
4088 const nsAString
& aName
, nsAtom
** aOnName
) {
4089 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe");
4091 // Because of SVG/SMIL sStringEventTable contains a subset of the event names
4092 // comparing to the sAtomEventTable. However, usually sStringEventTable
4093 // contains the information we need, so in order to reduce hashtable
4094 // lookups, start from it.
4095 EventNameMapping mapping
;
4096 EventMessage msg
= eUnidentifiedEvent
;
4097 RefPtr
<nsAtom
> atom
;
4098 if (sStringEventTable
->Get(aName
, &mapping
)) {
4099 if (mapping
.mMaybeSpecialSVGorSMILEvent
) {
4100 // Try the atom version so that we should get the right message for
4102 atom
= NS_AtomizeMainThread(u
"on"_ns
+ aName
);
4103 msg
= GetEventMessage(atom
);
4105 atom
= mapping
.mAtom
;
4106 msg
= mapping
.mMessage
;
4108 atom
.forget(aOnName
);
4112 // GetEventMessageAndAtom will cache the event type for the future usage...
4113 GetEventMessageAndAtom(aName
, eBasicEventClass
, &msg
);
4115 // ...and then call this method recursively to get the message and atom from
4116 // now updated sStringEventTable.
4117 return GetEventMessageAndAtomForListener(aName
, aOnName
);
4120 static nsresult
GetEventAndTarget(Document
* aDoc
, nsISupports
* aTarget
,
4121 const nsAString
& aEventName
,
4122 CanBubble aCanBubble
, Cancelable aCancelable
,
4123 Composed aComposed
, Trusted aTrusted
,
4124 Event
** aEvent
, EventTarget
** aTargetOut
) {
4125 nsCOMPtr
<EventTarget
> target(do_QueryInterface(aTarget
));
4126 NS_ENSURE_TRUE(aDoc
&& target
, NS_ERROR_INVALID_ARG
);
4129 RefPtr
<Event
> event
=
4130 aDoc
->CreateEvent(u
"Events"_ns
, CallerType::System
, err
);
4131 if (NS_WARN_IF(err
.Failed())) {
4132 return err
.StealNSResult();
4135 event
->InitEvent(aEventName
, aCanBubble
, aCancelable
, aComposed
);
4136 event
->SetTrusted(aTrusted
== Trusted::eYes
);
4138 event
->SetTarget(target
);
4140 event
.forget(aEvent
);
4141 target
.forget(aTargetOut
);
4146 nsresult
nsContentUtils::DispatchTrustedEvent(
4147 Document
* aDoc
, nsISupports
* aTarget
, const nsAString
& aEventName
,
4148 CanBubble aCanBubble
, Cancelable aCancelable
, Composed aComposed
,
4149 bool* aDefaultAction
) {
4150 MOZ_ASSERT(!aEventName
.EqualsLiteral("input") &&
4151 !aEventName
.EqualsLiteral("beforeinput"),
4152 "Use DispatchInputEvent() instead");
4153 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4154 aComposed
, Trusted::eYes
, aDefaultAction
);
4158 nsresult
nsContentUtils::DispatchUntrustedEvent(
4159 Document
* aDoc
, nsISupports
* aTarget
, const nsAString
& aEventName
,
4160 CanBubble aCanBubble
, Cancelable aCancelable
, bool* aDefaultAction
) {
4161 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4162 Composed::eDefault
, Trusted::eNo
, aDefaultAction
);
4166 nsresult
nsContentUtils::DispatchEvent(Document
* aDoc
, nsISupports
* aTarget
,
4167 const nsAString
& aEventName
,
4168 CanBubble aCanBubble
,
4169 Cancelable aCancelable
,
4170 Composed aComposed
, Trusted aTrusted
,
4171 bool* aDefaultAction
,
4172 ChromeOnlyDispatch aOnlyChromeDispatch
) {
4173 RefPtr
<Event
> event
;
4174 nsCOMPtr
<EventTarget
> target
;
4175 nsresult rv
= GetEventAndTarget(
4176 aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
, aComposed
, aTrusted
,
4177 getter_AddRefs(event
), getter_AddRefs(target
));
4178 NS_ENSURE_SUCCESS(rv
, rv
);
4179 event
->WidgetEventPtr()->mFlags
.mOnlyChromeDispatch
=
4180 aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
;
4183 bool doDefault
= target
->DispatchEvent(*event
, CallerType::System
, err
);
4184 if (aDefaultAction
) {
4185 *aDefaultAction
= doDefault
;
4187 return err
.StealNSResult();
4191 nsresult
nsContentUtils::DispatchEvent(Document
* aDoc
, nsISupports
* aTarget
,
4192 WidgetEvent
& aEvent
,
4193 EventMessage aEventMessage
,
4194 CanBubble aCanBubble
,
4195 Cancelable aCancelable
, Trusted aTrusted
,
4196 bool* aDefaultAction
,
4197 ChromeOnlyDispatch aOnlyChromeDispatch
) {
4198 MOZ_ASSERT_IF(aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
,
4199 aTrusted
== Trusted::eYes
);
4201 nsCOMPtr
<EventTarget
> target(do_QueryInterface(aTarget
));
4203 aEvent
.mTime
= PR_Now();
4205 aEvent
.mSpecifiedEventType
= GetEventTypeFromMessage(aEventMessage
);
4206 aEvent
.SetDefaultComposed();
4207 aEvent
.SetDefaultComposedInNativeAnonymousContent();
4209 aEvent
.mFlags
.mBubbles
= aCanBubble
== CanBubble::eYes
;
4210 aEvent
.mFlags
.mCancelable
= aCancelable
== Cancelable::eYes
;
4211 aEvent
.mFlags
.mOnlyChromeDispatch
=
4212 aOnlyChromeDispatch
== ChromeOnlyDispatch::eYes
;
4214 aEvent
.mTarget
= target
;
4216 nsEventStatus status
= nsEventStatus_eIgnore
;
4217 nsresult rv
= EventDispatcher::DispatchDOMEvent(target
, &aEvent
, nullptr,
4219 if (aDefaultAction
) {
4220 *aDefaultAction
= (status
!= nsEventStatus_eConsumeNoDefault
);
4226 nsresult
nsContentUtils::DispatchInputEvent(Element
* aEventTarget
) {
4227 return DispatchInputEvent(aEventTarget
, mozilla::eEditorInput
,
4228 mozilla::EditorInputType::eUnknown
, nullptr,
4229 InputEventOptions());
4233 nsresult
nsContentUtils::DispatchInputEvent(
4234 Element
* aEventTargetElement
, EventMessage aEventMessage
,
4235 EditorInputType aEditorInputType
, TextEditor
* aTextEditor
,
4236 InputEventOptions
&& aOptions
, nsEventStatus
* aEventStatus
/* = nullptr */) {
4237 MOZ_ASSERT(aEventMessage
== eEditorInput
||
4238 aEventMessage
== eEditorBeforeInput
);
4240 if (NS_WARN_IF(!aEventTargetElement
)) {
4241 return NS_ERROR_INVALID_ARG
;
4244 // If this is called from editor, the instance should be set to aTextEditor.
4245 // Otherwise, we need to look for an editor for aEventTargetElement.
4246 // However, we don't need to do it for HTMLEditor since nobody shouldn't
4247 // dispatch "beforeinput" nor "input" event for HTMLEditor except HTMLEditor
4249 bool useInputEvent
= false;
4251 useInputEvent
= true;
4252 } else if (HTMLTextAreaElement
* textAreaElement
=
4253 HTMLTextAreaElement::FromNode(aEventTargetElement
)) {
4254 aTextEditor
= textAreaElement
->GetTextEditorWithoutCreation();
4255 useInputEvent
= true;
4256 } else if (HTMLInputElement
* inputElement
=
4257 HTMLInputElement::FromNode(aEventTargetElement
)) {
4258 if (inputElement
->IsInputEventTarget()) {
4259 aTextEditor
= inputElement
->GetTextEditorWithoutCreation();
4260 useInputEvent
= true;
4265 MOZ_ASSERT(!aEventTargetElement
->IsTextControlElement(),
4266 "The event target may have editor, but we've not known it yet.");
4268 #endif // #ifdef DEBUG
4270 if (!useInputEvent
) {
4271 MOZ_ASSERT(aEventMessage
== eEditorInput
);
4272 MOZ_ASSERT(aEditorInputType
== EditorInputType::eUnknown
);
4273 MOZ_ASSERT(!aOptions
.mNeverCancelable
);
4274 // Dispatch "input" event with Event instance.
4275 WidgetEvent
widgetEvent(true, eUnidentifiedEvent
);
4276 widgetEvent
.mSpecifiedEventType
= nsGkAtoms::oninput
;
4277 widgetEvent
.mFlags
.mCancelable
= false;
4278 widgetEvent
.mFlags
.mComposed
= true;
4279 // Using same time as nsContentUtils::DispatchEvent() for backward
4281 widgetEvent
.mTime
= PR_Now();
4282 (new AsyncEventDispatcher(aEventTargetElement
, widgetEvent
))
4283 ->RunDOMEventWhenSafe();
4287 MOZ_ASSERT_IF(aEventMessage
!= eEditorBeforeInput
,
4288 !aOptions
.mNeverCancelable
);
4290 aEventMessage
== eEditorBeforeInput
&& aOptions
.mNeverCancelable
,
4291 aEditorInputType
== EditorInputType::eInsertReplacementText
);
4293 nsCOMPtr
<nsIWidget
> widget
;
4295 widget
= aTextEditor
->GetWidget();
4296 if (NS_WARN_IF(!widget
)) {
4297 return NS_ERROR_FAILURE
;
4300 Document
* document
= aEventTargetElement
->OwnerDoc();
4301 if (NS_WARN_IF(!document
)) {
4302 return NS_ERROR_FAILURE
;
4304 // If we're running xpcshell tests, we fail to get presShell here.
4305 // Even in such case, we need to dispatch "input" event without widget.
4306 PresShell
* presShell
= document
->GetPresShell();
4308 nsPresContext
* presContext
= presShell
->GetPresContext();
4309 if (NS_WARN_IF(!presContext
)) {
4310 return NS_ERROR_FAILURE
;
4312 widget
= presContext
->GetRootWidget();
4313 if (NS_WARN_IF(!widget
)) {
4314 return NS_ERROR_FAILURE
;
4319 // Dispatch "input" event with InputEvent instance.
4320 InternalEditorInputEvent
inputEvent(true, aEventMessage
, widget
);
4322 inputEvent
.mFlags
.mCancelable
=
4323 !aOptions
.mNeverCancelable
&& aEventMessage
== eEditorBeforeInput
&&
4324 IsCancelableBeforeInputEvent(aEditorInputType
);
4325 MOZ_ASSERT(!inputEvent
.mFlags
.mCancelable
|| aEventStatus
);
4327 // Using same time as old event dispatcher in EditorBase for backward
4329 inputEvent
.mTime
= static_cast<uint64_t>(PR_Now() / 1000);
4331 // If there is an editor, set isComposing to true when it has composition.
4332 // Note that EditorBase::IsIMEComposing() may return false even when we
4333 // need to set it to true.
4334 // Otherwise, i.e., editor hasn't been created for the element yet,
4335 // we should set isComposing to false since the element can never has
4336 // composition without editor.
4337 inputEvent
.mIsComposing
= aTextEditor
&& aTextEditor
->GetComposition();
4339 if (!aTextEditor
|| !aTextEditor
->AsHTMLEditor()) {
4340 if (IsDataAvailableOnTextEditor(aEditorInputType
)) {
4341 inputEvent
.mData
= std::move(aOptions
.mData
);
4342 MOZ_ASSERT(!inputEvent
.mData
.IsVoid(),
4343 "inputEvent.mData shouldn't be void");
4347 MOZ_ASSERT(inputEvent
.mData
.IsVoid(), "inputEvent.mData should be void");
4349 #endif // #ifdef DEBUG
4351 aOptions
.mTargetRanges
.IsEmpty(),
4352 "Target ranges for <input> and <textarea> should always be empty");
4354 MOZ_ASSERT(aTextEditor
->AsHTMLEditor());
4355 if (IsDataAvailableOnHTMLEditor(aEditorInputType
)) {
4356 inputEvent
.mData
= std::move(aOptions
.mData
);
4357 MOZ_ASSERT(!inputEvent
.mData
.IsVoid(),
4358 "inputEvent.mData shouldn't be void");
4360 MOZ_ASSERT(inputEvent
.mData
.IsVoid(), "inputEvent.mData should be void");
4361 if (IsDataTransferAvailableOnHTMLEditor(aEditorInputType
)) {
4362 inputEvent
.mDataTransfer
= std::move(aOptions
.mDataTransfer
);
4363 MOZ_ASSERT(inputEvent
.mDataTransfer
,
4364 "inputEvent.mDataTransfer shouldn't be nullptr");
4365 MOZ_ASSERT(inputEvent
.mDataTransfer
->IsReadOnly(),
4366 "inputEvent.mDataTransfer should be read only");
4370 MOZ_ASSERT(!inputEvent
.mDataTransfer
,
4371 "inputEvent.mDataTransfer should be nullptr");
4373 #endif // #ifdef DEBUG
4375 if (aEventMessage
== eEditorBeforeInput
&&
4376 MayHaveTargetRangesOnHTMLEditor(aEditorInputType
)) {
4377 inputEvent
.mTargetRanges
= std::move(aOptions
.mTargetRanges
);
4381 MOZ_ASSERT(aOptions
.mTargetRanges
.IsEmpty(),
4382 "Target ranges shouldn't be set for the dispatching event");
4384 #endif // #ifdef DEBUG
4387 inputEvent
.mInputType
= aEditorInputType
;
4389 if (!IsSafeToRunScript()) {
4390 // If we cannot dispatch an event right now, we cannot make it cancelable.
4392 !inputEvent
.mFlags
.mCancelable
,
4393 "Cancelable beforeinput event dispatcher should run when it's safe");
4394 inputEvent
.mFlags
.mCancelable
= false;
4395 (new AsyncEventDispatcher(aEventTargetElement
, inputEvent
))
4396 ->RunDOMEventWhenSafe();
4400 // If we're running xpcshell tests, we fail to get presShell here.
4401 // Even in such case, we need to dispatch "input" event without widget.
4402 RefPtr
<nsPresContext
> presContext
=
4403 aEventTargetElement
->OwnerDoc()->GetPresContext();
4404 nsresult rv
= EventDispatcher::Dispatch(aEventTargetElement
, presContext
,
4405 &inputEvent
, nullptr, aEventStatus
);
4406 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
4407 "Dispatching `beforeinput` or `input` event failed");
4411 nsresult
nsContentUtils::DispatchChromeEvent(
4412 Document
* aDoc
, nsISupports
* aTarget
, const nsAString
& aEventName
,
4413 CanBubble aCanBubble
, Cancelable aCancelable
, bool* aDefaultAction
) {
4414 RefPtr
<Event
> event
;
4415 nsCOMPtr
<EventTarget
> target
;
4416 nsresult rv
= GetEventAndTarget(
4417 aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
, Composed::eDefault
,
4418 Trusted::eYes
, getter_AddRefs(event
), getter_AddRefs(target
));
4419 NS_ENSURE_SUCCESS(rv
, rv
);
4421 NS_ASSERTION(aDoc
, "GetEventAndTarget lied?");
4422 if (!aDoc
->GetWindow()) return NS_ERROR_INVALID_ARG
;
4424 EventTarget
* piTarget
= aDoc
->GetWindow()->GetParentTarget();
4425 if (!piTarget
) return NS_ERROR_INVALID_ARG
;
4428 bool defaultActionEnabled
=
4429 piTarget
->DispatchEvent(*event
, CallerType::System
, err
);
4430 if (aDefaultAction
) {
4431 *aDefaultAction
= defaultActionEnabled
;
4433 return err
.StealNSResult();
4436 void nsContentUtils::RequestFrameFocus(Element
& aFrameElement
, bool aCanRaise
,
4437 CallerType aCallerType
) {
4438 RefPtr
<Element
> target
= &aFrameElement
;
4439 bool defaultAction
= true;
4441 DispatchEventOnlyToChrome(target
->OwnerDoc(), target
,
4442 u
"framefocusrequested"_ns
, CanBubble::eYes
,
4443 Cancelable::eYes
, &defaultAction
);
4445 if (!defaultAction
) {
4449 RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager();
4454 uint32_t flags
= nsIFocusManager::FLAG_NOSCROLL
;
4456 flags
|= nsIFocusManager::FLAG_RAISE
;
4459 if (aCallerType
== CallerType::NonSystem
) {
4460 flags
|= nsIFocusManager::FLAG_NONSYSTEMCALLER
;
4463 fm
->SetFocus(target
, flags
);
4466 nsresult
nsContentUtils::DispatchEventOnlyToChrome(
4467 Document
* aDoc
, nsISupports
* aTarget
, const nsAString
& aEventName
,
4468 CanBubble aCanBubble
, Cancelable aCancelable
, Composed aComposed
,
4469 bool* aDefaultAction
) {
4470 return DispatchEvent(aDoc
, aTarget
, aEventName
, aCanBubble
, aCancelable
,
4471 aComposed
, Trusted::eYes
, aDefaultAction
,
4472 ChromeOnlyDispatch::eYes
);
4476 Element
* nsContentUtils::MatchElementId(nsIContent
* aContent
,
4477 const nsAtom
* aId
) {
4478 for (nsIContent
* cur
= aContent
; cur
; cur
= cur
->GetNextNode(aContent
)) {
4479 if (aId
== cur
->GetID()) {
4480 return cur
->AsElement();
4488 Element
* nsContentUtils::MatchElementId(nsIContent
* aContent
,
4489 const nsAString
& aId
) {
4490 MOZ_ASSERT(!aId
.IsEmpty(), "Will match random elements");
4492 // ID attrs are generally stored as atoms, so just atomize this up front
4493 RefPtr
<nsAtom
> id(NS_Atomize(aId
));
4495 // OOM, so just bail
4499 return MatchElementId(aContent
, id
);
4503 void nsContentUtils::RegisterShutdownObserver(nsIObserver
* aObserver
) {
4504 nsCOMPtr
<nsIObserverService
> observerService
=
4505 mozilla::services::GetObserverService();
4506 if (observerService
) {
4507 observerService
->AddObserver(aObserver
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
,
4513 void nsContentUtils::UnregisterShutdownObserver(nsIObserver
* aObserver
) {
4514 nsCOMPtr
<nsIObserverService
> observerService
=
4515 mozilla::services::GetObserverService();
4516 if (observerService
) {
4517 observerService
->RemoveObserver(aObserver
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
);
4522 bool nsContentUtils::HasNonEmptyAttr(const nsIContent
* aContent
,
4523 int32_t aNameSpaceID
, nsAtom
* aName
) {
4524 static Element::AttrValuesArray strings
[] = {nsGkAtoms::_empty
, nullptr};
4525 return aContent
->IsElement() &&
4526 aContent
->AsElement()->FindAttrValueIn(aNameSpaceID
, aName
, strings
,
4528 Element::ATTR_VALUE_NO_MATCH
;
4532 bool nsContentUtils::HasMutationListeners(nsINode
* aNode
, uint32_t aType
,
4533 nsINode
* aTargetForSubtreeModified
) {
4534 Document
* doc
= aNode
->OwnerDoc();
4536 // global object will be null for documents that don't have windows.
4537 nsPIDOMWindowInner
* window
= doc
->GetInnerWindow();
4538 // This relies on EventListenerManager::AddEventListener, which sets
4539 // all mutation bits when there is a listener for DOMSubtreeModified event.
4540 if (window
&& !window
->HasMutationListeners(aType
)) {
4544 if (aNode
->ChromeOnlyAccess() || aNode
->IsInShadowTree()) {
4548 doc
->MayDispatchMutationEvent(aTargetForSubtreeModified
);
4550 // If we have a window, we can check it for mutation listeners now.
4551 if (aNode
->IsInUncomposedDoc()) {
4552 nsCOMPtr
<EventTarget
> piTarget(do_QueryInterface(window
));
4554 EventListenerManager
* manager
= piTarget
->GetExistingListenerManager();
4555 if (manager
&& manager
->HasMutationListeners()) {
4561 // If we have a window, we know a mutation listener is registered, but it
4562 // might not be in our chain. If we don't have a window, we might have a
4563 // mutation listener. Check quickly to see.
4565 EventListenerManager
* manager
= aNode
->GetExistingListenerManager();
4566 if (manager
&& manager
->HasMutationListeners()) {
4570 aNode
= aNode
->GetParentNode();
4577 bool nsContentUtils::HasMutationListeners(Document
* aDocument
, uint32_t aType
) {
4578 nsPIDOMWindowInner
* window
=
4579 aDocument
? aDocument
->GetInnerWindow() : nullptr;
4581 // This relies on EventListenerManager::AddEventListener, which sets
4582 // all mutation bits when there is a listener for DOMSubtreeModified event.
4583 return !window
|| window
->HasMutationListeners(aType
);
4586 void nsContentUtils::MaybeFireNodeRemoved(nsINode
* aChild
, nsINode
* aParent
) {
4587 MOZ_ASSERT(aChild
, "Missing child");
4588 MOZ_ASSERT(aChild
->GetParentNode() == aParent
, "Wrong parent");
4589 MOZ_ASSERT(aChild
->OwnerDoc() == aParent
->OwnerDoc(), "Wrong owner-doc");
4591 // Having an explicit check here since it's an easy mistake to fall into,
4592 // and there might be existing code with problems. We'd rather be safe
4593 // than fire DOMNodeRemoved in all corner cases. We also rely on it for
4594 // nsAutoScriptBlockerSuppressNodeRemoved.
4595 if (!IsSafeToRunScript()) {
4596 // This checks that IsSafeToRunScript is true since we don't want to fire
4597 // events when that is false. We can't rely on EventDispatcher to assert
4598 // this in this situation since most of the time there are no mutation
4599 // event listeners, in which case we won't even attempt to dispatch events.
4600 // However this also allows for two exceptions. First off, we don't assert
4601 // if the mutation happens to native anonymous content since we never fire
4602 // mutation events on such content anyway.
4603 // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
4604 // that is a know case when we'd normally fire a mutation event, but can't
4605 // make that safe and so we suppress it at this time. Ideally this should
4606 // go away eventually.
4607 if (!aChild
->IsInNativeAnonymousSubtree() &&
4608 !sDOMNodeRemovedSuppressCount
) {
4609 NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe");
4610 WarnScriptWasIgnored(aChild
->OwnerDoc());
4616 Document
* doc
= aParent
->OwnerDoc();
4617 if (MOZ_UNLIKELY(doc
->DevToolsWatchingDOMMutations()) &&
4618 aChild
->IsInComposedDoc() && !aChild
->ChromeOnlyAccess()) {
4619 DispatchChromeEvent(doc
, aChild
, u
"devtoolschildremoved"_ns
,
4620 CanBubble::eNo
, Cancelable::eNo
);
4624 if (HasMutationListeners(aChild
, NS_EVENT_BITS_MUTATION_NODEREMOVED
,
4626 InternalMutationEvent
mutation(true, eLegacyNodeRemoved
);
4627 mutation
.mRelatedNode
= aParent
;
4629 mozAutoSubtreeModified
subtree(aParent
->OwnerDoc(), aParent
);
4630 EventDispatcher::Dispatch(aChild
, nullptr, &mutation
);
4634 void nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() {
4635 if (!sEventListenerManagersHash
) {
4639 for (auto i
= sEventListenerManagersHash
->Iter(); !i
.Done(); i
.Next()) {
4640 auto entry
= static_cast<EventListenerManagerMapEntry
*>(i
.Get());
4641 nsINode
* n
= static_cast<nsINode
*>(entry
->mListenerManager
->GetTarget());
4642 if (n
&& n
->IsInComposedDoc() &&
4643 nsCCUncollectableMarker::InGeneration(
4644 n
->OwnerDoc()->GetMarkedCCGeneration())) {
4645 entry
->mListenerManager
->MarkForCC();
4651 void nsContentUtils::TraverseListenerManager(
4652 nsINode
* aNode
, nsCycleCollectionTraversalCallback
& cb
) {
4653 if (!sEventListenerManagersHash
) {
4654 // We're already shut down, just return.
4658 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
4659 sEventListenerManagersHash
->Search(aNode
));
4661 CycleCollectionNoteChild(cb
, entry
->mListenerManager
.get(),
4662 "[via hash] mListenerManager");
4666 EventListenerManager
* nsContentUtils::GetListenerManagerForNode(
4668 if (!sEventListenerManagersHash
) {
4669 // We're already shut down, don't bother creating an event listener
4675 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
4676 sEventListenerManagersHash
->Add(aNode
, fallible
));
4682 if (!entry
->mListenerManager
) {
4683 entry
->mListenerManager
= new EventListenerManager(aNode
);
4685 aNode
->SetFlags(NODE_HAS_LISTENERMANAGER
);
4688 return entry
->mListenerManager
;
4691 EventListenerManager
* nsContentUtils::GetExistingListenerManagerForNode(
4692 const nsINode
* aNode
) {
4693 if (!aNode
->HasFlag(NODE_HAS_LISTENERMANAGER
)) {
4697 if (!sEventListenerManagersHash
) {
4698 // We're already shut down, don't bother creating an event listener
4704 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
4705 sEventListenerManagersHash
->Search(aNode
));
4707 return entry
->mListenerManager
;
4713 void nsContentUtils::AddEntryToDOMArenaTable(nsINode
* aNode
,
4714 DOMArena
* aDOMArena
) {
4715 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
4716 MOZ_ASSERT_IF(sDOMArenaHashtable
, !sDOMArenaHashtable
->Contains(aNode
));
4717 MOZ_ASSERT(!aNode
->HasFlag(NODE_KEEPS_DOMARENA
));
4718 if (!sDOMArenaHashtable
) {
4719 sDOMArenaHashtable
=
4720 new nsRefPtrHashtable
<nsPtrHashKey
<const nsINode
>, dom::DOMArena
>();
4722 aNode
->SetFlags(NODE_KEEPS_DOMARENA
);
4723 sDOMArenaHashtable
->InsertOrUpdate(aNode
, RefPtr
<DOMArena
>(aDOMArena
));
4726 already_AddRefed
<DOMArena
> nsContentUtils::TakeEntryFromDOMArenaTable(
4727 const nsINode
* aNode
) {
4728 MOZ_ASSERT(sDOMArenaHashtable
->Contains(aNode
));
4729 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup());
4730 RefPtr
<DOMArena
> arena
;
4731 sDOMArenaHashtable
->Remove(aNode
, getter_AddRefs(arena
));
4732 return arena
.forget();
4736 void nsContentUtils::RemoveListenerManager(nsINode
* aNode
) {
4737 if (sEventListenerManagersHash
) {
4738 auto entry
= static_cast<EventListenerManagerMapEntry
*>(
4739 sEventListenerManagersHash
->Search(aNode
));
4741 RefPtr
<EventListenerManager
> listenerManager
;
4742 listenerManager
.swap(entry
->mListenerManager
);
4743 // Remove the entry and *then* do operations that could cause further
4744 // modification of sEventListenerManagersHash. See bug 334177.
4745 sEventListenerManagersHash
->RawRemove(entry
);
4746 if (listenerManager
) {
4747 listenerManager
->Disconnect();
4754 bool nsContentUtils::IsValidNodeName(nsAtom
* aLocalName
, nsAtom
* aPrefix
,
4755 int32_t aNamespaceID
) {
4756 if (aNamespaceID
== kNameSpaceID_Unknown
) {
4761 // If the prefix is null, then either the QName must be xmlns or the
4762 // namespace must not be XMLNS.
4763 return (aLocalName
== nsGkAtoms::xmlns
) ==
4764 (aNamespaceID
== kNameSpaceID_XMLNS
);
4767 // If the prefix is non-null then the namespace must not be null.
4768 if (aNamespaceID
== kNameSpaceID_None
) {
4772 // If the namespace is the XMLNS namespace then the prefix must be xmlns,
4773 // but the localname must not be xmlns.
4774 if (aNamespaceID
== kNameSpaceID_XMLNS
) {
4775 return aPrefix
== nsGkAtoms::xmlns
&& aLocalName
!= nsGkAtoms::xmlns
;
4778 // If the namespace is not the XMLNS namespace then the prefix must not be
4780 // If the namespace is the XML namespace then the prefix can be anything.
4781 // If the namespace is not the XML namespace then the prefix must not be xml.
4782 return aPrefix
!= nsGkAtoms::xmlns
&&
4783 (aNamespaceID
== kNameSpaceID_XML
|| aPrefix
!= nsGkAtoms::xml
);
4786 already_AddRefed
<DocumentFragment
> nsContentUtils::CreateContextualFragment(
4787 nsINode
* aContextNode
, const nsAString
& aFragment
,
4788 bool aPreventScriptExecution
, ErrorResult
& aRv
) {
4789 if (!aContextNode
) {
4790 aRv
.Throw(NS_ERROR_INVALID_ARG
);
4794 // If we don't have a document here, we can't get the right security context
4795 // for compiling event handlers... so just bail out.
4796 RefPtr
<Document
> document
= aContextNode
->OwnerDoc();
4797 bool isHTML
= document
->IsHTMLDocument();
4800 RefPtr
<DocumentFragment
> frag
= new (document
->NodeInfoManager())
4801 DocumentFragment(document
->NodeInfoManager());
4803 Element
* element
= aContextNode
->GetAsElementOrParentElement();
4804 if (element
&& !element
->IsHTMLElement(nsGkAtoms::html
)) {
4805 aRv
= ParseFragmentHTML(
4806 aFragment
, frag
, element
->NodeInfo()->NameAtom(),
4807 element
->GetNameSpaceID(),
4808 (document
->GetCompatibilityMode() == eCompatibility_NavQuirks
),
4809 aPreventScriptExecution
);
4811 aRv
= ParseFragmentHTML(
4812 aFragment
, frag
, nsGkAtoms::body
, kNameSpaceID_XHTML
,
4813 (document
->GetCompatibilityMode() == eCompatibility_NavQuirks
),
4814 aPreventScriptExecution
);
4817 return frag
.forget();
4820 AutoTArray
<nsString
, 32> tagStack
;
4821 nsAutoString uriStr
, nameStr
;
4822 for (Element
* element
: aContextNode
->InclusiveAncestorsOfType
<Element
>()) {
4823 nsString
& tagName
= *tagStack
.AppendElement();
4824 // It mostly doesn't actually matter what tag name we use here: XML doesn't
4825 // have parsing that depends on the open tag stack, apart from namespace
4826 // declarations. So this whole tagStack bit is just there to get the right
4827 // namespace declarations to the XML parser. That said, the parser _is_
4828 // going to create elements with the tag names we provide here, so we need
4829 // to make sure they are not names that can trigger custom element
4830 // constructors. Just make up a name that is never going to be a valid
4831 // custom element name.
4833 // The principled way to do this would probably be to add a new FromParser
4834 // value and make sure we use it when creating the context elements, then
4835 // make sure we teach all FromParser consumers (and in particular the custom
4836 // element code) about it as needed. But right now the XML parser never
4837 // actually uses FromParser values other than NOT_FROM_PARSER, and changing
4838 // that is pretty complicated.
4839 tagName
.AssignLiteral("notacustomelement");
4841 // see if we need to add xmlns declarations
4842 uint32_t count
= element
->GetAttrCount();
4843 bool setDefaultNamespace
= false;
4847 for (index
= 0; index
< count
; index
++) {
4848 const BorrowedAttrInfo info
= element
->GetAttrInfoAt(index
);
4849 const nsAttrName
* name
= info
.mName
;
4850 if (name
->NamespaceEquals(kNameSpaceID_XMLNS
)) {
4851 info
.mValue
->ToString(uriStr
);
4853 // really want something like nsXMLContentSerializer::SerializeAttr
4854 tagName
.AppendLiteral(" xmlns"); // space important
4855 if (name
->GetPrefix()) {
4856 tagName
.Append(char16_t(':'));
4857 name
->LocalName()->ToString(nameStr
);
4858 tagName
.Append(nameStr
);
4860 setDefaultNamespace
= true;
4862 tagName
.AppendLiteral(R
"(=")");
4863 tagName.Append(uriStr);
4864 tagName.Append('"');
4869 if (!setDefaultNamespace) {
4870 mozilla::dom::NodeInfo* info = element->NodeInfo();
4871 if (!info->GetPrefixAtom() && info->NamespaceID() != kNameSpaceID_None) {
4872 // We have no namespace prefix, but have a namespace ID. Push
4873 // default namespace attr in, so that our kids will be in our
4875 info->GetNamespaceURI(uriStr);
4876 tagName.AppendLiteral(R"( xmlns=")");
4877 tagName.Append(uriStr);
4878 tagName.Append('"');
4883 RefPtr<DocumentFragment> frag;
4884 aRv = ParseFragmentXML(aFragment, document, tagStack, aPreventScriptExecution,
4885 -1, getter_AddRefs(frag));
4886 return frag.forget();
4890 void nsContentUtils::DropFragmentParsers() {
4891 NS_IF_RELEASE(sHTMLFragmentParser);
4892 NS_IF_RELEASE(sXMLFragmentParser);
4893 NS_IF_RELEASE(sXMLFragmentSink);
4897 void nsContentUtils::XPCOMShutdown() { nsContentUtils::DropFragmentParsers(); }
4899 /* Helper function to compuate Sanitization Flags for ParseFramentHTML/XML */
4900 uint32_t computeSanitizationFlags(nsIPrincipal* aPrincipal, int32_t aFlags) {
4901 uint32_t sanitizationFlags = 0;
4902 if (aPrincipal->IsSystemPrincipal()) {
4904 // if this is a chrome-privileged document and no explicit flags
4905 // were passed, then use this sanitization flags.
4906 sanitizationFlags = nsIParserUtils::SanitizerAllowStyle |
4907 nsIParserUtils::SanitizerAllowComments |
4908 nsIParserUtils::SanitizerDropForms |
4909 nsIParserUtils::SanitizerLogRemovals;
4911 // if the caller explicitly passes flags, then we use those
4912 // flags but additionally drop forms.
4913 sanitizationFlags = aFlags | nsIParserUtils::SanitizerDropForms;
4915 } else if (aFlags >= 0) {
4916 // aFlags by default is -1 and is only ever non equal to -1 if the
4917 // caller of ParseFragmentHTML/ParseFragmentXML is
4918 // ParserUtils::ParseFragment(). Only in that case we should use
4919 // the sanitization flags passed within aFlags.
4920 sanitizationFlags = aFlags;
4922 return sanitizationFlags;
4926 bool AllowsUnsanitizedContentForAboutNewTab(nsIPrincipal* aPrincipal) {
4927 if (StaticPrefs::dom_about_newtab_sanitization_enabled() ||
4928 !aPrincipal->SchemeIs("about
")) {
4931 uint32_t aboutModuleFlags = 0;
4932 aPrincipal->GetAboutModuleFlags(&aboutModuleFlags);
4933 return aboutModuleFlags & nsIAboutModule::ALLOW_UNSANITIZED_CONTENT;
4937 nsresult nsContentUtils::ParseFragmentHTML(
4938 const nsAString& aSourceBuffer, nsIContent* aTargetNode,
4939 nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks,
4940 bool aPreventScriptExecution, int32_t aFlags) {
4941 AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML
");
4943 if (nsContentUtils::sFragmentParsingActive) {
4944 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
4945 return NS_ERROR_DOM_INVALID_STATE_ERR;
4947 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
4948 nsContentUtils::sFragmentParsingActive = true;
4949 if (!sHTMLFragmentParser) {
4950 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
4951 // Now sHTMLFragmentParser owns the object
4954 nsCOMPtr<nsIPrincipal> nodePrincipal = aTargetNode->NodePrincipal();
4957 // aFlags should always be -1 unless the caller of ParseFragmentHTML
4958 // is ParserUtils::ParseFragment() which is the only caller that intends
4959 // sanitization. For all other callers we need to ensure to call
4960 // AuditParsingOfHTMLXMLFragments.
4962 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
4967 nsIContent* target = aTargetNode;
4969 RefPtr<Document> doc = aTargetNode->OwnerDoc();
4970 RefPtr<DocumentFragment> fragment;
4971 // We sanitize if the fragment occurs in a system privileged
4972 // context, an about: page, or if there are explicit sanitization flags.
4973 // Please note that about:blank and about:srcdoc inherit the security
4974 // context from the embedding context and hence are not loaded using
4975 // an about: scheme principal.
4976 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
4977 nodePrincipal->SchemeIs("about
") || aFlags >= 0;
4978 if (shouldSanitize &&
4979 !AllowsUnsanitizedContentForAboutNewTab(nodePrincipal)) {
4980 if (!doc->IsLoadedAsData()) {
4981 doc = nsContentUtils::CreateInertHTMLDocument(doc);
4983 return NS_ERROR_FAILURE;
4987 new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager());
4991 nsresult rv = sHTMLFragmentParser->ParseFragment(
4992 aSourceBuffer, target, aContextLocalName, aContextNamespace, aQuirks,
4993 aPreventScriptExecution);
4994 NS_ENSURE_SUCCESS(rv, rv);
4997 uint32_t sanitizationFlags =
4998 computeSanitizationFlags(nodePrincipal, aFlags);
4999 // Don't fire mutation events for nodes removed by the sanitizer.
5000 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
5001 nsTreeSanitizer sanitizer(sanitizationFlags);
5002 sanitizer.Sanitize(fragment);
5005 aTargetNode->AppendChild(*fragment, error);
5006 rv = error.StealNSResult();
5013 nsresult nsContentUtils::ParseDocumentHTML(
5014 const nsAString& aSourceBuffer, Document* aTargetDocument,
5015 bool aScriptingEnabledForNoscriptParsing) {
5016 AutoTimelineMarker m(aTargetDocument->GetDocShell(), "Parse HTML
");
5018 if (nsContentUtils::sFragmentParsingActive) {
5019 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
5020 return NS_ERROR_DOM_INVALID_STATE_ERR;
5022 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5023 nsContentUtils::sFragmentParsingActive = true;
5024 if (!sHTMLFragmentParser) {
5025 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
5026 // Now sHTMLFragmentParser owns the object
5028 nsresult rv = sHTMLFragmentParser->ParseDocument(
5029 aSourceBuffer, aTargetDocument, aScriptingEnabledForNoscriptParsing);
5034 nsresult nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
5035 Document* aDocument,
5036 nsTArray<nsString>& aTagStack,
5037 bool aPreventScriptExecution,
5039 DocumentFragment** aReturn) {
5040 AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML
");
5042 if (nsContentUtils::sFragmentParsingActive) {
5043 MOZ_ASSERT_UNREACHABLE("Re
-entrant fragment parsing attempted
.");
5044 return NS_ERROR_DOM_INVALID_STATE_ERR;
5046 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5047 nsContentUtils::sFragmentParsingActive = true;
5048 if (!sXMLFragmentParser) {
5049 nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID);
5050 parser.forget(&sXMLFragmentParser);
5051 // sXMLFragmentParser now owns the parser
5053 if (!sXMLFragmentSink) {
5054 NS_NewXMLFragmentContentSink(&sXMLFragmentSink);
5055 // sXMLFragmentSink now owns the sink
5057 nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink);
5058 MOZ_ASSERT(contentsink, "Sink doesn
't QI to nsIContentSink!");
5059 sXMLFragmentParser->SetContentSink(contentsink);
5061 RefPtr<Document> doc;
5062 nsCOMPtr<nsIPrincipal> nodePrincipal = aDocument->NodePrincipal();
5065 // aFlags should always be -1 unless the caller of ParseFragmentXML
5066 // is ParserUtils::ParseFragment() which is the only caller that intends
5067 // sanitization. For all other callers we need to ensure to call
5068 // AuditParsingOfHTMLXMLFragments.
5070 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
5075 // We sanitize if the fragment occurs in a system privileged
5076 // context, an about: page, or if there are explicit sanitization flags.
5077 // Please note that about:blank and about:srcdoc inherit the security
5078 // context from the embedding context and hence are not loaded using
5079 // an about: scheme principal.
5080 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
5081 nodePrincipal->SchemeIs("about") || aFlags >= 0;
5082 if (shouldSanitize && !aDocument->IsLoadedAsData()) {
5083 doc = nsContentUtils::CreateInertXMLDocument(aDocument);
5088 sXMLFragmentSink->SetTargetDocument(doc);
5089 sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution);
5091 nsresult rv = sXMLFragmentParser->ParseFragment(aSourceBuffer, aTagStack);
5092 if (NS_FAILED(rv)) {
5093 // Drop the fragment parser and sink that might be in an inconsistent state
5094 NS_IF_RELEASE(sXMLFragmentParser);
5095 NS_IF_RELEASE(sXMLFragmentSink);
5099 rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
5101 sXMLFragmentParser->Reset();
5102 NS_ENSURE_SUCCESS(rv, rv);
5104 if (shouldSanitize) {
5105 uint32_t sanitizationFlags =
5106 computeSanitizationFlags(nodePrincipal, aFlags);
5107 // Don't fire mutation events
for nodes removed by the sanitizer
.
5108 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker
;
5109 nsTreeSanitizer
sanitizer(sanitizationFlags
);
5110 sanitizer
.Sanitize(*aReturn
);
5117 nsresult
nsContentUtils::ConvertToPlainText(const nsAString
& aSourceBuffer
,
5118 nsAString
& aResultBuffer
,
5120 uint32_t aWrapCol
) {
5121 RefPtr
<Document
> document
= nsContentUtils::CreateInertHTMLDocument(nullptr);
5123 return NS_ERROR_FAILURE
;
5126 nsresult rv
= nsContentUtils::ParseDocumentHTML(
5127 aSourceBuffer
, document
,
5128 !(aFlags
& nsIDocumentEncoder::OutputNoScriptContent
));
5129 NS_ENSURE_SUCCESS(rv
, rv
);
5131 nsCOMPtr
<nsIDocumentEncoder
> encoder
= do_createDocumentEncoder("text/plain");
5133 rv
= encoder
->Init(document
, u
"text/plain"_ns
, aFlags
);
5134 NS_ENSURE_SUCCESS(rv
, rv
);
5136 encoder
->SetWrapColumn(aWrapCol
);
5138 return encoder
->EncodeToString(aResultBuffer
);
5141 static already_AddRefed
<Document
> CreateInertDocument(const Document
* aTemplate
,
5142 DocumentFlavor aFlavor
) {
5145 nsIScriptGlobalObject
* sgo
= aTemplate
->GetScriptHandlingObject(hasHad
);
5146 NS_ENSURE_TRUE(sgo
|| !hasHad
, nullptr);
5148 nsCOMPtr
<Document
> doc
;
5149 nsresult rv
= NS_NewDOMDocument(
5150 getter_AddRefs(doc
), u
""_ns
, u
""_ns
, nullptr,
5151 aTemplate
->GetDocumentURI(), aTemplate
->GetDocBaseURI(),
5152 aTemplate
->NodePrincipal(), true, sgo
, aFlavor
);
5153 if (NS_FAILED(rv
)) {
5156 return doc
.forget();
5158 nsCOMPtr
<nsIURI
> uri
;
5159 NS_NewURI(getter_AddRefs(uri
), "about:blank"_ns
);
5164 RefPtr
<NullPrincipal
> nullPrincipal
=
5165 NullPrincipal::CreateWithoutOriginAttributes();
5166 if (!nullPrincipal
) {
5170 nsCOMPtr
<Document
> doc
;
5172 NS_NewDOMDocument(getter_AddRefs(doc
), u
""_ns
, u
""_ns
, nullptr, uri
, uri
,
5173 nullPrincipal
, true, nullptr, aFlavor
);
5174 if (NS_FAILED(rv
)) {
5177 return doc
.forget();
5181 already_AddRefed
<Document
> nsContentUtils::CreateInertXMLDocument(
5182 const Document
* aTemplate
) {
5183 return CreateInertDocument(aTemplate
, DocumentFlavorXML
);
5187 already_AddRefed
<Document
> nsContentUtils::CreateInertHTMLDocument(
5188 const Document
* aTemplate
) {
5189 return CreateInertDocument(aTemplate
, DocumentFlavorHTML
);
5193 nsresult
nsContentUtils::SetNodeTextContent(nsIContent
* aContent
,
5194 const nsAString
& aValue
,
5196 // Fire DOMNodeRemoved mutation events before we do anything else.
5197 nsCOMPtr
<nsIContent
> owningContent
;
5199 // Batch possible DOMSubtreeModified events.
5200 mozAutoSubtreeModified
subtree(nullptr, nullptr);
5202 // Scope firing mutation events so that we don't carry any state that
5205 // We're relying on mozAutoSubtreeModified to keep a strong reference if
5207 Document
* doc
= aContent
->OwnerDoc();
5209 // Optimize the common case of there being no observers
5210 if (HasMutationListeners(doc
, NS_EVENT_BITS_MUTATION_NODEREMOVED
)) {
5211 subtree
.UpdateTarget(doc
, nullptr);
5212 owningContent
= aContent
;
5213 nsCOMPtr
<nsINode
> child
;
5214 bool skipFirst
= aTryReuse
;
5215 for (child
= aContent
->GetFirstChild();
5216 child
&& child
->GetParentNode() == aContent
;
5217 child
= child
->GetNextSibling()) {
5218 if (skipFirst
&& child
->IsText()) {
5222 nsContentUtils::MaybeFireNodeRemoved(child
, aContent
);
5227 // Might as well stick a batch around this since we're performing several
5229 mozAutoDocUpdate
updateBatch(aContent
->GetComposedDoc(), true);
5230 nsAutoMutationBatch mb
;
5232 if (aTryReuse
&& !aValue
.IsEmpty()) {
5233 // Let's remove nodes until we find a eTEXT.
5234 while (aContent
->HasChildren()) {
5235 nsIContent
* child
= aContent
->GetFirstChild();
5236 if (child
->IsText()) {
5239 aContent
->RemoveChildNode(child
, true);
5242 // If we have a node, it must be a eTEXT and we reuse it.
5243 if (aContent
->HasChildren()) {
5244 nsIContent
* child
= aContent
->GetFirstChild();
5245 nsresult rv
= child
->AsText()->SetText(aValue
, true);
5246 NS_ENSURE_SUCCESS(rv
, rv
);
5248 // All the following nodes, if they exist, must be deleted.
5249 while (nsIContent
* nextChild
= child
->GetNextSibling()) {
5250 aContent
->RemoveChildNode(nextChild
, true);
5254 if (aContent
->HasChildren()) {
5258 mb
.Init(aContent
, true, false);
5259 while (aContent
->HasChildren()) {
5260 aContent
->RemoveChildNode(aContent
->GetFirstChild(), true);
5265 if (aValue
.IsEmpty()) {
5269 RefPtr
<nsTextNode
> textContent
= new (aContent
->NodeInfo()->NodeInfoManager())
5270 nsTextNode(aContent
->NodeInfo()->NodeInfoManager());
5272 textContent
->SetText(aValue
, true);
5274 nsresult rv
= aContent
->AppendChildTo(textContent
, true);
5279 static bool AppendNodeTextContentsRecurse(nsINode
* aNode
, nsAString
& aResult
,
5280 const fallible_t
& aFallible
) {
5281 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5282 child
= child
->GetNextSibling()) {
5283 if (child
->IsElement()) {
5284 bool ok
= AppendNodeTextContentsRecurse(child
, aResult
, aFallible
);
5288 } else if (Text
* text
= child
->GetAsText()) {
5289 bool ok
= text
->AppendTextTo(aResult
, aFallible
);
5300 bool nsContentUtils::AppendNodeTextContent(nsINode
* aNode
, bool aDeep
,
5302 const fallible_t
& aFallible
) {
5303 if (Text
* text
= aNode
->GetAsText()) {
5304 return text
->AppendTextTo(aResult
, aFallible
);
5307 return AppendNodeTextContentsRecurse(aNode
, aResult
, aFallible
);
5310 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5311 child
= child
->GetNextSibling()) {
5312 if (Text
* text
= child
->GetAsText()) {
5313 bool ok
= text
->AppendTextTo(aResult
, fallible
);
5322 bool nsContentUtils::HasNonEmptyTextContent(
5323 nsINode
* aNode
, TextContentDiscoverMode aDiscoverMode
) {
5324 for (nsIContent
* child
= aNode
->GetFirstChild(); child
;
5325 child
= child
->GetNextSibling()) {
5326 if (child
->IsText() && child
->TextLength() > 0) {
5330 if (aDiscoverMode
== eRecurseIntoChildren
&&
5331 HasNonEmptyTextContent(child
, aDiscoverMode
)) {
5340 bool nsContentUtils::IsInSameAnonymousTree(const nsINode
* aNode
,
5341 const nsIContent
* aContent
) {
5342 MOZ_ASSERT(aNode
, "Must have a node to work with");
5343 MOZ_ASSERT(aContent
, "Must have a content to work with");
5345 if (aNode
->IsInNativeAnonymousSubtree() !=
5346 aContent
->IsInNativeAnonymousSubtree()) {
5350 if (aNode
->IsInNativeAnonymousSubtree()) {
5351 return aContent
->GetClosestNativeAnonymousSubtreeRoot() ==
5352 aNode
->GetClosestNativeAnonymousSubtreeRoot();
5355 // FIXME: This doesn't deal with disconnected nodes whatsoever, but it didn't
5356 // use to either. Maybe that's fine.
5357 return aNode
->GetContainingShadow() == aContent
->GetContainingShadow();
5361 bool nsContentUtils::IsInInteractiveHTMLContent(const Element
* aElement
,
5362 const Element
* aStop
) {
5363 const Element
* element
= aElement
;
5364 while (element
&& element
!= aStop
) {
5365 if (element
->IsInteractiveHTMLContent()) {
5368 element
= element
->GetFlattenedTreeParentElement();
5374 void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling
) {
5375 IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling
);
5379 bool nsContentUtils::SchemeIs(nsIURI
* aURI
, const char* aScheme
) {
5380 nsCOMPtr
<nsIURI
> baseURI
= NS_GetInnermostURI(aURI
);
5381 NS_ENSURE_TRUE(baseURI
, false);
5382 return baseURI
->SchemeIs(aScheme
);
5385 bool nsContentUtils::IsExpandedPrincipal(nsIPrincipal
* aPrincipal
) {
5386 nsCOMPtr
<nsIExpandedPrincipal
> ep
= do_QueryInterface(aPrincipal
);
5390 bool nsContentUtils::IsSystemOrExpandedPrincipal(nsIPrincipal
* aPrincipal
) {
5391 return (aPrincipal
&& aPrincipal
->IsSystemPrincipal()) ||
5392 IsExpandedPrincipal(aPrincipal
);
5395 nsIPrincipal
* nsContentUtils::GetSystemPrincipal() {
5396 MOZ_ASSERT(IsInitialized());
5397 return sSystemPrincipal
;
5400 bool nsContentUtils::CombineResourcePrincipals(
5401 nsCOMPtr
<nsIPrincipal
>* aResourcePrincipal
, nsIPrincipal
* aExtraPrincipal
) {
5402 if (!aExtraPrincipal
) {
5405 if (!*aResourcePrincipal
) {
5406 *aResourcePrincipal
= aExtraPrincipal
;
5409 if (*aResourcePrincipal
== aExtraPrincipal
) {
5414 (*aResourcePrincipal
)->Subsumes(aExtraPrincipal
, &subsumes
)) &&
5418 *aResourcePrincipal
= sSystemPrincipal
;
5423 void nsContentUtils::TriggerLink(nsIContent
* aContent
, nsIURI
* aLinkURI
,
5424 const nsString
& aTargetSpec
, bool aClick
,
5426 MOZ_ASSERT(aLinkURI
, "No link URI");
5428 if (aContent
->IsEditable() || !aContent
->OwnerDoc()->LinkHandlingEnabled()) {
5432 nsCOMPtr
<nsIDocShell
> docShell
= aContent
->OwnerDoc()->GetDocShell();
5438 nsDocShell::Cast(docShell
)->OnOverLink(aContent
, aLinkURI
, aTargetSpec
);
5442 // Check that this page is allowed to load this URI.
5443 nsresult proceed
= NS_OK
;
5445 if (sSecurityManager
) {
5446 uint32_t flag
= static_cast<uint32_t>(nsIScriptSecurityManager::STANDARD
);
5447 proceed
= sSecurityManager
->CheckLoadURIWithPrincipal(
5448 aContent
->NodePrincipal(), aLinkURI
, flag
,
5449 aContent
->OwnerDoc()->InnerWindowID());
5452 // Only pass off the click event if the script security manager says it's ok.
5453 // We need to rest aTargetSpec for forced downloads.
5454 if (NS_SUCCEEDED(proceed
)) {
5455 // A link/area element with a download attribute is allowed to set
5456 // a pseudo Content-Disposition header.
5457 // For security reasons we only allow websites to declare same-origin
5458 // resources as downloadable. If this check fails we will just do the normal
5459 // thing (i.e. navigate to the resource).
5460 nsAutoString fileName
;
5461 if ((!aContent
->IsHTMLElement(nsGkAtoms::a
) &&
5462 !aContent
->IsHTMLElement(nsGkAtoms::area
) &&
5463 !aContent
->IsSVGElement(nsGkAtoms::a
)) ||
5464 !aContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::download
,
5466 NS_FAILED(aContent
->NodePrincipal()->CheckMayLoad(aLinkURI
, true))) {
5467 fileName
.SetIsVoid(true); // No actionable download attribute was found.
5470 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
= aContent
->NodePrincipal();
5471 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= aContent
->GetCsp();
5473 // Sanitize fileNames containing null characters by replacing them with
5475 if (!fileName
.IsVoid()) {
5476 fileName
.ReplaceChar(char16_t(0), '_');
5478 nsDocShell::Cast(docShell
)->OnLinkClick(
5479 aContent
, aLinkURI
, fileName
.IsVoid() ? aTargetSpec
: u
""_ns
, fileName
,
5480 nullptr, nullptr, UserActivation::IsHandlingUserInput(), aIsTrusted
,
5481 triggeringPrincipal
, csp
);
5486 void nsContentUtils::GetLinkLocation(Element
* aElement
,
5487 nsString
& aLocationString
) {
5488 nsCOMPtr
<nsIURI
> hrefURI
= aElement
->GetHrefURI();
5490 nsAutoCString specUTF8
;
5491 nsresult rv
= hrefURI
->GetSpec(specUTF8
);
5492 if (NS_SUCCEEDED(rv
)) CopyUTF8toUTF16(specUTF8
, aLocationString
);
5497 nsIWidget
* nsContentUtils::GetTopLevelWidget(nsIWidget
* aWidget
) {
5498 if (!aWidget
) return nullptr;
5500 return aWidget
->GetTopLevelWidget();
5504 const nsDependentString
nsContentUtils::GetLocalizedEllipsis() {
5505 static char16_t sBuf
[4] = {0, 0, 0, 0};
5507 if (!SpoofLocaleEnglish()) {
5509 Preferences::GetLocalizedString("intl.ellipsis", tmp
);
5511 std::min(uint32_t(tmp
.Length()), uint32_t(ArrayLength(sBuf
) - 1));
5512 CopyUnicodeTo(tmp
, 0, sBuf
, len
);
5514 if (!sBuf
[0]) sBuf
[0] = char16_t(0x2026);
5516 return nsDependentString(sBuf
);
5520 void nsContentUtils::AddScriptBlocker() {
5521 MOZ_ASSERT(NS_IsMainThread());
5522 if (!sScriptBlockerCount
) {
5523 MOZ_ASSERT(sRunnersCountAtFirstBlocker
== 0,
5524 "Should not already have a count");
5525 sRunnersCountAtFirstBlocker
=
5526 sBlockedScriptRunners
? sBlockedScriptRunners
->Length() : 0;
5528 ++sScriptBlockerCount
;
5532 static bool sRemovingScriptBlockers
= false;
5536 void nsContentUtils::RemoveScriptBlocker() {
5537 MOZ_ASSERT(NS_IsMainThread());
5538 MOZ_ASSERT(!sRemovingScriptBlockers
);
5539 NS_ASSERTION(sScriptBlockerCount
!= 0, "Negative script blockers");
5540 --sScriptBlockerCount
;
5541 if (sScriptBlockerCount
) {
5545 if (!sBlockedScriptRunners
) {
5549 uint32_t firstBlocker
= sRunnersCountAtFirstBlocker
;
5550 uint32_t lastBlocker
= sBlockedScriptRunners
->Length();
5551 uint32_t originalFirstBlocker
= firstBlocker
;
5552 uint32_t blockersCount
= lastBlocker
- firstBlocker
;
5553 sRunnersCountAtFirstBlocker
= 0;
5554 NS_ASSERTION(firstBlocker
<= lastBlocker
, "bad sRunnersCountAtFirstBlocker");
5556 while (firstBlocker
< lastBlocker
) {
5557 nsCOMPtr
<nsIRunnable
> runnable
;
5558 runnable
.swap((*sBlockedScriptRunners
)[firstBlocker
]);
5561 // Calling the runnable can reenter us
5563 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable
);
5566 // So can dropping the reference to the runnable
5569 NS_ASSERTION(sRunnersCountAtFirstBlocker
== 0, "Bad count");
5570 NS_ASSERTION(!sScriptBlockerCount
, "This is really bad");
5573 AutoRestore
<bool> removingScriptBlockers(sRemovingScriptBlockers
);
5574 sRemovingScriptBlockers
= true;
5576 sBlockedScriptRunners
->RemoveElementsAt(originalFirstBlocker
, blockersCount
);
5580 already_AddRefed
<nsPIDOMWindowOuter
>
5581 nsContentUtils::GetMostRecentNonPBWindow() {
5582 nsCOMPtr
<nsIWindowMediator
> wm
= do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
);
5584 nsCOMPtr
<mozIDOMWindowProxy
> window
;
5585 wm
->GetMostRecentNonPBWindow(u
"navigator:browser", getter_AddRefs(window
));
5586 nsCOMPtr
<nsPIDOMWindowOuter
> pwindow
;
5587 pwindow
= do_QueryInterface(window
);
5589 return pwindow
.forget();
5593 void nsContentUtils::WarnScriptWasIgnored(Document
* aDocument
) {
5595 bool privateBrowsing
= false;
5596 bool chromeContext
= false;
5599 nsCOMPtr
<nsIURI
> uri
= aDocument
->GetDocumentURI();
5601 msg
.Append(NS_ConvertUTF8toUTF16(uri
->GetSpecOrDefault()));
5602 msg
.AppendLiteral(" : ");
5605 !!aDocument
->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId
;
5606 chromeContext
= aDocument
->NodePrincipal()->IsSystemPrincipal();
5610 "Unable to run script because scripts are blocked internally.");
5611 LogSimpleConsoleError(msg
, "DOM", privateBrowsing
, chromeContext
);
5615 void nsContentUtils::AddScriptRunner(already_AddRefed
<nsIRunnable
> aRunnable
) {
5616 nsCOMPtr
<nsIRunnable
> runnable
= aRunnable
;
5621 if (sScriptBlockerCount
) {
5622 sBlockedScriptRunners
->AppendElement(runnable
.forget());
5626 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable
);
5631 void nsContentUtils::AddScriptRunner(nsIRunnable
* aRunnable
) {
5632 nsCOMPtr
<nsIRunnable
> runnable
= aRunnable
;
5633 AddScriptRunner(runnable
.forget());
5636 /* static */ bool nsContentUtils::IsSafeToRunScript() {
5637 MOZ_ASSERT(NS_IsMainThread(),
5638 "This static variable only makes sense on the main thread!");
5639 return sScriptBlockerCount
== 0;
5643 void nsContentUtils::RunInStableState(already_AddRefed
<nsIRunnable
> aRunnable
) {
5644 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
5645 CycleCollectedJSContext::Get()->RunInStableState(std::move(aRunnable
));
5649 void nsContentUtils::AddPendingIDBTransaction(
5650 already_AddRefed
<nsIRunnable
> aTransaction
) {
5651 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
5652 CycleCollectedJSContext::Get()->AddPendingIDBTransaction(
5653 std::move(aTransaction
));
5657 bool nsContentUtils::IsInStableOrMetaStableState() {
5658 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
5659 return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState();
5663 void nsContentUtils::HidePopupsInDocument(Document
* aDocument
) {
5665 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
5666 if (pm
&& aDocument
) {
5667 nsCOMPtr
<nsIDocShellTreeItem
> docShellToHide
= aDocument
->GetDocShell();
5668 if (docShellToHide
) pm
->HidePopupsInDocShell(docShellToHide
);
5674 already_AddRefed
<nsIDragSession
> nsContentUtils::GetDragSession() {
5675 nsCOMPtr
<nsIDragSession
> dragSession
;
5676 nsCOMPtr
<nsIDragService
> dragService
=
5677 do_GetService("@mozilla.org/widget/dragservice;1");
5678 if (dragService
) dragService
->GetCurrentSession(getter_AddRefs(dragSession
));
5679 return dragSession
.forget();
5683 nsresult
nsContentUtils::SetDataTransferInEvent(WidgetDragEvent
* aDragEvent
) {
5684 if (aDragEvent
->mDataTransfer
|| !aDragEvent
->IsTrusted()) {
5688 // For dragstart events, the data transfer object is
5689 // created before the event fires, so it should already be set. For other
5690 // drag events, get the object from the drag session.
5691 NS_ASSERTION(aDragEvent
->mMessage
!= eDragStart
,
5692 "draggesture event created without a dataTransfer");
5694 nsCOMPtr
<nsIDragSession
> dragSession
= GetDragSession();
5695 NS_ENSURE_TRUE(dragSession
, NS_OK
); // no drag in progress
5697 RefPtr
<DataTransfer
> initialDataTransfer
= dragSession
->GetDataTransfer();
5698 if (!initialDataTransfer
) {
5699 // A dataTransfer won't exist when a drag was started by some other
5700 // means, for instance calling the drag service directly, or a drag
5701 // from another application. In either case, a new dataTransfer should
5702 // be created that reflects the data.
5703 initialDataTransfer
=
5704 new DataTransfer(aDragEvent
->mTarget
, aDragEvent
->mMessage
, true, -1);
5706 // now set it in the drag session so we don't need to create it again
5707 dragSession
->SetDataTransfer(initialDataTransfer
);
5710 bool isCrossDomainSubFrameDrop
= false;
5711 if (aDragEvent
->mMessage
== eDrop
) {
5712 isCrossDomainSubFrameDrop
= CheckForSubFrameDrop(dragSession
, aDragEvent
);
5715 // each event should use a clone of the original dataTransfer.
5716 initialDataTransfer
->Clone(
5717 aDragEvent
->mTarget
, aDragEvent
->mMessage
, aDragEvent
->mUserCancelled
,
5718 isCrossDomainSubFrameDrop
, getter_AddRefs(aDragEvent
->mDataTransfer
));
5719 if (NS_WARN_IF(!aDragEvent
->mDataTransfer
)) {
5720 return NS_ERROR_OUT_OF_MEMORY
;
5723 // for the dragenter and dragover events, initialize the drop effect
5724 // from the drop action, which platform specific widget code sets before
5725 // the event is fired based on the keyboard state.
5726 if (aDragEvent
->mMessage
== eDragEnter
|| aDragEvent
->mMessage
== eDragOver
) {
5728 dragSession
->GetDragAction(&action
);
5729 uint32_t effectAllowed
= aDragEvent
->mDataTransfer
->EffectAllowedInt();
5730 aDragEvent
->mDataTransfer
->SetDropEffectInt(
5731 FilterDropEffect(action
, effectAllowed
));
5732 } else if (aDragEvent
->mMessage
== eDrop
||
5733 aDragEvent
->mMessage
== eDragEnd
) {
5734 // For the drop and dragend events, set the drop effect based on the
5735 // last value that the dropEffect had. This will have been set in
5736 // EventStateManager::PostHandleEvent for the last dragenter or
5738 aDragEvent
->mDataTransfer
->SetDropEffectInt(
5739 initialDataTransfer
->DropEffectInt());
5746 uint32_t nsContentUtils::FilterDropEffect(uint32_t aAction
,
5747 uint32_t aEffectAllowed
) {
5748 // It is possible for the drag action to include more than one action, but
5749 // the widget code which sets the action from the keyboard state should only
5750 // be including one. If multiple actions were set, we just consider them in
5751 // the following order:
5753 if (aAction
& nsIDragService::DRAGDROP_ACTION_COPY
)
5754 aAction
= nsIDragService::DRAGDROP_ACTION_COPY
;
5755 else if (aAction
& nsIDragService::DRAGDROP_ACTION_LINK
)
5756 aAction
= nsIDragService::DRAGDROP_ACTION_LINK
;
5757 else if (aAction
& nsIDragService::DRAGDROP_ACTION_MOVE
)
5758 aAction
= nsIDragService::DRAGDROP_ACTION_MOVE
;
5760 // Filter the action based on the effectAllowed. If the effectAllowed
5761 // doesn't include the action, then that action cannot be done, so adjust
5762 // the action to something that is allowed. For a copy, adjust to move or
5763 // link. For a move, adjust to copy or link. For a link, adjust to move or
5764 // link. Otherwise, use none.
5765 if (aAction
& aEffectAllowed
||
5766 aEffectAllowed
== nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
)
5768 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_MOVE
)
5769 return nsIDragService::DRAGDROP_ACTION_MOVE
;
5770 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_COPY
)
5771 return nsIDragService::DRAGDROP_ACTION_COPY
;
5772 if (aEffectAllowed
& nsIDragService::DRAGDROP_ACTION_LINK
)
5773 return nsIDragService::DRAGDROP_ACTION_LINK
;
5774 return nsIDragService::DRAGDROP_ACTION_NONE
;
5778 bool nsContentUtils::CheckForSubFrameDrop(nsIDragSession
* aDragSession
,
5779 WidgetDragEvent
* aDropEvent
) {
5780 nsCOMPtr
<nsIContent
> target
= do_QueryInterface(aDropEvent
->mOriginalTarget
);
5785 // Always allow dropping onto chrome shells.
5786 BrowsingContext
* targetBC
= target
->OwnerDoc()->GetBrowsingContext();
5787 if (targetBC
->IsChrome()) {
5791 // If there is no source node, then this is a drag from another
5792 // application, which should be allowed.
5793 RefPtr
<Document
> doc(aDragSession
->GetSourceDocument());
5794 if (doc
&& doc
->GetBrowsingContext()) {
5795 // Get each successive parent of the source document and compare it to
5796 // the drop document. If they match, then this is a drag from a child frame.
5797 for (BrowsingContext
* bc
= doc
->GetBrowsingContext()->GetParent(); bc
;
5798 bc
= bc
->GetParent()) {
5799 if (bc
== targetBC
) {
5800 // The drag is from a descendant frame.
5810 bool nsContentUtils::URIIsLocalFile(nsIURI
* aURI
) {
5812 nsCOMPtr
<nsINetUtil
> util
= do_QueryInterface(sIOService
);
5814 // Important: we do NOT test the entire URI chain here!
5816 NS_SUCCEEDED(util
->ProtocolHasFlags(
5817 aURI
, nsIProtocolHandler::URI_IS_LOCAL_FILE
, &isFile
)) &&
5822 JSContext
* nsContentUtils::GetCurrentJSContext() {
5823 MOZ_ASSERT(IsInitialized());
5824 if (!IsJSAPIActive()) {
5827 return danger::GetJSContext();
5830 template <typename StringType
, typename CharType
>
5831 void _ASCIIToLowerInSitu(StringType
& aStr
) {
5832 CharType
* iter
= aStr
.BeginWriting();
5833 CharType
* end
= aStr
.EndWriting();
5834 MOZ_ASSERT(iter
&& end
);
5836 while (iter
!= end
) {
5838 if (c
>= 'A' && c
<= 'Z') {
5839 *iter
= c
+ ('a' - 'A');
5846 void nsContentUtils::ASCIIToLower(nsAString
& aStr
) {
5847 return _ASCIIToLowerInSitu
<nsAString
, char16_t
>(aStr
);
5851 void nsContentUtils::ASCIIToLower(nsACString
& aStr
) {
5852 return _ASCIIToLowerInSitu
<nsACString
, char>(aStr
);
5855 template <typename StringType
, typename CharType
>
5856 void _ASCIIToLowerCopy(const StringType
& aSource
, StringType
& aDest
) {
5857 uint32_t len
= aSource
.Length();
5858 aDest
.SetLength(len
);
5859 MOZ_ASSERT(aDest
.Length() == len
);
5861 CharType
* dest
= aDest
.BeginWriting();
5864 const CharType
* iter
= aSource
.BeginReading();
5865 const CharType
* end
= aSource
.EndReading();
5866 while (iter
!= end
) {
5868 *dest
= (c
>= 'A' && c
<= 'Z') ? c
+ ('a' - 'A') : c
;
5875 void nsContentUtils::ASCIIToLower(const nsAString
& aSource
, nsAString
& aDest
) {
5876 return _ASCIIToLowerCopy
<nsAString
, char16_t
>(aSource
, aDest
);
5880 void nsContentUtils::ASCIIToLower(const nsACString
& aSource
,
5881 nsACString
& aDest
) {
5882 return _ASCIIToLowerCopy
<nsACString
, char>(aSource
, aDest
);
5885 template <typename StringType
, typename CharType
>
5886 void _ASCIIToUpperInSitu(StringType
& aStr
) {
5887 CharType
* iter
= aStr
.BeginWriting();
5888 CharType
* end
= aStr
.EndWriting();
5889 MOZ_ASSERT(iter
&& end
);
5891 while (iter
!= end
) {
5893 if (c
>= 'a' && c
<= 'z') {
5894 *iter
= c
+ ('A' - 'a');
5901 void nsContentUtils::ASCIIToUpper(nsAString
& aStr
) {
5902 return _ASCIIToUpperInSitu
<nsAString
, char16_t
>(aStr
);
5906 void nsContentUtils::ASCIIToUpper(nsACString
& aStr
) {
5907 return _ASCIIToUpperInSitu
<nsACString
, char>(aStr
);
5910 template <typename StringType
, typename CharType
>
5911 void _ASCIIToUpperCopy(const StringType
& aSource
, StringType
& aDest
) {
5912 uint32_t len
= aSource
.Length();
5913 aDest
.SetLength(len
);
5914 MOZ_ASSERT(aDest
.Length() == len
);
5916 CharType
* dest
= aDest
.BeginWriting();
5919 const CharType
* iter
= aSource
.BeginReading();
5920 const CharType
* end
= aSource
.EndReading();
5921 while (iter
!= end
) {
5923 *dest
= (c
>= 'a' && c
<= 'z') ? c
+ ('A' - 'a') : c
;
5930 void nsContentUtils::ASCIIToUpper(const nsAString
& aSource
, nsAString
& aDest
) {
5931 return _ASCIIToUpperCopy
<nsAString
, char16_t
>(aSource
, aDest
);
5935 void nsContentUtils::ASCIIToUpper(const nsACString
& aSource
,
5936 nsACString
& aDest
) {
5937 return _ASCIIToUpperCopy
<nsACString
, char>(aSource
, aDest
);
5941 bool nsContentUtils::EqualsIgnoreASCIICase(nsAtom
* aAtom1
, nsAtom
* aAtom2
) {
5942 if (aAtom1
== aAtom2
) {
5946 // If both are ascii lowercase already, we know that the slow comparison
5947 // below is going to return false.
5948 if (aAtom1
->IsAsciiLowercase() && aAtom2
->IsAsciiLowercase()) {
5952 return EqualsIgnoreASCIICase(nsDependentAtomString(aAtom1
),
5953 nsDependentAtomString(aAtom2
));
5957 bool nsContentUtils::EqualsIgnoreASCIICase(const nsAString
& aStr1
,
5958 const nsAString
& aStr2
) {
5959 uint32_t len
= aStr1
.Length();
5960 if (len
!= aStr2
.Length()) {
5964 const char16_t
* str1
= aStr1
.BeginReading();
5965 const char16_t
* str2
= aStr2
.BeginReading();
5966 const char16_t
* end
= str1
+ len
;
5968 while (str1
< end
) {
5969 char16_t c1
= *str1
++;
5970 char16_t c2
= *str2
++;
5972 // First check if any bits other than the 0x0020 differs
5973 if ((c1
^ c2
) & 0xffdf) {
5977 // We know they can only differ in the 0x0020 bit.
5978 // Likely the two chars are the same, so check that first
5980 // They do differ, but since it's only in the 0x0020 bit, check if it's
5981 // the same ascii char, but just differing in case
5982 char16_t c1Upper
= c1
& 0xffdf;
5983 if (!('A' <= c1Upper
&& c1Upper
<= 'Z')) {
5993 bool nsContentUtils::StringContainsASCIIUpper(const nsAString
& aStr
) {
5994 const char16_t
* iter
= aStr
.BeginReading();
5995 const char16_t
* end
= aStr
.EndReading();
5996 while (iter
!= end
) {
5998 if (c
>= 'A' && c
<= 'Z') {
6008 nsIInterfaceRequestor
* nsContentUtils::SameOriginChecker() {
6009 if (!sSameOriginChecker
) {
6010 sSameOriginChecker
= new SameOriginCheckerImpl();
6011 NS_ADDREF(sSameOriginChecker
);
6013 return sSameOriginChecker
;
6017 nsresult
nsContentUtils::CheckSameOrigin(nsIChannel
* aOldChannel
,
6018 nsIChannel
* aNewChannel
) {
6019 if (!nsContentUtils::GetSecurityManager()) return NS_ERROR_NOT_AVAILABLE
;
6021 nsCOMPtr
<nsIPrincipal
> oldPrincipal
;
6022 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
6023 aOldChannel
, getter_AddRefs(oldPrincipal
));
6025 nsCOMPtr
<nsIURI
> newURI
;
6026 aNewChannel
->GetURI(getter_AddRefs(newURI
));
6027 nsCOMPtr
<nsIURI
> newOriginalURI
;
6028 aNewChannel
->GetOriginalURI(getter_AddRefs(newOriginalURI
));
6030 NS_ENSURE_STATE(oldPrincipal
&& newURI
&& newOriginalURI
);
6032 nsresult rv
= oldPrincipal
->CheckMayLoad(newURI
, false);
6033 if (NS_SUCCEEDED(rv
) && newOriginalURI
!= newURI
) {
6034 rv
= oldPrincipal
->CheckMayLoad(newOriginalURI
, false);
6040 NS_IMPL_ISUPPORTS(SameOriginCheckerImpl
, nsIChannelEventSink
,
6041 nsIInterfaceRequestor
)
6044 SameOriginCheckerImpl::AsyncOnChannelRedirect(
6045 nsIChannel
* aOldChannel
, nsIChannel
* aNewChannel
, uint32_t aFlags
,
6046 nsIAsyncVerifyRedirectCallback
* cb
) {
6047 MOZ_ASSERT(aNewChannel
, "Redirecting to null channel?");
6049 nsresult rv
= nsContentUtils::CheckSameOrigin(aOldChannel
, aNewChannel
);
6050 if (NS_SUCCEEDED(rv
)) {
6051 cb
->OnRedirectVerifyCallback(NS_OK
);
6058 SameOriginCheckerImpl::GetInterface(const nsIID
& aIID
, void** aResult
) {
6059 return QueryInterface(aIID
, aResult
);
6063 nsresult
nsContentUtils::GetASCIIOrigin(nsIURI
* aURI
, nsACString
& aOrigin
) {
6064 MOZ_ASSERT(aURI
, "missing uri");
6066 // For Blob URI, the path is the URL of the owning page.
6067 if (aURI
->SchemeIs(BLOBURI_SCHEME
)) {
6069 nsresult rv
= aURI
->GetPathQueryRef(path
);
6070 NS_ENSURE_SUCCESS(rv
, rv
);
6072 nsCOMPtr
<nsIURI
> uri
;
6073 rv
= NS_NewURI(getter_AddRefs(uri
), path
);
6074 if (NS_FAILED(rv
)) {
6075 aOrigin
.AssignLiteral("null");
6079 return GetASCIIOrigin(uri
, aOrigin
);
6084 nsCOMPtr
<nsIURI
> uri
= NS_GetInnermostURI(aURI
);
6085 NS_ENSURE_TRUE(uri
, NS_ERROR_UNEXPECTED
);
6088 nsresult rv
= uri
->GetAsciiHost(host
);
6090 if (NS_SUCCEEDED(rv
) && !host
.IsEmpty()) {
6091 nsAutoCString userPass
;
6092 uri
->GetUserPass(userPass
);
6094 nsAutoCString prePath
;
6095 if (!userPass
.IsEmpty()) {
6096 rv
= NS_MutateURI(uri
).SetUserPass(""_ns
).Finalize(uri
);
6097 NS_ENSURE_SUCCESS(rv
, rv
);
6100 rv
= uri
->GetPrePath(prePath
);
6101 NS_ENSURE_SUCCESS(rv
, rv
);
6105 aOrigin
.AssignLiteral("null");
6112 nsresult
nsContentUtils::GetUTFOrigin(nsIPrincipal
* aPrincipal
,
6113 nsAString
& aOrigin
) {
6114 MOZ_ASSERT(aPrincipal
, "missing principal");
6117 nsAutoCString asciiOrigin
;
6119 nsresult rv
= aPrincipal
->GetAsciiOrigin(asciiOrigin
);
6120 if (NS_FAILED(rv
)) {
6121 asciiOrigin
.AssignLiteral("null");
6124 CopyUTF8toUTF16(asciiOrigin
, aOrigin
);
6129 nsresult
nsContentUtils::GetUTFOrigin(nsIURI
* aURI
, nsAString
& aOrigin
) {
6130 MOZ_ASSERT(aURI
, "missing uri");
6133 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
6134 // Check if either URI has a special origin.
6135 nsCOMPtr
<nsIURIWithSpecialOrigin
> uriWithSpecialOrigin
=
6136 do_QueryInterface(aURI
);
6137 if (uriWithSpecialOrigin
) {
6138 nsCOMPtr
<nsIURI
> origin
;
6139 rv
= uriWithSpecialOrigin
->GetOrigin(getter_AddRefs(origin
));
6140 NS_ENSURE_SUCCESS(rv
, rv
);
6142 return GetUTFOrigin(origin
, aOrigin
);
6146 nsAutoCString asciiOrigin
;
6147 rv
= GetASCIIOrigin(aURI
, asciiOrigin
);
6148 NS_ENSURE_SUCCESS(rv
, rv
);
6150 CopyUTF8toUTF16(asciiOrigin
, aOrigin
);
6155 bool nsContentUtils::CheckMayLoad(nsIPrincipal
* aPrincipal
,
6156 nsIChannel
* aChannel
,
6157 bool aAllowIfInheritsPrincipal
) {
6158 nsCOMPtr
<nsIURI
> channelURI
;
6159 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
6160 NS_ENSURE_SUCCESS(rv
, false);
6162 return NS_SUCCEEDED(
6163 aPrincipal
->CheckMayLoad(channelURI
, aAllowIfInheritsPrincipal
));
6167 bool nsContentUtils::CanAccessNativeAnon() {
6168 return LegacyIsCallerChromeOrNativeCode();
6172 nsresult
nsContentUtils::DispatchXULCommand(nsIContent
* aTarget
, bool aTrusted
,
6173 Event
* aSourceEvent
,
6174 PresShell
* aPresShell
, bool aCtrl
,
6175 bool aAlt
, bool aShift
, bool aMeta
,
6176 uint16_t aInputSource
) {
6177 NS_ENSURE_STATE(aTarget
);
6178 Document
* doc
= aTarget
->OwnerDoc();
6179 nsPresContext
* presContext
= doc
->GetPresContext();
6181 RefPtr
<XULCommandEvent
> xulCommand
=
6182 new XULCommandEvent(doc
, presContext
, nullptr);
6183 xulCommand
->InitCommandEvent(u
"command"_ns
, true, true,
6184 nsGlobalWindowInner::Cast(doc
->GetInnerWindow()),
6185 0, aCtrl
, aAlt
, aShift
, aMeta
, aSourceEvent
,
6186 aInputSource
, IgnoreErrors());
6189 nsEventStatus status
= nsEventStatus_eIgnore
;
6190 return aPresShell
->HandleDOMEventWithTarget(aTarget
, xulCommand
, &status
);
6194 aTarget
->DispatchEvent(*xulCommand
, rv
);
6195 return rv
.StealNSResult();
6199 nsresult
nsContentUtils::WrapNative(JSContext
* cx
, nsISupports
* native
,
6200 nsWrapperCache
* cache
, const nsIID
* aIID
,
6201 JS::MutableHandle
<JS::Value
> vp
,
6202 bool aAllowWrapping
) {
6203 MOZ_ASSERT(cx
== GetCurrentJSContext());
6211 JSObject
* wrapper
= xpc_FastGetCachedWrapper(cx
, cache
, vp
);
6216 NS_ENSURE_TRUE(sXPConnect
, NS_ERROR_UNEXPECTED
);
6218 if (!NS_IsMainThread()) {
6222 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
6223 nsresult rv
= sXPConnect
->WrapNativeToJSVal(cx
, scope
, native
, cache
, aIID
,
6224 aAllowWrapping
, vp
);
6228 nsresult
nsContentUtils::CreateArrayBuffer(JSContext
* aCx
,
6229 const nsACString
& aData
,
6230 JSObject
** aResult
) {
6232 return NS_ERROR_FAILURE
;
6235 size_t dataLen
= aData
.Length();
6236 *aResult
= JS::NewArrayBuffer(aCx
, dataLen
);
6238 return NS_ERROR_FAILURE
;
6242 NS_ASSERTION(JS::IsArrayBufferObject(*aResult
), "What happened?");
6243 JS::AutoCheckCannotGC nogc
;
6245 memcpy(JS::GetArrayBufferData(*aResult
, &isShared
, nogc
),
6246 aData
.BeginReading(), dataLen
);
6247 MOZ_ASSERT(!isShared
);
6253 void nsContentUtils::StripNullChars(const nsAString
& aInStr
,
6254 nsAString
& aOutStr
) {
6255 // In common cases where we don't have nulls in the
6256 // string we can simple simply bypass the checking code.
6257 int32_t firstNullPos
= aInStr
.FindChar('\0');
6258 if (firstNullPos
== kNotFound
) {
6259 aOutStr
.Assign(aInStr
);
6263 aOutStr
.SetCapacity(aInStr
.Length() - 1);
6264 nsAString::const_iterator start
, end
;
6265 aInStr
.BeginReading(start
);
6266 aInStr
.EndReading(end
);
6267 while (start
!= end
) {
6268 if (*start
!= '\0') aOutStr
.Append(*start
);
6273 struct ClassMatchingInfo
{
6275 nsCaseTreatment mCaseTreatment
;
6279 bool nsContentUtils::MatchClassNames(Element
* aElement
, int32_t aNamespaceID
,
6280 nsAtom
* aAtom
, void* aData
) {
6281 // We can't match if there are no class names
6282 const nsAttrValue
* classAttr
= aElement
->GetClasses();
6287 // need to match *all* of the classes
6288 ClassMatchingInfo
* info
= static_cast<ClassMatchingInfo
*>(aData
);
6289 uint32_t length
= info
->mClasses
.Length();
6291 // If we actually had no classes, don't match.
6295 for (i
= 0; i
< length
; ++i
) {
6296 if (!classAttr
->Contains(info
->mClasses
[i
], info
->mCaseTreatment
)) {
6305 void nsContentUtils::DestroyClassNameArray(void* aData
) {
6306 ClassMatchingInfo
* info
= static_cast<ClassMatchingInfo
*>(aData
);
6311 void* nsContentUtils::AllocClassMatchingInfo(nsINode
* aRootNode
,
6312 const nsString
* aClasses
) {
6313 nsAttrValue attrValue
;
6314 attrValue
.ParseAtomArray(*aClasses
);
6315 // nsAttrValue::Equals is sensitive to order, so we'll send an array
6316 auto* info
= new ClassMatchingInfo
;
6317 if (attrValue
.Type() == nsAttrValue::eAtomArray
) {
6318 info
->mClasses
= std::move(*(attrValue
.GetAtomArrayValue()));
6319 } else if (attrValue
.Type() == nsAttrValue::eAtom
) {
6320 info
->mClasses
.AppendElement(attrValue
.GetAtomValue());
6323 info
->mCaseTreatment
=
6324 aRootNode
->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks
6331 bool nsContentUtils::IsFocusedContent(const nsIContent
* aContent
) {
6332 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
6334 return fm
&& fm
->GetFocusedElement() == aContent
;
6337 bool nsContentUtils::IsSubDocumentTabbable(nsIContent
* aContent
) {
6338 Document
* doc
= aContent
->GetComposedDoc();
6343 // If the subdocument lives in another process, the frame is
6345 if (EventStateManager::IsRemoteTarget(aContent
)) {
6349 // XXXbz should this use OwnerDoc() for GetSubDocumentFor?
6351 Document
* subDoc
= doc
->GetSubDocumentFor(aContent
);
6356 nsCOMPtr
<nsIDocShell
> docShell
= subDoc
->GetDocShell();
6361 nsCOMPtr
<nsIContentViewer
> contentViewer
;
6362 docShell
->GetContentViewer(getter_AddRefs(contentViewer
));
6363 if (!contentViewer
) {
6367 // If there are 2 viewers for the current docshell, that
6368 // means the current document may be a zombie document.
6369 // While load and pageshow events are dispatched, zombie viewer is the old,
6370 // to be hidden document.
6371 if (contentViewer
->GetPreviousViewer()) {
6372 bool inOnLoad
= false;
6373 docShell
->GetIsExecutingOnLoadHandler(&inOnLoad
);
6380 bool nsContentUtils::HasScrollgrab(nsIContent
* aContent
) {
6381 // If we ever standardize this feature we'll want to hook this up properly
6382 // again. For now we're removing all the DOM-side code related to it but
6383 // leaving the layout and APZ handling for it in place.
6387 void nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter
* aWindow
) {
6392 // Note that because FlushPendingNotifications flushes parents, this
6393 // is O(N^2) in docshell tree depth. However, the docshell tree is
6394 // usually pretty shallow.
6396 if (RefPtr
<Document
> doc
= aWindow
->GetDoc()) {
6397 doc
->FlushPendingNotifications(FlushType::Layout
);
6400 if (nsCOMPtr
<nsIDocShell
> docShell
= aWindow
->GetDocShell()) {
6401 int32_t i
= 0, i_end
;
6402 docShell
->GetInProcessChildCount(&i_end
);
6403 for (; i
< i_end
; ++i
) {
6404 nsCOMPtr
<nsIDocShellTreeItem
> item
;
6405 if (docShell
->GetInProcessChildAt(i
, getter_AddRefs(item
)) == NS_OK
&&
6407 if (nsCOMPtr
<nsPIDOMWindowOuter
> win
= item
->GetWindow()) {
6408 FlushLayoutForTree(win
);
6415 void nsContentUtils::RemoveNewlines(nsString
& aString
) { aString
.StripCRLF(); }
6417 void nsContentUtils::PlatformToDOMLineBreaks(nsString
& aString
) {
6418 if (!PlatformToDOMLineBreaks(aString
, fallible
)) {
6419 aString
.AllocFailed(aString
.Length());
6423 bool nsContentUtils::PlatformToDOMLineBreaks(nsString
& aString
,
6424 const fallible_t
& aFallible
) {
6425 if (aString
.FindChar(char16_t('\r')) != -1) {
6426 // Windows linebreaks: Map CRLF to LF:
6427 if (!aString
.ReplaceSubstring(u
"\r\n", u
"\n", aFallible
)) {
6431 // Mac linebreaks: Map any remaining CR to LF:
6432 if (!aString
.ReplaceSubstring(u
"\r", u
"\n", aFallible
)) {
6440 void nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer
* aBuf
,
6441 nsAString
& aResultString
) {
6442 MOZ_ASSERT(aBuf
, "Expecting a non-null string buffer");
6444 uint32_t stringLen
= NS_strlen(static_cast<char16_t
*>(aBuf
->Data()));
6446 // SANITY CHECK: In case the nsStringBuffer isn't correctly
6447 // null-terminated, let's clamp its length using the allocated size, to be
6448 // sure the resulting string doesn't sample past the end of the the buffer.
6449 // (Note that StorageSize() is in units of bytes, so we have to convert that
6450 // to units of PRUnichars, and subtract 1 for the null-terminator.)
6451 uint32_t allocStringLen
= (aBuf
->StorageSize() / sizeof(char16_t
)) - 1;
6452 MOZ_ASSERT(stringLen
<= allocStringLen
,
6453 "string buffer lacks null terminator!");
6454 stringLen
= std::min(stringLen
, allocStringLen
);
6456 aBuf
->ToString(stringLen
, aResultString
);
6459 already_AddRefed
<nsContentList
> nsContentUtils::GetElementsByClassName(
6460 nsINode
* aRootNode
, const nsAString
& aClasses
) {
6461 MOZ_ASSERT(aRootNode
, "Must have root node");
6463 return GetFuncStringContentList
<nsCacheableFuncStringHTMLCollection
>(
6464 aRootNode
, MatchClassNames
, DestroyClassNameArray
, AllocClassMatchingInfo
,
6468 PresShell
* nsContentUtils::FindPresShellForDocument(const Document
* aDocument
) {
6469 const Document
* doc
= aDocument
;
6470 Document
* displayDoc
= doc
->GetDisplayDocument();
6475 PresShell
* presShell
= doc
->GetPresShell();
6480 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= doc
->GetDocShell();
6481 while (docShellTreeItem
) {
6482 // We may be in a display:none subdocument, or we may not have a presshell
6484 // Walk the docshell tree to find the nearest container that has a
6485 // presshell, and return that.
6486 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(docShellTreeItem
);
6487 if (PresShell
* presShell
= docShell
->GetPresShell()) {
6490 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
6491 docShellTreeItem
->GetInProcessParent(getter_AddRefs(parent
));
6492 docShellTreeItem
= parent
;
6499 nsPresContext
* nsContentUtils::FindPresContextForDocument(
6500 const Document
* aDocument
) {
6501 if (PresShell
* presShell
= FindPresShellForDocument(aDocument
)) {
6502 return presShell
->GetPresContext();
6507 nsIWidget
* nsContentUtils::WidgetForDocument(const Document
* aDocument
) {
6508 PresShell
* presShell
= FindPresShellForDocument(aDocument
);
6512 nsViewManager
* vm
= presShell
->GetViewManager();
6516 nsView
* rootView
= vm
->GetRootView();
6520 nsView
* displayRoot
= nsViewManager::GetDisplayRootFor(rootView
);
6524 return displayRoot
->GetNearestWidget(nullptr);
6527 nsIWidget
* nsContentUtils::WidgetForContent(const nsIContent
* aContent
) {
6528 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
6530 frame
= nsLayoutUtils::GetDisplayRootFrame(frame
);
6532 nsView
* view
= frame
->GetView();
6534 return view
->GetWidget();
6541 already_AddRefed
<LayerManager
> nsContentUtils::LayerManagerForContent(
6542 const nsIContent
* aContent
) {
6543 nsIWidget
* widget
= nsContentUtils::WidgetForContent(aContent
);
6545 RefPtr
<LayerManager
> manager
= widget
->GetLayerManager();
6546 return manager
.forget();
6552 static already_AddRefed
<LayerManager
> LayerManagerForDocumentInternal(
6553 const Document
* aDoc
, bool aRequirePersistent
) {
6554 nsIWidget
* widget
= nsContentUtils::WidgetForDocument(aDoc
);
6556 RefPtr
<LayerManager
> manager
= widget
->GetLayerManager(
6557 aRequirePersistent
? nsIWidget::LAYER_MANAGER_PERSISTENT
6558 : nsIWidget::LAYER_MANAGER_CURRENT
);
6559 return manager
.forget();
6565 already_AddRefed
<LayerManager
> nsContentUtils::LayerManagerForDocument(
6566 const Document
* aDoc
) {
6567 return LayerManagerForDocumentInternal(aDoc
, false);
6570 already_AddRefed
<LayerManager
>
6571 nsContentUtils::PersistentLayerManagerForDocument(Document
* aDoc
) {
6572 return LayerManagerForDocumentInternal(aDoc
, true);
6575 bool nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal
* aPrincipal
) {
6580 if (aPrincipal
->IsSystemPrincipal()) {
6584 return (StaticPrefs::dom_allow_XUL_XBL_for_file() &&
6585 aPrincipal
->SchemeIs("file")) ||
6586 IsSitePermAllow(aPrincipal
, "allowXULXBL"_ns
);
6589 bool nsContentUtils::IsPDFJSEnabled() {
6590 nsCOMPtr
<nsIStreamConverter
> conv
= do_CreateInstance(
6591 "@mozilla.org/streamconv;1?from=application/pdf&to=text/html");
6595 bool nsContentUtils::IsPDFJS(nsIPrincipal
* aPrincipal
) {
6600 nsresult rv
= aPrincipal
->GetAsciiSpec(spec
);
6601 NS_ENSURE_SUCCESS(rv
, false);
6602 return spec
.EqualsLiteral("resource://pdf.js/web/viewer.html");
6605 bool nsContentUtils::IsPDFJS(JSContext
* aCx
, JSObject
*) {
6606 return IsPDFJS(SubjectPrincipal(aCx
));
6609 already_AddRefed
<nsIDocumentLoaderFactory
>
6610 nsContentUtils::FindInternalContentViewer(const nsACString
& aType
,
6611 ContentViewerType
* aLoaderType
) {
6613 *aLoaderType
= TYPE_UNSUPPORTED
;
6616 // one helper factory, please
6617 nsCOMPtr
<nsICategoryManager
> catMan(
6618 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
));
6619 if (!catMan
) return nullptr;
6621 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory
;
6623 nsCString contractID
;
6625 catMan
->GetCategoryEntry("Gecko-Content-Viewers", aType
, contractID
);
6626 if (NS_SUCCEEDED(rv
)) {
6627 docFactory
= do_GetService(contractID
.get());
6628 if (docFactory
&& aLoaderType
) {
6629 if (contractID
.EqualsLiteral(CONTENT_DLF_CONTRACTID
))
6630 *aLoaderType
= TYPE_CONTENT
;
6631 else if (contractID
.EqualsLiteral(PLUGIN_DLF_CONTRACTID
))
6632 *aLoaderType
= TYPE_FALLBACK
;
6634 *aLoaderType
= TYPE_UNKNOWN
;
6636 return docFactory
.forget();
6639 if (DecoderTraits::IsSupportedInVideoDocument(aType
)) {
6641 do_GetService("@mozilla.org/content/document-loader-factory;1");
6642 if (docFactory
&& aLoaderType
) {
6643 *aLoaderType
= TYPE_CONTENT
;
6645 return docFactory
.forget();
6651 static void ReportPatternCompileFailure(nsAString
& aPattern
,
6652 const Document
* aDocument
,
6653 JS::MutableHandle
<JS::Value
> error
,
6655 JS::AutoSaveExceptionState
savedExc(cx
);
6656 JS::RootedObject
exnObj(cx
, &error
.toObject());
6657 JS::RootedValue
messageVal(cx
);
6658 if (!JS_GetProperty(cx
, exnObj
, "message", &messageVal
)) {
6661 JS::RootedString
messageStr(cx
, messageVal
.toString());
6662 MOZ_ASSERT(messageStr
);
6664 AutoTArray
<nsString
, 2> strings
;
6665 strings
.AppendElement(aPattern
);
6666 if (!AssignJSString(cx
, *strings
.AppendElement(), messageStr
)) {
6670 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "DOM"_ns
,
6671 aDocument
, nsContentUtils::eDOM_PROPERTIES
,
6672 "PatternAttributeCompileFailure", strings
);
6677 Maybe
<bool> nsContentUtils::IsPatternMatching(nsAString
& aValue
,
6678 nsAString
& aPattern
,
6679 const Document
* aDocument
) {
6680 NS_ASSERTION(aDocument
, "aDocument should be a valid pointer (not null)");
6682 // The fact that we're using a JS regexp under the hood should not be visible
6683 // to things like window onerror handlers, so we don't initialize our JSAPI
6684 // with the document's window (which may not exist anyway).
6687 JSContext
* cx
= jsapi
.cx();
6688 AutoDisableJSInterruptCallback
disabler(cx
);
6690 // We can use the junk scope here, because we're just using it for regexp
6691 // evaluation, not actual script execution, and we disable statics so that the
6692 // evaluation does not interact with the execution global.
6693 JSAutoRealm
ar(cx
, xpc::PrivilegedJunkScope());
6695 // Check if the pattern by itself is valid first, and not that it only becomes
6696 // valid once we add ^(?: and )$.
6697 JS::RootedValue
error(cx
);
6698 if (!JS::CheckRegExpSyntax(
6699 cx
, static_cast<char16_t
*>(aPattern
.BeginWriting()),
6700 aPattern
.Length(), JS::RegExpFlag::Unicode
, &error
)) {
6704 if (!error
.isUndefined()) {
6705 ReportPatternCompileFailure(aPattern
, aDocument
, &error
, cx
);
6709 // The pattern has to match the entire value.
6710 aPattern
.InsertLiteral(u
"^(?:", 0);
6711 aPattern
.AppendLiteral(")$");
6713 JS::Rooted
<JSObject
*> re(
6715 JS::NewUCRegExpObject(cx
, static_cast<char16_t
*>(aPattern
.BeginWriting()),
6716 aPattern
.Length(), JS::RegExpFlag::Unicode
));
6721 JS::Rooted
<JS::Value
> rval(cx
, JS::NullValue());
6723 if (!JS::ExecuteRegExpNoStatics(cx
, re
,
6724 static_cast<char16_t
*>(aValue
.BeginWriting()),
6725 aValue
.Length(), &idx
, true, &rval
)) {
6729 return Some(!rval
.isNull());
6733 nsresult
nsContentUtils::URIInheritsSecurityContext(nsIURI
* aURI
,
6735 // Note: about:blank URIs do NOT inherit the security context from the
6736 // current document, which is what this function tests for...
6737 return NS_URIChainHasFlags(
6738 aURI
, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
, aResult
);
6742 bool nsContentUtils::ChannelShouldInheritPrincipal(
6743 nsIPrincipal
* aLoadingPrincipal
, nsIURI
* aURI
, bool aInheritForAboutBlank
,
6744 bool aForceInherit
) {
6745 MOZ_ASSERT(aLoadingPrincipal
,
6746 "Can not check inheritance without a principal");
6748 // Only tell the channel to inherit if it can't provide its own security
6751 // XXX: If this is ever changed, check all callers for what owners
6752 // they're passing in. In particular, see the code and
6753 // comments in nsDocShell::LoadURI where we fall back on
6754 // inheriting the owner if called from chrome. That would be
6755 // very wrong if this code changed anything but channels that
6756 // can't provide their own security context!
6758 // If aForceInherit is true, we will inherit, even for a channel that
6759 // can provide its own security context. This is used for srcdoc loads.
6760 bool inherit
= aForceInherit
;
6763 // We expect URIInheritsSecurityContext to return success for an
6764 // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
6765 // This condition needs to match the one in nsDocShell::InternalLoad where
6766 // we're checking for things that will use the owner.
6768 (NS_SUCCEEDED(URIInheritsSecurityContext(aURI
, &uriInherits
)) &&
6769 (uriInherits
|| (aInheritForAboutBlank
&& NS_IsAboutBlank(aURI
)))) ||
6771 // file: uri special-casing
6773 // If this is a file: load opened from another file: then it may need
6774 // to inherit the owner from the referrer so they can script each other.
6775 // If we don't set the owner explicitly then each file: gets an owner
6776 // based on its own codebase later.
6778 (URIIsLocalFile(aURI
) &&
6779 NS_SUCCEEDED(aLoadingPrincipal
->CheckMayLoad(aURI
, false)) &&
6780 // One more check here. CheckMayLoad will always return true for the
6781 // system principal, but we do NOT want to inherit in that case.
6782 !aLoadingPrincipal
->IsSystemPrincipal());
6788 bool nsContentUtils::IsCutCopyAllowed(Document
* aDocument
,
6789 nsIPrincipal
& aSubjectPrincipal
) {
6790 if (StaticPrefs::dom_allow_cut_copy() && aDocument
&&
6791 aDocument
->HasValidTransientUserGestureActivation()) {
6795 return PrincipalHasPermission(aSubjectPrincipal
, nsGkAtoms::clipboardWrite
);
6799 bool nsContentUtils::HaveEqualPrincipals(Document
* aDoc1
, Document
* aDoc2
) {
6800 if (!aDoc1
|| !aDoc2
) {
6803 bool principalsEqual
= false;
6804 aDoc1
->NodePrincipal()->Equals(aDoc2
->NodePrincipal(), &principalsEqual
);
6805 return principalsEqual
;
6809 bool nsContentUtils::HasPluginWithUncontrolledEventDispatch(
6810 nsIContent
* aContent
) {
6815 void nsContentUtils::FireMutationEventsForDirectParsing(
6816 Document
* aDoc
, nsIContent
* aDest
, int32_t aOldChildCount
) {
6817 // Fire mutation events. Optimize for the case when there are no listeners
6818 int32_t newChildCount
= aDest
->GetChildCount();
6819 if (newChildCount
&& nsContentUtils::HasMutationListeners(
6820 aDoc
, NS_EVENT_BITS_MUTATION_NODEINSERTED
)) {
6821 AutoTArray
<nsCOMPtr
<nsIContent
>, 50> childNodes
;
6822 NS_ASSERTION(newChildCount
- aOldChildCount
>= 0,
6823 "What, some unexpected dom mutation has happened?");
6824 childNodes
.SetCapacity(newChildCount
- aOldChildCount
);
6825 for (nsIContent
* child
= aDest
->GetFirstChild(); child
;
6826 child
= child
->GetNextSibling()) {
6827 childNodes
.AppendElement(child
);
6829 FragmentOrElement::FireNodeInserted(aDoc
, aDest
, childNodes
);
6834 Document
* nsContentUtils::GetRootDocument(Document
* aDoc
) {
6838 Document
* doc
= aDoc
;
6839 while (doc
->GetInProcessParentDocument()) {
6840 doc
= doc
->GetInProcessParentDocument();
6846 int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame
* aOffsetFrame
,
6848 // The structure of the anonymous frames within a text control frame is
6849 // an optional block frame, followed by an optional br frame.
6851 // If the offset frame has a child, then this frame is the block which
6852 // has the text frames (containing the content) as its children. This will
6853 // be the case if we click to the right of any of the text frames, or at the
6854 // bottom of the text area.
6855 nsIFrame
* firstChild
= aOffsetFrame
->PrincipalChildList().FirstChild();
6857 // In this case, the passed-in offset is incorrect, and we want the length
6858 // of the entire content in the text control frame.
6859 return firstChild
->GetContent()->Length();
6862 if (aOffsetFrame
->GetPrevSibling() && !aOffsetFrame
->GetNextSibling()) {
6863 // In this case, we're actually within the last frame, which is a br
6864 // frame. Our offset should therefore be the length of the first child of
6866 int32_t aOutOffset
= aOffsetFrame
->GetParent()
6867 ->PrincipalChildList()
6874 // Otherwise, we're within one of the text frames, in which case our offset
6875 // has already been correctly calculated.
6880 void nsContentUtils::GetSelectionInTextControl(Selection
* aSelection
,
6882 uint32_t& aOutStartOffset
,
6883 uint32_t& aOutEndOffset
) {
6884 MOZ_ASSERT(aSelection
&& aRoot
);
6886 // We don't care which end of this selection is anchor and which is focus. In
6887 // fact, we explicitly want to know which is the _start_ and which is the
6888 // _end_, not anchor vs focus.
6889 const nsRange
* range
= aSelection
->GetAnchorFocusRange();
6892 aOutStartOffset
= aOutEndOffset
= 0;
6896 // All the node pointers here are raw pointers for performance. We shouldn't
6897 // be doing anything in this function that invalidates the node tree.
6898 nsINode
* startContainer
= range
->GetStartContainer();
6899 uint32_t startOffset
= range
->StartOffset();
6900 nsINode
* endContainer
= range
->GetEndContainer();
6901 uint32_t endOffset
= range
->EndOffset();
6903 // We have at most two children, consisting of an optional text node followed
6904 // by an optional <br>.
6905 NS_ASSERTION(aRoot
->GetChildCount() <= 2, "Unexpected children");
6906 nsIContent
* firstChild
= aRoot
->GetFirstChild();
6908 nsCOMPtr
<nsIContent
> lastChild
= aRoot
->GetLastChild();
6909 NS_ASSERTION(startContainer
== aRoot
|| startContainer
== firstChild
||
6910 startContainer
== lastChild
,
6911 "Unexpected startContainer");
6912 NS_ASSERTION(endContainer
== aRoot
|| endContainer
== firstChild
||
6913 endContainer
== lastChild
,
6914 "Unexpected endContainer");
6915 // firstChild is either text or a <br> (hence an element).
6916 MOZ_ASSERT_IF(firstChild
, firstChild
->IsText() || firstChild
->IsElement());
6918 // Testing IsElement() is faster than testing IsNodeOfType(), since it's
6920 if (!firstChild
|| firstChild
->IsElement()) {
6921 // No text node, so everything is 0
6922 startOffset
= endOffset
= 0;
6924 // First child is text. If the start/end is already in the text node,
6925 // or the start of the root node, no change needed. If it's in the root
6926 // node but not the start, or in the trailing <br>, we need to set the
6927 // offset to the end.
6928 if ((startContainer
== aRoot
&& startOffset
!= 0) ||
6929 (startContainer
!= aRoot
&& startContainer
!= firstChild
)) {
6930 startOffset
= firstChild
->Length();
6932 if ((endContainer
== aRoot
&& endOffset
!= 0) ||
6933 (endContainer
!= aRoot
&& endContainer
!= firstChild
)) {
6934 endOffset
= firstChild
->Length();
6938 MOZ_ASSERT(startOffset
<= endOffset
);
6939 aOutStartOffset
= startOffset
;
6940 aOutEndOffset
= endOffset
;
6944 HTMLEditor
* nsContentUtils::GetHTMLEditor(nsPresContext
* aPresContext
) {
6945 if (!aPresContext
) {
6948 return GetHTMLEditor(aPresContext
->GetDocShell());
6952 HTMLEditor
* nsContentUtils::GetHTMLEditor(nsDocShell
* aDocShell
) {
6954 if (!aDocShell
|| NS_FAILED(aDocShell
->GetEditable(&isEditable
)) ||
6958 return aDocShell
->GetHTMLEditor();
6962 TextEditor
* nsContentUtils::GetActiveEditor(nsPresContext
* aPresContext
) {
6963 if (!aPresContext
) {
6967 return GetActiveEditor(aPresContext
->Document()->GetWindow());
6971 TextEditor
* nsContentUtils::GetActiveEditor(nsPIDOMWindowOuter
* aWindow
) {
6972 if (!aWindow
|| !aWindow
->GetExtantDoc()) {
6976 // If it's in designMode, nobody can have focus. Therefore, the HTMLEditor
6977 // handles all events. I.e., it's focused editor in this case.
6978 if (aWindow
->GetExtantDoc()->HasFlag(NODE_IS_EDITABLE
)) {
6979 return GetHTMLEditor(nsDocShell::Cast(aWindow
->GetDocShell()));
6982 // If focused element is associated with TextEditor, it must be <input>
6983 // element or <textarea> element. Let's return it even if it's in a
6984 // contenteditable element.
6985 nsCOMPtr
<nsPIDOMWindowOuter
> focusedWindow
;
6986 if (Element
* focusedElement
= nsFocusManager::GetFocusedDescendant(
6987 aWindow
, nsFocusManager::SearchRange::eOnlyCurrentWindow
,
6988 getter_AddRefs(focusedWindow
))) {
6989 if (TextEditor
* textEditor
= focusedElement
->GetTextEditorInternal()) {
6994 // Otherwise, HTMLEditor may handle inputs even non-editable element has
6995 // focus or nobody has focus.
6996 return GetHTMLEditor(nsDocShell::Cast(aWindow
->GetDocShell()));
7000 TextEditor
* nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
7001 nsIContent
* aAnonymousContent
) {
7002 if (!aAnonymousContent
) {
7005 nsIContent
* parent
= aAnonymousContent
->FindFirstNonChromeOnlyAccessContent();
7006 if (!parent
|| parent
== aAnonymousContent
) {
7009 if (HTMLInputElement
* inputElement
=
7010 HTMLInputElement::FromNodeOrNull(parent
)) {
7011 return inputElement
->GetTextEditorWithoutCreation();
7013 if (HTMLTextAreaElement
* textareaElement
=
7014 HTMLTextAreaElement::FromNodeOrNull(parent
)) {
7015 return textareaElement
->GetTextEditorWithoutCreation();
7021 bool nsContentUtils::IsNodeInEditableRegion(nsINode
* aNode
) {
7023 if (aNode
->IsEditable()) {
7026 aNode
= aNode
->GetParent();
7032 bool nsContentUtils::IsForbiddenRequestHeader(const nsACString
& aHeader
) {
7033 if (IsForbiddenSystemRequestHeader(aHeader
)) {
7037 return StringBeginsWith(aHeader
, "proxy-"_ns
,
7038 nsCaseInsensitiveCStringComparator
) ||
7039 StringBeginsWith(aHeader
, "sec-"_ns
,
7040 nsCaseInsensitiveCStringComparator
);
7044 bool nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString
& aHeader
) {
7045 static const char* kInvalidHeaders
[] = {"accept-charset",
7047 "access-control-request-headers",
7048 "access-control-request-method",
7062 "transfer-encoding",
7065 for (auto& kInvalidHeader
: kInvalidHeaders
) {
7066 if (aHeader
.LowerCaseEqualsASCII(kInvalidHeader
)) {
7074 bool nsContentUtils::IsForbiddenResponseHeader(const nsACString
& aHeader
) {
7075 return (aHeader
.LowerCaseEqualsASCII("set-cookie") ||
7076 aHeader
.LowerCaseEqualsASCII("set-cookie2"));
7080 bool nsContentUtils::IsCorsUnsafeRequestHeaderValue(
7081 const nsACString
& aHeaderValue
) {
7082 const char* cur
= aHeaderValue
.BeginReading();
7083 const char* end
= aHeaderValue
.EndReading();
7085 while (cur
!= end
) {
7086 // Implementation of
7087 // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less
7088 // than a space but not a horizontal tab
7089 if ((*cur
< ' ' && *cur
!= '\t') || *cur
== '"' || *cur
== '(' ||
7090 *cur
== ')' || *cur
== ':' || *cur
== '<' || *cur
== '>' ||
7091 *cur
== '?' || *cur
== '@' || *cur
== '[' || *cur
== '\\' ||
7092 *cur
== ']' || *cur
== '{' || *cur
== '}' ||
7093 *cur
== 0x7F) { // 0x75 is DEL
7102 bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString
& aHeaderValue
) {
7103 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue
)) {
7110 bool nsContentUtils::IsAllowedNonCorsContentType(
7111 const nsACString
& aHeaderValue
) {
7112 nsAutoCString contentType
;
7113 nsAutoCString unused
;
7115 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue
)) {
7119 nsresult rv
= NS_ParseRequestContentType(aHeaderValue
, contentType
, unused
);
7120 if (NS_FAILED(rv
)) {
7124 return contentType
.LowerCaseEqualsLiteral("text/plain") ||
7125 contentType
.LowerCaseEqualsLiteral(
7126 "application/x-www-form-urlencoded") ||
7127 contentType
.LowerCaseEqualsLiteral("multipart/form-data");
7131 bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString
& aHeaderValue
) {
7132 const char* cur
= aHeaderValue
.BeginReading();
7133 const char* end
= aHeaderValue
.EndReading();
7135 while (cur
!= end
) {
7136 if ((*cur
>= '0' && *cur
<= '9') || (*cur
>= 'A' && *cur
<= 'Z') ||
7137 (*cur
>= 'a' && *cur
<= 'z') || *cur
== ' ' || *cur
== '*' ||
7138 *cur
== ',' || *cur
== '-' || *cur
== '.' || *cur
== ';' ||
7149 bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString
& aName
,
7150 const nsACString
& aValue
) {
7151 // see https://fetch.spec.whatwg.org/#cors-safelisted-request-header
7152 if (aValue
.Length() > 128) {
7155 return (aName
.LowerCaseEqualsLiteral("accept") &&
7156 nsContentUtils::IsAllowedNonCorsAccept(aValue
)) ||
7157 (aName
.LowerCaseEqualsLiteral("accept-language") &&
7158 nsContentUtils::IsAllowedNonCorsLanguage(aValue
)) ||
7159 (aName
.LowerCaseEqualsLiteral("content-language") &&
7160 nsContentUtils::IsAllowedNonCorsLanguage(aValue
)) ||
7161 (aName
.LowerCaseEqualsLiteral("content-type") &&
7162 nsContentUtils::IsAllowedNonCorsContentType(aValue
));
7165 mozilla::LogModule
* nsContentUtils::DOMDumpLog() { return sDOMDumpLog
; }
7167 bool nsContentUtils::GetNodeTextContent(nsINode
* aNode
, bool aDeep
,
7169 const fallible_t
& aFallible
) {
7171 return AppendNodeTextContent(aNode
, aDeep
, aResult
, aFallible
);
7174 void nsContentUtils::GetNodeTextContent(nsINode
* aNode
, bool aDeep
,
7175 nsAString
& aResult
) {
7176 if (!GetNodeTextContent(aNode
, aDeep
, aResult
, fallible
)) {
7177 NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size
7181 void nsContentUtils::DestroyMatchString(void* aData
) {
7183 nsString
* matchString
= static_cast<nsString
*>(aData
);
7188 bool nsContentUtils::IsJavascriptMIMEType(const nsAString
& aMIMEType
) {
7189 // Table ordered from most to least likely JS MIME types.
7190 static const char* jsTypes
[] = {"text/javascript",
7192 "application/javascript",
7193 "application/ecmascript",
7194 "application/x-javascript",
7195 "application/x-ecmascript",
7196 "text/javascript1.0",
7197 "text/javascript1.1",
7198 "text/javascript1.2",
7199 "text/javascript1.3",
7200 "text/javascript1.4",
7201 "text/javascript1.5",
7204 "text/x-ecmascript",
7205 "text/x-javascript",
7208 for (uint32_t i
= 0; jsTypes
[i
]; ++i
) {
7209 if (aMIMEType
.LowerCaseEqualsASCII(jsTypes
[i
])) {
7217 nsresult
nsContentUtils::GenerateUUIDInPlace(nsID
& aUUID
) {
7218 MOZ_ASSERT(sUUIDGenerator
);
7220 nsresult rv
= sUUIDGenerator
->GenerateUUIDInPlace(&aUUID
);
7221 if (NS_WARN_IF(NS_FAILED(rv
))) {
7228 nsID
nsContentUtils::GenerateUUID() {
7229 MOZ_DIAGNOSTIC_ASSERT(sUUIDGenerator
);
7232 nsresult rv
= sUUIDGenerator
->GenerateUUIDInPlace(&uuid
);
7233 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
7238 bool nsContentUtils::PrefetchPreloadEnabled(nsIDocShell
* aDocShell
) {
7240 // SECURITY CHECK: disable prefetching and preloading from mailnews!
7242 // walk up the docshell tree to see if any containing
7243 // docshell are of type MAIL.
7250 nsCOMPtr
<nsIDocShell
> docshell
= aDocShell
;
7251 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
7254 auto appType
= docshell
->GetAppType();
7255 if (appType
== nsIDocShell::APP_TYPE_MAIL
) {
7256 return false; // do not prefetch, preload, preconnect from mailnews
7259 docshell
->GetInProcessParent(getter_AddRefs(parentItem
));
7261 docshell
= do_QueryInterface(parentItem
);
7263 NS_ERROR("cannot get a docshell from a treeItem!");
7267 } while (parentItem
);
7272 uint64_t nsContentUtils::GetInnerWindowID(nsIRequest
* aRequest
) {
7273 // can't do anything if there's no nsIRequest!
7278 nsCOMPtr
<nsILoadGroup
> loadGroup
;
7279 nsresult rv
= aRequest
->GetLoadGroup(getter_AddRefs(loadGroup
));
7281 if (NS_FAILED(rv
) || !loadGroup
) {
7285 return GetInnerWindowID(loadGroup
);
7288 uint64_t nsContentUtils::GetInnerWindowID(nsILoadGroup
* aLoadGroup
) {
7293 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
7294 nsresult rv
= aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
7295 if (NS_FAILED(rv
) || !callbacks
) {
7299 nsCOMPtr
<nsILoadContext
> loadContext
= do_GetInterface(callbacks
);
7304 nsCOMPtr
<mozIDOMWindowProxy
> window
;
7305 rv
= loadContext
->GetAssociatedWindow(getter_AddRefs(window
));
7306 if (NS_FAILED(rv
) || !window
) {
7310 auto* pwindow
= nsPIDOMWindowOuter::From(window
);
7315 nsPIDOMWindowInner
* inner
= pwindow
->GetCurrentInnerWindow();
7316 return inner
? inner
->WindowID() : 0;
7320 void nsContentUtils::MaybeFixIPv6Host(nsACString
& aHost
) {
7321 if (aHost
.FindChar(':') != -1) { // Escape IPv6 address
7322 MOZ_ASSERT(!aHost
.Length() ||
7323 (aHost
[0] != '[' && aHost
[aHost
.Length() - 1] != ']'));
7324 aHost
.Insert('[', 0);
7329 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI
* aURI
,
7330 nsACString
& aHost
) {
7332 nsresult rv
= aURI
->GetHost(aHost
);
7333 if (NS_FAILED(rv
)) { // Some URIs do not have a host
7337 MaybeFixIPv6Host(aHost
);
7342 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI
* aURI
,
7344 nsAutoCString hostname
;
7345 nsresult rv
= GetHostOrIPv6WithBrackets(aURI
, hostname
);
7346 if (NS_FAILED(rv
)) {
7349 CopyUTF8toUTF16(hostname
, aHost
);
7353 nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIPrincipal
* aPrincipal
,
7354 nsACString
& aHost
) {
7355 nsresult rv
= aPrincipal
->GetAsciiHost(aHost
);
7356 if (NS_FAILED(rv
)) { // Some URIs do not have a host
7360 MaybeFixIPv6Host(aHost
);
7364 CallState
nsContentUtils::CallOnAllRemoteChildren(
7365 MessageBroadcaster
* aManager
,
7366 const std::function
<CallState(BrowserParent
*)>& aCallback
) {
7367 uint32_t browserChildCount
= aManager
->ChildCount();
7368 for (uint32_t j
= 0; j
< browserChildCount
; ++j
) {
7369 RefPtr
<MessageListenerManager
> childMM
= aManager
->GetChildAt(j
);
7374 RefPtr
<MessageBroadcaster
> nonLeafMM
= MessageBroadcaster::From(childMM
);
7376 if (CallOnAllRemoteChildren(nonLeafMM
, aCallback
) == CallState::Stop
) {
7377 return CallState::Stop
;
7382 mozilla::dom::ipc::MessageManagerCallback
* cb
= childMM
->GetCallback();
7384 nsFrameLoader
* fl
= static_cast<nsFrameLoader
*>(cb
);
7385 BrowserParent
* remote
= BrowserParent::GetFrom(fl
);
7386 if (remote
&& aCallback
) {
7387 if (aCallback(remote
) == CallState::Stop
) {
7388 return CallState::Stop
;
7394 return CallState::Continue
;
7397 void nsContentUtils::CallOnAllRemoteChildren(
7398 nsPIDOMWindowOuter
* aWindow
,
7399 const std::function
<CallState(BrowserParent
*)>& aCallback
) {
7400 nsGlobalWindowOuter
* window
= nsGlobalWindowOuter::Cast(aWindow
);
7401 if (window
->IsChromeWindow()) {
7402 RefPtr
<MessageBroadcaster
> windowMM
= window
->GetMessageManager();
7404 CallOnAllRemoteChildren(windowMM
, aCallback
);
7409 struct UIStateChangeInfo
{
7410 UIStateChangeType mShowFocusRings
;
7412 explicit UIStateChangeInfo(UIStateChangeType aShowFocusRings
)
7413 : mShowFocusRings(aShowFocusRings
) {}
7416 void nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(
7417 nsPIDOMWindowOuter
* aWindow
, UIStateChangeType aShowFocusRings
) {
7418 UIStateChangeInfo
stateInfo(aShowFocusRings
);
7419 CallOnAllRemoteChildren(aWindow
, [&stateInfo
](BrowserParent
* aBrowserParent
) {
7420 Unused
<< aBrowserParent
->SendSetKeyboardIndicators(
7421 stateInfo
.mShowFocusRings
);
7422 return CallState::Continue
;
7426 nsresult
nsContentUtils::IPCTransferableToTransferable(
7427 const IPCDataTransfer
& aDataTransfer
, const bool& aIsPrivateData
,
7428 nsIPrincipal
* aRequestingPrincipal
,
7429 const nsContentPolicyType
& aContentPolicyType
,
7430 nsITransferable
* aTransferable
, mozilla::dom::ContentParent
* aContentParent
,
7431 mozilla::dom::BrowserChild
* aBrowserChild
) {
7434 aTransferable
->SetIsPrivateData(aIsPrivateData
);
7436 const nsTArray
<IPCDataTransferItem
>& items
= aDataTransfer
.items();
7437 for (const auto& item
: items
) {
7438 aTransferable
->AddDataFlavor(item
.flavor().get());
7440 if (item
.data().type() == IPCDataTransferData::TnsString
) {
7441 nsCOMPtr
<nsISupportsString
> dataWrapper
=
7442 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
7443 NS_ENSURE_SUCCESS(rv
, rv
);
7445 const nsString
& text
= item
.data().get_nsString();
7446 rv
= dataWrapper
->SetData(text
);
7447 NS_ENSURE_SUCCESS(rv
, rv
);
7449 rv
= aTransferable
->SetTransferData(item
.flavor().get(), dataWrapper
);
7451 NS_ENSURE_SUCCESS(rv
, rv
);
7452 } else if (item
.data().type() == IPCDataTransferData::TShmem
) {
7453 if (nsContentUtils::IsFlavorImage(item
.flavor())) {
7454 nsCOMPtr
<imgIContainer
> imageContainer
;
7455 rv
= nsContentUtils::DataTransferItemToImage(
7456 item
, getter_AddRefs(imageContainer
));
7457 NS_ENSURE_SUCCESS(rv
, rv
);
7459 aTransferable
->SetTransferData(item
.flavor().get(), imageContainer
);
7461 nsCOMPtr
<nsISupportsCString
> dataWrapper
=
7462 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID
, &rv
);
7463 NS_ENSURE_SUCCESS(rv
, rv
);
7465 // The buffer contains the terminating null.
7466 Shmem itemData
= item
.data().get_Shmem();
7467 const nsDependentCSubstring
text(itemData
.get
<char>(),
7468 itemData
.Size
<char>());
7469 rv
= dataWrapper
->SetData(text
);
7470 NS_ENSURE_SUCCESS(rv
, rv
);
7472 rv
= aTransferable
->SetTransferData(item
.flavor().get(), dataWrapper
);
7474 NS_ENSURE_SUCCESS(rv
, rv
);
7477 if (aContentParent
) {
7478 Unused
<< aContentParent
->DeallocShmem(item
.data().get_Shmem());
7479 } else if (aBrowserChild
) {
7480 Unused
<< aBrowserChild
->DeallocShmem(item
.data().get_Shmem());
7485 aTransferable
->SetRequestingPrincipal(aRequestingPrincipal
);
7486 aTransferable
->SetContentPolicyType(aContentPolicyType
);
7490 void nsContentUtils::TransferablesToIPCTransferables(
7491 nsIArray
* aTransferables
, nsTArray
<IPCDataTransfer
>& aIPC
,
7492 bool aInSyncMessage
, mozilla::dom::ContentChild
* aChild
,
7493 mozilla::dom::ContentParent
* aParent
) {
7495 if (aTransferables
) {
7496 uint32_t transferableCount
= 0;
7497 aTransferables
->GetLength(&transferableCount
);
7498 for (uint32_t i
= 0; i
< transferableCount
; ++i
) {
7499 IPCDataTransfer
* dt
= aIPC
.AppendElement();
7500 nsCOMPtr
<nsITransferable
> transferable
=
7501 do_QueryElementAt(aTransferables
, i
);
7502 TransferableToIPCTransferable(transferable
, dt
, aInSyncMessage
, aChild
,
7508 nsresult
nsContentUtils::SlurpFileToString(nsIFile
* aFile
,
7509 nsACString
& aString
) {
7512 nsCOMPtr
<nsIURI
> fileURI
;
7513 nsresult rv
= NS_NewFileURI(getter_AddRefs(fileURI
), aFile
);
7514 if (NS_FAILED(rv
)) {
7518 nsCOMPtr
<nsIChannel
> channel
;
7519 rv
= NS_NewChannel(getter_AddRefs(channel
), fileURI
,
7520 nsContentUtils::GetSystemPrincipal(),
7521 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
,
7522 nsIContentPolicy::TYPE_OTHER
);
7523 if (NS_FAILED(rv
)) {
7527 nsCOMPtr
<nsIInputStream
> stream
;
7528 rv
= channel
->Open(getter_AddRefs(stream
));
7529 if (NS_FAILED(rv
)) {
7533 rv
= NS_ConsumeStream(stream
, UINT32_MAX
, aString
);
7534 if (NS_FAILED(rv
)) {
7538 rv
= stream
->Close();
7539 if (NS_FAILED(rv
)) {
7546 bool nsContentUtils::IsFileImage(nsIFile
* aFile
, nsACString
& aType
) {
7547 nsCOMPtr
<nsIMIMEService
> mime
= do_GetService("@mozilla.org/mime;1");
7552 nsresult rv
= mime
->GetTypeFromFile(aFile
, aType
);
7553 if (NS_FAILED(rv
)) {
7557 return StringBeginsWith(aType
, "image/"_ns
);
7560 nsresult
nsContentUtils::CalculateBufferSizeForImage(
7561 const uint32_t& aStride
, const IntSize
& aImageSize
,
7562 const SurfaceFormat
& aFormat
, size_t* aMaxBufferSize
,
7563 size_t* aUsedBufferSize
) {
7564 CheckedInt32 requiredBytes
=
7565 CheckedInt32(aStride
) * CheckedInt32(aImageSize
.height
);
7567 CheckedInt32 usedBytes
=
7568 requiredBytes
- aStride
+
7569 (CheckedInt32(aImageSize
.width
) * BytesPerPixel(aFormat
));
7570 if (!usedBytes
.isValid()) {
7571 return NS_ERROR_FAILURE
;
7574 MOZ_ASSERT(requiredBytes
.isValid(), "usedBytes valid but not required?");
7575 *aMaxBufferSize
= requiredBytes
.value();
7576 *aUsedBufferSize
= usedBytes
.value();
7580 nsresult
nsContentUtils::DataTransferItemToImage(
7581 const IPCDataTransferItem
& aItem
, imgIContainer
** aContainer
) {
7582 MOZ_ASSERT(aItem
.data().type() == IPCDataTransferData::TShmem
);
7583 MOZ_ASSERT(IsFlavorImage(aItem
.flavor()));
7585 const IPCDataTransferImage
& imageDetails
= aItem
.imageDetails();
7586 const IntSize
size(imageDetails
.width(), imageDetails
.height());
7587 if (!size
.width
|| !size
.height
) {
7588 return NS_ERROR_FAILURE
;
7591 Shmem data
= aItem
.data().get_Shmem();
7593 // Validate shared memory buffer size
7594 size_t imageBufLen
= 0;
7595 size_t maxBufLen
= 0;
7596 nsresult rv
= CalculateBufferSizeForImage(imageDetails
.stride(), size
,
7597 imageDetails
.format(), &maxBufLen
,
7599 if (NS_FAILED(rv
)) {
7602 if (imageBufLen
> data
.Size
<uint8_t>()) {
7603 return NS_ERROR_FAILURE
;
7606 RefPtr
<DataSourceSurface
> image
= CreateDataSourceSurfaceFromData(
7607 size
, imageDetails
.format(), data
.get
<uint8_t>(), imageDetails
.stride());
7609 RefPtr
<gfxDrawable
> drawable
= new gfxSurfaceDrawable(image
, size
);
7610 nsCOMPtr
<imgIContainer
> imageContainer
=
7611 image::ImageOps::CreateFromDrawable(drawable
);
7612 imageContainer
.forget(aContainer
);
7617 bool nsContentUtils::IsFlavorImage(const nsACString
& aFlavor
) {
7618 return aFlavor
.EqualsLiteral(kNativeImageMime
) ||
7619 aFlavor
.EqualsLiteral(kJPEGImageMime
) ||
7620 aFlavor
.EqualsLiteral(kJPGImageMime
) ||
7621 aFlavor
.EqualsLiteral(kPNGImageMime
) ||
7622 aFlavor
.EqualsLiteral(kGIFImageMime
);
7625 static Shmem
ConvertToShmem(mozilla::dom::ContentChild
* aChild
,
7626 mozilla::dom::ContentParent
* aParent
,
7627 const nsACString
& aInput
) {
7628 MOZ_ASSERT((aChild
&& !aParent
) || (!aChild
&& aParent
));
7630 IShmemAllocator
* allocator
= aChild
? static_cast<IShmemAllocator
*>(aChild
)
7631 : static_cast<IShmemAllocator
*>(aParent
);
7634 if (!allocator
->AllocShmem(aInput
.Length(), SharedMemory::TYPE_BASIC
,
7639 memcpy(result
.get
<char>(), aInput
.BeginReading(), aInput
.Length());
7644 void nsContentUtils::TransferableToIPCTransferable(
7645 nsITransferable
* aTransferable
, IPCDataTransfer
* aIPCDataTransfer
,
7646 bool aInSyncMessage
, mozilla::dom::ContentChild
* aChild
,
7647 mozilla::dom::ContentParent
* aParent
) {
7648 MOZ_ASSERT((aChild
&& !aParent
) || (!aChild
&& aParent
));
7650 if (aTransferable
) {
7651 nsTArray
<nsCString
> flavorList
;
7652 aTransferable
->FlavorsTransferableCanExport(flavorList
);
7654 for (uint32_t j
= 0; j
< flavorList
.Length(); ++j
) {
7655 nsCString
& flavorStr
= flavorList
[j
];
7656 if (!flavorStr
.Length()) {
7660 nsCOMPtr
<nsISupports
> data
;
7662 aTransferable
->GetTransferData(flavorStr
.get(), getter_AddRefs(data
));
7664 if (NS_FAILED(rv
) || !data
) {
7665 if (aInSyncMessage
) {
7666 // Can't do anything.
7670 // This is a hack to support kFilePromiseMime.
7671 // On Windows there just needs to be an entry for it,
7672 // and for OSX we need to create
7673 // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
7674 if (flavorStr
.EqualsLiteral(kFilePromiseMime
)) {
7675 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7676 item
->flavor() = flavorStr
;
7677 item
->data() = NS_ConvertUTF8toUTF16(flavorStr
);
7681 // Empty element, transfer only the flavor
7682 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7683 item
->flavor() = flavorStr
;
7684 item
->data() = nsString();
7688 if (nsCOMPtr
<nsISupportsString
> text
= do_QueryInterface(data
)) {
7689 nsAutoString dataAsString
;
7690 text
->GetData(dataAsString
);
7691 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7692 item
->flavor() = flavorStr
;
7693 item
->data() = dataAsString
;
7694 } else if (nsCOMPtr
<nsISupportsCString
> ctext
= do_QueryInterface(data
)) {
7695 nsAutoCString dataAsString
;
7696 ctext
->GetData(dataAsString
);
7698 Shmem dataAsShmem
= ConvertToShmem(aChild
, aParent
, dataAsString
);
7699 if (!dataAsShmem
.IsReadable() || !dataAsShmem
.Size
<char>()) {
7703 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7704 item
->flavor() = flavorStr
;
7705 item
->data() = std::move(dataAsShmem
);
7706 } else if (nsCOMPtr
<nsIInputStream
> stream
= do_QueryInterface(data
)) {
7707 // Images to be pasted on the clipboard are nsIInputStreams
7708 nsCString imageData
;
7709 NS_ConsumeStream(stream
, UINT32_MAX
, imageData
);
7711 Shmem imageDataShmem
= ConvertToShmem(aChild
, aParent
, imageData
);
7712 if (!imageDataShmem
.IsReadable() || !imageDataShmem
.Size
<char>()) {
7716 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7717 item
->flavor() = flavorStr
;
7718 item
->data() = std::move(imageDataShmem
);
7719 } else if (nsCOMPtr
<imgIContainer
> image
= do_QueryInterface(data
)) {
7720 // Images to be placed on the clipboard are imgIContainers.
7721 RefPtr
<mozilla::gfx::SourceSurface
> surface
= image
->GetFrame(
7722 imgIContainer::FRAME_CURRENT
,
7723 imgIContainer::FLAG_SYNC_DECODE
| imgIContainer::FLAG_ASYNC_NOTIFY
);
7727 RefPtr
<mozilla::gfx::DataSourceSurface
> dataSurface
=
7728 surface
->GetDataSurface();
7734 IShmemAllocator
* allocator
=
7735 aChild
? static_cast<IShmemAllocator
*>(aChild
)
7736 : static_cast<IShmemAllocator
*>(aParent
);
7737 Maybe
<Shmem
> surfaceData
=
7738 GetSurfaceData(dataSurface
, &length
, &stride
, allocator
);
7740 if (surfaceData
.isNothing()) {
7744 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7745 item
->flavor() = flavorStr
;
7746 // Turn item->data() into an nsCString prior to accessing it.
7747 item
->data() = std::move(surfaceData
.ref());
7749 IPCDataTransferImage
& imageDetails
= item
->imageDetails();
7750 mozilla::gfx::IntSize size
= dataSurface
->GetSize();
7751 imageDetails
.width() = size
.width
;
7752 imageDetails
.height() = size
.height
;
7753 imageDetails
.stride() = stride
;
7754 imageDetails
.format() = dataSurface
->GetFormat();
7756 // Otherwise, handle this as a file.
7757 nsCOMPtr
<BlobImpl
> blobImpl
;
7758 if (nsCOMPtr
<nsIFile
> file
= do_QueryInterface(data
)) {
7759 // If we can send this over as a blob, do so. Otherwise, we're
7760 // responding to a sync message and the child can't process the blob
7761 // constructor before processing our response, which would crash. In
7762 // that case, hope that the caller is nsClipboardProxy::GetData,
7763 // called from editor and send over images as raw data.
7764 if (aInSyncMessage
) {
7766 if (IsFileImage(file
, type
)) {
7768 SlurpFileToString(file
, data
);
7770 Shmem dataAsShmem
= ConvertToShmem(aChild
, aParent
, data
);
7771 if (!dataAsShmem
.IsReadable() || !dataAsShmem
.Size
<char>()) {
7775 IPCDataTransferItem
* item
=
7776 aIPCDataTransfer
->items().AppendElement();
7777 item
->flavor() = type
;
7778 item
->data() = std::move(dataAsShmem
);
7786 if (NS_SUCCEEDED(file
->IsDirectory(&isDir
)) && isDir
) {
7788 if (NS_WARN_IF(NS_FAILED(file
->GetPath(path
)))) {
7792 RefPtr
<FileSystemSecurity
> fss
=
7793 FileSystemSecurity::GetOrCreate();
7794 fss
->GrantAccessToContentProcess(aParent
->ChildID(), path
);
7798 blobImpl
= new FileBlobImpl(file
);
7800 IgnoredErrorResult rv
;
7802 // Ensure that file data is cached no that the content process
7803 // has this data available to it when passed over:
7804 blobImpl
->GetSize(rv
);
7805 if (NS_WARN_IF(rv
.Failed())) {
7809 blobImpl
->GetLastModified(rv
);
7810 if (NS_WARN_IF(rv
.Failed())) {
7814 if (aInSyncMessage
) {
7815 // Can't do anything.
7818 blobImpl
= do_QueryInterface(data
);
7821 IPCDataTransferData data
;
7824 // If we failed to create the blob actor, then this blob probably
7825 // can't get the file size for the underlying file, ignore it for
7826 // now. TODO pass this through anyway.
7828 nsresult rv
= IPCBlobUtils::Serialize(blobImpl
, aChild
, ipcBlob
);
7829 if (NS_WARN_IF(NS_FAILED(rv
))) {
7834 } else if (aParent
) {
7835 nsresult rv
= IPCBlobUtils::Serialize(blobImpl
, aParent
, ipcBlob
);
7836 if (NS_WARN_IF(NS_FAILED(rv
))) {
7843 IPCDataTransferItem
* item
= aIPCDataTransfer
->items().AppendElement();
7844 item
->flavor() = flavorStr
;
7845 item
->data() = data
;
7853 // The default type used for calling GetSurfaceData(). Gets surface data as
7855 struct GetSurfaceDataRawBuffer
{
7856 using ReturnType
= mozilla::UniquePtr
<char[]>;
7857 using BufferType
= char*;
7859 ReturnType
Allocate(size_t aSize
) { return ReturnType(new char[aSize
]); }
7861 static BufferType
GetBuffer(const ReturnType
& aReturnValue
) {
7862 return aReturnValue
.get();
7865 static ReturnType
NullValue() { return ReturnType(); }
7868 // The type used for calling GetSurfaceData() that allocates and writes to
7869 // a shared memory buffer.
7870 struct GetSurfaceDataShmem
{
7871 using ReturnType
= Maybe
<Shmem
>;
7872 using BufferType
= char*;
7874 explicit GetSurfaceDataShmem(IShmemAllocator
* aAllocator
)
7875 : mAllocator(aAllocator
) {}
7877 ReturnType
Allocate(size_t aSize
) {
7879 if (!mAllocator
->AllocShmem(aSize
, SharedMemory::TYPE_BASIC
, &shmem
)) {
7886 static BufferType
GetBuffer(const ReturnType
& aReturnValue
) {
7887 return aReturnValue
.isSome() ? aReturnValue
.ref().get
<char>() : nullptr;
7890 static ReturnType
NullValue() { return ReturnType(); }
7893 IShmemAllocator
* mAllocator
;
7897 * Get the pixel data from the given source surface and return it as a buffer.
7898 * The length and stride will be assigned from the surface.
7900 template <typename GetSurfaceDataContext
= GetSurfaceDataRawBuffer
>
7901 typename
GetSurfaceDataContext::ReturnType
GetSurfaceDataImpl(
7902 mozilla::gfx::DataSourceSurface
* aSurface
, size_t* aLength
,
7904 GetSurfaceDataContext aContext
= GetSurfaceDataContext()) {
7905 mozilla::gfx::DataSourceSurface::MappedSurface map
;
7906 if (!aSurface
->Map(mozilla::gfx::DataSourceSurface::MapType::READ
, &map
)) {
7907 return GetSurfaceDataContext::NullValue();
7911 size_t maxBufLen
= 0;
7912 nsresult rv
= nsContentUtils::CalculateBufferSizeForImage(
7913 map
.mStride
, aSurface
->GetSize(), aSurface
->GetFormat(), &maxBufLen
,
7915 if (NS_FAILED(rv
)) {
7917 return GetSurfaceDataContext::NullValue();
7920 // nsDependentCString wants null-terminated string.
7921 typename
GetSurfaceDataContext::ReturnType surfaceData
=
7922 aContext
.Allocate(maxBufLen
+ 1);
7923 if (GetSurfaceDataContext::GetBuffer(surfaceData
)) {
7924 memcpy(GetSurfaceDataContext::GetBuffer(surfaceData
),
7925 reinterpret_cast<char*>(map
.mData
), bufLen
);
7926 memset(GetSurfaceDataContext::GetBuffer(surfaceData
) + bufLen
, 0,
7927 maxBufLen
- bufLen
+ 1);
7930 *aLength
= maxBufLen
;
7931 *aStride
= map
.mStride
;
7936 } // Anonymous namespace.
7938 mozilla::UniquePtr
<char[]> nsContentUtils::GetSurfaceData(
7939 NotNull
<mozilla::gfx::DataSourceSurface
*> aSurface
, size_t* aLength
,
7941 return GetSurfaceDataImpl(aSurface
, aLength
, aStride
);
7944 Maybe
<Shmem
> nsContentUtils::GetSurfaceData(
7945 mozilla::gfx::DataSourceSurface
* aSurface
, size_t* aLength
,
7946 int32_t* aStride
, IShmemAllocator
* aAllocator
) {
7947 return GetSurfaceDataImpl(aSurface
, aLength
, aStride
,
7948 GetSurfaceDataShmem(aAllocator
));
7951 mozilla::Modifiers
nsContentUtils::GetWidgetModifiers(int32_t aModifiers
) {
7952 Modifiers result
= 0;
7953 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SHIFT
) {
7954 result
|= mozilla::MODIFIER_SHIFT
;
7956 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_CONTROL
) {
7957 result
|= mozilla::MODIFIER_CONTROL
;
7959 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_ALT
) {
7960 result
|= mozilla::MODIFIER_ALT
;
7962 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_META
) {
7963 result
|= mozilla::MODIFIER_META
;
7965 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_ALTGRAPH
) {
7966 result
|= mozilla::MODIFIER_ALTGRAPH
;
7968 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_CAPSLOCK
) {
7969 result
|= mozilla::MODIFIER_CAPSLOCK
;
7971 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_FN
) {
7972 result
|= mozilla::MODIFIER_FN
;
7974 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_FNLOCK
) {
7975 result
|= mozilla::MODIFIER_FNLOCK
;
7977 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_NUMLOCK
) {
7978 result
|= mozilla::MODIFIER_NUMLOCK
;
7980 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SCROLLLOCK
) {
7981 result
|= mozilla::MODIFIER_SCROLLLOCK
;
7983 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SYMBOL
) {
7984 result
|= mozilla::MODIFIER_SYMBOL
;
7986 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK
) {
7987 result
|= mozilla::MODIFIER_SYMBOLLOCK
;
7989 if (aModifiers
& nsIDOMWindowUtils::MODIFIER_OS
) {
7990 result
|= mozilla::MODIFIER_OS
;
7995 nsIWidget
* nsContentUtils::GetWidget(PresShell
* aPresShell
, nsPoint
* aOffset
) {
7999 nsIFrame
* frame
= aPresShell
->GetRootFrame();
8003 return frame
->GetView()->GetNearestWidget(aOffset
);
8006 int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton
) {
8009 return MouseButtonsFlag::eNoButtons
;
8010 case MouseButton::ePrimary
:
8011 return MouseButtonsFlag::ePrimaryFlag
;
8012 case MouseButton::eMiddle
:
8013 return MouseButtonsFlag::eMiddleFlag
;
8014 case MouseButton::eSecondary
:
8015 return MouseButtonsFlag::eSecondaryFlag
;
8017 return MouseButtonsFlag::e4thFlag
;
8019 return MouseButtonsFlag::e5thFlag
;
8021 NS_ERROR("Button not known.");
8026 LayoutDeviceIntPoint
nsContentUtils::ToWidgetPoint(
8027 const CSSPoint
& aPoint
, const nsPoint
& aOffset
,
8028 nsPresContext
* aPresContext
) {
8029 nsPoint layoutRelative
= CSSPoint::ToAppUnits(aPoint
) + aOffset
;
8030 nsPoint visualRelative
=
8031 ViewportUtils::LayoutToVisual(layoutRelative
, aPresContext
->PresShell());
8032 return LayoutDeviceIntPoint::FromAppUnitsRounded(
8033 visualRelative
, aPresContext
->AppUnitsPerDevPixel());
8036 nsView
* nsContentUtils::GetViewToDispatchEvent(nsPresContext
* aPresContext
,
8037 PresShell
** aPresShell
) {
8038 if (!aPresContext
|| !aPresShell
) {
8041 RefPtr
<PresShell
> presShell
= aPresContext
->PresShell();
8042 if (NS_WARN_IF(!presShell
)) {
8043 *aPresShell
= nullptr;
8046 nsViewManager
* viewManager
= presShell
->GetViewManager();
8048 presShell
.forget(aPresShell
); // XXX Is this intentional?
8051 presShell
.forget(aPresShell
);
8052 return viewManager
->GetRootView();
8055 nsresult
nsContentUtils::SendMouseEvent(
8056 mozilla::PresShell
* aPresShell
, const nsAString
& aType
, float aX
, float aY
,
8057 int32_t aButton
, int32_t aButtons
, int32_t aClickCount
, int32_t aModifiers
,
8058 bool aIgnoreRootScrollFrame
, float aPressure
,
8059 unsigned short aInputSourceArg
, uint32_t aIdentifier
, bool aToWindow
,
8060 bool* aPreventDefault
, bool aIsDOMEventSynthesized
,
8061 bool aIsWidgetEventSynthesized
) {
8063 nsCOMPtr
<nsIWidget
> widget
= GetWidget(aPresShell
, &offset
);
8064 if (!widget
) return NS_ERROR_FAILURE
;
8067 Maybe
<WidgetMouseEvent::ExitFrom
> exitFrom
;
8068 bool contextMenuKey
= false;
8069 if (aType
.EqualsLiteral("mousedown")) {
8071 } else if (aType
.EqualsLiteral("mouseup")) {
8073 } else if (aType
.EqualsLiteral("mousemove")) {
8075 } else if (aType
.EqualsLiteral("mouseover")) {
8076 msg
= eMouseEnterIntoWidget
;
8077 } else if (aType
.EqualsLiteral("mouseout")) {
8078 msg
= eMouseExitFromWidget
;
8079 exitFrom
= Some(WidgetMouseEvent::ePlatformChild
);
8080 } else if (aType
.EqualsLiteral("mousecancel")) {
8081 msg
= eMouseExitFromWidget
;
8082 exitFrom
= Some(XRE_IsParentProcess() ? WidgetMouseEvent::ePlatformTopLevel
8083 : WidgetMouseEvent::ePuppet
);
8084 } else if (aType
.EqualsLiteral("mouselongtap")) {
8085 msg
= eMouseLongTap
;
8086 } else if (aType
.EqualsLiteral("contextmenu")) {
8088 contextMenuKey
= (aButton
== 0);
8089 } else if (aType
.EqualsLiteral("MozMouseHittest")) {
8090 msg
= eMouseHitTest
;
8092 return NS_ERROR_FAILURE
;
8095 if (aInputSourceArg
== MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
) {
8096 aInputSourceArg
= MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
8099 WidgetMouseEvent
event(true, msg
, widget
,
8100 aIsWidgetEventSynthesized
8101 ? WidgetMouseEvent::eSynthesized
8102 : WidgetMouseEvent::eReal
,
8103 contextMenuKey
? WidgetMouseEvent::eContextMenuKey
8104 : WidgetMouseEvent::eNormal
);
8105 event
.pointerId
= aIdentifier
;
8106 event
.mModifiers
= GetWidgetModifiers(aModifiers
);
8107 event
.mButton
= aButton
;
8108 event
.mButtons
= aButtons
!= nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED
8110 : msg
== eMouseUp
? 0
8111 : GetButtonsFlagForButton(aButton
);
8112 event
.mPressure
= aPressure
;
8113 event
.mInputSource
= aInputSourceArg
;
8114 event
.mClickCount
= aClickCount
;
8115 event
.mTime
= PR_IntervalNow();
8116 event
.mFlags
.mIsSynthesizedForTests
= aIsDOMEventSynthesized
;
8117 event
.mExitFrom
= exitFrom
;
8119 nsPresContext
* presContext
= aPresShell
->GetPresContext();
8120 if (!presContext
) return NS_ERROR_FAILURE
;
8122 event
.mRefPoint
= ToWidgetPoint(CSSPoint(aX
, aY
), offset
, presContext
);
8123 event
.mIgnoreRootScrollFrame
= aIgnoreRootScrollFrame
;
8125 nsEventStatus status
= nsEventStatus_eIgnore
;
8127 RefPtr
<PresShell
> presShell
;
8129 GetViewToDispatchEvent(presContext
, getter_AddRefs(presShell
));
8130 if (!presShell
|| !view
) {
8131 return NS_ERROR_FAILURE
;
8133 return presShell
->HandleEvent(view
->GetFrame(), &event
, false, &status
);
8135 if (StaticPrefs::test_events_async_enabled()) {
8136 status
= widget
->DispatchInputEvent(&event
).mContentStatus
;
8138 nsresult rv
= widget
->DispatchEvent(&event
, status
);
8139 NS_ENSURE_SUCCESS(rv
, rv
);
8141 if (aPreventDefault
) {
8142 *aPreventDefault
= (status
== nsEventStatus_eConsumeNoDefault
);
8149 void nsContentUtils::FirePageHideEventForFrameLoaderSwap(
8150 nsIDocShellTreeItem
* aItem
, EventTarget
* aChromeEventHandler
,
8151 bool aOnlySystemGroup
) {
8152 MOZ_DIAGNOSTIC_ASSERT(aItem
);
8153 MOZ_DIAGNOSTIC_ASSERT(aChromeEventHandler
);
8155 RefPtr
<Document
> doc
= aItem
->GetDocument();
8156 NS_ASSERTION(doc
, "What happened here?");
8157 doc
->OnPageHide(true, aChromeEventHandler
, aOnlySystemGroup
);
8159 int32_t childCount
= 0;
8160 aItem
->GetInProcessChildCount(&childCount
);
8161 AutoTArray
<nsCOMPtr
<nsIDocShellTreeItem
>, 8> kids
;
8162 kids
.AppendElements(childCount
);
8163 for (int32_t i
= 0; i
< childCount
; ++i
) {
8164 aItem
->GetInProcessChildAt(i
, getter_AddRefs(kids
[i
]));
8167 for (uint32_t i
= 0; i
< kids
.Length(); ++i
) {
8169 FirePageHideEventForFrameLoaderSwap(kids
[i
], aChromeEventHandler
,
8175 // The pageshow event is fired for a given document only if IsShowing() returns
8176 // the same thing as aFireIfShowing. This gives us a way to fire pageshow only
8177 // on documents that are still loading or only on documents that are already
8180 void nsContentUtils::FirePageShowEventForFrameLoaderSwap(
8181 nsIDocShellTreeItem
* aItem
, EventTarget
* aChromeEventHandler
,
8182 bool aFireIfShowing
, bool aOnlySystemGroup
) {
8183 int32_t childCount
= 0;
8184 aItem
->GetInProcessChildCount(&childCount
);
8185 AutoTArray
<nsCOMPtr
<nsIDocShellTreeItem
>, 8> kids
;
8186 kids
.AppendElements(childCount
);
8187 for (int32_t i
= 0; i
< childCount
; ++i
) {
8188 aItem
->GetInProcessChildAt(i
, getter_AddRefs(kids
[i
]));
8191 for (uint32_t i
= 0; i
< kids
.Length(); ++i
) {
8193 FirePageShowEventForFrameLoaderSwap(kids
[i
], aChromeEventHandler
,
8194 aFireIfShowing
, aOnlySystemGroup
);
8198 RefPtr
<Document
> doc
= aItem
->GetDocument();
8199 NS_ASSERTION(doc
, "What happened here?");
8200 if (doc
->IsShowing() == aFireIfShowing
) {
8201 doc
->OnPageShow(true, aChromeEventHandler
, aOnlySystemGroup
);
8206 already_AddRefed
<nsPIWindowRoot
> nsContentUtils::GetWindowRoot(Document
* aDoc
) {
8208 if (nsPIDOMWindowOuter
* win
= aDoc
->GetWindow()) {
8209 return win
->GetTopWindowRoot();
8216 bool nsContentUtils::IsPreloadType(nsContentPolicyType aType
) {
8217 return (aType
== nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD
||
8218 aType
== nsIContentPolicy::TYPE_INTERNAL_MODULE_PRELOAD
||
8219 aType
== nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD
||
8220 aType
== nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
||
8221 aType
== nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD
||
8222 aType
== nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD
);
8226 bool nsContentUtils::IsUpgradableDisplayType(ExtContentPolicyType aType
) {
8227 MOZ_ASSERT(NS_IsMainThread());
8228 return (aType
== ExtContentPolicy::TYPE_IMAGE
||
8229 aType
== ExtContentPolicy::TYPE_MEDIA
);
8233 ReferrerPolicy
nsContentUtils::GetReferrerPolicyFromChannel(
8234 nsIChannel
* aChannel
) {
8235 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
8237 return ReferrerPolicy::_empty
;
8241 nsAutoCString headerValue
;
8242 rv
= httpChannel
->GetResponseHeader("referrer-policy"_ns
, headerValue
);
8243 if (NS_FAILED(rv
) || headerValue
.IsEmpty()) {
8244 return ReferrerPolicy::_empty
;
8247 return ReferrerInfo::ReferrerPolicyFromHeaderString(
8248 NS_ConvertUTF8toUTF16(headerValue
));
8252 bool nsContentUtils::IsNonSubresourceRequest(nsIChannel
* aChannel
) {
8253 nsLoadFlags loadFlags
= 0;
8254 aChannel
->GetLoadFlags(&loadFlags
);
8255 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
) {
8259 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
8260 nsContentPolicyType type
= loadInfo
->InternalContentPolicyType();
8261 return IsNonSubresourceInternalPolicyType(type
);
8265 bool nsContentUtils::IsNonSubresourceInternalPolicyType(
8266 nsContentPolicyType aType
) {
8267 return aType
== nsIContentPolicy::TYPE_DOCUMENT
||
8268 aType
== nsIContentPolicy::TYPE_INTERNAL_IFRAME
||
8269 aType
== nsIContentPolicy::TYPE_INTERNAL_FRAME
||
8270 aType
== nsIContentPolicy::TYPE_INTERNAL_WORKER
||
8271 aType
== nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
8275 bool nsContentUtils::IsThirdPartyWindowOrChannel(nsPIDOMWindowInner
* aWindow
,
8276 nsIChannel
* aChannel
,
8278 MOZ_ASSERT(!aWindow
|| !aChannel
,
8279 "A window and channel should not both be provided.");
8281 ThirdPartyUtil
* thirdPartyUtil
= ThirdPartyUtil::GetInstance();
8282 if (!thirdPartyUtil
) {
8286 // In the absence of a window or channel, we assume that we are first-party.
8287 bool thirdParty
= false;
8290 nsresult rv
= thirdPartyUtil
->IsThirdPartyWindow(aWindow
->GetOuterWindow(),
8292 if (NS_FAILED(rv
)) {
8293 // Ideally we would do something similar to the channel code path here,
8294 // but existing code depends on this behaviour.
8300 // Note, we must call IsThirdPartyChannel() here and not just try to
8301 // use nsILoadInfo.isThirdPartyContext. That nsILoadInfo property only
8302 // indicates if the parent loading window is third party or not. We
8303 // want to check the channel URI against the loading principal as well.
8305 thirdPartyUtil
->IsThirdPartyChannel(aChannel
, nullptr, &thirdParty
);
8306 if (NS_FAILED(rv
)) {
8307 // Assume third-party in case of failure
8311 // We check isThirdPartyWindow to expand the list of domains that are
8312 // considered first party (e.g., if facebook.com includes an iframe from
8313 // fatratgames.com, all subsources included in that iframe are considered
8314 // third-party with isThirdPartyChannel, even if they are not third-party
8315 // w.r.t. facebook.com), and isThirdPartyChannel to prevent top-level
8316 // navigations from being detected as third-party.
8317 bool isThirdPartyWindow
= true;
8318 nsCOMPtr
<nsIHttpChannelInternal
> chan
= do_QueryInterface(aChannel
, &rv
);
8319 if (NS_SUCCEEDED(rv
) && chan
) {
8320 nsCOMPtr
<nsIURI
> topWinURI
;
8321 rv
= chan
->GetTopWindowURI(getter_AddRefs(topWinURI
));
8322 if (NS_SUCCEEDED(rv
) && topWinURI
) {
8323 rv
= thirdPartyUtil
->IsThirdPartyURI(aURI
, topWinURI
,
8324 &isThirdPartyWindow
);
8325 if (NS_SUCCEEDED(rv
)) {
8326 thirdParty
= thirdParty
&& isThirdPartyWindow
;
8336 bool nsContentUtils::IsThirdPartyTrackingResourceWindow(
8337 nsPIDOMWindowInner
* aWindow
) {
8338 MOZ_ASSERT(aWindow
);
8340 Document
* document
= aWindow
->GetExtantDoc();
8345 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
8346 do_QueryInterface(document
->GetChannel());
8347 if (!classifiedChannel
) {
8351 return classifiedChannel
->IsThirdPartyTrackingResource();
8355 bool nsContentUtils::IsFirstPartyTrackingResourceWindow(
8356 nsPIDOMWindowInner
* aWindow
) {
8357 MOZ_ASSERT(aWindow
);
8359 Document
* document
= aWindow
->GetExtantDoc();
8364 nsCOMPtr
<nsIClassifiedChannel
> classifiedChannel
=
8365 do_QueryInterface(document
->GetChannel());
8366 if (!classifiedChannel
) {
8370 uint32_t classificationFlags
=
8371 classifiedChannel
->GetFirstPartyClassificationFlags();
8373 return mozilla::net::UrlClassifierCommon::IsTrackingClassificationFlag(
8374 classificationFlags
);
8379 // We put StringBuilder in the anonymous namespace to prevent anything outside
8380 // this file from accidentally being linked against it.
8381 class BulkAppender
{
8382 typedef typename
nsAString::size_type size_type
;
8385 explicit BulkAppender(BulkWriteHandle
<char16_t
>&& aHandle
)
8386 : mHandle(std::move(aHandle
)), mPosition(0) {}
8387 ~BulkAppender() = default;
8390 void AppendLiteral(const char16_t (&aStr
)[N
]) {
8392 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8393 memcpy(mHandle
.Elements() + mPosition
, aStr
, len
* sizeof(char16_t
));
8397 void Append(Span
<const char16_t
> aStr
) {
8398 size_t len
= aStr
.Length();
8399 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8400 // Both mHandle.Elements() and aStr.Elements() are guaranteed
8401 // to be non-null (by the string implementation and by Span,
8402 // respectively), so not checking the pointers for null before
8403 // memcpy does not lead to UB even if len was zero.
8404 memcpy(mHandle
.Elements() + mPosition
, aStr
.Elements(),
8405 len
* sizeof(char16_t
));
8409 void Append(Span
<const char> aStr
) {
8410 size_t len
= aStr
.Length();
8411 MOZ_ASSERT(mPosition
+ len
<= mHandle
.Length());
8412 ConvertLatin1toUtf16(aStr
, mHandle
.AsSpan().From(mPosition
));
8416 void Finish() { mHandle
.Finish(mPosition
, false); }
8419 mozilla::BulkWriteHandle
<char16_t
> mHandle
;
8420 size_type mPosition
;
8423 class StringBuilder
{
8425 // Try to keep the size of StringBuilder close to a jemalloc bucket size.
8426 static const uint32_t STRING_BUFFER_UNITS
= 1020;
8429 Unit() : mAtom(nullptr), mType(eUnknown
), mLength(0) {
8430 MOZ_COUNT_CTOR(StringBuilder::Unit
);
8433 if (mType
== eString
|| mType
== eStringWithEncode
) {
8436 MOZ_COUNT_DTOR(StringBuilder::Unit
);
8446 eTextFragmentWithEncode
,
8451 const char16_t
* mLiteral
;
8452 nsAutoString
* mString
;
8453 const nsTextFragment
* mTextFragment
;
8460 StringBuilder() : mLast(this), mLength(0) { MOZ_COUNT_CTOR(StringBuilder
); }
8462 MOZ_COUNTED_DTOR(StringBuilder
)
8464 void Append(nsAtom
* aAtom
) {
8465 Unit
* u
= AddUnit();
8467 u
->mType
= Unit::eAtom
;
8468 uint32_t len
= aAtom
->GetLength();
8474 void Append(const char16_t (&aLiteral
)[N
]) {
8475 Unit
* u
= AddUnit();
8476 u
->mLiteral
= aLiteral
;
8477 u
->mType
= Unit::eLiteral
;
8478 uint32_t len
= N
- 1;
8483 void Append(const nsAString
& aString
) {
8484 Unit
* u
= AddUnit();
8485 u
->mString
= new nsAutoString(aString
);
8486 u
->mType
= Unit::eString
;
8487 uint32_t len
= aString
.Length();
8492 void Append(nsAutoString
* aString
) {
8493 Unit
* u
= AddUnit();
8494 u
->mString
= aString
;
8495 u
->mType
= Unit::eString
;
8496 uint32_t len
= aString
->Length();
8501 void AppendWithAttrEncode(nsAutoString
* aString
, uint32_t aLen
) {
8502 Unit
* u
= AddUnit();
8503 u
->mString
= aString
;
8504 u
->mType
= Unit::eStringWithEncode
;
8509 void Append(const nsTextFragment
* aTextFragment
) {
8510 Unit
* u
= AddUnit();
8511 u
->mTextFragment
= aTextFragment
;
8512 u
->mType
= Unit::eTextFragment
;
8513 uint32_t len
= aTextFragment
->GetLength();
8518 void AppendWithEncode(const nsTextFragment
* aTextFragment
, uint32_t aLen
) {
8519 Unit
* u
= AddUnit();
8520 u
->mTextFragment
= aTextFragment
;
8521 u
->mType
= Unit::eTextFragmentWithEncode
;
8526 bool ToString(nsAString
& aOut
) {
8527 if (!mLength
.isValid()) {
8530 auto appenderOrErr
= aOut
.BulkWrite(mLength
.value(), 0, true);
8531 if (appenderOrErr
.isErr()) {
8535 BulkAppender appender
{appenderOrErr
.unwrap()};
8537 for (StringBuilder
* current
= this; current
;
8538 current
= current
->mNext
.get()) {
8539 uint32_t len
= current
->mUnits
.Length();
8540 for (uint32_t i
= 0; i
< len
; ++i
) {
8541 Unit
& u
= current
->mUnits
[i
];
8544 appender
.Append(*(u
.mAtom
));
8547 appender
.Append(*(u
.mString
));
8549 case Unit::eStringWithEncode
:
8550 EncodeAttrString(*(u
.mString
), appender
);
8552 case Unit::eLiteral
:
8553 appender
.Append(Span(u
.mLiteral
, u
.mLength
));
8555 case Unit::eTextFragment
:
8556 if (u
.mTextFragment
->Is2b()) {
8558 Span(u
.mTextFragment
->Get2b(), u
.mTextFragment
->GetLength()));
8561 Span(u
.mTextFragment
->Get1b(), u
.mTextFragment
->GetLength()));
8564 case Unit::eTextFragmentWithEncode
:
8565 if (u
.mTextFragment
->Is2b()) {
8567 Span(u
.mTextFragment
->Get2b(), u
.mTextFragment
->GetLength()),
8571 Span(u
.mTextFragment
->Get1b(), u
.mTextFragment
->GetLength()),
8576 MOZ_CRASH("Unknown unit type?");
8586 if (mLast
->mUnits
.Length() == STRING_BUFFER_UNITS
) {
8587 new StringBuilder(this);
8589 return mLast
->mUnits
.AppendElement();
8592 explicit StringBuilder(StringBuilder
* aFirst
) : mLast(nullptr), mLength(0) {
8593 MOZ_COUNT_CTOR(StringBuilder
);
8594 aFirst
->mLast
->mNext
= WrapUnique(this);
8595 aFirst
->mLast
= this;
8598 void EncodeAttrString(Span
<const char16_t
> aStr
, BulkAppender
& aAppender
) {
8599 size_t flushedUntil
= 0;
8600 size_t currentPosition
= 0;
8601 for (char16_t c
: aStr
) {
8604 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8605 aAppender
.AppendLiteral(u
""");
8606 flushedUntil
= currentPosition
+ 1;
8609 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8610 aAppender
.AppendLiteral(u
"&");
8611 flushedUntil
= currentPosition
+ 1;
8614 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8615 aAppender
.AppendLiteral(u
" ");
8616 flushedUntil
= currentPosition
+ 1;
8623 if (currentPosition
> flushedUntil
) {
8624 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8629 void EncodeTextFragment(Span
<const T
> aStr
, BulkAppender
& aAppender
) {
8630 size_t flushedUntil
= 0;
8631 size_t currentPosition
= 0;
8635 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8636 aAppender
.AppendLiteral(u
"<");
8637 flushedUntil
= currentPosition
+ 1;
8640 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8641 aAppender
.AppendLiteral(u
">");
8642 flushedUntil
= currentPosition
+ 1;
8645 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8646 aAppender
.AppendLiteral(u
"&");
8647 flushedUntil
= currentPosition
+ 1;
8650 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8651 aAppender
.AppendLiteral(u
" ");
8652 flushedUntil
= currentPosition
+ 1;
8659 if (currentPosition
> flushedUntil
) {
8660 aAppender
.Append(aStr
.FromTo(flushedUntil
, currentPosition
));
8664 AutoTArray
<Unit
, STRING_BUFFER_UNITS
> mUnits
;
8665 mozilla::UniquePtr
<StringBuilder
> mNext
;
8666 StringBuilder
* mLast
;
8667 // mLength is used only in the first StringBuilder object in the linked list.
8668 CheckedInt
<uint32_t> mLength
;
8673 static void AppendEncodedCharacters(const nsTextFragment
* aText
,
8674 StringBuilder
& aBuilder
) {
8675 uint32_t extraSpaceNeeded
= 0;
8676 uint32_t len
= aText
->GetLength();
8677 if (aText
->Is2b()) {
8678 const char16_t
* data
= aText
->Get2b();
8679 for (uint32_t i
= 0; i
< len
; ++i
) {
8680 const char16_t c
= data
[i
];
8683 extraSpaceNeeded
+= ArrayLength("<") - 2;
8686 extraSpaceNeeded
+= ArrayLength(">") - 2;
8689 extraSpaceNeeded
+= ArrayLength("&") - 2;
8692 extraSpaceNeeded
+= ArrayLength(" ") - 2;
8699 const char* data
= aText
->Get1b();
8700 for (uint32_t i
= 0; i
< len
; ++i
) {
8701 const unsigned char c
= data
[i
];
8704 extraSpaceNeeded
+= ArrayLength("<") - 2;
8707 extraSpaceNeeded
+= ArrayLength(">") - 2;
8710 extraSpaceNeeded
+= ArrayLength("&") - 2;
8713 extraSpaceNeeded
+= ArrayLength(" ") - 2;
8721 if (extraSpaceNeeded
) {
8722 aBuilder
.AppendWithEncode(aText
, len
+ extraSpaceNeeded
);
8724 aBuilder
.Append(aText
);
8728 static void AppendEncodedAttributeValue(nsAutoString
* aValue
,
8729 StringBuilder
& aBuilder
) {
8730 const char16_t
* c
= aValue
->BeginReading();
8731 const char16_t
* end
= aValue
->EndReading();
8733 uint32_t extraSpaceNeeded
= 0;
8737 extraSpaceNeeded
+= ArrayLength(""") - 2;
8740 extraSpaceNeeded
+= ArrayLength("&") - 2;
8743 extraSpaceNeeded
+= ArrayLength(" ") - 2;
8751 if (extraSpaceNeeded
) {
8752 aBuilder
.AppendWithAttrEncode(aValue
, aValue
->Length() + extraSpaceNeeded
);
8754 aBuilder
.Append(aValue
);
8758 static void StartElement(Element
* aContent
, StringBuilder
& aBuilder
) {
8759 nsAtom
* localName
= aContent
->NodeInfo()->NameAtom();
8760 int32_t tagNS
= aContent
->GetNameSpaceID();
8762 aBuilder
.Append(u
"<");
8763 if (aContent
->IsHTMLElement() || aContent
->IsSVGElement() ||
8764 aContent
->IsMathMLElement()) {
8765 aBuilder
.Append(localName
);
8767 aBuilder
.Append(aContent
->NodeName());
8770 CustomElementData
* ceData
= aContent
->GetCustomElementData();
8772 nsAtom
* isAttr
= ceData
->GetIs(aContent
);
8773 if (isAttr
&& !aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::is
)) {
8774 aBuilder
.Append(uR
"( is=")");
8775 aBuilder.Append(nsDependentAtomString(isAttr));
8776 aBuilder.Append(uR"(")");
8780 int32_t count
= aContent
->GetAttrCount();
8781 for (int32_t i
= 0; i
< count
; i
++) {
8782 const nsAttrName
* name
= aContent
->GetAttrNameAt(i
);
8783 int32_t attNs
= name
->NamespaceID();
8784 nsAtom
* attName
= name
->LocalName();
8786 // Filter out any attribute starting with [-|_]moz
8787 nsDependentAtomString
attrNameStr(attName
);
8788 if (StringBeginsWith(attrNameStr
, u
"_moz"_ns
) ||
8789 StringBeginsWith(attrNameStr
, u
"-moz"_ns
)) {
8793 auto* attValue
= new nsAutoString();
8794 aContent
->GetAttr(attNs
, attName
, *attValue
);
8796 // Filter out special case of <br type="_moz*"> used by the editor.
8798 if (localName
== nsGkAtoms::br
&& tagNS
== kNameSpaceID_XHTML
&&
8799 attName
== nsGkAtoms::type
&& attNs
== kNameSpaceID_None
&&
8800 StringBeginsWith(*attValue
, u
"_moz"_ns
)) {
8805 aBuilder
.Append(u
" ");
8807 if (MOZ_LIKELY(attNs
== kNameSpaceID_None
) ||
8808 (attNs
== kNameSpaceID_XMLNS
&& attName
== nsGkAtoms::xmlns
)) {
8809 // Nothing else required
8810 } else if (attNs
== kNameSpaceID_XML
) {
8811 aBuilder
.Append(u
"xml:");
8812 } else if (attNs
== kNameSpaceID_XMLNS
) {
8813 aBuilder
.Append(u
"xmlns:");
8814 } else if (attNs
== kNameSpaceID_XLink
) {
8815 aBuilder
.Append(u
"xlink:");
8817 nsAtom
* prefix
= name
->GetPrefix();
8819 aBuilder
.Append(prefix
);
8820 aBuilder
.Append(u
":");
8824 aBuilder
.Append(attName
);
8825 aBuilder
.Append(uR
"(=")");
8826 AppendEncodedAttributeValue(attValue, aBuilder);
8827 aBuilder.Append(uR"(")");
8830 aBuilder
.Append(u
">");
8833 // Per HTML spec we should append one \n if the first child of
8834 // pre/textarea/listing is a textnode and starts with a \n.
8835 // But because browsers haven't traditionally had that behavior,
8836 // we're not changing our behavior either - yet.
8837 if (aContent->IsHTMLElement()) {
8838 if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
8839 localName == nsGkAtoms::listing) {
8840 nsIContent* fc = aContent->GetFirstChild();
8842 (fc->NodeType() == nsINode::TEXT_NODE ||
8843 fc->NodeType() == nsINode::CDATA_SECTION_NODE)) {
8844 const nsTextFragment* text = fc->GetText();
8845 if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
8846 aBuilder.Append("\n");
8853 static inline bool ShouldEscape(nsIContent
* aParent
) {
8854 if (!aParent
|| !aParent
->IsHTMLElement()) {
8858 static const nsAtom
* nonEscapingElements
[] = {
8859 nsGkAtoms::style
, nsGkAtoms::script
, nsGkAtoms::xmp
,
8860 nsGkAtoms::iframe
, nsGkAtoms::noembed
, nsGkAtoms::noframes
,
8861 nsGkAtoms::plaintext
, nsGkAtoms::noscript
};
8862 static mozilla::BitBloomFilter
<12, nsAtom
> sFilter
;
8863 static bool sInitialized
= false;
8864 if (!sInitialized
) {
8865 sInitialized
= true;
8866 for (auto& nonEscapingElement
: nonEscapingElements
) {
8867 sFilter
.add(nonEscapingElement
);
8871 nsAtom
* tag
= aParent
->NodeInfo()->NameAtom();
8872 if (sFilter
.mightContain(tag
)) {
8873 for (auto& nonEscapingElement
: nonEscapingElements
) {
8874 if (tag
== nonEscapingElement
) {
8875 if (MOZ_UNLIKELY(tag
== nsGkAtoms::noscript
) &&
8876 MOZ_UNLIKELY(!aParent
->OwnerDoc()->IsScriptEnabled())) {
8886 static inline bool IsVoidTag(Element
* aElement
) {
8887 if (!aElement
->IsHTMLElement()) {
8890 return FragmentOrElement::IsHTMLVoid(aElement
->NodeInfo()->NameAtom());
8893 bool nsContentUtils::SerializeNodeToMarkup(nsINode
* aRoot
,
8894 bool aDescendentsOnly
,
8896 // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true
8897 MOZ_ASSERT(aDescendentsOnly
|| aRoot
->NodeType() != nsINode::DOCUMENT_NODE
);
8900 aDescendentsOnly
? aRoot
->GetFirstChildOfTemplateOrNode() : aRoot
;
8906 StringBuilder builder
;
8909 bool isVoid
= false;
8910 switch (current
->NodeType()) {
8911 case nsINode::ELEMENT_NODE
: {
8912 Element
* elem
= current
->AsElement();
8913 StartElement(elem
, builder
);
8914 isVoid
= IsVoidTag(elem
);
8915 if (!isVoid
&& (next
= current
->GetFirstChildOfTemplateOrNode())) {
8922 case nsINode::TEXT_NODE
:
8923 case nsINode::CDATA_SECTION_NODE
: {
8924 const nsTextFragment
* text
= ¤t
->AsText()->TextFragment();
8925 nsIContent
* parent
= current
->GetParent();
8926 if (ShouldEscape(parent
)) {
8927 AppendEncodedCharacters(text
, builder
);
8929 builder
.Append(text
);
8934 case nsINode::COMMENT_NODE
: {
8935 builder
.Append(u
"<!--");
8936 builder
.Append(static_cast<nsIContent
*>(current
)->GetText());
8937 builder
.Append(u
"-->");
8941 case nsINode::DOCUMENT_TYPE_NODE
: {
8942 builder
.Append(u
"<!DOCTYPE ");
8943 builder
.Append(current
->NodeName());
8944 builder
.Append(u
">");
8948 case nsINode::PROCESSING_INSTRUCTION_NODE
: {
8949 builder
.Append(u
"<?");
8950 builder
.Append(current
->NodeName());
8951 builder
.Append(u
" ");
8952 builder
.Append(static_cast<nsIContent
*>(current
)->GetText());
8953 builder
.Append(u
">");
8959 if (!isVoid
&& current
->NodeType() == nsINode::ELEMENT_NODE
) {
8960 builder
.Append(u
"</");
8961 nsIContent
* elem
= static_cast<nsIContent
*>(current
);
8962 if (elem
->IsHTMLElement() || elem
->IsSVGElement() ||
8963 elem
->IsMathMLElement()) {
8964 builder
.Append(elem
->NodeInfo()->NameAtom());
8966 builder
.Append(current
->NodeName());
8968 builder
.Append(u
">");
8972 if (current
== aRoot
) {
8973 return builder
.ToString(aOut
);
8976 if ((next
= current
->GetNextSibling())) {
8981 current
= current
->GetParentNode();
8983 // Handle template element. If the parent is a template's content,
8984 // then adjust the parent to be the template element.
8985 if (current
!= aRoot
&&
8986 current
->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE
) {
8987 DocumentFragment
* frag
= static_cast<DocumentFragment
*>(current
);
8988 nsIContent
* fragHost
= frag
->GetHost();
8989 if (fragHost
&& fragHost
->IsTemplateElement()) {
8994 if (aDescendentsOnly
&& current
== aRoot
) {
8995 return builder
.ToString(aOut
);
9001 bool nsContentUtils::IsSpecificAboutPage(JSObject
* aGlobal
, const char* aUri
) {
9002 // aUri must start with about: or this isn't the right function to be using.
9003 MOZ_ASSERT(strncmp(aUri
, "about:", 6) == 0);
9005 // Make sure the global is a window
9006 MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal
));
9007 nsGlobalWindowInner
* win
= xpc::WindowOrNull(aGlobal
);
9012 nsCOMPtr
<nsIPrincipal
> principal
= win
->GetPrincipal();
9013 NS_ENSURE_TRUE(principal
, false);
9015 // First check the scheme to avoid getting long specs in the common case.
9016 if (!principal
->SchemeIs("about")) {
9021 principal
->GetAsciiSpec(spec
);
9023 return spec
.EqualsASCII(aUri
);
9027 void nsContentUtils::SetScrollbarsVisibility(nsIDocShell
* aDocShell
,
9032 auto pref
= aVisible
? ScrollbarPreference::Auto
: ScrollbarPreference::Never
;
9033 nsDocShell::Cast(aDocShell
)->SetScrollbarPreference(pref
);
9037 nsIDocShell
* nsContentUtils::GetDocShellForEventTarget(EventTarget
* aTarget
) {
9038 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
;
9040 if (nsCOMPtr
<nsINode
> node
= do_QueryInterface(aTarget
)) {
9043 do_QueryInterface(node
->OwnerDoc()->GetScriptHandlingObject(ignore
));
9044 } else if ((innerWindow
= do_QueryInterface(aTarget
))) {
9045 // Nothing else to do
9047 nsCOMPtr
<DOMEventTargetHelper
> helper
= do_QueryInterface(aTarget
);
9049 innerWindow
= helper
->GetOwner();
9054 return innerWindow
->GetDocShell();
9061 * Note: this function only relates to figuring out HTTPS state, which is an
9062 * input to the Secure Context algorithm. We are not actually implementing any
9063 * part of the Secure Context algorithm itself here.
9065 * This is a bit of a hack. Ideally we'd propagate HTTPS state through
9066 * nsIChannel as described in the Fetch and HTML specs, but making channels
9067 * know about whether they should inherit HTTPS state, propagating information
9068 * about who the channel's "client" is, exposing GetHttpsState API on channels
9069 * and modifying the various cache implementations to store and retrieve HTTPS
9070 * state involves a huge amount of code (see bug 1220687). We avoid that for
9071 * now using this function.
9073 * This function takes advantage of the observation that we can return true if
9074 * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for
9075 * the document's origin (e.g. the origin has a scheme of 'https' or host
9076 * 'localhost' etc.). Since we generally propagate a creator document's origin
9077 * onto data:, blob:, etc. documents, this works for them too.
9079 * The scenario where this observation breaks down is sandboxing without the
9080 * 'allow-same-origin' flag, since in this case a document is given a unique
9081 * origin (IsOriginPotentiallyTrustworthy would return false). We handle that
9082 * by using the origin that the document would have had had it not been
9085 * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's
9086 * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of
9087 * sandboxing is limited to the immediate sandbox. In the case that aDocument
9088 * should inherit its origin (e.g. data: URI) but its parent has ended up
9089 * with a unique origin due to sandboxing further up the parent chain we may
9090 * end up returning false when we would ideally return true (since we will
9091 * examine the parent's origin for 'https' and not finding it.) This means
9092 * that we may restrict the privileges of some pages unnecessarily in this
9096 bool nsContentUtils::HttpsStateIsModern(Document
* aDocument
) {
9101 nsCOMPtr
<nsIPrincipal
> principal
= aDocument
->NodePrincipal();
9103 if (principal
->IsSystemPrincipal()) {
9107 // If aDocument is sandboxed, try and get the principal that it would have
9108 // been given had it not been sandboxed:
9109 if (principal
->GetIsNullPrincipal() &&
9110 (aDocument
->GetSandboxFlags() & SANDBOXED_ORIGIN
)) {
9111 nsIChannel
* channel
= aDocument
->GetChannel();
9113 nsCOMPtr
<nsIScriptSecurityManager
> ssm
=
9114 nsContentUtils::GetSecurityManager();
9115 nsresult rv
= ssm
->GetChannelResultPrincipalIfNotSandboxed(
9116 channel
, getter_AddRefs(principal
));
9117 if (NS_FAILED(rv
)) {
9120 if (principal
->IsSystemPrincipal()) {
9121 // If a document with the system principal is sandboxing a subdocument
9122 // that would normally inherit the embedding element's principal (e.g.
9123 // a srcdoc document) then the embedding document does not trust the
9124 // content that is written to the embedded document. Unlike when the
9125 // embedding document is https, in this case we have no indication as
9126 // to whether the embedded document's contents are delivered securely
9127 // or not, and the sandboxing would possibly indicate that they were
9128 // not. To play it safe we return false here. (See bug 1162772
9135 if (principal
->GetIsNullPrincipal()) {
9139 MOZ_ASSERT(principal
->GetIsContentPrincipal());
9141 return principal
->GetIsOriginPotentiallyTrustworthy();
9145 bool nsContentUtils::ComputeIsSecureContext(nsIChannel
* aChannel
) {
9146 MOZ_ASSERT(aChannel
);
9148 nsCOMPtr
<nsIScriptSecurityManager
> ssm
= nsContentUtils::GetSecurityManager();
9149 nsCOMPtr
<nsIPrincipal
> principal
;
9150 nsresult rv
= ssm
->GetChannelResultPrincipalIfNotSandboxed(
9151 aChannel
, getter_AddRefs(principal
));
9152 if (NS_FAILED(rv
)) {
9156 const RefPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
9158 if (principal
->IsSystemPrincipal()) {
9159 // If the load would've been sandboxed, treat this load as an untrusted
9160 // load, as system code considers sandboxed resources insecure.
9161 return !loadInfo
->GetLoadingSandboxed();
9164 if (principal
->GetIsNullPrincipal()) {
9168 if (const RefPtr
<WindowContext
> windowContext
=
9169 WindowContext::GetById(loadInfo
->GetInnerWindowID())) {
9170 if (!windowContext
->GetIsSecureContext()) {
9175 return principal
->GetIsOriginPotentiallyTrustworthy();
9179 void nsContentUtils::TryToUpgradeElement(Element
* aElement
) {
9180 NodeInfo
* nodeInfo
= aElement
->NodeInfo();
9181 RefPtr
<nsAtom
> typeAtom
=
9182 aElement
->GetCustomElementData()->GetCustomElementType();
9184 MOZ_ASSERT(nodeInfo
->NameAtom()->Equals(nodeInfo
->LocalName()));
9185 CustomElementDefinition
* definition
=
9186 nsContentUtils::LookupCustomElementDefinition(
9187 nodeInfo
->GetDocument(), nodeInfo
->NameAtom(),
9188 nodeInfo
->NamespaceID(), typeAtom
);
9190 nsContentUtils::EnqueueUpgradeReaction(aElement
, definition
);
9192 // Add an unresolved custom element that is a candidate for upgrade when a
9193 // custom element is connected to the document.
9194 nsContentUtils::RegisterUnresolvedElement(aElement
, typeAtom
);
9199 static void DoCustomElementCreate(Element
** aElement
, JSContext
* aCx
,
9200 Document
* aDoc
, NodeInfo
* aNodeInfo
,
9201 CustomElementConstructor
* aConstructor
,
9203 JS::Rooted
<JS::Value
> constructResult(aCx
);
9204 aConstructor
->Construct(&constructResult
, aRv
, "Custom Element Create",
9205 CallbackFunction::eRethrowExceptions
);
9210 RefPtr
<Element
> element
;
9211 // constructResult is an ObjectValue because construction with a callback
9212 // always forms the return value from a JSObject.
9213 UNWRAP_OBJECT(Element
, &constructResult
, element
);
9214 if (aNodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9215 if (!element
|| !element
->IsHTMLElement()) {
9216 aRv
.ThrowTypeError
<MSG_DOES_NOT_IMPLEMENT_INTERFACE
>("\"this\"",
9221 if (!element
|| !element
->IsXULElement()) {
9222 aRv
.ThrowTypeError
<MSG_DOES_NOT_IMPLEMENT_INTERFACE
>("\"this\"",
9228 nsAtom
* localName
= aNodeInfo
->NameAtom();
9230 if (aDoc
!= element
->OwnerDoc() || element
->GetParentNode() ||
9231 element
->HasChildren() || element
->GetAttrCount() ||
9232 element
->NodeInfo()->NameAtom() != localName
) {
9233 aRv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
9237 element
.forget(aElement
);
9241 nsresult
nsContentUtils::NewXULOrHTMLElement(
9242 Element
** aResult
, mozilla::dom::NodeInfo
* aNodeInfo
,
9243 FromParser aFromParser
, nsAtom
* aIsAtom
,
9244 mozilla::dom::CustomElementDefinition
* aDefinition
) {
9245 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
= aNodeInfo
;
9246 MOZ_ASSERT(nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
) ||
9247 nodeInfo
->NamespaceEquals(kNameSpaceID_XUL
),
9248 "Can only create XUL or XHTML elements.");
9250 nsAtom
* name
= nodeInfo
->NameAtom();
9251 int32_t tag
= eHTMLTag_unknown
;
9252 bool isCustomElementName
= false;
9253 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9254 tag
= nsHTMLTags::CaseSensitiveAtomTagToId(name
);
9255 isCustomElementName
=
9256 (tag
== eHTMLTag_userdefined
&&
9257 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XHTML
));
9258 } else { // kNameSpaceID_XUL
9260 // Make sure the customized built-in element to be constructed confirms
9261 // to our naming requirement, i.e. [is] must be a dashed name and
9262 // the tag name must not.
9263 // if so, set isCustomElementName to false to kick off all the logics
9264 // that pick up aIsAtom.
9265 if (nsContentUtils::IsNameWithDash(aIsAtom
) &&
9266 !nsContentUtils::IsNameWithDash(name
)) {
9267 isCustomElementName
= false;
9269 isCustomElementName
=
9270 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XUL
);
9273 isCustomElementName
=
9274 nsContentUtils::IsCustomElementName(name
, kNameSpaceID_XUL
);
9278 nsAtom
* tagAtom
= nodeInfo
->NameAtom();
9279 nsAtom
* typeAtom
= nullptr;
9280 bool isCustomElement
= isCustomElementName
|| aIsAtom
;
9281 if (isCustomElement
) {
9282 typeAtom
= isCustomElementName
? tagAtom
: aIsAtom
;
9285 MOZ_ASSERT_IF(aDefinition
, isCustomElement
);
9287 // https://dom.spec.whatwg.org/#concept-create-element
9288 // We only handle the "synchronous custom elements flag is set" now.
9289 // For the unset case (e.g. cloning a node), see bug 1319342 for that.
9291 RefPtr
<CustomElementDefinition
> definition
= aDefinition
;
9292 if (isCustomElement
&& !definition
) {
9293 MOZ_ASSERT(nodeInfo
->NameAtom()->Equals(nodeInfo
->LocalName()));
9294 definition
= nsContentUtils::LookupCustomElementDefinition(
9295 nodeInfo
->GetDocument(), nodeInfo
->NameAtom(), nodeInfo
->NamespaceID(),
9299 // It might be a problem that parser synchronously calls constructor, so filed
9300 // bug 1378079 to figure out what we should do for parser case.
9303 * Synchronous custom elements flag is determined by 3 places in spec,
9304 * 1) create an element for a token, the flag is determined by
9305 * "will execute script" which is not originally created
9306 * for the HTML fragment parsing algorithm.
9307 * 2) createElement and createElementNS, the flag is the same as
9309 * 3) clone a node, our implementation will not go into this function.
9310 * For the unset case which is non-synchronous only applied for
9313 bool synchronousCustomElements
= aFromParser
!= dom::FROM_PARSER_FRAGMENT
;
9314 // Per discussion in https://github.com/w3c/webcomponents/issues/635,
9315 // use entry global in those places that are called from JS APIs and use the
9316 // node document's global object if it is called from parser.
9317 nsIGlobalObject
* global
;
9318 if (aFromParser
== dom::NOT_FROM_PARSER
) {
9319 global
= GetEntryGlobal();
9321 // Documents created from the PrototypeDocumentSink always use
9322 // NOT_FROM_PARSER for non-XUL elements. We can get the global from the
9323 // document in that case.
9325 Document
* doc
= nodeInfo
->GetDocument();
9326 if (doc
&& doc
->LoadedFromPrototype()) {
9327 global
= doc
->GetScopeObject();
9331 global
= nodeInfo
->GetDocument()->GetScopeObject();
9334 // In browser chrome code, one may have access to a document which doesn't
9335 // have scope object anymore.
9336 return NS_ERROR_FAILURE
;
9339 AutoAllowLegacyScriptExecution exemption
;
9340 AutoEntryScript
aes(global
, "create custom elements");
9341 JSContext
* cx
= aes
.cx();
9345 if (definition
->IsCustomBuiltIn()) {
9346 // SetupCustomElement() should be called with an element that don't have
9347 // CustomElementData setup, if not we will hit the assertion in
9348 // SetCustomElementData().
9350 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9352 CreateHTMLElement(tag
, nodeInfo
.forget(), aFromParser
).take();
9354 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9356 (*aResult
)->SetCustomElementData(new CustomElementData(typeAtom
));
9357 if (synchronousCustomElements
) {
9358 CustomElementRegistry::Upgrade(*aResult
, definition
, rv
);
9359 if (rv
.MaybeSetPendingException(cx
)) {
9360 aes
.ReportException();
9363 nsContentUtils::EnqueueUpgradeReaction(*aResult
, definition
);
9370 if (synchronousCustomElements
) {
9371 definition
->mPrefixStack
.AppendElement(nodeInfo
->GetPrefixAtom());
9372 RefPtr
<Document
> doc
= nodeInfo
->GetDocument();
9373 DoCustomElementCreate(aResult
, cx
, doc
, nodeInfo
,
9374 MOZ_KnownLive(definition
->mConstructor
), rv
);
9375 if (rv
.MaybeSetPendingException(cx
)) {
9376 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9377 NS_IF_ADDREF(*aResult
= NS_NewHTMLUnknownElement(nodeInfo
.forget(),
9380 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9382 (*aResult
)->SetDefined(false);
9384 definition
->mPrefixStack
.RemoveLastElement();
9389 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9390 NS_IF_ADDREF(*aResult
=
9391 NS_NewHTMLElement(nodeInfo
.forget(), aFromParser
));
9393 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9395 (*aResult
)->SetCustomElementData(new CustomElementData(definition
->mType
));
9396 nsContentUtils::EnqueueUpgradeReaction(*aResult
, definition
);
9400 if (nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
9401 // Per the Custom Element specification, unknown tags that are valid custom
9402 // element names should be HTMLElement instead of HTMLUnknownElement.
9403 if (isCustomElementName
) {
9404 NS_IF_ADDREF(*aResult
=
9405 NS_NewHTMLElement(nodeInfo
.forget(), aFromParser
));
9407 *aResult
= CreateHTMLElement(tag
, nodeInfo
.forget(), aFromParser
).take();
9410 NS_IF_ADDREF(*aResult
= nsXULElement::Construct(nodeInfo
.forget()));
9414 return NS_ERROR_OUT_OF_MEMORY
;
9417 if (isCustomElement
) {
9418 (*aResult
)->SetCustomElementData(new CustomElementData(typeAtom
));
9419 nsContentUtils::RegisterCallbackUpgradeElement(*aResult
, typeAtom
);
9425 CustomElementRegistry
* nsContentUtils::GetCustomElementRegistry(
9429 if (!aDoc
->GetDocShell()) {
9433 nsPIDOMWindowInner
* window
= aDoc
->GetInnerWindow();
9438 return window
->CustomElements();
9442 CustomElementDefinition
* nsContentUtils::LookupCustomElementDefinition(
9443 Document
* aDoc
, nsAtom
* aNameAtom
, uint32_t aNameSpaceID
,
9444 nsAtom
* aTypeAtom
) {
9445 if (aNameSpaceID
!= kNameSpaceID_XUL
&& aNameSpaceID
!= kNameSpaceID_XHTML
) {
9449 RefPtr
<CustomElementRegistry
> registry
= GetCustomElementRegistry(aDoc
);
9454 return registry
->LookupCustomElementDefinition(aNameAtom
, aNameSpaceID
,
9459 void nsContentUtils::RegisterCallbackUpgradeElement(Element
* aElement
,
9460 nsAtom
* aTypeName
) {
9461 MOZ_ASSERT(aElement
);
9463 Document
* doc
= aElement
->OwnerDoc();
9464 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
9466 registry
->RegisterCallbackUpgradeElement(aElement
, aTypeName
);
9471 void nsContentUtils::RegisterUnresolvedElement(Element
* aElement
,
9472 nsAtom
* aTypeName
) {
9473 MOZ_ASSERT(aElement
);
9475 Document
* doc
= aElement
->OwnerDoc();
9476 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
9478 registry
->RegisterUnresolvedElement(aElement
, aTypeName
);
9483 void nsContentUtils::UnregisterUnresolvedElement(Element
* aElement
) {
9484 MOZ_ASSERT(aElement
);
9486 nsAtom
* typeAtom
= aElement
->GetCustomElementData()->GetCustomElementType();
9487 Document
* doc
= aElement
->OwnerDoc();
9488 CustomElementRegistry
* registry
= GetCustomElementRegistry(doc
);
9490 registry
->UnregisterUnresolvedElement(aElement
, typeAtom
);
9495 void nsContentUtils::EnqueueUpgradeReaction(
9496 Element
* aElement
, CustomElementDefinition
* aDefinition
) {
9497 MOZ_ASSERT(aElement
);
9499 Document
* doc
= aElement
->OwnerDoc();
9501 // No DocGroup means no custom element reactions stack.
9502 if (!doc
->GetDocGroup()) {
9506 CustomElementReactionsStack
* stack
=
9507 doc
->GetDocGroup()->CustomElementReactionsStack();
9508 stack
->EnqueueUpgradeReaction(aElement
, aDefinition
);
9512 void nsContentUtils::EnqueueLifecycleCallback(
9513 ElementCallbackType aType
, Element
* aCustomElement
,
9514 LifecycleCallbackArgs
* aArgs
,
9515 LifecycleAdoptedCallbackArgs
* aAdoptedCallbackArgs
,
9516 CustomElementDefinition
* aDefinition
) {
9517 // No DocGroup means no custom element reactions stack.
9518 if (!aCustomElement
->OwnerDoc()->GetDocGroup()) {
9522 CustomElementRegistry::EnqueueLifecycleCallback(
9523 aType
, aCustomElement
, aArgs
, aAdoptedCallbackArgs
, aDefinition
);
9527 void nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
9528 Document
* aDocument
, nsTArray
<nsIContent
*>& aElements
) {
9529 MOZ_ASSERT(aDocument
);
9531 size_t oldLength
= aElements
.Length();
9534 if (PresShell
* presShell
= aDocument
->GetPresShell()) {
9535 if (nsIFrame
* scrollFrame
= presShell
->GetRootScrollFrame()) {
9536 nsIAnonymousContentCreator
* creator
= do_QueryFrame(scrollFrame
);
9539 "scroll frame should always implement nsIAnonymousContentCreator");
9540 creator
->AppendAnonymousContentTo(aElements
, 0);
9542 if (nsCanvasFrame
* canvasFrame
= presShell
->GetCanvasFrame()) {
9543 canvasFrame
->AppendAnonymousContentTo(aElements
, 0);
9548 for (size_t i
= oldLength
; i
< aElements
.Length(); i
++) {
9550 aElements
[i
]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
),
9551 "Someone here has lied, or missed to flag the node");
9556 static void AppendNativeAnonymousChildrenFromFrame(nsIFrame
* aFrame
,
9557 nsTArray
<nsIContent
*>& aKids
,
9559 if (nsIAnonymousContentCreator
* ac
= do_QueryFrame(aFrame
)) {
9560 ac
->AppendAnonymousContentTo(aKids
, aFlags
);
9565 void nsContentUtils::AppendNativeAnonymousChildren(const nsIContent
* aContent
,
9566 nsTArray
<nsIContent
*>& aKids
,
9568 if (aContent
->MayHaveAnonymousChildren()) {
9569 if (nsIFrame
* primaryFrame
= aContent
->GetPrimaryFrame()) {
9570 // NAC created by the element's primary frame.
9571 AppendNativeAnonymousChildrenFromFrame(primaryFrame
, aKids
, aFlags
);
9573 // NAC created by any other non-primary frames for the element.
9574 AutoTArray
<nsIFrame::OwnedAnonBox
, 8> ownedAnonBoxes
;
9575 primaryFrame
->AppendOwnedAnonBoxes(ownedAnonBoxes
);
9576 for (nsIFrame::OwnedAnonBox
& box
: ownedAnonBoxes
) {
9577 MOZ_ASSERT(box
.mAnonBoxFrame
->GetContent() == aContent
);
9578 AppendNativeAnonymousChildrenFromFrame(box
.mAnonBoxFrame
, aKids
,
9583 // Get manually created NAC (editor resize handles, etc.).
9584 if (auto nac
= static_cast<ManualNACArray
*>(
9585 aContent
->GetProperty(nsGkAtoms::manualNACProperty
))) {
9586 aKids
.AppendElements(*nac
);
9590 // The root scroll frame is not the primary frame of the root element.
9591 // Detect and handle this case.
9592 if (!(aFlags
& nsIContent::eSkipDocumentLevelNativeAnonymousContent
) &&
9593 aContent
== aContent
->OwnerDoc()->GetRootElement()) {
9594 AppendDocumentLevelNativeAnonymousContentTo(aContent
->OwnerDoc(), aKids
);
9599 bool nsContentUtils::QueryTriggeringPrincipal(
9600 nsIContent
* aLoadingNode
, nsIPrincipal
* aDefaultPrincipal
,
9601 nsIPrincipal
** aTriggeringPrincipal
) {
9602 MOZ_ASSERT(aLoadingNode
);
9603 MOZ_ASSERT(aTriggeringPrincipal
);
9605 bool result
= false;
9606 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
= aDefaultPrincipal
;
9607 if (!loadingPrincipal
) {
9608 loadingPrincipal
= aLoadingNode
->NodePrincipal();
9611 // If aLoadingNode is content, bail out early.
9612 if (!aLoadingNode
->NodePrincipal()->IsSystemPrincipal()) {
9613 loadingPrincipal
.forget(aTriggeringPrincipal
);
9617 nsAutoString loadingStr
;
9618 if (aLoadingNode
->IsElement()) {
9619 aLoadingNode
->AsElement()->GetAttr(
9620 kNameSpaceID_None
, nsGkAtoms::triggeringprincipal
, loadingStr
);
9623 // Fall back if 'triggeringprincipal' isn't specified,
9624 if (loadingStr
.IsEmpty()) {
9625 loadingPrincipal
.forget(aTriggeringPrincipal
);
9630 nsresult rv
= Base64Decode(NS_ConvertUTF16toUTF8(loadingStr
), binary
);
9631 if (NS_SUCCEEDED(rv
)) {
9632 nsCOMPtr
<nsIPrincipal
> serializedPrin
= BasePrincipal::FromJSON(binary
);
9633 if (serializedPrin
) {
9635 serializedPrin
.forget(aTriggeringPrincipal
);
9638 MOZ_ASSERT(false, "Unable to deserialize base64 principal");
9642 // Fallback if the deserialization is failed.
9643 loadingPrincipal
.forget(aTriggeringPrincipal
);
9650 void nsContentUtils::GetContentPolicyTypeForUIImageLoading(
9651 nsIContent
* aLoadingNode
, nsIPrincipal
** aTriggeringPrincipal
,
9652 nsContentPolicyType
& aContentPolicyType
, uint64_t* aRequestContextID
) {
9653 MOZ_ASSERT(aRequestContextID
);
9655 bool result
= QueryTriggeringPrincipal(aLoadingNode
, aTriggeringPrincipal
);
9657 // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
9658 // indicating it's a favicon loading.
9659 aContentPolicyType
= nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON
;
9661 nsAutoString requestContextID
;
9662 if (aLoadingNode
->IsElement()) {
9663 aLoadingNode
->AsElement()->GetAttr(
9664 kNameSpaceID_None
, nsGkAtoms::requestcontextid
, requestContextID
);
9667 int64_t val
= requestContextID
.ToInteger64(&rv
);
9668 *aRequestContextID
= NS_SUCCEEDED(rv
) ? val
: 0;
9670 aContentPolicyType
= nsIContentPolicy::TYPE_INTERNAL_IMAGE
;
9675 nsresult
nsContentUtils::CreateJSValueFromSequenceOfObject(
9676 JSContext
* aCx
, const Sequence
<JSObject
*>& aTransfer
,
9677 JS::MutableHandle
<JS::Value
> aValue
) {
9678 if (aTransfer
.IsEmpty()) {
9682 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, aTransfer
.Length()));
9684 return NS_ERROR_OUT_OF_MEMORY
;
9687 for (uint32_t i
= 0; i
< aTransfer
.Length(); ++i
) {
9688 JS::Rooted
<JSObject
*> object(aCx
, aTransfer
[i
]);
9694 !JS_DefineElement(aCx
, array
, i
, object
, JSPROP_ENUMERATE
))) {
9695 return NS_ERROR_OUT_OF_MEMORY
;
9699 aValue
.setObject(*array
);
9704 bool nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent
* aKeyEvent
) {
9705 nsCOMPtr
<nsIPrincipal
> principal
;
9706 nsCOMPtr
<Element
> targetElement
=
9707 do_QueryInterface(aKeyEvent
->mOriginalTarget
);
9708 nsCOMPtr
<nsIBrowser
> targetBrowser
;
9709 if (targetElement
) {
9710 targetBrowser
= targetElement
->AsBrowser();
9712 bool isRemoteBrowser
= false;
9713 if (targetBrowser
) {
9714 targetBrowser
->GetIsRemoteBrowser(&isRemoteBrowser
);
9717 if (isRemoteBrowser
) {
9718 targetBrowser
->GetContentPrincipal(getter_AddRefs(principal
));
9719 return principal
? nsContentUtils::IsSitePermDeny(principal
, "shortcuts"_ns
)
9723 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aKeyEvent
->mOriginalTarget
);
9725 Document
* doc
= content
->GetUncomposedDoc();
9727 RefPtr
<WindowContext
> wc
= doc
->GetWindowContext();
9729 return wc
->TopWindowContext()->GetShortcutsPermission() ==
9730 nsIPermissionManager::DENY_ACTION
;
9739 * Checks whether the given type is a supported document type for
9740 * loading within the nsObjectLoadingContent specified by aContent.
9742 * NOTE Helper method for nsContentUtils::HtmlObjectContentTypeForMIMEType.
9743 * NOTE Does not take content policy or capabilities into account
9745 static bool HtmlObjectContentSupportsDocument(const nsCString
& aMimeType
,
9746 nsIContent
* aContent
) {
9747 nsCOMPtr
<nsIWebNavigationInfo
> info(
9748 do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID
));
9753 nsCOMPtr
<nsIWebNavigation
> webNav
;
9755 Document
* currentDoc
= aContent
->GetComposedDoc();
9757 webNav
= do_GetInterface(currentDoc
->GetWindow());
9762 nsresult rv
= info
->IsTypeSupported(aMimeType
, webNav
, &supported
);
9764 if (NS_FAILED(rv
)) {
9768 if (supported
!= nsIWebNavigationInfo::UNSUPPORTED
) {
9769 // Don't want to support plugins as documents
9770 return supported
!= nsIWebNavigationInfo::FALLBACK
;
9773 // Try a stream converter
9774 // NOTE: We treat any type we can convert from as a supported type. If a
9775 // type is not actually supported, the URI loader will detect that and
9776 // return an error, and we'll fallback.
9777 nsCOMPtr
<nsIStreamConverterService
> convServ
=
9778 do_GetService("@mozilla.org/streamConverters;1");
9779 bool canConvert
= false;
9781 rv
= convServ
->CanConvert(aMimeType
.get(), "*/*", &canConvert
);
9783 return NS_SUCCEEDED(rv
) && canConvert
;
9787 already_AddRefed
<nsIPluginTag
> nsContentUtils::PluginTagForType(
9788 const nsCString
& aMIMEType
, bool aNoFakePlugin
) {
9789 RefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
9790 nsCOMPtr
<nsIPluginTag
> tag
;
9791 NS_ENSURE_TRUE(pluginHost
, nullptr);
9793 // ShouldPlay will handle the case where the plugin is disabled
9794 pluginHost
->GetPluginTagForType(
9796 aNoFakePlugin
? nsPluginHost::eExcludeFake
: nsPluginHost::eExcludeNone
,
9797 getter_AddRefs(tag
));
9799 return tag
.forget();
9803 uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType(
9804 const nsCString
& aMIMEType
, bool aNoFakePlugin
, nsIContent
* aContent
) {
9805 if (aMIMEType
.IsEmpty()) {
9806 return nsIObjectLoadingContent::TYPE_NULL
;
9809 if (imgLoader::SupportImageWithMimeType(aMIMEType
)) {
9810 return nsIObjectLoadingContent::TYPE_IMAGE
;
9813 // Faking support of the PDF content as a document for EMBED tags
9814 // when internal PDF viewer is enabled.
9815 if (aMIMEType
.LowerCaseEqualsLiteral("application/pdf") && IsPDFJSEnabled()) {
9816 return nsIObjectLoadingContent::TYPE_DOCUMENT
;
9819 if (HtmlObjectContentSupportsDocument(aMIMEType
, aContent
)) {
9820 return nsIObjectLoadingContent::TYPE_DOCUMENT
;
9823 bool isSpecialPlugin
= nsPluginHost::GetSpecialType(aMIMEType
) !=
9824 nsPluginHost::eSpecialType_None
;
9825 if (isSpecialPlugin
) {
9826 return nsIObjectLoadingContent::TYPE_FALLBACK
;
9829 return nsIObjectLoadingContent::TYPE_NULL
;
9833 already_AddRefed
<nsISerialEventTarget
> nsContentUtils::GetEventTargetByLoadInfo(
9834 nsILoadInfo
* aLoadInfo
, TaskCategory aCategory
) {
9835 if (NS_WARN_IF(!aLoadInfo
)) {
9839 RefPtr
<Document
> doc
;
9840 aLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
9841 nsCOMPtr
<nsISerialEventTarget
> target
;
9843 if (DocGroup
* group
= doc
->GetDocGroup()) {
9844 target
= group
->EventTargetFor(aCategory
);
9847 target
= GetMainThreadSerialEventTarget();
9850 return target
.forget();
9854 bool nsContentUtils::IsLocalRefURL(const nsAString
& aString
) {
9855 return !aString
.IsEmpty() && aString
[0] == '#';
9858 // We use only 53 bits for the ID so that it can be converted to and from a JS
9859 // value without loss of precision. The upper bits of the ID hold the process
9860 // ID. The lower bits identify the object itself.
9861 static constexpr uint64_t kIdTotalBits
= 53;
9862 static constexpr uint64_t kIdProcessBits
= 22;
9863 static constexpr uint64_t kIdBits
= kIdTotalBits
- kIdProcessBits
;
9866 uint64_t nsContentUtils::GenerateProcessSpecificId(uint64_t aId
) {
9867 uint64_t processId
= 0;
9868 if (XRE_IsContentProcess()) {
9869 ContentChild
* cc
= ContentChild::GetSingleton();
9870 processId
= cc
->GetID();
9873 MOZ_RELEASE_ASSERT(processId
< (uint64_t(1) << kIdProcessBits
));
9874 uint64_t processBits
= processId
& ((uint64_t(1) << kIdProcessBits
) - 1);
9877 MOZ_RELEASE_ASSERT(id
< (uint64_t(1) << kIdBits
));
9878 uint64_t bits
= id
& ((uint64_t(1) << kIdBits
) - 1);
9880 return (processBits
<< kIdBits
) | bits
;
9884 std::tuple
<uint64_t, uint64_t> nsContentUtils::SplitProcessSpecificId(
9886 return {aId
>> kIdBits
, aId
& ((uint64_t(1) << kIdBits
) - 1)};
9889 // Next process-local Tab ID.
9890 static uint64_t gNextTabId
= 0;
9893 uint64_t nsContentUtils::GenerateTabId() {
9894 return GenerateProcessSpecificId(++gNextTabId
);
9897 // Next process-local Browser ID.
9898 static uint64_t gNextBrowserId
= 0;
9901 uint64_t nsContentUtils::GenerateBrowserId() {
9902 return GenerateProcessSpecificId(++gNextBrowserId
);
9905 // Next process-local Browsing Context ID.
9906 static uint64_t gNextBrowsingContextId
= 0;
9909 uint64_t nsContentUtils::GenerateBrowsingContextId() {
9910 return GenerateProcessSpecificId(++gNextBrowsingContextId
);
9913 // Next process-local Window ID.
9914 static uint64_t gNextWindowId
= 0;
9917 uint64_t nsContentUtils::GenerateWindowId() {
9918 return GenerateProcessSpecificId(++gNextWindowId
);
9921 // Next process-local load.
9922 static Atomic
<uint64_t> gNextLoadIdentifier(0);
9925 uint64_t nsContentUtils::GenerateLoadIdentifier() {
9926 return GenerateProcessSpecificId(++gNextLoadIdentifier
);
9930 bool nsContentUtils::GetUserIsInteracting() {
9931 return UserInteractionObserver::sUserActive
;
9935 bool nsContentUtils::GetSourceMapURL(nsIHttpChannel
* aChannel
,
9936 nsACString
& aResult
) {
9937 nsresult rv
= aChannel
->GetResponseHeader("SourceMap"_ns
, aResult
);
9938 if (NS_FAILED(rv
)) {
9939 rv
= aChannel
->GetResponseHeader("X-SourceMap"_ns
, aResult
);
9941 return NS_SUCCEEDED(rv
);
9945 bool nsContentUtils::IsMessageInputEvent(const IPC::Message
& aMsg
) {
9946 if ((aMsg
.type() & mozilla::dom::PBrowser::PBrowserStart
) ==
9947 mozilla::dom::PBrowser::PBrowserStart
) {
9948 switch (aMsg
.type()) {
9949 case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID
:
9950 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID
:
9951 case mozilla::dom::PBrowser::Msg_RealMouseEnterExitWidgetEvent__ID
:
9952 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID
:
9953 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID
:
9954 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID
:
9955 case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID
:
9956 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID
:
9957 case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID
:
9958 case mozilla::dom::PBrowser::Msg_MouseEvent__ID
:
9966 bool nsContentUtils::IsMessageCriticalInputEvent(const IPC::Message
& aMsg
) {
9967 if ((aMsg
.type() & mozilla::dom::PBrowser::PBrowserStart
) ==
9968 mozilla::dom::PBrowser::PBrowserStart
) {
9969 switch (aMsg
.type()) {
9970 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID
:
9971 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID
:
9972 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID
:
9973 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID
:
9974 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID
:
9981 static const char* kUserInteractionInactive
= "user-interaction-inactive";
9982 static const char* kUserInteractionActive
= "user-interaction-active";
9984 void nsContentUtils::UserInteractionObserver::Init() {
9985 // Listen for the observer messages from EventStateManager which are telling
9986 // us whether or not the user is interacting.
9987 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
9988 obs
->AddObserver(this, kUserInteractionInactive
, false);
9989 obs
->AddObserver(this, kUserInteractionActive
, false);
9991 // We can't register ourselves as an annotator yet, as the
9992 // BackgroundHangMonitor hasn't started yet. It will have started by the
9993 // time we have the chance to spin the event loop.
9994 RefPtr
<UserInteractionObserver
> self
= this;
9995 NS_DispatchToMainThread(NS_NewRunnableFunction(
9996 "nsContentUtils::UserInteractionObserver::Init",
9997 [=]() { BackgroundHangMonitor::RegisterAnnotator(*self
); }));
10000 void nsContentUtils::UserInteractionObserver::Shutdown() {
10001 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
10003 obs
->RemoveObserver(this, kUserInteractionInactive
);
10004 obs
->RemoveObserver(this, kUserInteractionActive
);
10007 BackgroundHangMonitor::UnregisterAnnotator(*this);
10011 * NB: This function is always called by the BackgroundHangMonitor thread.
10014 void nsContentUtils::UserInteractionObserver::AnnotateHang(
10015 BackgroundHangAnnotations
& aAnnotations
) {
10016 // NOTE: Only annotate the hang report if the user is known to be interacting.
10018 aAnnotations
.AddAnnotation(u
"UserInteracting"_ns
, true);
10023 nsContentUtils::UserInteractionObserver::Observe(nsISupports
* aSubject
,
10024 const char* aTopic
,
10025 const char16_t
* aData
) {
10026 if (!strcmp(aTopic
, kUserInteractionInactive
)) {
10027 sUserActive
= false;
10028 } else if (!strcmp(aTopic
, kUserInteractionActive
)) {
10029 sUserActive
= true;
10031 NS_WARNING("Unexpected observer notification");
10036 Atomic
<bool> nsContentUtils::UserInteractionObserver::sUserActive(false);
10037 NS_IMPL_ISUPPORTS(nsContentUtils::UserInteractionObserver
, nsIObserver
)
10040 bool nsContentUtils::IsSpecialName(const nsAString
& aName
) {
10041 return aName
.LowerCaseEqualsLiteral("_blank") ||
10042 aName
.LowerCaseEqualsLiteral("_top") ||
10043 aName
.LowerCaseEqualsLiteral("_parent") ||
10044 aName
.LowerCaseEqualsLiteral("_self");
10048 bool nsContentUtils::IsOverridingWindowName(const nsAString
& aName
) {
10049 return !aName
.IsEmpty() && !IsSpecialName(aName
);
10052 // Unfortunately, we can't unwrap an IDL object using only a concrete type.
10053 // We need to calculate type data based on the IDL typename. Which means
10054 // wrapping our templated function in a macro.
10055 #define EXTRACT_EXN_VALUES(T, ...) \
10056 ExtractExceptionValues<mozilla::dom::prototypes::id::T, \
10057 T##_Binding::NativeType, T>(__VA_ARGS__) \
10060 template <prototypes::ID PrototypeID
, class NativeType
, typename T
>
10061 static Result
<Ok
, nsresult
> ExtractExceptionValues(
10062 JSContext
* aCx
, JS::HandleObject aObj
, nsAString
& aSourceSpecOut
,
10063 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10064 AssertStaticUnwrapOK
<PrototypeID
>();
10066 MOZ_TRY((UnwrapObject
<PrototypeID
, NativeType
>(aObj
, exn
, nullptr)));
10068 exn
->GetFilename(aCx
, aSourceSpecOut
);
10069 if (!aSourceSpecOut
.IsEmpty()) {
10070 *aLineOut
= exn
->LineNumber(aCx
);
10071 *aColumnOut
= exn
->ColumnNumber();
10074 exn
->GetName(aMessageOut
);
10075 aMessageOut
.AppendLiteral(": ");
10077 nsAutoString message
;
10078 exn
->GetMessageMoz(message
);
10079 aMessageOut
.Append(message
);
10084 void nsContentUtils::ExtractErrorValues(
10085 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, nsACString
& aSourceSpecOut
,
10086 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10087 nsAutoString sourceSpec
;
10088 ExtractErrorValues(aCx
, aValue
, sourceSpec
, aLineOut
, aColumnOut
,
10090 CopyUTF16toUTF8(sourceSpec
, aSourceSpecOut
);
10094 void nsContentUtils::ExtractErrorValues(
10095 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
, nsAString
& aSourceSpecOut
,
10096 uint32_t* aLineOut
, uint32_t* aColumnOut
, nsString
& aMessageOut
) {
10097 MOZ_ASSERT(aLineOut
);
10098 MOZ_ASSERT(aColumnOut
);
10100 if (aValue
.isObject()) {
10101 JS::Rooted
<JSObject
*> obj(aCx
, &aValue
.toObject());
10103 // Try to process as an Error object. Use the file/line/column values
10104 // from the Error as they will be more specific to the root cause of
10106 JSErrorReport
* err
= obj
? JS_ErrorFromException(aCx
, obj
) : nullptr;
10108 // Use xpc to extract the error message only. We don't actually send
10109 // this report anywhere.
10110 RefPtr
<xpc::ErrorReport
> report
= new xpc::ErrorReport();
10112 nullptr, // toString result
10116 if (!report
->mFileName
.IsEmpty()) {
10117 aSourceSpecOut
= report
->mFileName
;
10118 *aLineOut
= report
->mLineNumber
;
10119 *aColumnOut
= report
->mColumn
;
10121 aMessageOut
.Assign(report
->mErrorMsg
);
10124 // Next, try to unwrap the rejection value as a DOMException.
10125 else if (EXTRACT_EXN_VALUES(DOMException
, aCx
, obj
, aSourceSpecOut
,
10126 aLineOut
, aColumnOut
, aMessageOut
)) {
10130 // Next, try to unwrap the rejection value as an XPC Exception.
10131 else if (EXTRACT_EXN_VALUES(Exception
, aCx
, obj
, aSourceSpecOut
, aLineOut
,
10132 aColumnOut
, aMessageOut
)) {
10137 // If we could not unwrap a specific error type, then perform default safe
10138 // string conversions on primitives. Objects will result in "[Object]"
10140 if (aMessageOut
.IsEmpty()) {
10141 nsAutoJSString jsString
;
10142 if (jsString
.init(aCx
, aValue
)) {
10143 aMessageOut
= jsString
;
10145 JS_ClearPendingException(aCx
);
10150 #undef EXTRACT_EXN_VALUES
10153 bool nsContentUtils::ContentIsLink(nsIContent
* aContent
) {
10154 if (!aContent
|| !aContent
->IsElement()) {
10158 if (aContent
->IsHTMLElement(nsGkAtoms::a
)) {
10162 return aContent
->AsElement()->AttrValueIs(kNameSpaceID_XLink
, nsGkAtoms::type
,
10163 nsGkAtoms::simple
, eCaseMatters
);
10167 already_AddRefed
<ContentFrameMessageManager
>
10168 nsContentUtils::TryGetBrowserChildGlobal(nsISupports
* aFrom
) {
10169 RefPtr
<nsFrameLoaderOwner
> frameLoaderOwner
= do_QueryObject(aFrom
);
10170 if (!frameLoaderOwner
) {
10174 RefPtr
<nsFrameLoader
> frameLoader
= frameLoaderOwner
->GetFrameLoader();
10175 if (!frameLoader
) {
10179 RefPtr
<ContentFrameMessageManager
> manager
=
10180 frameLoader
->GetBrowserChildMessageManager();
10181 return manager
.forget();
10185 uint32_t nsContentUtils::InnerOrOuterWindowCreated() {
10186 MOZ_ASSERT(NS_IsMainThread());
10187 ++sInnerOrOuterWindowCount
;
10188 return ++sInnerOrOuterWindowSerialCounter
;
10192 void nsContentUtils::InnerOrOuterWindowDestroyed() {
10193 MOZ_ASSERT(NS_IsMainThread());
10194 MOZ_ASSERT(sInnerOrOuterWindowCount
> 0);
10195 --sInnerOrOuterWindowCount
;
10198 static bool JSONCreator(const char16_t
* aBuf
, uint32_t aLen
, void* aData
) {
10199 nsAString
* result
= static_cast<nsAString
*>(aData
);
10200 result
->Append(static_cast<const char16_t
*>(aBuf
),
10201 static_cast<uint32_t>(aLen
));
10206 bool nsContentUtils::StringifyJSON(JSContext
* aCx
,
10207 JS::MutableHandle
<JS::Value
> aValue
,
10208 nsAString
& aOutStr
) {
10210 aOutStr
.Truncate();
10211 JS::RootedValue
value(aCx
, aValue
.get());
10212 nsAutoString serializedValue
;
10213 NS_ENSURE_TRUE(JS_Stringify(aCx
, &value
, nullptr, JS::NullHandleValue
,
10214 JSONCreator
, &serializedValue
),
10216 aOutStr
= serializedValue
;
10221 bool nsContentUtils::
10222 HighPriorityEventPendingForTopLevelDocumentBeforeContentfulPaint(
10223 Document
* aDocument
) {
10224 MOZ_ASSERT(XRE_IsContentProcess(),
10225 "This function only makes sense in content processes");
10227 if (aDocument
&& !aDocument
->IsLoadedAsData()) {
10228 if (nsPresContext
* presContext
= FindPresContextForDocument(aDocument
)) {
10229 MOZ_ASSERT(!presContext
->IsChrome(),
10230 "Should never have a chrome PresContext in a content process");
10232 return !presContext
->GetInProcessRootContentDocumentPresContext()
10233 ->HadContentfulPaint() &&
10234 nsThreadManager::MainThreadHasPendingHighPriorityEvents();
10241 nsGlobalWindowInner
* nsContentUtils::CallerInnerWindow() {
10242 nsIGlobalObject
* global
= GetIncumbentGlobal();
10243 NS_ENSURE_TRUE(global
, nullptr);
10245 if (auto* window
= global
->AsInnerWindow()) {
10246 return nsGlobalWindowInner::Cast(window
);
10249 // When Extensions run content scripts inside a sandbox, it uses
10250 // sandboxPrototype to make them appear as though they're running in the
10251 // scope of the page. So when a content script invokes postMessage, it expects
10252 // the |source| of the received message to be the window set as the
10253 // sandboxPrototype. This used to work incidentally for unrelated reasons, but
10254 // now we need to do some special handling to support it.
10255 JS::Rooted
<JSObject
*> scope(RootingCx(), global
->GetGlobalJSObject());
10256 NS_ENSURE_TRUE(scope
, nullptr);
10258 if (xpc::IsSandbox(scope
)) {
10260 MOZ_ALWAYS_TRUE(jsapi
.Init(scope
));
10261 JSContext
* cx
= jsapi
.cx();
10262 // Our current Realm on aCx is the sandbox. Using that for unwrapping
10263 // makes sense: if the sandbox can unwrap the window, we can use it.
10264 return xpc::SandboxWindowOrNull(scope
, cx
);
10267 // The calling window must be holding a reference, so we can return a weak
10269 return nsGlobalWindowInner::Cast(global
->AsInnerWindow());
10273 bool nsContentUtils::IsURIInPrefList(nsIURI
* aURI
, const char* aPrefName
) {
10274 MOZ_ASSERT(aPrefName
);
10276 nsAutoCString list
;
10277 Preferences::GetCString(aPrefName
, list
);
10279 return IsURIInList(aURI
, list
);
10283 bool nsContentUtils::IsURIInList(nsIURI
* aURI
, const nsCString
& aList
) {
10285 nsAutoCString
listLowerCase(aList
);
10286 ToLowerCase(listLowerCase
);
10287 MOZ_ASSERT(listLowerCase
.Equals(aList
),
10288 "The aList argument should be lower-case");
10295 nsAutoCString scheme
;
10296 aURI
->GetScheme(scheme
);
10297 if (!scheme
.EqualsLiteral("http") && !scheme
.EqualsLiteral("https")) {
10301 if (aList
.IsEmpty()) {
10305 // The list is comma separated domain list. Each item may start with "*.".
10306 // If starts with "*.", it matches any sub-domains.
10308 nsCCharSeparatedTokenizer
tokenizer(aList
, ',');
10309 while (tokenizer
.hasMoreTokens()) {
10310 const nsCString
token(tokenizer
.nextToken());
10312 nsAutoCString host
;
10313 aURI
->GetHost(host
);
10314 if (host
.IsEmpty()) {
10320 int32_t index
= token
.Find(host
, false);
10322 static_cast<uint32_t>(index
) + host
.Length() <= token
.Length()) {
10323 // If we found a full match, return true.
10324 size_t indexAfterHost
= index
+ host
.Length();
10325 if (index
== 0 && indexAfterHost
== token
.Length()) {
10328 // If next character is '/', we need to check the path too.
10329 // We assume the path in the list means "/foo" + "*".
10330 if (token
[indexAfterHost
] == '/') {
10331 nsDependentCSubstring
pathInList(
10332 token
, indexAfterHost
,
10333 static_cast<nsDependentCSubstring::size_type
>(-1));
10334 nsAutoCString filePath
;
10335 aURI
->GetFilePath(filePath
);
10336 ToLowerCase(filePath
);
10337 if (StringBeginsWith(filePath
, pathInList
) &&
10338 (filePath
.Length() == pathInList
.Length() ||
10339 pathInList
.EqualsLiteral("/") ||
10340 filePath
[pathInList
.Length() - 1] == '/' ||
10341 filePath
[pathInList
.Length() - 1] == '?' ||
10342 filePath
[pathInList
.Length() - 1] == '#')) {
10347 int32_t startIndexOfCurrentLevel
= host
[0] == '*' ? 1 : 0;
10348 int32_t startIndexOfNextLevel
=
10349 host
.Find(".", false, startIndexOfCurrentLevel
+ 1);
10350 if (startIndexOfNextLevel
<= 0) {
10353 host
= "*"_ns
+ nsDependentCSubstring(host
, startIndexOfNextLevel
);
10361 ScreenIntMargin
nsContentUtils::GetWindowSafeAreaInsets(
10362 nsIScreen
* aScreen
, const ScreenIntMargin
& aSafeAreaInsets
,
10363 const LayoutDeviceIntRect
& aWindowRect
) {
10364 // This calculates safe area insets of window from screen rectangle, window
10365 // rectangle and safe area insets of screen.
10367 // +----------------------------------------+ <-- screen
10368 // | +-------------------------------+ <------- window
10369 // | | window's safe area inset top) | |
10370 // +--+-------------------------------+--+ |
10371 // | | | |<------ safe area rectangle of
10372 // | | | | | screen
10373 // +--+-------------------------------+--+ |
10374 // | |window's safe area inset bottom| |
10375 // | +-------------------------------+ |
10376 // +----------------------------------------+
10378 ScreenIntMargin windowSafeAreaInsets
;
10380 if (windowSafeAreaInsets
== aSafeAreaInsets
) {
10381 // no safe area insets.
10382 return windowSafeAreaInsets
;
10385 int32_t screenLeft
, screenTop
, screenWidth
, screenHeight
;
10387 aScreen
->GetRect(&screenLeft
, &screenTop
, &screenWidth
, &screenHeight
);
10388 if (NS_WARN_IF(NS_FAILED(rv
))) {
10389 return windowSafeAreaInsets
;
10392 // Screen's rect of safe area
10393 LayoutDeviceIntRect
safeAreaRect(
10394 screenLeft
+ aSafeAreaInsets
.left
, screenTop
+ aSafeAreaInsets
.top
,
10395 screenWidth
- aSafeAreaInsets
.right
- aSafeAreaInsets
.left
,
10396 screenHeight
- aSafeAreaInsets
.bottom
- aSafeAreaInsets
.top
);
10397 // window's rect of safe area
10398 safeAreaRect
= safeAreaRect
.Intersect(aWindowRect
);
10400 windowSafeAreaInsets
.top
=
10401 aSafeAreaInsets
.top
? std::max(safeAreaRect
.y
- aWindowRect
.y
, 0) : 0;
10402 windowSafeAreaInsets
.left
=
10403 aSafeAreaInsets
.left
? std::max(safeAreaRect
.x
- aWindowRect
.x
, 0) : 0;
10404 windowSafeAreaInsets
.right
=
10405 aSafeAreaInsets
.right
10406 ? std::max((aWindowRect
.x
+ aWindowRect
.width
) -
10407 (safeAreaRect
.x
+ safeAreaRect
.width
),
10410 windowSafeAreaInsets
.bottom
=
10411 aSafeAreaInsets
.bottom
10412 ? std::max(aWindowRect
.y
+ aWindowRect
.height
-
10413 (safeAreaRect
.y
+ safeAreaRect
.height
),
10417 return windowSafeAreaInsets
;
10421 nsContentUtils::SubresourceCacheValidationInfo
10422 nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest
* aRequest
) {
10423 SubresourceCacheValidationInfo info
;
10424 if (nsCOMPtr
<nsICacheInfoChannel
> cache
= do_QueryInterface(aRequest
)) {
10425 uint32_t value
= 0;
10426 if (NS_SUCCEEDED(cache
->GetCacheTokenExpirationTime(&value
))) {
10427 info
.mExpirationTime
.emplace(value
);
10431 // Determine whether the cache entry must be revalidated when we try to use
10432 // it. Currently, only HTTP specifies this information...
10433 if (nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aRequest
)) {
10434 Unused
<< httpChannel
->IsNoStoreResponse(&info
.mMustRevalidate
);
10436 if (!info
.mMustRevalidate
) {
10437 Unused
<< httpChannel
->IsNoCacheResponse(&info
.mMustRevalidate
);
10444 nsCString
nsContentUtils::TruncatedURLForDisplay(nsIURI
* aURL
,
10445 uint32_t aMaxLen
) {
10448 aURL
->GetSpec(spec
);
10449 spec
.Truncate(std::min(aMaxLen
, spec
.Length()));