/src/mozilla-central/dom/base/nsContentUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* A namespace class for static layout utilities. */ |
8 | | |
9 | | #include "nsContentUtils.h" |
10 | | |
11 | | #include <algorithm> |
12 | | #include <math.h> |
13 | | |
14 | | #include "DecoderTraits.h" |
15 | | #include "harfbuzz/hb.h" |
16 | | #include "imgICache.h" |
17 | | #include "imgIContainer.h" |
18 | | #include "imgINotificationObserver.h" |
19 | | #include "imgLoader.h" |
20 | | #include "imgRequestProxy.h" |
21 | | #include "jsapi.h" |
22 | | #include "jsfriendapi.h" |
23 | | #include "js/JSON.h" |
24 | | #include "js/Value.h" |
25 | | #include "Layers.h" |
26 | | #include "nsAppRunner.h" |
27 | | // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h. |
28 | | #include "nsNPAPIPluginInstance.h" |
29 | | #include "gfxDrawable.h" |
30 | | #include "gfxPrefs.h" |
31 | | #include "ImageOps.h" |
32 | | #include "mozAutoDocUpdate.h" |
33 | | #include "mozilla/AntiTrackingCommon.h" |
34 | | #include "mozilla/ArrayUtils.h" |
35 | | #include "mozilla/Attributes.h" |
36 | | #include "mozilla/AutoRestore.h" |
37 | | #include "mozilla/AutoTimelineMarker.h" |
38 | | #include "mozilla/BackgroundHangMonitor.h" |
39 | | #include "mozilla/Base64.h" |
40 | | #include "mozilla/CheckedInt.h" |
41 | | #include "mozilla/DebugOnly.h" |
42 | | #include "mozilla/LoadInfo.h" |
43 | | #include "mozilla/dom/BlobURLProtocolHandler.h" |
44 | | #include "mozilla/dom/ContentChild.h" |
45 | | #include "mozilla/dom/CustomElementRegistry.h" |
46 | | #include "mozilla/dom/MessageBroadcaster.h" |
47 | | #include "mozilla/dom/DocumentFragment.h" |
48 | | #include "mozilla/dom/DOMException.h" |
49 | | #include "mozilla/dom/DOMExceptionBinding.h" |
50 | | #include "mozilla/dom/DOMTypes.h" |
51 | | #include "mozilla/dom/Element.h" |
52 | | #include "mozilla/dom/ElementInlines.h" |
53 | | #include "mozilla/dom/Event.h" |
54 | | #include "mozilla/dom/FileSystemSecurity.h" |
55 | | #include "mozilla/dom/FileBlobImpl.h" |
56 | | #include "mozilla/dom/FontTableURIProtocolHandler.h" |
57 | | #include "mozilla/dom/HTMLInputElement.h" |
58 | | #include "mozilla/dom/HTMLSlotElement.h" |
59 | | #include "mozilla/dom/HTMLTemplateElement.h" |
60 | | #include "mozilla/dom/IDTracker.h" |
61 | | #include "mozilla/dom/MouseEventBinding.h" |
62 | | #include "mozilla/dom/KeyboardEventBinding.h" |
63 | | #include "mozilla/dom/IPCBlobUtils.h" |
64 | | #include "mozilla/dom/NodeBinding.h" |
65 | | #include "mozilla/dom/Promise.h" |
66 | | #include "mozilla/dom/ScriptSettings.h" |
67 | | #include "mozilla/dom/TabParent.h" |
68 | | #include "mozilla/dom/Text.h" |
69 | | #include "mozilla/dom/TouchEvent.h" |
70 | | #include "mozilla/dom/ShadowRoot.h" |
71 | | #include "mozilla/dom/XULCommandEvent.h" |
72 | | #include "mozilla/dom/WorkerCommon.h" |
73 | | #include "mozilla/EventDispatcher.h" |
74 | | #include "mozilla/EventListenerManager.h" |
75 | | #include "mozilla/EventStateManager.h" |
76 | | #include "mozilla/gfx/DataSurfaceHelpers.h" |
77 | | #include "mozilla/HTMLEditor.h" |
78 | | #include "mozilla/IMEStateManager.h" |
79 | | #include "mozilla/InternalMutationEvent.h" |
80 | | #include "mozilla/Likely.h" |
81 | | #include "mozilla/ManualNAC.h" |
82 | | #include "mozilla/MouseEvents.h" |
83 | | #include "mozilla/Preferences.h" |
84 | | #include "mozilla/ResultExtensions.h" |
85 | | #include "mozilla/dom/Selection.h" |
86 | | #include "mozilla/Services.h" |
87 | | #include "mozilla/StaticPrefs.h" |
88 | | #include "mozilla/TextEvents.h" |
89 | | #include "nsArrayUtils.h" |
90 | | #include "nsAString.h" |
91 | | #include "nsAttrName.h" |
92 | | #include "nsAttrValue.h" |
93 | | #include "nsAttrValueInlines.h" |
94 | | #include "nsBindingManager.h" |
95 | | #include "nsCanvasFrame.h" |
96 | | #include "nsCaret.h" |
97 | | #include "nsCCUncollectableMarker.h" |
98 | | #include "nsCharSeparatedTokenizer.h" |
99 | | #include "nsCOMPtr.h" |
100 | | #include "nsContentCreatorFunctions.h" |
101 | | #include "nsContentDLF.h" |
102 | | #include "nsContentList.h" |
103 | | #include "nsContentPolicyUtils.h" |
104 | | #include "nsContentSecurityManager.h" |
105 | | #include "nsCPrefetchService.h" |
106 | | #include "nsCRT.h" |
107 | | #include "nsCycleCollectionParticipant.h" |
108 | | #include "nsCycleCollector.h" |
109 | | #include "nsDataHashtable.h" |
110 | | #include "nsDocShellCID.h" |
111 | | #include "nsDocument.h" |
112 | | #include "nsDOMCID.h" |
113 | | #include "mozilla/dom/DataTransfer.h" |
114 | | #include "nsDOMJSUtils.h" |
115 | | #include "nsDOMMutationObserver.h" |
116 | | #include "nsError.h" |
117 | | #include "nsFocusManager.h" |
118 | | #include "nsGenericHTMLElement.h" |
119 | | #include "nsGenericHTMLFrameElement.h" |
120 | | #include "nsGkAtoms.h" |
121 | | #include "nsHtml5Module.h" |
122 | | #include "nsHtml5StringParser.h" |
123 | | #include "nsHTMLDocument.h" |
124 | | #include "nsHTMLTags.h" |
125 | | #include "nsIAddonPolicyService.h" |
126 | | #include "nsIAnonymousContentCreator.h" |
127 | | #include "nsIAsyncVerifyRedirectCallback.h" |
128 | | #include "nsICategoryManager.h" |
129 | | #include "nsIChannelEventSink.h" |
130 | | #include "nsICharsetDetectionObserver.h" |
131 | | #include "nsIChromeRegistry.h" |
132 | | #include "nsIConsoleService.h" |
133 | | #include "nsIContent.h" |
134 | | #include "nsIContentInlines.h" |
135 | | #include "nsIContentSecurityPolicy.h" |
136 | | #include "nsIContentSink.h" |
137 | | #include "nsIContentViewer.h" |
138 | | #include "nsIDocShell.h" |
139 | | #include "nsIDocShellTreeOwner.h" |
140 | | #include "nsIDocument.h" |
141 | | #include "nsIDocumentEncoder.h" |
142 | | #include "nsIDOMChromeWindow.h" |
143 | | #include "nsIDOMWindowUtils.h" |
144 | | #include "nsIDragService.h" |
145 | | #include "nsIFormControl.h" |
146 | | #include "nsIForm.h" |
147 | | #include "nsIFragmentContentSink.h" |
148 | | #include "nsContainerFrame.h" |
149 | | #include "nsIHTMLDocument.h" |
150 | | #include "nsIIdleService.h" |
151 | | #include "nsIImageLoadingContent.h" |
152 | | #include "nsIInterfaceRequestor.h" |
153 | | #include "nsIInterfaceRequestorUtils.h" |
154 | | #include "nsIIOService.h" |
155 | | #include "nsILoadContext.h" |
156 | | #include "nsILoadGroup.h" |
157 | | #include "nsIMemoryReporter.h" |
158 | | #include "nsIMIMEHeaderParam.h" |
159 | | #include "nsIMIMEService.h" |
160 | | #include "nsINode.h" |
161 | | #include "mozilla/dom/NodeInfo.h" |
162 | | #include "mozilla/NullPrincipal.h" |
163 | | #include "nsIObjectLoadingContent.h" |
164 | | #include "nsIObserver.h" |
165 | | #include "nsIObserverService.h" |
166 | | #include "nsIOfflineCacheUpdate.h" |
167 | | #include "nsIParser.h" |
168 | | #include "nsIParserUtils.h" |
169 | | #include "nsIPermissionManager.h" |
170 | | #include "nsIPluginHost.h" |
171 | | #include "nsIRequest.h" |
172 | | #include "nsIRunnable.h" |
173 | | #include "nsIScriptContext.h" |
174 | | #include "nsIScriptError.h" |
175 | | #include "nsIScriptGlobalObject.h" |
176 | | #include "nsIScriptObjectPrincipal.h" |
177 | | #include "nsIScriptSecurityManager.h" |
178 | | #include "nsIScrollable.h" |
179 | | #include "nsIStreamConverter.h" |
180 | | #include "nsIStreamConverterService.h" |
181 | | #include "nsIStringBundle.h" |
182 | | #include "nsIURI.h" |
183 | | #include "nsIURIWithSpecialOrigin.h" |
184 | | #include "nsIURL.h" |
185 | | #include "nsIWebNavigation.h" |
186 | | #include "nsIWidget.h" |
187 | | #include "nsIWindowMediator.h" |
188 | | #include "nsIXPConnect.h" |
189 | | #include "nsJSUtils.h" |
190 | | #include "nsMappedAttributes.h" |
191 | | #include "nsNetCID.h" |
192 | | #include "nsNetUtil.h" |
193 | | #include "nsNodeInfoManager.h" |
194 | | #include "nsParserCIID.h" |
195 | | #include "nsParserConstants.h" |
196 | | #include "nsPIDOMWindow.h" |
197 | | #include "nsPresContext.h" |
198 | | #include "nsPrintfCString.h" |
199 | | #include "nsSandboxFlags.h" |
200 | | #include "nsScriptSecurityManager.h" |
201 | | #include "nsSerializationHelper.h" |
202 | | #include "nsStreamUtils.h" |
203 | | #include "nsTextEditorState.h" |
204 | | #include "nsTextFragment.h" |
205 | | #include "nsTextNode.h" |
206 | | #include "nsThreadUtils.h" |
207 | | #include "nsTreeSanitizer.h" |
208 | | #include "nsUnicodeProperties.h" |
209 | | #include "nsURLHelper.h" |
210 | | #include "nsViewManager.h" |
211 | | #include "nsViewportInfo.h" |
212 | | #include "nsWidgetsCID.h" |
213 | | #include "nsIWindowProvider.h" |
214 | | #include "nsWrapperCacheInlines.h" |
215 | | #include "nsXULPopupManager.h" |
216 | | #include "xpcprivate.h" // nsXPConnect |
217 | | #include "HTMLSplitOnSpacesTokenizer.h" |
218 | | #include "InProcessTabChildMessageManager.h" |
219 | | #include "nsContentTypeParser.h" |
220 | | #include "nsICookiePermission.h" |
221 | | #include "nsICookieService.h" |
222 | | #include "mozIThirdPartyUtil.h" |
223 | | #include "mozilla/EnumSet.h" |
224 | | #include "mozilla/BloomFilter.h" |
225 | | #include "TabChild.h" |
226 | | #include "mozilla/dom/DocGroup.h" |
227 | | #include "mozilla/dom/TabGroup.h" |
228 | | #include "nsIWebNavigationInfo.h" |
229 | | #include "nsPluginHost.h" |
230 | | #include "nsIBrowser.h" |
231 | | #include "mozilla/HangAnnotations.h" |
232 | | #include "mozilla/Encoding.h" |
233 | | #include "nsXULElement.h" |
234 | | |
235 | | #include "nsIBidiKeyboard.h" |
236 | | |
237 | | #if defined(XP_WIN) |
238 | | // Undefine LoadImage to prevent naming conflict with Windows. |
239 | | #undef LoadImage |
240 | | #endif |
241 | | |
242 | | extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, |
243 | | const char** next, char16_t* result); |
244 | | extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, |
245 | | int ns_aware, const char** colon); |
246 | | |
247 | | class imgLoader; |
248 | | class nsAtom; |
249 | | |
250 | | using namespace mozilla::dom; |
251 | | using namespace mozilla::ipc; |
252 | | using namespace mozilla::gfx; |
253 | | using namespace mozilla::layers; |
254 | | using namespace mozilla::widget; |
255 | | using namespace mozilla; |
256 | | |
257 | | const char kLoadAsData[] = "loadAsData"; |
258 | | |
259 | | nsIXPConnect *nsContentUtils::sXPConnect; |
260 | | nsIScriptSecurityManager *nsContentUtils::sSecurityManager; |
261 | | nsIPrincipal *nsContentUtils::sSystemPrincipal; |
262 | | nsIPrincipal *nsContentUtils::sNullSubjectPrincipal; |
263 | | nsNameSpaceManager *nsContentUtils::sNameSpaceManager; |
264 | | nsIIOService *nsContentUtils::sIOService; |
265 | | nsIUUIDGenerator *nsContentUtils::sUUIDGenerator; |
266 | | nsIConsoleService *nsContentUtils::sConsoleService; |
267 | | nsDataHashtable<nsRefPtrHashKey<nsAtom>, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr; |
268 | | nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr; |
269 | | nsTArray<RefPtr<nsAtom>>* nsContentUtils::sUserDefinedEvents = nullptr; |
270 | | nsIStringBundleService *nsContentUtils::sStringBundleService; |
271 | | nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT]; |
272 | | nsIContentPolicy *nsContentUtils::sContentPolicyService; |
273 | | bool nsContentUtils::sTriedToGetContentPolicy = false; |
274 | | RefPtr<mozilla::intl::LineBreaker> nsContentUtils::sLineBreaker; |
275 | | RefPtr<mozilla::intl::WordBreaker> nsContentUtils::sWordBreaker; |
276 | | StaticRefPtr<nsIBidiKeyboard> nsContentUtils::sBidiKeyboard; |
277 | | uint32_t nsContentUtils::sScriptBlockerCount = 0; |
278 | | uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; |
279 | | AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr; |
280 | | uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; |
281 | | nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; |
282 | | |
283 | | bool nsContentUtils::sIsHandlingKeyBoardEvent = false; |
284 | | bool nsContentUtils::sAllowXULXBL_for_file = false; |
285 | | bool nsContentUtils::sDisablePopups = false; |
286 | | |
287 | | nsString* nsContentUtils::sShiftText = nullptr; |
288 | | nsString* nsContentUtils::sControlText = nullptr; |
289 | | nsString* nsContentUtils::sMetaText = nullptr; |
290 | | nsString* nsContentUtils::sOSText = nullptr; |
291 | | nsString* nsContentUtils::sAltText = nullptr; |
292 | | nsString* nsContentUtils::sModifierSeparator = nullptr; |
293 | | |
294 | | bool nsContentUtils::sInitialized = false; |
295 | | bool nsContentUtils::sIsFullscreenApiEnabled = false; |
296 | | bool nsContentUtils::sIsUnprefixedFullscreenApiEnabled = false; |
297 | | bool nsContentUtils::sTrustedFullscreenOnly = true; |
298 | | bool nsContentUtils::sIsCutCopyAllowed = true; |
299 | | bool nsContentUtils::sIsUpgradableDisplayContentPrefEnabled = false; |
300 | | bool nsContentUtils::sIsFrameTimingPrefEnabled = false; |
301 | | bool nsContentUtils::sIsPerformanceTimingEnabled = false; |
302 | | bool nsContentUtils::sIsResourceTimingEnabled = false; |
303 | | bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false; |
304 | | bool nsContentUtils::sIsFormAutofillAutocompleteEnabled = false; |
305 | | bool nsContentUtils::sIsUAWidgetEnabled = false; |
306 | | bool nsContentUtils::sIsShadowDOMEnabled = false; |
307 | | bool nsContentUtils::sIsCustomElementsEnabled = false; |
308 | | bool nsContentUtils::sSendPerformanceTimingNotifications = false; |
309 | | bool nsContentUtils::sUseActivityCursor = false; |
310 | | bool nsContentUtils::sAnimationsAPICoreEnabled = false; |
311 | | bool nsContentUtils::sGetBoxQuadsEnabled = false; |
312 | | bool nsContentUtils::sSkipCursorMoveForSameValueSet = false; |
313 | | bool nsContentUtils::sRequestIdleCallbackEnabled = false; |
314 | | bool nsContentUtils::sLowerNetworkPriority = false; |
315 | | bool nsContentUtils::sTailingEnabled = false; |
316 | | bool nsContentUtils::sShowInputPlaceholderOnFocus = true; |
317 | | bool nsContentUtils::sAutoFocusEnabled = true; |
318 | | #ifndef RELEASE_OR_BETA |
319 | | bool nsContentUtils::sBypassCSSOMOriginCheck = false; |
320 | | #endif |
321 | | |
322 | | bool nsContentUtils::sIsBytecodeCacheEnabled = false; |
323 | | int32_t nsContentUtils::sBytecodeCacheStrategy = 0; |
324 | | nsCString* nsContentUtils::sJSBytecodeMimeType = nullptr; |
325 | | |
326 | | int32_t nsContentUtils::sPrivacyMaxInnerWidth = 1000; |
327 | | int32_t nsContentUtils::sPrivacyMaxInnerHeight = 1000; |
328 | | |
329 | | nsContentUtils::UserInteractionObserver* |
330 | | nsContentUtils::sUserInteractionObserver = nullptr; |
331 | | |
332 | | uint32_t nsContentUtils::sHandlingInputTimeout = 1000; |
333 | | |
334 | | uint32_t nsContentUtils::sCookiesLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
335 | | |
336 | | nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; |
337 | | nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; |
338 | | nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; |
339 | | bool nsContentUtils::sFragmentParsingActive = false; |
340 | | |
341 | | bool nsContentUtils::sDoNotTrackEnabled = false; |
342 | | |
343 | | bool nsContentUtils::sAntiTrackingControlCenterUIEnabled = false; |
344 | | |
345 | | mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump"); |
346 | | |
347 | | PopupControlState nsContentUtils::sPopupControlState = openAbused; |
348 | | |
349 | | int32_t nsContentUtils::sInnerOrOuterWindowCount = 0; |
350 | | uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0; |
351 | | |
352 | | // Subset of http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name |
353 | | enum AutocompleteUnsupportedFieldName : uint8_t |
354 | | { |
355 | | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ |
356 | | eAutocompleteUnsupportedFieldName_##name_, |
357 | | #include "AutocompleteFieldList.h" |
358 | | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME |
359 | | }; |
360 | | |
361 | | enum AutocompleteUnsupportFieldContactHint : uint8_t |
362 | | { |
363 | | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ |
364 | | eAutocompleteUnsupportedFieldContactHint_##name_, |
365 | | #include "AutocompleteFieldList.h" |
366 | | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT |
367 | | }; |
368 | | |
369 | | enum AutocompleteFieldName : uint8_t |
370 | | { |
371 | | #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \ |
372 | | eAutocompleteFieldName_##name_, |
373 | | #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ |
374 | | AUTOCOMPLETE_FIELD_NAME(name_, value_) |
375 | | #include "AutocompleteFieldList.h" |
376 | | #undef AUTOCOMPLETE_FIELD_NAME |
377 | | #undef AUTOCOMPLETE_CONTACT_FIELD_NAME |
378 | | }; |
379 | | |
380 | | enum AutocompleteFieldHint : uint8_t |
381 | | { |
382 | | #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \ |
383 | | eAutocompleteFieldHint_##name_, |
384 | | #include "AutocompleteFieldList.h" |
385 | | #undef AUTOCOMPLETE_FIELD_HINT |
386 | | }; |
387 | | |
388 | | enum AutocompleteFieldContactHint : uint8_t |
389 | | { |
390 | | #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ |
391 | | eAutocompleteFieldContactHint_##name_, |
392 | | #include "AutocompleteFieldList.h" |
393 | | #undef AUTOCOMPLETE_FIELD_CONTACT_HINT |
394 | | }; |
395 | | |
396 | | enum AutocompleteCategory |
397 | | { |
398 | | #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_, |
399 | | #include "AutocompleteFieldList.h" |
400 | | #undef AUTOCOMPLETE_CATEGORY |
401 | | }; |
402 | | |
403 | | static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable[] = { |
404 | | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ |
405 | | { value_, eAutocompleteUnsupportedFieldName_##name_ }, |
406 | | #include "AutocompleteFieldList.h" |
407 | | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME |
408 | | { nullptr, 0 } |
409 | | }; |
410 | | |
411 | | static const nsAttrValue::EnumTable kAutocompleteUnsupportedContactFieldHintTable[] = { |
412 | | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ |
413 | | { value_, eAutocompleteUnsupportedFieldContactHint_##name_ }, |
414 | | #include "AutocompleteFieldList.h" |
415 | | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT |
416 | | { nullptr, 0 } |
417 | | }; |
418 | | |
419 | | |
420 | | static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = { |
421 | | #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \ |
422 | | { value_, eAutocompleteFieldName_##name_ }, |
423 | | #include "AutocompleteFieldList.h" |
424 | | #undef AUTOCOMPLETE_FIELD_NAME |
425 | | { nullptr, 0 } |
426 | | }; |
427 | | |
428 | | static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = { |
429 | | #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ |
430 | | { value_, eAutocompleteFieldName_##name_ }, |
431 | | #include "AutocompleteFieldList.h" |
432 | | #undef AUTOCOMPLETE_CONTACT_FIELD_NAME |
433 | | { nullptr, 0 } |
434 | | }; |
435 | | |
436 | | static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = { |
437 | | #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \ |
438 | | { value_, eAutocompleteFieldHint_##name_ }, |
439 | | #include "AutocompleteFieldList.h" |
440 | | #undef AUTOCOMPLETE_FIELD_HINT |
441 | | { nullptr, 0 } |
442 | | }; |
443 | | |
444 | | static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = { |
445 | | #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ |
446 | | { value_, eAutocompleteFieldContactHint_##name_ }, |
447 | | #include "AutocompleteFieldList.h" |
448 | | #undef AUTOCOMPLETE_FIELD_CONTACT_HINT |
449 | | { nullptr, 0 } |
450 | | }; |
451 | | |
452 | | namespace { |
453 | | |
454 | | static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); |
455 | | |
456 | | static PLDHashTable* sEventListenerManagersHash; |
457 | | |
458 | | class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter |
459 | | { |
460 | | MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) |
461 | | |
462 | | ~DOMEventListenerManagersHashReporter() = default; |
463 | | |
464 | | public: |
465 | | NS_DECL_ISUPPORTS |
466 | | |
467 | | NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, |
468 | | nsISupports* aData, bool aAnonymize) override |
469 | 0 | { |
470 | 0 | // We don't measure the |EventListenerManager| objects pointed to by the |
471 | 0 | // entries because those references are non-owning. |
472 | 0 | int64_t amount = sEventListenerManagersHash |
473 | 0 | ? sEventListenerManagersHash->ShallowSizeOfIncludingThis( |
474 | 0 | MallocSizeOf) |
475 | 0 | : 0; |
476 | 0 |
|
477 | 0 | MOZ_COLLECT_REPORT( |
478 | 0 | "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES, |
479 | 0 | amount, |
480 | 0 | "Memory used by the event listener manager's hash table."); |
481 | 0 |
|
482 | 0 | return NS_OK; |
483 | 0 | } |
484 | | }; |
485 | | |
486 | | NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter) |
487 | | |
488 | | class EventListenerManagerMapEntry : public PLDHashEntryHdr |
489 | | { |
490 | | public: |
491 | | explicit EventListenerManagerMapEntry(const void* aKey) |
492 | | : mKey(aKey) |
493 | 0 | { |
494 | 0 | } |
495 | | |
496 | | ~EventListenerManagerMapEntry() |
497 | 0 | { |
498 | 0 | NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM"); |
499 | 0 | } |
500 | | |
501 | | protected: // declared protected to silence clang warnings |
502 | | const void *mKey; // must be first, to look like PLDHashEntryStub |
503 | | |
504 | | public: |
505 | | RefPtr<EventListenerManager> mListenerManager; |
506 | | }; |
507 | | |
508 | | static void |
509 | | EventListenerManagerHashInitEntry(PLDHashEntryHdr *entry, const void *key) |
510 | 0 | { |
511 | 0 | // Initialize the entry with placement new |
512 | 0 | new (entry) EventListenerManagerMapEntry(key); |
513 | 0 | } |
514 | | |
515 | | static void |
516 | | EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) |
517 | 0 | { |
518 | 0 | EventListenerManagerMapEntry *lm = |
519 | 0 | static_cast<EventListenerManagerMapEntry *>(entry); |
520 | 0 |
|
521 | 0 | // Let the EventListenerManagerMapEntry clean itself up... |
522 | 0 | lm->~EventListenerManagerMapEntry(); |
523 | 0 | } |
524 | | |
525 | | class SameOriginCheckerImpl final : public nsIChannelEventSink, |
526 | | public nsIInterfaceRequestor |
527 | | { |
528 | | ~SameOriginCheckerImpl() = default; |
529 | | |
530 | | NS_DECL_ISUPPORTS |
531 | | NS_DECL_NSICHANNELEVENTSINK |
532 | | NS_DECL_NSIINTERFACEREQUESTOR |
533 | | }; |
534 | | |
535 | | } // namespace |
536 | | |
537 | | /** |
538 | | * This class is used to determine whether or not the user is currently |
539 | | * interacting with the browser. It listens to observer events to toggle the |
540 | | * value of the sUserActive static. |
541 | | * |
542 | | * This class is an internal implementation detail. |
543 | | * nsContentUtils::GetUserIsInteracting() should be used to access current |
544 | | * user interaction status. |
545 | | */ |
546 | | class nsContentUtils::UserInteractionObserver final : public nsIObserver |
547 | | , public BackgroundHangAnnotator |
548 | | { |
549 | | public: |
550 | | NS_DECL_ISUPPORTS |
551 | | NS_DECL_NSIOBSERVER |
552 | | |
553 | | void Init(); |
554 | | void Shutdown(); |
555 | | void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override; |
556 | | |
557 | | static Atomic<bool> sUserActive; |
558 | | |
559 | | private: |
560 | 0 | ~UserInteractionObserver() {} |
561 | | }; |
562 | | |
563 | | /* static */ |
564 | | TimeDuration |
565 | | nsContentUtils::HandlingUserInputTimeout() |
566 | 0 | { |
567 | 0 | return TimeDuration::FromMilliseconds(sHandlingInputTimeout); |
568 | 0 | } |
569 | | |
570 | | // static |
571 | | nsresult |
572 | | nsContentUtils::Init() |
573 | 3 | { |
574 | 3 | if (sInitialized) { |
575 | 0 | NS_WARNING("Init() called twice"); |
576 | 0 |
|
577 | 0 | return NS_OK; |
578 | 0 | } |
579 | 3 | |
580 | 3 | nsHTMLTags::AddRefTable(); |
581 | 3 | |
582 | 3 | sNameSpaceManager = nsNameSpaceManager::GetInstance(); |
583 | 3 | NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY); |
584 | 3 | |
585 | 3 | sXPConnect = nsXPConnect::XPConnect(); |
586 | 3 | // We hold a strong ref to sXPConnect to ensure that it does not go away until |
587 | 3 | // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be |
588 | 3 | // triggered by xpcModuleDtor late in shutdown and cause crashes due to |
589 | 3 | // various stuff already being torn down by then. Note that this means that |
590 | 3 | // we are effectively making sure that if we leak nsLayoutStatics then we also |
591 | 3 | // leak nsXPConnect. |
592 | 3 | NS_ADDREF(sXPConnect); |
593 | 3 | |
594 | 3 | sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); |
595 | 3 | if(!sSecurityManager) |
596 | 0 | return NS_ERROR_FAILURE; |
597 | 3 | NS_ADDREF(sSecurityManager); |
598 | 3 | |
599 | 3 | sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); |
600 | 3 | MOZ_ASSERT(sSystemPrincipal); |
601 | 3 | |
602 | 3 | RefPtr<NullPrincipal> nullPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); |
603 | 3 | if (!nullPrincipal) { |
604 | 0 | return NS_ERROR_FAILURE; |
605 | 0 | } |
606 | 3 | |
607 | 3 | nullPrincipal.forget(&sNullSubjectPrincipal); |
608 | 3 | |
609 | 3 | nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); |
610 | 3 | if (NS_FAILED(rv)) { |
611 | 0 | // This makes life easier, but we can live without it. |
612 | 0 |
|
613 | 0 | sIOService = nullptr; |
614 | 0 | } |
615 | 3 | |
616 | 3 | sLineBreaker = mozilla::intl::LineBreaker::Create(); |
617 | 3 | |
618 | 3 | sWordBreaker = mozilla::intl::WordBreaker::Create(); |
619 | 3 | |
620 | 3 | if (!InitializeEventTable()) |
621 | 0 | return NS_ERROR_FAILURE; |
622 | 3 | |
623 | 3 | if (!sEventListenerManagersHash) { |
624 | 3 | static const PLDHashTableOps hash_table_ops = |
625 | 3 | { |
626 | 3 | PLDHashTable::HashVoidPtrKeyStub, |
627 | 3 | PLDHashTable::MatchEntryStub, |
628 | 3 | PLDHashTable::MoveEntryStub, |
629 | 3 | EventListenerManagerHashClearEntry, |
630 | 3 | EventListenerManagerHashInitEntry |
631 | 3 | }; |
632 | 3 | |
633 | 3 | sEventListenerManagersHash = |
634 | 3 | new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry)); |
635 | 3 | |
636 | 3 | RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); |
637 | 3 | } |
638 | 3 | |
639 | 3 | sBlockedScriptRunners = new AutoTArray<nsCOMPtr<nsIRunnable>, 8>; |
640 | 3 | |
641 | 3 | Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, |
642 | 3 | "dom.allow_XUL_XBL_for_file"); |
643 | 3 | |
644 | 3 | Preferences::AddBoolVarCache(&sIsFullscreenApiEnabled, |
645 | 3 | "full-screen-api.enabled"); |
646 | 3 | |
647 | 3 | Preferences::AddBoolVarCache(&sIsUnprefixedFullscreenApiEnabled, |
648 | 3 | "full-screen-api.unprefix.enabled"); |
649 | 3 | |
650 | 3 | Preferences::AddBoolVarCache(&sTrustedFullscreenOnly, |
651 | 3 | "full-screen-api.allow-trusted-requests-only"); |
652 | 3 | |
653 | 3 | Preferences::AddBoolVarCache(&sIsCutCopyAllowed, |
654 | 3 | "dom.allow_cut_copy", true); |
655 | 3 | |
656 | 3 | Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled, |
657 | 3 | "dom.enable_performance", true); |
658 | 3 | |
659 | 3 | Preferences::AddBoolVarCache(&sIsResourceTimingEnabled, |
660 | 3 | "dom.enable_resource_timing", true); |
661 | 3 | |
662 | 3 | Preferences::AddBoolVarCache(&sIsPerformanceNavigationTimingEnabled, |
663 | 3 | "dom.enable_performance_navigation_timing", true); |
664 | 3 | |
665 | 3 | Preferences::AddBoolVarCache(&sIsUpgradableDisplayContentPrefEnabled, |
666 | 3 | "security.mixed_content.upgrade_display_content", false); |
667 | 3 | |
668 | 3 | Preferences::AddBoolVarCache(&sIsFrameTimingPrefEnabled, |
669 | 3 | "dom.enable_frame_timing", false); |
670 | 3 | |
671 | 3 | Preferences::AddBoolVarCache(&sIsFormAutofillAutocompleteEnabled, |
672 | 3 | "dom.forms.autocomplete.formautofill", false); |
673 | 3 | |
674 | 3 | Preferences::AddBoolVarCache(&sIsUAWidgetEnabled, |
675 | 3 | "dom.ua_widget.enabled", false); |
676 | 3 | |
677 | 3 | Preferences::AddBoolVarCache(&sIsShadowDOMEnabled, |
678 | 3 | "dom.webcomponents.shadowdom.enabled", false); |
679 | 3 | |
680 | 3 | Preferences::AddBoolVarCache(&sIsCustomElementsEnabled, |
681 | 3 | "dom.webcomponents.customelements.enabled", false); |
682 | 3 | |
683 | 3 | Preferences::AddIntVarCache(&sPrivacyMaxInnerWidth, |
684 | 3 | "privacy.window.maxInnerWidth", |
685 | 3 | 1000); |
686 | 3 | |
687 | 3 | Preferences::AddIntVarCache(&sPrivacyMaxInnerHeight, |
688 | 3 | "privacy.window.maxInnerHeight", |
689 | 3 | 1000); |
690 | 3 | |
691 | 3 | Preferences::AddUintVarCache(&sHandlingInputTimeout, |
692 | 3 | "dom.event.handling-user-input-time-limit", |
693 | 3 | 1000); |
694 | 3 | |
695 | 3 | Preferences::AddBoolVarCache(&sSendPerformanceTimingNotifications, |
696 | 3 | "dom.performance.enable_notify_performance_timing", false); |
697 | 3 | |
698 | 3 | Preferences::AddUintVarCache(&sCookiesLifetimePolicy, |
699 | 3 | "network.cookie.lifetimePolicy", |
700 | 3 | nsICookieService::ACCEPT_NORMALLY); |
701 | 3 | |
702 | 3 | Preferences::AddBoolVarCache(&sDoNotTrackEnabled, |
703 | 3 | "privacy.donottrackheader.enabled", false); |
704 | 3 | |
705 | 3 | Preferences::AddBoolVarCache(&sUseActivityCursor, |
706 | 3 | "ui.use_activity_cursor", false); |
707 | 3 | |
708 | 3 | Preferences::AddBoolVarCache(&sAnimationsAPICoreEnabled, |
709 | 3 | "dom.animations-api.core.enabled", false); |
710 | 3 | |
711 | 3 | Preferences::AddBoolVarCache(&sGetBoxQuadsEnabled, |
712 | 3 | "layout.css.getBoxQuads.enabled", false); |
713 | 3 | |
714 | 3 | Preferences::AddBoolVarCache(&sSkipCursorMoveForSameValueSet, |
715 | 3 | "dom.input.skip_cursor_move_for_same_value_set", |
716 | 3 | true); |
717 | 3 | |
718 | 3 | Preferences::AddBoolVarCache(&sRequestIdleCallbackEnabled, |
719 | 3 | "dom.requestIdleCallback.enabled", false); |
720 | 3 | |
721 | 3 | #ifndef RELEASE_OR_BETA |
722 | 3 | sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK"); |
723 | 3 | #endif |
724 | 3 | |
725 | 3 | Preferences::AddBoolVarCache(&sLowerNetworkPriority, |
726 | 3 | "privacy.trackingprotection.lower_network_priority", false); |
727 | 3 | |
728 | 3 | Preferences::AddBoolVarCache(&sTailingEnabled, |
729 | 3 | "network.http.tailing.enabled", true); |
730 | 3 | |
731 | 3 | Preferences::AddBoolVarCache(&sShowInputPlaceholderOnFocus, |
732 | 3 | "dom.placeholder.show_on_focus", true); |
733 | 3 | |
734 | 3 | Preferences::AddBoolVarCache(&sAutoFocusEnabled, |
735 | 3 | "browser.autofocus", true); |
736 | 3 | |
737 | 3 | Preferences::AddBoolVarCache(&sIsBytecodeCacheEnabled, |
738 | 3 | "dom.script_loader.bytecode_cache.enabled", false); |
739 | 3 | |
740 | 3 | Preferences::AddBoolVarCache(&sDisablePopups, |
741 | 3 | "dom.disable_open_during_load", false); |
742 | 3 | |
743 | 3 | Preferences::AddBoolVarCache(&sAntiTrackingControlCenterUIEnabled, |
744 | 3 | "browser.contentblocking.rejecttrackers.control-center.ui.enabled", false); |
745 | 3 | |
746 | 3 | Preferences::AddIntVarCache(&sBytecodeCacheStrategy, |
747 | 3 | "dom.script_loader.bytecode_cache.strategy", 0); |
748 | 3 | |
749 | 3 | nsDependentCString buildID(mozilla::PlatformBuildID()); |
750 | 3 | sJSBytecodeMimeType = new nsCString(NS_LITERAL_CSTRING("javascript/moz-bytecode-") + buildID); |
751 | 3 | |
752 | 3 | Element::InitCCCallbacks(); |
753 | 3 | |
754 | 3 | Unused << nsRFPService::GetOrCreate(); |
755 | 3 | |
756 | 3 | nsCOMPtr<nsIUUIDGenerator> uuidGenerator = |
757 | 3 | do_GetService("@mozilla.org/uuid-generator;1", &rv); |
758 | 3 | if (NS_WARN_IF(NS_FAILED(rv))) { |
759 | 0 | return rv; |
760 | 0 | } |
761 | 3 | uuidGenerator.forget(&sUUIDGenerator); |
762 | 3 | |
763 | 3 | if (XRE_IsParentProcess()) { |
764 | 3 | AsyncPrecreateStringBundles(); |
765 | 3 | } |
766 | 3 | |
767 | 3 | RefPtr<UserInteractionObserver> uio = new UserInteractionObserver(); |
768 | 3 | uio->Init(); |
769 | 3 | uio.forget(&sUserInteractionObserver); |
770 | 3 | |
771 | 3 | sInitialized = true; |
772 | 3 | |
773 | 3 | return NS_OK; |
774 | 3 | } |
775 | | |
776 | | nsresult nsContentUtils::RemoveWyciwygScheme(nsIURI* aURI, nsIURI** aReturn) |
777 | 0 | { |
778 | | #ifdef DEBUG |
779 | | bool isWyciwyg = false; |
780 | | aURI->SchemeIs("wyciwyg", &isWyciwyg); |
781 | | MOZ_ASSERT(isWyciwyg, "Scheme should be wyciwyg"); |
782 | | #endif |
783 | | nsAutoCString path; |
784 | 0 | nsresult rv = aURI->GetPathQueryRef(path); |
785 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
786 | 0 |
|
787 | 0 | uint32_t pathLength = path.Length(); |
788 | 0 | if (pathLength <= 2) { |
789 | 0 | return NS_ERROR_FAILURE; |
790 | 0 | } |
791 | 0 | |
792 | 0 | // Path is of the form "//123/http://foo/bar", with a variable number of |
793 | 0 | // digits. To figure out where the "real" URL starts, search path for a '/', |
794 | 0 | // starting at the third character. |
795 | 0 | int32_t slashIndex = path.FindChar('/', 2); |
796 | 0 | if (slashIndex == kNotFound) { |
797 | 0 | return NS_ERROR_FAILURE; |
798 | 0 | } |
799 | 0 | |
800 | 0 | return NS_NewURI(aReturn, |
801 | 0 | Substring(path, slashIndex + 1, pathLength - slashIndex - 1)); |
802 | 0 | } |
803 | | |
804 | | void |
805 | | nsContentUtils::GetShiftText(nsAString& text) |
806 | 0 | { |
807 | 0 | if (!sShiftText) |
808 | 0 | InitializeModifierStrings(); |
809 | 0 | text.Assign(*sShiftText); |
810 | 0 | } |
811 | | |
812 | | void |
813 | | nsContentUtils::GetControlText(nsAString& text) |
814 | 0 | { |
815 | 0 | if (!sControlText) |
816 | 0 | InitializeModifierStrings(); |
817 | 0 | text.Assign(*sControlText); |
818 | 0 | } |
819 | | |
820 | | void |
821 | | nsContentUtils::GetMetaText(nsAString& text) |
822 | 0 | { |
823 | 0 | if (!sMetaText) |
824 | 0 | InitializeModifierStrings(); |
825 | 0 | text.Assign(*sMetaText); |
826 | 0 | } |
827 | | |
828 | | void |
829 | | nsContentUtils::GetOSText(nsAString& text) |
830 | 0 | { |
831 | 0 | if (!sOSText) { |
832 | 0 | InitializeModifierStrings(); |
833 | 0 | } |
834 | 0 | text.Assign(*sOSText); |
835 | 0 | } |
836 | | |
837 | | void |
838 | | nsContentUtils::GetAltText(nsAString& text) |
839 | 0 | { |
840 | 0 | if (!sAltText) |
841 | 0 | InitializeModifierStrings(); |
842 | 0 | text.Assign(*sAltText); |
843 | 0 | } |
844 | | |
845 | | void |
846 | | nsContentUtils::GetModifierSeparatorText(nsAString& text) |
847 | 0 | { |
848 | 0 | if (!sModifierSeparator) |
849 | 0 | InitializeModifierStrings(); |
850 | 0 | text.Assign(*sModifierSeparator); |
851 | 0 | } |
852 | | |
853 | | void |
854 | | nsContentUtils::InitializeModifierStrings() |
855 | 0 | { |
856 | 0 | //load the display strings for the keyboard accelerators |
857 | 0 | nsCOMPtr<nsIStringBundleService> bundleService = |
858 | 0 | mozilla::services::GetStringBundleService(); |
859 | 0 | nsCOMPtr<nsIStringBundle> bundle; |
860 | 0 | DebugOnly<nsresult> rv = NS_OK; |
861 | 0 | if (bundleService) { |
862 | 0 | rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties", |
863 | 0 | getter_AddRefs(bundle)); |
864 | 0 | } |
865 | 0 |
|
866 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded"); |
867 | 0 | nsAutoString shiftModifier; |
868 | 0 | nsAutoString metaModifier; |
869 | 0 | nsAutoString osModifier; |
870 | 0 | nsAutoString altModifier; |
871 | 0 | nsAutoString controlModifier; |
872 | 0 | nsAutoString modifierSeparator; |
873 | 0 | if (bundle) { |
874 | 0 | //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n |
875 | 0 | bundle->GetStringFromName("VK_SHIFT", shiftModifier); |
876 | 0 | bundle->GetStringFromName("VK_META", metaModifier); |
877 | 0 | bundle->GetStringFromName("VK_WIN", osModifier); |
878 | 0 | bundle->GetStringFromName("VK_ALT", altModifier); |
879 | 0 | bundle->GetStringFromName("VK_CONTROL", controlModifier); |
880 | 0 | bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator); |
881 | 0 | } |
882 | 0 | //if any of these don't exist, we get an empty string |
883 | 0 | sShiftText = new nsString(shiftModifier); |
884 | 0 | sMetaText = new nsString(metaModifier); |
885 | 0 | sOSText = new nsString(osModifier); |
886 | 0 | sAltText = new nsString(altModifier); |
887 | 0 | sControlText = new nsString(controlModifier); |
888 | 0 | sModifierSeparator = new nsString(modifierSeparator); |
889 | 0 | } |
890 | | |
891 | | mozilla::EventClassID |
892 | | nsContentUtils::GetEventClassIDFromMessage(EventMessage aEventMessage) |
893 | 0 | { |
894 | 0 | switch (aEventMessage) { |
895 | 0 | #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ |
896 | 0 | case message_: return struct_; |
897 | 0 | #include "mozilla/EventNameList.h" |
898 | 0 | #undef MESSAGE_TO_EVENT |
899 | 0 | default: |
900 | 0 | MOZ_ASSERT_UNREACHABLE("Invalid event message?"); |
901 | 0 | return eBasicEventClass; |
902 | 0 | } |
903 | 0 | } |
904 | | |
905 | | static nsAtom* |
906 | | GetEventTypeFromMessage(EventMessage aEventMessage) |
907 | 609 | { |
908 | 609 | switch (aEventMessage) { |
909 | 609 | #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ |
910 | 609 | case message_: return nsGkAtoms::on##name_; |
911 | 609 | #include "mozilla/EventNameList.h" |
912 | 609 | #undef MESSAGE_TO_EVENT |
913 | 609 | default: |
914 | 0 | return nullptr; |
915 | 609 | } |
916 | 609 | } |
917 | | |
918 | | // Because of SVG/SMIL we have several atoms mapped to the same |
919 | | // id, but we can rely on MESSAGE_TO_EVENT to map id to only one atom. |
920 | | static bool |
921 | | ShouldAddEventToStringEventTable(const EventNameMapping& aMapping) |
922 | 609 | { |
923 | 609 | MOZ_ASSERT(aMapping.mAtom); |
924 | 609 | return GetEventTypeFromMessage(aMapping.mMessage) == aMapping.mAtom; |
925 | 609 | } |
926 | | |
927 | | bool |
928 | 3 | nsContentUtils::InitializeEventTable() { |
929 | 3 | NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!"); |
930 | 3 | NS_ASSERTION(!sStringEventTable, "EventTable already initialized!"); |
931 | 3 | |
932 | 3 | static const EventNameMapping eventArray[] = { |
933 | 3 | #define EVENT(name_, _message, _type, _class) \ |
934 | 609 | { nsGkAtoms::on##name_, _type, _message, _class, false }, |
935 | 78 | #define WINDOW_ONLY_EVENT EVENT |
936 | 9 | #define DOCUMENT_ONLY_EVENT EVENT |
937 | 204 | #define NON_IDL_EVENT EVENT |
938 | 3 | #include "mozilla/EventNameList.h" |
939 | 3 | #undef WINDOW_ONLY_EVENT |
940 | 3 | #undef NON_IDL_EVENT |
941 | 3 | #undef EVENT |
942 | 3 | { nullptr } |
943 | 3 | }; |
944 | 3 | |
945 | 3 | sAtomEventTable = new nsDataHashtable<nsRefPtrHashKey<nsAtom>, EventNameMapping>( |
946 | 3 | ArrayLength(eventArray)); |
947 | 3 | sStringEventTable = new nsDataHashtable<nsStringHashKey, EventNameMapping>( |
948 | 3 | ArrayLength(eventArray)); |
949 | 3 | sUserDefinedEvents = new nsTArray<RefPtr<nsAtom>>(64); |
950 | 3 | |
951 | 3 | // Subtract one from the length because of the trailing null |
952 | 612 | for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) { |
953 | 609 | MOZ_ASSERT(!sAtomEventTable->Lookup(eventArray[i].mAtom), |
954 | 609 | "Double-defining event name; fix your EventNameList.h"); |
955 | 609 | sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]); |
956 | 609 | if (ShouldAddEventToStringEventTable(eventArray[i])) { |
957 | 588 | sStringEventTable->Put( |
958 | 588 | Substring(nsDependentAtomString(eventArray[i].mAtom), 2), |
959 | 588 | eventArray[i]); |
960 | 588 | } |
961 | 609 | } |
962 | 3 | |
963 | 3 | return true; |
964 | 3 | } |
965 | | |
966 | | void |
967 | | nsContentUtils::InitializeTouchEventTable() |
968 | 0 | { |
969 | 0 | static bool sEventTableInitialized = false; |
970 | 0 | if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) { |
971 | 0 | sEventTableInitialized = true; |
972 | 0 | static const EventNameMapping touchEventArray[] = { |
973 | 0 | #define EVENT(name_, _message, _type, _class) |
974 | 0 | #define TOUCH_EVENT(name_, _message, _type, _class) \ |
975 | 0 | { nsGkAtoms::on##name_, _type, _message, _class }, |
976 | 0 | #include "mozilla/EventNameList.h" |
977 | 0 | #undef TOUCH_EVENT |
978 | 0 | #undef EVENT |
979 | 0 | { nullptr } |
980 | 0 | }; |
981 | 0 | // Subtract one from the length because of the trailing null |
982 | 0 | for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) { |
983 | 0 | sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]); |
984 | 0 | sStringEventTable->Put(Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2), |
985 | 0 | touchEventArray[i]); |
986 | 0 | } |
987 | 0 | } |
988 | 0 | } |
989 | | |
990 | | static bool |
991 | | Is8bit(const nsAString& aString) |
992 | 0 | { |
993 | 0 | static const char16_t EIGHT_BIT = char16_t(~0x00FF); |
994 | 0 |
|
995 | 0 | for (nsAString::const_char_iterator start = aString.BeginReading(), |
996 | 0 | end = aString.EndReading(); |
997 | 0 | start != end; |
998 | 0 | ++start) { |
999 | 0 | if (*start & EIGHT_BIT) { |
1000 | 0 | return false; |
1001 | 0 | } |
1002 | 0 | } |
1003 | 0 |
|
1004 | 0 | return true; |
1005 | 0 | } |
1006 | | |
1007 | | nsresult |
1008 | | nsContentUtils::Btoa(const nsAString& aBinaryData, |
1009 | | nsAString& aAsciiBase64String) |
1010 | 0 | { |
1011 | 0 | if (!Is8bit(aBinaryData)) { |
1012 | 0 | aAsciiBase64String.Truncate(); |
1013 | 0 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; |
1014 | 0 | } |
1015 | 0 | |
1016 | 0 | return Base64Encode(aBinaryData, aAsciiBase64String); |
1017 | 0 | } |
1018 | | |
1019 | | nsresult |
1020 | | nsContentUtils::Atob(const nsAString& aAsciiBase64String, |
1021 | | nsAString& aBinaryData) |
1022 | 0 | { |
1023 | 0 | if (!Is8bit(aAsciiBase64String)) { |
1024 | 0 | aBinaryData.Truncate(); |
1025 | 0 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; |
1026 | 0 | } |
1027 | 0 | |
1028 | 0 | const char16_t* start = aAsciiBase64String.BeginReading(); |
1029 | 0 | const char16_t* cur = start; |
1030 | 0 | const char16_t* end = aAsciiBase64String.EndReading(); |
1031 | 0 | bool hasWhitespace = false; |
1032 | 0 |
|
1033 | 0 | while (cur < end) { |
1034 | 0 | if (nsContentUtils::IsHTMLWhitespace(*cur)) { |
1035 | 0 | hasWhitespace = true; |
1036 | 0 | break; |
1037 | 0 | } |
1038 | 0 | cur++; |
1039 | 0 | } |
1040 | 0 |
|
1041 | 0 | nsresult rv; |
1042 | 0 |
|
1043 | 0 | if (hasWhitespace) { |
1044 | 0 | nsString trimmedString; |
1045 | 0 |
|
1046 | 0 | if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) { |
1047 | 0 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; |
1048 | 0 | } |
1049 | 0 | |
1050 | 0 | trimmedString.Append(start, cur - start); |
1051 | 0 |
|
1052 | 0 | while (cur < end) { |
1053 | 0 | if (!nsContentUtils::IsHTMLWhitespace(*cur)) { |
1054 | 0 | trimmedString.Append(*cur); |
1055 | 0 | } |
1056 | 0 | cur++; |
1057 | 0 | } |
1058 | 0 | rv = Base64Decode(trimmedString, aBinaryData); |
1059 | 0 | } else { |
1060 | 0 | rv = Base64Decode(aAsciiBase64String, aBinaryData); |
1061 | 0 | } |
1062 | 0 |
|
1063 | 0 | if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) { |
1064 | 0 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; |
1065 | 0 | } |
1066 | 0 | return rv; |
1067 | 0 | } |
1068 | | |
1069 | | bool |
1070 | | nsContentUtils::IsAutocompleteEnabled(mozilla::dom::HTMLInputElement* aInput) |
1071 | 0 | { |
1072 | 0 | MOZ_ASSERT(aInput, "aInput should not be null!"); |
1073 | 0 |
|
1074 | 0 | nsAutoString autocomplete; |
1075 | 0 | aInput->GetAutocomplete(autocomplete); |
1076 | 0 |
|
1077 | 0 | if (autocomplete.IsEmpty()) { |
1078 | 0 | auto* form = aInput->GetForm(); |
1079 | 0 | if (!form) { |
1080 | 0 | return true; |
1081 | 0 | } |
1082 | 0 | |
1083 | 0 | form->GetAutocomplete(autocomplete); |
1084 | 0 | } |
1085 | 0 |
|
1086 | 0 | return !autocomplete.EqualsLiteral("off"); |
1087 | 0 | } |
1088 | | |
1089 | | nsContentUtils::AutocompleteAttrState |
1090 | | nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr, |
1091 | | nsAString& aResult, |
1092 | | AutocompleteAttrState aCachedState) |
1093 | 0 | { |
1094 | 0 | if (!aAttr || |
1095 | 0 | aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { |
1096 | 0 | return aCachedState; |
1097 | 0 | } |
1098 | 0 | |
1099 | 0 | if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) { |
1100 | 0 | uint32_t atomCount = aAttr->GetAtomCount(); |
1101 | 0 | for (uint32_t i = 0; i < atomCount; i++) { |
1102 | 0 | if (i != 0) { |
1103 | 0 | aResult.Append(' '); |
1104 | 0 | } |
1105 | 0 | aResult.Append(nsDependentAtomString(aAttr->AtomAt(i))); |
1106 | 0 | } |
1107 | 0 | nsContentUtils::ASCIIToLower(aResult); |
1108 | 0 | return aCachedState; |
1109 | 0 | } |
1110 | 0 |
|
1111 | 0 | aResult.Truncate(); |
1112 | 0 |
|
1113 | 0 | mozilla::dom::AutocompleteInfo info; |
1114 | 0 | AutocompleteAttrState state = |
1115 | 0 | InternalSerializeAutocompleteAttribute(aAttr, info); |
1116 | 0 | if (state == eAutocompleteAttrState_Valid) { |
1117 | 0 | // Concatenate the info fields. |
1118 | 0 | aResult = info.mSection; |
1119 | 0 |
|
1120 | 0 | if (!info.mAddressType.IsEmpty()) { |
1121 | 0 | if (!aResult.IsEmpty()) { |
1122 | 0 | aResult += ' '; |
1123 | 0 | } |
1124 | 0 | aResult += info.mAddressType; |
1125 | 0 | } |
1126 | 0 |
|
1127 | 0 | if (!info.mContactType.IsEmpty()) { |
1128 | 0 | if (!aResult.IsEmpty()) { |
1129 | 0 | aResult += ' '; |
1130 | 0 | } |
1131 | 0 | aResult += info.mContactType; |
1132 | 0 | } |
1133 | 0 |
|
1134 | 0 | if (!info.mFieldName.IsEmpty()) { |
1135 | 0 | if (!aResult.IsEmpty()) { |
1136 | 0 | aResult += ' '; |
1137 | 0 | } |
1138 | 0 | aResult += info.mFieldName; |
1139 | 0 | } |
1140 | 0 | } |
1141 | 0 |
|
1142 | 0 | return state; |
1143 | 0 | } |
1144 | | |
1145 | | nsContentUtils::AutocompleteAttrState |
1146 | | nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr, |
1147 | | mozilla::dom::AutocompleteInfo& aInfo, |
1148 | | AutocompleteAttrState aCachedState, |
1149 | | bool aGrantAllValidValue) |
1150 | 0 | { |
1151 | 0 | if (!aAttr || |
1152 | 0 | aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { |
1153 | 0 | return aCachedState; |
1154 | 0 | } |
1155 | 0 | |
1156 | 0 | return InternalSerializeAutocompleteAttribute(aAttr, aInfo, aGrantAllValidValue); |
1157 | 0 | } |
1158 | | |
1159 | | /** |
1160 | | * Helper to validate the @autocomplete tokens. |
1161 | | * |
1162 | | * @return {AutocompleteAttrState} The state of the attribute (invalid/valid). |
1163 | | */ |
1164 | | nsContentUtils::AutocompleteAttrState |
1165 | | nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal, |
1166 | | mozilla::dom::AutocompleteInfo& aInfo, |
1167 | | bool aGrantAllValidValue) |
1168 | 0 | { |
1169 | 0 | // No autocomplete attribute so we are done |
1170 | 0 | if (!aAttrVal) { |
1171 | 0 | return eAutocompleteAttrState_Invalid; |
1172 | 0 | } |
1173 | 0 | |
1174 | 0 | uint32_t numTokens = aAttrVal->GetAtomCount(); |
1175 | 0 | if (!numTokens) { |
1176 | 0 | return eAutocompleteAttrState_Invalid; |
1177 | 0 | } |
1178 | 0 | |
1179 | 0 | uint32_t index = numTokens - 1; |
1180 | 0 | nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); |
1181 | 0 | AutocompleteCategory category; |
1182 | 0 | nsAttrValue enumValue; |
1183 | 0 |
|
1184 | 0 | bool unsupported = false; |
1185 | 0 | if (!aGrantAllValidValue) { |
1186 | 0 | unsupported = enumValue.ParseEnumValue(tokenString, |
1187 | 0 | kAutocompleteUnsupportedFieldNameTable, |
1188 | 0 | false); |
1189 | 0 | if (unsupported) { |
1190 | 0 | return eAutocompleteAttrState_Invalid; |
1191 | 0 | } |
1192 | 0 | } |
1193 | 0 | |
1194 | 0 | nsAutoString str; |
1195 | 0 | bool result = enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false); |
1196 | 0 | if (result) { |
1197 | 0 | // Off/Automatic/Normal categories. |
1198 | 0 | if (enumValue.Equals(NS_LITERAL_STRING("off"), eIgnoreCase) || |
1199 | 0 | enumValue.Equals(NS_LITERAL_STRING("on"), eIgnoreCase)) { |
1200 | 0 | if (numTokens > 1) { |
1201 | 0 | return eAutocompleteAttrState_Invalid; |
1202 | 0 | } |
1203 | 0 | enumValue.ToString(str); |
1204 | 0 | ASCIIToLower(str); |
1205 | 0 | aInfo.mFieldName.Assign(str); |
1206 | 0 | return eAutocompleteAttrState_Valid; |
1207 | 0 | } |
1208 | 0 | |
1209 | 0 | // Only allow on/off if form autofill @autocomplete values aren't enabled |
1210 | 0 | // and it doesn't grant all valid values. |
1211 | 0 | if (!sIsFormAutofillAutocompleteEnabled && !aGrantAllValidValue) { |
1212 | 0 | return eAutocompleteAttrState_Invalid; |
1213 | 0 | } |
1214 | 0 | |
1215 | 0 | // Normal category |
1216 | 0 | if (numTokens > 3) { |
1217 | 0 | return eAutocompleteAttrState_Invalid; |
1218 | 0 | } |
1219 | 0 | category = eAutocompleteCategory_NORMAL; |
1220 | 0 | } else { // Check if the last token is of the contact category instead. |
1221 | 0 | // Only allow on/off if form autofill @autocomplete values aren't enabled |
1222 | 0 | // and it doesn't grant all valid values. |
1223 | 0 | if (!sIsFormAutofillAutocompleteEnabled && !aGrantAllValidValue) { |
1224 | 0 | return eAutocompleteAttrState_Invalid; |
1225 | 0 | } |
1226 | 0 | |
1227 | 0 | result = enumValue.ParseEnumValue(tokenString, kAutocompleteContactFieldNameTable, false); |
1228 | 0 | if (!result || numTokens > 4) { |
1229 | 0 | return eAutocompleteAttrState_Invalid; |
1230 | 0 | } |
1231 | 0 | |
1232 | 0 | category = eAutocompleteCategory_CONTACT; |
1233 | 0 | } |
1234 | 0 |
|
1235 | 0 | enumValue.ToString(str); |
1236 | 0 | ASCIIToLower(str); |
1237 | 0 | aInfo.mFieldName.Assign(str); |
1238 | 0 |
|
1239 | 0 | // We are done if this was the only token. |
1240 | 0 | if (numTokens == 1) { |
1241 | 0 | return eAutocompleteAttrState_Valid; |
1242 | 0 | } |
1243 | 0 | |
1244 | 0 | --index; |
1245 | 0 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); |
1246 | 0 |
|
1247 | 0 | if (category == eAutocompleteCategory_CONTACT) { |
1248 | 0 | if (!aGrantAllValidValue) { |
1249 | 0 | unsupported = enumValue.ParseEnumValue(tokenString, |
1250 | 0 | kAutocompleteUnsupportedContactFieldHintTable, |
1251 | 0 | false); |
1252 | 0 | if (unsupported) { |
1253 | 0 | return eAutocompleteAttrState_Invalid; |
1254 | 0 | } |
1255 | 0 | } |
1256 | 0 | |
1257 | 0 | |
1258 | 0 | nsAttrValue contactFieldHint; |
1259 | 0 | result = contactFieldHint.ParseEnumValue(tokenString, kAutocompleteContactFieldHintTable, false); |
1260 | 0 | if (result) { |
1261 | 0 | nsAutoString contactFieldHintString; |
1262 | 0 | contactFieldHint.ToString(contactFieldHintString); |
1263 | 0 | ASCIIToLower(contactFieldHintString); |
1264 | 0 | aInfo.mContactType.Assign(contactFieldHintString); |
1265 | 0 | if (index == 0) { |
1266 | 0 | return eAutocompleteAttrState_Valid; |
1267 | 0 | } |
1268 | 0 | --index; |
1269 | 0 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); |
1270 | 0 | } |
1271 | 0 | } |
1272 | 0 |
|
1273 | 0 | // Check for billing/shipping tokens |
1274 | 0 | nsAttrValue fieldHint; |
1275 | 0 | if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable, false)) { |
1276 | 0 | nsString fieldHintString; |
1277 | 0 | fieldHint.ToString(fieldHintString); |
1278 | 0 | ASCIIToLower(fieldHintString); |
1279 | 0 | aInfo.mAddressType.Assign(fieldHintString); |
1280 | 0 | if (index == 0) { |
1281 | 0 | return eAutocompleteAttrState_Valid; |
1282 | 0 | } |
1283 | 0 | --index; |
1284 | 0 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); |
1285 | 0 | } |
1286 | 0 |
|
1287 | 0 | // Check for section-* token |
1288 | 0 | const nsDependentSubstring& section = Substring(tokenString, 0, 8); |
1289 | 0 | if (section.LowerCaseEqualsASCII("section-")) { |
1290 | 0 | ASCIIToLower(tokenString); |
1291 | 0 | aInfo.mSection.Assign(tokenString); |
1292 | 0 | if (index == 0) { |
1293 | 0 | return eAutocompleteAttrState_Valid; |
1294 | 0 | } |
1295 | 0 | } |
1296 | 0 | |
1297 | 0 | // Clear the fields as the autocomplete attribute is invalid. |
1298 | 0 | aInfo.mSection.Truncate(); |
1299 | 0 | aInfo.mAddressType.Truncate(); |
1300 | 0 | aInfo.mContactType.Truncate(); |
1301 | 0 | aInfo.mFieldName.Truncate(); |
1302 | 0 |
|
1303 | 0 | return eAutocompleteAttrState_Invalid; |
1304 | 0 | } |
1305 | | |
1306 | | // Parse an integer according to HTML spec |
1307 | | int32_t |
1308 | | nsContentUtils::ParseHTMLInteger(const nsAString& aValue, |
1309 | | ParseHTMLIntegerResultFlags *aResult) |
1310 | 0 | { |
1311 | 0 | int result = eParseHTMLInteger_NoFlags; |
1312 | 0 |
|
1313 | 0 | nsAString::const_iterator iter, end; |
1314 | 0 | aValue.BeginReading(iter); |
1315 | 0 | aValue.EndReading(end); |
1316 | 0 |
|
1317 | 0 | while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { |
1318 | 0 | result |= eParseHTMLInteger_NonStandard; |
1319 | 0 | ++iter; |
1320 | 0 | } |
1321 | 0 |
|
1322 | 0 | if (iter == end) { |
1323 | 0 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; |
1324 | 0 | *aResult = (ParseHTMLIntegerResultFlags)result; |
1325 | 0 | return 0; |
1326 | 0 | } |
1327 | 0 | |
1328 | 0 | int sign = 1; |
1329 | 0 | if (*iter == char16_t('-')) { |
1330 | 0 | sign = -1; |
1331 | 0 | result |= eParseHTMLInteger_Negative; |
1332 | 0 | ++iter; |
1333 | 0 | } else if (*iter == char16_t('+')) { |
1334 | 0 | result |= eParseHTMLInteger_NonStandard; |
1335 | 0 | ++iter; |
1336 | 0 | } |
1337 | 0 |
|
1338 | 0 | bool foundValue = false; |
1339 | 0 | CheckedInt32 value = 0; |
1340 | 0 |
|
1341 | 0 | // Check for leading zeros first. |
1342 | 0 | uint64_t leadingZeros = 0; |
1343 | 0 | while (iter != end) { |
1344 | 0 | if (*iter != char16_t('0')) { |
1345 | 0 | break; |
1346 | 0 | } |
1347 | 0 | |
1348 | 0 | ++leadingZeros; |
1349 | 0 | foundValue = true; |
1350 | 0 | ++iter; |
1351 | 0 | } |
1352 | 0 |
|
1353 | 0 | while (iter != end) { |
1354 | 0 | if (*iter >= char16_t('0') && *iter <= char16_t('9')) { |
1355 | 0 | value = (value * 10) + (*iter - char16_t('0')) * sign; |
1356 | 0 | ++iter; |
1357 | 0 | if (!value.isValid()) { |
1358 | 0 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow; |
1359 | 0 | break; |
1360 | 0 | } |
1361 | 0 | foundValue = true; |
1362 | 0 | } else if (*iter == char16_t('%')) { |
1363 | 0 | ++iter; |
1364 | 0 | result |= eParseHTMLInteger_IsPercent; |
1365 | 0 | break; |
1366 | 0 | } else { |
1367 | 0 | break; |
1368 | 0 | } |
1369 | 0 | } |
1370 | 0 |
|
1371 | 0 | if (!foundValue) { |
1372 | 0 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; |
1373 | 0 | } |
1374 | 0 |
|
1375 | 0 | if (value.isValid() && |
1376 | 0 | ((leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) || |
1377 | 0 | (sign == -1 && value == 0))) { |
1378 | 0 | result |= eParseHTMLInteger_NonStandard; |
1379 | 0 | } |
1380 | 0 |
|
1381 | 0 | if (iter != end) { |
1382 | 0 | result |= eParseHTMLInteger_DidNotConsumeAllInput; |
1383 | 0 | } |
1384 | 0 |
|
1385 | 0 | *aResult = (ParseHTMLIntegerResultFlags)result; |
1386 | 0 | return value.isValid() ? value.value() : 0; |
1387 | 0 | } |
1388 | | |
1389 | | #define SKIP_WHITESPACE(iter, end_iter, end_res) \ |
1390 | 0 | while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ |
1391 | 0 | ++(iter); \ |
1392 | 0 | } \ |
1393 | 0 | if ((iter) == (end_iter)) { \ |
1394 | 0 | return (end_res); \ |
1395 | 0 | } |
1396 | | |
1397 | | #define SKIP_ATTR_NAME(iter, end_iter) \ |
1398 | 0 | while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ |
1399 | 0 | *(iter) != '=') { \ |
1400 | 0 | ++(iter); \ |
1401 | 0 | } |
1402 | | |
1403 | | bool |
1404 | | nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsAtom *aName, |
1405 | | nsAString& aValue) |
1406 | 0 | { |
1407 | 0 | aValue.Truncate(); |
1408 | 0 |
|
1409 | 0 | const char16_t *start = aSource.get(); |
1410 | 0 | const char16_t *end = start + aSource.Length(); |
1411 | 0 | const char16_t *iter; |
1412 | 0 |
|
1413 | 0 | while (start != end) { |
1414 | 0 | SKIP_WHITESPACE(start, end, false) |
1415 | 0 | iter = start; |
1416 | 0 | SKIP_ATTR_NAME(iter, end) |
1417 | 0 |
|
1418 | 0 | if (start == iter) { |
1419 | 0 | return false; |
1420 | 0 | } |
1421 | 0 | |
1422 | 0 | // Remember the attr name. |
1423 | 0 | const nsDependentSubstring & attrName = Substring(start, iter); |
1424 | 0 |
|
1425 | 0 | // Now check whether this is a valid name="value" pair. |
1426 | 0 | start = iter; |
1427 | 0 | SKIP_WHITESPACE(start, end, false) |
1428 | 0 | if (*start != '=') { |
1429 | 0 | // No '=', so this is not a name="value" pair. We don't know |
1430 | 0 | // what it is, and we have no way to handle it. |
1431 | 0 | return false; |
1432 | 0 | } |
1433 | 0 | |
1434 | 0 | // Have to skip the value. |
1435 | 0 | ++start; |
1436 | 0 | SKIP_WHITESPACE(start, end, false) |
1437 | 0 | char16_t q = *start; |
1438 | 0 | if (q != kQuote && q != kApostrophe) { |
1439 | 0 | // Not a valid quoted value, so bail. |
1440 | 0 | return false; |
1441 | 0 | } |
1442 | 0 | |
1443 | 0 | ++start; // Point to the first char of the value. |
1444 | 0 | iter = start; |
1445 | 0 |
|
1446 | 0 | while (iter != end && *iter != q) { |
1447 | 0 | ++iter; |
1448 | 0 | } |
1449 | 0 |
|
1450 | 0 | if (iter == end) { |
1451 | 0 | // Oops, unterminated quoted string. |
1452 | 0 | return false; |
1453 | 0 | } |
1454 | 0 | |
1455 | 0 | // At this point attrName holds the name of the "attribute" and |
1456 | 0 | // the value is between start and iter. |
1457 | 0 | |
1458 | 0 | if (aName->Equals(attrName)) { |
1459 | 0 | // We'll accumulate as many characters as possible (until we hit either |
1460 | 0 | // the end of the string or the beginning of an entity). Chunks will be |
1461 | 0 | // delimited by start and chunkEnd. |
1462 | 0 | const char16_t *chunkEnd = start; |
1463 | 0 | while (chunkEnd != iter) { |
1464 | 0 | if (*chunkEnd == kLessThan) { |
1465 | 0 | aValue.Truncate(); |
1466 | 0 |
|
1467 | 0 | return false; |
1468 | 0 | } |
1469 | 0 | |
1470 | 0 | if (*chunkEnd == kAmpersand) { |
1471 | 0 | aValue.Append(start, chunkEnd - start); |
1472 | 0 |
|
1473 | 0 | const char16_t *afterEntity = nullptr; |
1474 | 0 | char16_t result[2]; |
1475 | 0 | uint32_t count = |
1476 | 0 | MOZ_XMLTranslateEntity(reinterpret_cast<const char*>(chunkEnd), |
1477 | 0 | reinterpret_cast<const char*>(iter), |
1478 | 0 | reinterpret_cast<const char**>(&afterEntity), |
1479 | 0 | result); |
1480 | 0 | if (count == 0) { |
1481 | 0 | aValue.Truncate(); |
1482 | 0 |
|
1483 | 0 | return false; |
1484 | 0 | } |
1485 | 0 | |
1486 | 0 | aValue.Append(result, count); |
1487 | 0 |
|
1488 | 0 | // Advance to after the entity and begin a new chunk. |
1489 | 0 | start = chunkEnd = afterEntity; |
1490 | 0 | } |
1491 | 0 | else { |
1492 | 0 | ++chunkEnd; |
1493 | 0 | } |
1494 | 0 | } |
1495 | 0 |
|
1496 | 0 | // Append remainder. |
1497 | 0 | aValue.Append(start, iter - start); |
1498 | 0 |
|
1499 | 0 | return true; |
1500 | 0 | } |
1501 | 0 | |
1502 | 0 | // Resume scanning after the end of the attribute value (past the quote |
1503 | 0 | // char). |
1504 | 0 | start = iter + 1; |
1505 | 0 | } |
1506 | 0 |
|
1507 | 0 | return false; |
1508 | 0 | } |
1509 | | |
1510 | | bool |
1511 | | nsContentUtils::IsJavaScriptLanguage(const nsString& aName) |
1512 | 0 | { |
1513 | 0 | return aName.LowerCaseEqualsLiteral("javascript") || |
1514 | 0 | aName.LowerCaseEqualsLiteral("livescript") || |
1515 | 0 | aName.LowerCaseEqualsLiteral("mocha") || |
1516 | 0 | aName.LowerCaseEqualsLiteral("javascript1.0") || |
1517 | 0 | aName.LowerCaseEqualsLiteral("javascript1.1") || |
1518 | 0 | aName.LowerCaseEqualsLiteral("javascript1.2") || |
1519 | 0 | aName.LowerCaseEqualsLiteral("javascript1.3") || |
1520 | 0 | aName.LowerCaseEqualsLiteral("javascript1.4") || |
1521 | 0 | aName.LowerCaseEqualsLiteral("javascript1.5"); |
1522 | 0 | } |
1523 | | |
1524 | | void |
1525 | | nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, |
1526 | | nsString& aParams) |
1527 | 0 | { |
1528 | 0 | aType.Truncate(); |
1529 | 0 | aParams.Truncate(); |
1530 | 0 | int32_t semiIndex = aValue.FindChar(char16_t(';')); |
1531 | 0 | if (-1 != semiIndex) { |
1532 | 0 | aType = Substring(aValue, 0, semiIndex); |
1533 | 0 | aParams = Substring(aValue, semiIndex + 1, |
1534 | 0 | aValue.Length() - (semiIndex + 1)); |
1535 | 0 | aParams.StripWhitespace(); |
1536 | 0 | } |
1537 | 0 | else { |
1538 | 0 | aType = aValue; |
1539 | 0 | } |
1540 | 0 | aType.StripWhitespace(); |
1541 | 0 | } |
1542 | | |
1543 | | nsresult |
1544 | | nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS, bool* aUserIsIdle) |
1545 | 0 | { |
1546 | 0 | nsresult rv; |
1547 | 0 | nsCOMPtr<nsIIdleService> idleService = |
1548 | 0 | do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
1549 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1550 | 0 |
|
1551 | 0 | uint32_t idleTimeInMS; |
1552 | 0 | rv = idleService->GetIdleTime(&idleTimeInMS); |
1553 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1554 | 0 |
|
1555 | 0 | *aUserIsIdle = idleTimeInMS >= aRequestedIdleTimeInMS; |
1556 | 0 | return NS_OK; |
1557 | 0 | } |
1558 | | |
1559 | | /** |
1560 | | * A helper function that parses a sandbox attribute (of an <iframe> or a CSP |
1561 | | * directive) and converts it to the set of flags used internally. |
1562 | | * |
1563 | | * @param aSandboxAttr the sandbox attribute |
1564 | | * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is |
1565 | | * null) |
1566 | | */ |
1567 | | uint32_t |
1568 | | nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* aSandboxAttr) |
1569 | 0 | { |
1570 | 0 | if (!aSandboxAttr) { |
1571 | 0 | return SANDBOXED_NONE; |
1572 | 0 | } |
1573 | 0 | |
1574 | 0 | uint32_t out = SANDBOX_ALL_FLAGS; |
1575 | 0 |
|
1576 | 0 | #define SANDBOX_KEYWORD(string, atom, flags) \ |
1577 | 0 | if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \ |
1578 | 0 | out &= ~(flags); \ |
1579 | 0 | } |
1580 | 0 | #include "IframeSandboxKeywordList.h" |
1581 | 0 | #undef SANDBOX_KEYWORD |
1582 | 0 |
|
1583 | 0 | return out; |
1584 | 0 | } |
1585 | | |
1586 | | /** |
1587 | | * A helper function that checks if a string matches a valid sandbox flag. |
1588 | | * |
1589 | | * @param aFlag the potential sandbox flag. |
1590 | | * @return true if the flag is a sandbox flag. |
1591 | | */ |
1592 | | bool |
1593 | | nsContentUtils::IsValidSandboxFlag(const nsAString& aFlag) |
1594 | 18.4k | { |
1595 | 18.4k | #define SANDBOX_KEYWORD(string, atom, flags) \ |
1596 | 191k | if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \ |
1597 | 1.36k | return true; \ |
1598 | 1.36k | } |
1599 | 173k | #include "IframeSandboxKeywordList.h" |
1600 | 173k | #undef SANDBOX_KEYWORD |
1601 | 173k | return false; |
1602 | 173k | } |
1603 | | |
1604 | | /** |
1605 | | * A helper function that returns a string attribute corresponding to the |
1606 | | * sandbox flags. |
1607 | | * |
1608 | | * @param aFlags the sandbox flags |
1609 | | * @param aString the attribute corresponding to the flags (null if aFlags |
1610 | | * is zero) |
1611 | | */ |
1612 | | void |
1613 | | nsContentUtils::SandboxFlagsToString(uint32_t aFlags, nsAString& aString) |
1614 | 0 | { |
1615 | 0 | if (!aFlags) { |
1616 | 0 | SetDOMStringToNull(aString); |
1617 | 0 | return; |
1618 | 0 | } |
1619 | 0 | |
1620 | 0 | aString.Truncate(); |
1621 | 0 |
|
1622 | 0 | #define SANDBOX_KEYWORD(string, atom, flags) \ |
1623 | 0 | if (!(aFlags & (flags))) { \ |
1624 | 0 | if (!aString.IsEmpty()) { \ |
1625 | 0 | aString.AppendLiteral(u" "); \ |
1626 | 0 | } \ |
1627 | 0 | aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \ |
1628 | 0 | } |
1629 | 0 | #include "IframeSandboxKeywordList.h" |
1630 | 0 | #undef SANDBOX_KEYWORD |
1631 | 0 | } |
1632 | | |
1633 | | nsIBidiKeyboard* |
1634 | | nsContentUtils::GetBidiKeyboard() |
1635 | 0 | { |
1636 | 0 | if (!sBidiKeyboard) { |
1637 | 0 | sBidiKeyboard = nsIWidget::CreateBidiKeyboard(); |
1638 | 0 | } |
1639 | 0 | return sBidiKeyboard; |
1640 | 0 | } |
1641 | | |
1642 | | /** |
1643 | | * This is used to determine whether a character is in one of the classes |
1644 | | * which CSS says should be part of the first-letter. Currently, that is |
1645 | | * all punctuation classes (P*). Note that this is a change from CSS2 |
1646 | | * which excluded Pc and Pd. |
1647 | | * |
1648 | | * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo |
1649 | | * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode |
1650 | | * general category [UAX44]) [...]" |
1651 | | */ |
1652 | | |
1653 | | // static |
1654 | | bool |
1655 | | nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar) |
1656 | | { |
1657 | | switch (mozilla::unicode::GetGeneralCategory(aChar)) { |
1658 | | case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: /* Pc */ |
1659 | | case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: /* Pd */ |
1660 | | case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: /* Pe */ |
1661 | | case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: /* Pf */ |
1662 | | case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: /* Pi */ |
1663 | | case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: /* Po */ |
1664 | | case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: /* Ps */ |
1665 | | return true; |
1666 | | default: |
1667 | | return false; |
1668 | | } |
1669 | | } |
1670 | | |
1671 | | // static |
1672 | | bool |
1673 | | nsContentUtils::IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, uint32_t aOffset) |
1674 | 0 | { |
1675 | 0 | char16_t h = aFrag->CharAt(aOffset); |
1676 | 0 | if (!IS_SURROGATE(h)) { |
1677 | 0 | return IsFirstLetterPunctuation(h); |
1678 | 0 | } |
1679 | 0 | if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) { |
1680 | 0 | char16_t l = aFrag->CharAt(aOffset + 1); |
1681 | 0 | if (NS_IS_LOW_SURROGATE(l)) { |
1682 | 0 | return IsFirstLetterPunctuation(SURROGATE_TO_UCS4(h, l)); |
1683 | 0 | } |
1684 | 0 | } |
1685 | 0 | return false; |
1686 | 0 | } |
1687 | | |
1688 | | // static |
1689 | | bool nsContentUtils::IsAlphanumeric(uint32_t aChar) |
1690 | 0 | { |
1691 | 0 | nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar); |
1692 | 0 |
|
1693 | 0 | return (cat == nsUGenCategory::kLetter || cat == nsUGenCategory::kNumber); |
1694 | 0 | } |
1695 | | |
1696 | | // static |
1697 | | bool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, uint32_t aOffset) |
1698 | 0 | { |
1699 | 0 | char16_t h = aFrag->CharAt(aOffset); |
1700 | 0 | if (!IS_SURROGATE(h)) { |
1701 | 0 | return IsAlphanumeric(h); |
1702 | 0 | } |
1703 | 0 | if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) { |
1704 | 0 | char16_t l = aFrag->CharAt(aOffset + 1); |
1705 | 0 | if (NS_IS_LOW_SURROGATE(l)) { |
1706 | 0 | return IsAlphanumeric(SURROGATE_TO_UCS4(h, l)); |
1707 | 0 | } |
1708 | 0 | } |
1709 | 0 | return false; |
1710 | 0 | } |
1711 | | |
1712 | | /* static */ |
1713 | | bool |
1714 | | nsContentUtils::IsHTMLWhitespace(char16_t aChar) |
1715 | 55.3M | { |
1716 | 55.3M | return aChar == char16_t(0x0009) || |
1717 | 55.3M | aChar == char16_t(0x000A) || |
1718 | 55.3M | aChar == char16_t(0x000C) || |
1719 | 55.3M | aChar == char16_t(0x000D) || |
1720 | 55.3M | aChar == char16_t(0x0020); |
1721 | 55.3M | } |
1722 | | |
1723 | | /* static */ |
1724 | | bool |
1725 | | nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar) |
1726 | 0 | { |
1727 | 0 | return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0); |
1728 | 0 | } |
1729 | | |
1730 | | /* static */ |
1731 | | bool |
1732 | | nsContentUtils::IsHTMLBlock(nsIContent* aContent) |
1733 | 0 | { |
1734 | 0 | return aContent->IsAnyOfHTMLElements(nsGkAtoms::address, |
1735 | 0 | nsGkAtoms::article, |
1736 | 0 | nsGkAtoms::aside, |
1737 | 0 | nsGkAtoms::blockquote, |
1738 | 0 | nsGkAtoms::center, |
1739 | 0 | nsGkAtoms::dir, |
1740 | 0 | nsGkAtoms::div, |
1741 | 0 | nsGkAtoms::dl, // XXX why not dt and dd? |
1742 | 0 | nsGkAtoms::fieldset, |
1743 | 0 | nsGkAtoms::figure, // XXX shouldn't figcaption be on this list |
1744 | 0 | nsGkAtoms::footer, |
1745 | 0 | nsGkAtoms::form, |
1746 | 0 | nsGkAtoms::h1, |
1747 | 0 | nsGkAtoms::h2, |
1748 | 0 | nsGkAtoms::h3, |
1749 | 0 | nsGkAtoms::h4, |
1750 | 0 | nsGkAtoms::h5, |
1751 | 0 | nsGkAtoms::h6, |
1752 | 0 | nsGkAtoms::header, |
1753 | 0 | nsGkAtoms::hgroup, |
1754 | 0 | nsGkAtoms::hr, |
1755 | 0 | nsGkAtoms::li, |
1756 | 0 | nsGkAtoms::listing, |
1757 | 0 | nsGkAtoms::menu, |
1758 | 0 | nsGkAtoms::multicol, // XXX get rid of this one? |
1759 | 0 | nsGkAtoms::nav, |
1760 | 0 | nsGkAtoms::ol, |
1761 | 0 | nsGkAtoms::p, |
1762 | 0 | nsGkAtoms::pre, |
1763 | 0 | nsGkAtoms::section, |
1764 | 0 | nsGkAtoms::table, |
1765 | 0 | nsGkAtoms::ul, |
1766 | 0 | nsGkAtoms::xmp); |
1767 | 0 | } |
1768 | | |
1769 | | /* static */ |
1770 | | bool |
1771 | | nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result) |
1772 | 0 | { |
1773 | 0 | nsAutoString marginStr(aString); |
1774 | 0 | marginStr.CompressWhitespace(true, true); |
1775 | 0 | if (marginStr.IsEmpty()) { |
1776 | 0 | return false; |
1777 | 0 | } |
1778 | 0 | |
1779 | 0 | int32_t start = 0, end = 0; |
1780 | 0 | for (int count = 0; count < 4; count++) { |
1781 | 0 | if ((uint32_t)end >= marginStr.Length()) |
1782 | 0 | return false; |
1783 | 0 | |
1784 | 0 | // top, right, bottom, left |
1785 | 0 | if (count < 3) |
1786 | 0 | end = Substring(marginStr, start).FindChar(','); |
1787 | 0 | else |
1788 | 0 | end = Substring(marginStr, start).Length(); |
1789 | 0 |
|
1790 | 0 | if (end <= 0) |
1791 | 0 | return false; |
1792 | 0 | |
1793 | 0 | nsresult ec; |
1794 | 0 | int32_t val = nsString(Substring(marginStr, start, end)).ToInteger(&ec); |
1795 | 0 | if (NS_FAILED(ec)) |
1796 | 0 | return false; |
1797 | 0 | |
1798 | 0 | switch(count) { |
1799 | 0 | case 0: |
1800 | 0 | result.top = val; |
1801 | 0 | break; |
1802 | 0 | case 1: |
1803 | 0 | result.right = val; |
1804 | 0 | break; |
1805 | 0 | case 2: |
1806 | 0 | result.bottom = val; |
1807 | 0 | break; |
1808 | 0 | case 3: |
1809 | 0 | result.left = val; |
1810 | 0 | break; |
1811 | 0 | } |
1812 | 0 | start += end + 1; |
1813 | 0 | } |
1814 | 0 | return true; |
1815 | 0 | } |
1816 | | |
1817 | | // static |
1818 | | int32_t |
1819 | | nsContentUtils::ParseLegacyFontSize(const nsAString& aValue) |
1820 | 0 | { |
1821 | 0 | nsAString::const_iterator iter, end; |
1822 | 0 | aValue.BeginReading(iter); |
1823 | 0 | aValue.EndReading(end); |
1824 | 0 |
|
1825 | 0 | while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { |
1826 | 0 | ++iter; |
1827 | 0 | } |
1828 | 0 |
|
1829 | 0 | if (iter == end) { |
1830 | 0 | return 0; |
1831 | 0 | } |
1832 | 0 | |
1833 | 0 | bool relative = false; |
1834 | 0 | bool negate = false; |
1835 | 0 | if (*iter == char16_t('-')) { |
1836 | 0 | relative = true; |
1837 | 0 | negate = true; |
1838 | 0 | ++iter; |
1839 | 0 | } else if (*iter == char16_t('+')) { |
1840 | 0 | relative = true; |
1841 | 0 | ++iter; |
1842 | 0 | } |
1843 | 0 |
|
1844 | 0 | if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) { |
1845 | 0 | return 0; |
1846 | 0 | } |
1847 | 0 | |
1848 | 0 | // We don't have to worry about overflow, since we can bail out as soon as |
1849 | 0 | // we're bigger than 7. |
1850 | 0 | int32_t value = 0; |
1851 | 0 | while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) { |
1852 | 0 | value = 10*value + (*iter - char16_t('0')); |
1853 | 0 | if (value >= 7) { |
1854 | 0 | break; |
1855 | 0 | } |
1856 | 0 | ++iter; |
1857 | 0 | } |
1858 | 0 |
|
1859 | 0 | if (relative) { |
1860 | 0 | if (negate) { |
1861 | 0 | value = 3 - value; |
1862 | 0 | } else { |
1863 | 0 | value = 3 + value; |
1864 | 0 | } |
1865 | 0 | } |
1866 | 0 |
|
1867 | 0 | return clamped(value, 1, 7); |
1868 | 0 | } |
1869 | | |
1870 | | /* static */ |
1871 | | void |
1872 | | nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI) |
1873 | 0 | { |
1874 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1875 | 0 | MOZ_ASSERT(aDocument); |
1876 | 0 | *aURI = nullptr; |
1877 | 0 |
|
1878 | 0 | if (aDocument->GetController().isSome()) { |
1879 | 0 | return; |
1880 | 0 | } |
1881 | 0 | |
1882 | 0 | Element* docElement = aDocument->GetRootElement(); |
1883 | 0 | if (!docElement) { |
1884 | 0 | return; |
1885 | 0 | } |
1886 | 0 | |
1887 | 0 | nsAutoString manifestSpec; |
1888 | 0 | docElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec); |
1889 | 0 |
|
1890 | 0 | // Manifest URIs can't have fragment identifiers. |
1891 | 0 | if (manifestSpec.IsEmpty() || |
1892 | 0 | manifestSpec.Contains('#')) { |
1893 | 0 | return; |
1894 | 0 | } |
1895 | 0 | |
1896 | 0 | nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec, |
1897 | 0 | aDocument, |
1898 | 0 | aDocument->GetDocBaseURI()); |
1899 | 0 | } |
1900 | | |
1901 | | /* static */ |
1902 | | bool |
1903 | | nsContentUtils::OfflineAppAllowed(nsIURI *aURI) |
1904 | 0 | { |
1905 | 0 | nsCOMPtr<nsIOfflineCacheUpdateService> updateService = |
1906 | 0 | do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); |
1907 | 0 | if (!updateService) { |
1908 | 0 | return false; |
1909 | 0 | } |
1910 | 0 | |
1911 | 0 | bool allowed; |
1912 | 0 | nsresult rv = |
1913 | 0 | updateService->OfflineAppAllowedForURI(aURI, |
1914 | 0 | Preferences::GetRootBranch(), |
1915 | 0 | &allowed); |
1916 | 0 | return NS_SUCCEEDED(rv) && allowed; |
1917 | 0 | } |
1918 | | |
1919 | | /* static */ |
1920 | | bool |
1921 | | nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal) |
1922 | 0 | { |
1923 | 0 | nsCOMPtr<nsIOfflineCacheUpdateService> updateService = |
1924 | 0 | do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); |
1925 | 0 | if (!updateService) { |
1926 | 0 | return false; |
1927 | 0 | } |
1928 | 0 | |
1929 | 0 | bool allowed; |
1930 | 0 | nsresult rv = updateService->OfflineAppAllowed(aPrincipal, |
1931 | 0 | Preferences::GetRootBranch(), |
1932 | 0 | &allowed); |
1933 | 0 | return NS_SUCCEEDED(rv) && allowed; |
1934 | 0 | } |
1935 | | |
1936 | | bool |
1937 | | nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) |
1938 | 0 | { |
1939 | 0 | if (!Preferences::GetRootBranch()) |
1940 | 0 | return false; |
1941 | 0 | |
1942 | 0 | nsresult rv; |
1943 | 0 |
|
1944 | 0 | bool allowedByDefault; |
1945 | 0 | rv = Preferences::GetRootBranch()->GetBoolPref( |
1946 | 0 | "offline-apps.allow_by_default", &allowedByDefault); |
1947 | 0 | if (NS_FAILED(rv)) |
1948 | 0 | return false; |
1949 | 0 | |
1950 | 0 | if (!allowedByDefault) |
1951 | 0 | return false; |
1952 | 0 | |
1953 | 0 | nsCOMPtr<nsIOfflineCacheUpdateService> updateService = |
1954 | 0 | do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); |
1955 | 0 | if (!updateService) { |
1956 | 0 | return false; |
1957 | 0 | } |
1958 | 0 | |
1959 | 0 | rv = updateService->AllowOfflineApp(aPrincipal); |
1960 | 0 | return NS_SUCCEEDED(rv); |
1961 | 0 | } |
1962 | | |
1963 | | // static |
1964 | | void |
1965 | | nsContentUtils::Shutdown() |
1966 | 0 | { |
1967 | 0 | sInitialized = false; |
1968 | 0 |
|
1969 | 0 | nsHTMLTags::ReleaseTable(); |
1970 | 0 |
|
1971 | 0 | NS_IF_RELEASE(sContentPolicyService); |
1972 | 0 | sTriedToGetContentPolicy = false; |
1973 | 0 | uint32_t i; |
1974 | 0 | for (i = 0; i < PropertiesFile_COUNT; ++i) |
1975 | 0 | NS_IF_RELEASE(sStringBundles[i]); |
1976 | 0 |
|
1977 | 0 | NS_IF_RELEASE(sStringBundleService); |
1978 | 0 | NS_IF_RELEASE(sConsoleService); |
1979 | 0 | NS_IF_RELEASE(sXPConnect); |
1980 | 0 | NS_IF_RELEASE(sSecurityManager); |
1981 | 0 | NS_IF_RELEASE(sSystemPrincipal); |
1982 | 0 | NS_IF_RELEASE(sNullSubjectPrincipal); |
1983 | 0 | NS_IF_RELEASE(sIOService); |
1984 | 0 | NS_IF_RELEASE(sUUIDGenerator); |
1985 | 0 | sLineBreaker = nullptr; |
1986 | 0 | sWordBreaker = nullptr; |
1987 | 0 | sBidiKeyboard = nullptr; |
1988 | 0 |
|
1989 | 0 | delete sAtomEventTable; |
1990 | 0 | sAtomEventTable = nullptr; |
1991 | 0 | delete sStringEventTable; |
1992 | 0 | sStringEventTable = nullptr; |
1993 | 0 | delete sUserDefinedEvents; |
1994 | 0 | sUserDefinedEvents = nullptr; |
1995 | 0 |
|
1996 | 0 | if (sEventListenerManagersHash) { |
1997 | 0 | NS_ASSERTION(sEventListenerManagersHash->EntryCount() == 0, |
1998 | 0 | "Event listener manager hash not empty at shutdown!"); |
1999 | 0 |
|
2000 | 0 | // See comment above. |
2001 | 0 |
|
2002 | 0 | // However, we have to handle this table differently. If it still |
2003 | 0 | // has entries, we want to leak it too, so that we can keep it alive |
2004 | 0 | // in case any elements are destroyed. Because if they are, we need |
2005 | 0 | // their event listener managers to be destroyed too, or otherwise |
2006 | 0 | // it could leave dangling references in DOMClassInfo's preserved |
2007 | 0 | // wrapper table. |
2008 | 0 |
|
2009 | 0 | if (sEventListenerManagersHash->EntryCount() == 0) { |
2010 | 0 | delete sEventListenerManagersHash; |
2011 | 0 | sEventListenerManagersHash = nullptr; |
2012 | 0 | } |
2013 | 0 | } |
2014 | 0 |
|
2015 | 0 | NS_ASSERTION(!sBlockedScriptRunners || |
2016 | 0 | sBlockedScriptRunners->Length() == 0, |
2017 | 0 | "How'd this happen?"); |
2018 | 0 | delete sBlockedScriptRunners; |
2019 | 0 | sBlockedScriptRunners = nullptr; |
2020 | 0 |
|
2021 | 0 | delete sShiftText; |
2022 | 0 | sShiftText = nullptr; |
2023 | 0 | delete sControlText; |
2024 | 0 | sControlText = nullptr; |
2025 | 0 | delete sMetaText; |
2026 | 0 | sMetaText = nullptr; |
2027 | 0 | delete sOSText; |
2028 | 0 | sOSText = nullptr; |
2029 | 0 | delete sAltText; |
2030 | 0 | sAltText = nullptr; |
2031 | 0 | delete sModifierSeparator; |
2032 | 0 | sModifierSeparator = nullptr; |
2033 | 0 |
|
2034 | 0 | delete sJSBytecodeMimeType; |
2035 | 0 | sJSBytecodeMimeType = nullptr; |
2036 | 0 |
|
2037 | 0 | NS_IF_RELEASE(sSameOriginChecker); |
2038 | 0 |
|
2039 | 0 | if (sUserInteractionObserver) { |
2040 | 0 | sUserInteractionObserver->Shutdown(); |
2041 | 0 | NS_RELEASE(sUserInteractionObserver); |
2042 | 0 | } |
2043 | 0 |
|
2044 | 0 | HTMLInputElement::Shutdown(); |
2045 | 0 | nsMappedAttributes::Shutdown(); |
2046 | 0 | } |
2047 | | |
2048 | | /** |
2049 | | * Checks whether two nodes come from the same origin. aTrustedNode is |
2050 | | * considered 'safe' in that a user can operate on it. |
2051 | | */ |
2052 | | // static |
2053 | | nsresult |
2054 | | nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode, |
2055 | | const nsINode* unTrustedNode) |
2056 | 0 | { |
2057 | 0 | MOZ_ASSERT(aTrustedNode); |
2058 | 0 | MOZ_ASSERT(unTrustedNode); |
2059 | 0 |
|
2060 | 0 | /* |
2061 | 0 | * Get hold of each node's principal |
2062 | 0 | */ |
2063 | 0 |
|
2064 | 0 | nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal(); |
2065 | 0 | nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal(); |
2066 | 0 |
|
2067 | 0 | if (trustedPrincipal == unTrustedPrincipal) { |
2068 | 0 | return NS_OK; |
2069 | 0 | } |
2070 | 0 | |
2071 | 0 | bool equal; |
2072 | 0 | // XXXbz should we actually have a Subsumes() check here instead? Or perhaps |
2073 | 0 | // a separate method for that, with callers using one or the other? |
2074 | 0 | if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) || |
2075 | 0 | !equal) { |
2076 | 0 | return NS_ERROR_DOM_PROP_ACCESS_DENIED; |
2077 | 0 | } |
2078 | 0 | |
2079 | 0 | return NS_OK; |
2080 | 0 | } |
2081 | | |
2082 | | // static |
2083 | | bool |
2084 | | nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal, |
2085 | | nsIPrincipal* aPrincipal) |
2086 | 0 | { |
2087 | 0 | bool subsumes; |
2088 | 0 | nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes); |
2089 | 0 | NS_ENSURE_SUCCESS(rv, false); |
2090 | 0 |
|
2091 | 0 | if (subsumes) { |
2092 | 0 | return true; |
2093 | 0 | } |
2094 | 0 | |
2095 | 0 | // The subject doesn't subsume aPrincipal. Allow access only if the subject |
2096 | 0 | // is chrome. |
2097 | 0 | return IsCallerChrome(); |
2098 | 0 | } |
2099 | | |
2100 | | // static |
2101 | | bool |
2102 | | nsContentUtils::CanCallerAccess(nsINode* aNode) |
2103 | 0 | { |
2104 | 0 | return CanCallerAccess(SubjectPrincipal(), aNode->NodePrincipal()); |
2105 | 0 | } |
2106 | | |
2107 | | // static |
2108 | | bool |
2109 | | nsContentUtils::CanCallerAccess(nsPIDOMWindowInner* aWindow) |
2110 | 0 | { |
2111 | 0 | nsCOMPtr<nsIScriptObjectPrincipal> scriptObject = do_QueryInterface(aWindow); |
2112 | 0 | NS_ENSURE_TRUE(scriptObject, false); |
2113 | 0 |
|
2114 | 0 | return CanCallerAccess(SubjectPrincipal(), scriptObject->GetPrincipal()); |
2115 | 0 | } |
2116 | | |
2117 | | // static |
2118 | | bool |
2119 | | nsContentUtils::PrincipalHasPermission(nsIPrincipal* aPrincipal, const nsAtom* aPerm) |
2120 | 0 | { |
2121 | 0 | // Chrome gets access by default. |
2122 | 0 | if (IsSystemPrincipal(aPrincipal)) { |
2123 | 0 | return true; |
2124 | 0 | } |
2125 | 0 | |
2126 | 0 | // Otherwise, only allow if caller is an addon with the permission. |
2127 | 0 | return BasePrincipal::Cast(aPrincipal)->AddonHasPermission(aPerm); |
2128 | 0 | } |
2129 | | |
2130 | | // static |
2131 | | bool |
2132 | | nsContentUtils::CallerHasPermission(JSContext* aCx, const nsAtom* aPerm) |
2133 | 0 | { |
2134 | 0 | return PrincipalHasPermission(SubjectPrincipal(aCx), aPerm); |
2135 | 0 | } |
2136 | | |
2137 | | // static |
2138 | | nsIPrincipal* |
2139 | | nsContentUtils::GetAttrTriggeringPrincipal(nsIContent* aContent, const nsAString& aAttrValue, |
2140 | | nsIPrincipal* aSubjectPrincipal) |
2141 | 0 | { |
2142 | 0 | nsIPrincipal* contentPrin = aContent ? aContent->NodePrincipal() : nullptr; |
2143 | 0 |
|
2144 | 0 | // If the subject principal is the same as the content principal, or no |
2145 | 0 | // explicit subject principal was provided, we don't need to do any further |
2146 | 0 | // checks. Just return the content principal. |
2147 | 0 | if (contentPrin == aSubjectPrincipal || !aSubjectPrincipal) { |
2148 | 0 | return contentPrin; |
2149 | 0 | } |
2150 | 0 | |
2151 | 0 | // If the attribute value is empty, it's not an absolute URL, so don't bother |
2152 | 0 | // with more expensive checks. |
2153 | 0 | if (!aAttrValue.IsEmpty() && |
2154 | 0 | IsAbsoluteURL(NS_ConvertUTF16toUTF8(aAttrValue))) { |
2155 | 0 | return aSubjectPrincipal; |
2156 | 0 | } |
2157 | 0 | |
2158 | 0 | return contentPrin; |
2159 | 0 | } |
2160 | | |
2161 | | // static |
2162 | | bool |
2163 | | nsContentUtils::IsAbsoluteURL(const nsACString& aURL) |
2164 | 0 | { |
2165 | 0 | nsAutoCString scheme; |
2166 | 0 | if (NS_FAILED(net_ExtractURLScheme(aURL, scheme))) { |
2167 | 0 | // If we can't extract a scheme, it's not an absolute URL. |
2168 | 0 | return false; |
2169 | 0 | } |
2170 | 0 | |
2171 | 0 | // If it parses as an absolute StandardURL, it's definitely an absolute URL, |
2172 | 0 | // so no need to check with the IO service. |
2173 | 0 | if (net_IsAbsoluteURL(aURL)) { |
2174 | 0 | return true; |
2175 | 0 | } |
2176 | 0 | |
2177 | 0 | uint32_t flags; |
2178 | 0 | if (NS_SUCCEEDED(sIOService->GetProtocolFlags(scheme.get(), &flags))) { |
2179 | 0 | return flags & nsIProtocolHandler::URI_NORELATIVE; |
2180 | 0 | } |
2181 | 0 | |
2182 | 0 | return false; |
2183 | 0 | } |
2184 | | |
2185 | | //static |
2186 | | bool |
2187 | | nsContentUtils::InProlog(nsINode *aNode) |
2188 | 0 | { |
2189 | 0 | MOZ_ASSERT(aNode, "missing node to nsContentUtils::InProlog"); |
2190 | 0 |
|
2191 | 0 | nsINode* parent = aNode->GetParentNode(); |
2192 | 0 | if (!parent || !parent->IsDocument()) { |
2193 | 0 | return false; |
2194 | 0 | } |
2195 | 0 | |
2196 | 0 | nsIDocument* doc = parent->AsDocument(); |
2197 | 0 | nsIContent* root = doc->GetRootElement(); |
2198 | 0 |
|
2199 | 0 | return !root || doc->ComputeIndexOf(aNode) < doc->ComputeIndexOf(root); |
2200 | 0 | } |
2201 | | |
2202 | | bool |
2203 | | nsContentUtils::IsCallerChrome() |
2204 | 4.87M | { |
2205 | 4.87M | MOZ_ASSERT(NS_IsMainThread()); |
2206 | 4.87M | if (SubjectPrincipal() == sSystemPrincipal) { |
2207 | 4.87M | return true; |
2208 | 4.87M | } |
2209 | 0 | |
2210 | 0 | // If the check failed, look for UniversalXPConnect on the cx compartment. |
2211 | 0 | return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext()); |
2212 | 0 | } |
2213 | | |
2214 | | /* static */ |
2215 | | bool |
2216 | | nsContentUtils::ShouldResistFingerprinting() |
2217 | 0 | { |
2218 | 0 | return StaticPrefs::privacy_resistFingerprinting(); |
2219 | 0 | } |
2220 | | |
2221 | | bool |
2222 | | nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell) |
2223 | 0 | { |
2224 | 0 | if (!aDocShell) { |
2225 | 0 | return false; |
2226 | 0 | } |
2227 | 0 | return ShouldResistFingerprinting(aDocShell->GetDocument()); |
2228 | 0 | } |
2229 | | |
2230 | | /* static */ |
2231 | | bool |
2232 | 0 | nsContentUtils::ShouldResistFingerprinting(nsIDocument* aDoc) { |
2233 | 0 | if (!aDoc) { |
2234 | 0 | return false; |
2235 | 0 | } |
2236 | 0 | bool isChrome = nsContentUtils::IsChromeDoc(aDoc); |
2237 | 0 | return !isChrome && ShouldResistFingerprinting(); |
2238 | 0 | } |
2239 | | |
2240 | | /* static */ |
2241 | | void |
2242 | | nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(int32_t aChromeWidth, |
2243 | | int32_t aChromeHeight, |
2244 | | int32_t aScreenWidth, |
2245 | | int32_t aScreenHeight, |
2246 | | int32_t aInputWidth, |
2247 | | int32_t aInputHeight, |
2248 | | bool aSetOuterWidth, |
2249 | | bool aSetOuterHeight, |
2250 | | int32_t* aOutputWidth, |
2251 | | int32_t* aOutputHeight) |
2252 | 0 | { |
2253 | 0 | MOZ_ASSERT(aOutputWidth); |
2254 | 0 | MOZ_ASSERT(aOutputHeight); |
2255 | 0 |
|
2256 | 0 | int32_t availContentWidth = 0; |
2257 | 0 | int32_t availContentHeight = 0; |
2258 | 0 |
|
2259 | 0 | availContentWidth = std::min(sPrivacyMaxInnerWidth, |
2260 | 0 | aScreenWidth - aChromeWidth); |
2261 | 0 | #ifdef MOZ_WIDGET_GTK |
2262 | 0 | // In the GTK window, it will not report outside system decorations |
2263 | 0 | // when we get available window size, see Bug 581863. So, we leave a |
2264 | 0 | // 40 pixels space for them when calculating the available content |
2265 | 0 | // height. It is not necessary for the width since the content width |
2266 | 0 | // is usually pretty much the same as the chrome width. |
2267 | 0 | availContentHeight = std::min(sPrivacyMaxInnerHeight, |
2268 | 0 | (-40 + aScreenHeight) - aChromeHeight); |
2269 | | #else |
2270 | | availContentHeight = std::min(sPrivacyMaxInnerHeight, |
2271 | | aScreenHeight - aChromeHeight); |
2272 | | #endif |
2273 | |
|
2274 | 0 | // Ideally, we'd like to round window size to 1000x1000, but the |
2275 | 0 | // screen space could be too small to accommodate this size in some |
2276 | 0 | // cases. If it happens, we would round the window size to the nearest |
2277 | 0 | // 200x100. |
2278 | 0 | availContentWidth = availContentWidth - (availContentWidth % 200); |
2279 | 0 | availContentHeight = availContentHeight - (availContentHeight % 100); |
2280 | 0 |
|
2281 | 0 | // If aIsOuter is true, we are setting the outer window. So we |
2282 | 0 | // have to consider the chrome UI. |
2283 | 0 | int32_t chromeOffsetWidth = aSetOuterWidth ? aChromeWidth : 0; |
2284 | 0 | int32_t chromeOffsetHeight = aSetOuterHeight ? aChromeHeight : 0; |
2285 | 0 | int32_t resultWidth = 0, resultHeight = 0; |
2286 | 0 |
|
2287 | 0 | // if the original size is greater than the maximum available size, we set |
2288 | 0 | // it to the maximum size. And if the original value is less than the |
2289 | 0 | // minimum rounded size, we set it to the minimum 200x100. |
2290 | 0 | if (aInputWidth > (availContentWidth + chromeOffsetWidth)) { |
2291 | 0 | resultWidth = availContentWidth + chromeOffsetWidth; |
2292 | 0 | } else if (aInputWidth < (200 + chromeOffsetWidth)) { |
2293 | 0 | resultWidth = 200 + chromeOffsetWidth; |
2294 | 0 | } else { |
2295 | 0 | // Otherwise, we round the window to the nearest upper rounded 200x100. |
2296 | 0 | resultWidth = NSToIntCeil((aInputWidth - chromeOffsetWidth) / 200.0) * 200 + chromeOffsetWidth; |
2297 | 0 | } |
2298 | 0 |
|
2299 | 0 | if (aInputHeight > (availContentHeight + chromeOffsetHeight)) { |
2300 | 0 | resultHeight = availContentHeight + chromeOffsetHeight; |
2301 | 0 | } else if (aInputHeight < (100 + chromeOffsetHeight)) { |
2302 | 0 | resultHeight = 100 + chromeOffsetHeight; |
2303 | 0 | } else { |
2304 | 0 | resultHeight = NSToIntCeil((aInputHeight - chromeOffsetHeight) / 100.0) * 100 + chromeOffsetHeight; |
2305 | 0 | } |
2306 | 0 |
|
2307 | 0 | *aOutputWidth = resultWidth; |
2308 | 0 | *aOutputHeight = resultHeight; |
2309 | 0 | } |
2310 | | |
2311 | | bool |
2312 | | nsContentUtils::ThreadsafeIsCallerChrome() |
2313 | 0 | { |
2314 | 0 | return NS_IsMainThread() |
2315 | 0 | ? IsCallerChrome() |
2316 | 0 | : IsCurrentThreadRunningChromeWorker(); |
2317 | 0 | } |
2318 | | |
2319 | | bool |
2320 | | nsContentUtils::IsCallerContentXBL() |
2321 | 0 | { |
2322 | 0 | JSContext *cx = GetCurrentJSContext(); |
2323 | 0 | if (!cx) |
2324 | 0 | return false; |
2325 | 0 | |
2326 | 0 | JS::Realm* realm = JS::GetCurrentRealmOrNull(cx); |
2327 | 0 | if (!realm) |
2328 | 0 | return false; |
2329 | 0 | |
2330 | 0 | // For remote XUL, we run XBL in the XUL scope. Given that we care about |
2331 | 0 | // compat and not security for remote XUL, just always claim to be XBL. |
2332 | 0 | if (!xpc::AllowContentXBLScope(realm)) { |
2333 | 0 | MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetRealmPrincipal(realm))); |
2334 | 0 | return true; |
2335 | 0 | } |
2336 | 0 |
|
2337 | 0 | return xpc::IsContentXBLScope(realm); |
2338 | 0 | } |
2339 | | |
2340 | | bool |
2341 | | nsContentUtils::IsSystemCaller(JSContext* aCx) |
2342 | 3 | { |
2343 | 3 | // Note that SubjectPrincipal() assumes we are in a compartment here. |
2344 | 3 | return SubjectPrincipal(aCx) == sSystemPrincipal; |
2345 | 3 | } |
2346 | | |
2347 | | bool |
2348 | | nsContentUtils::ThreadsafeIsSystemCaller(JSContext* aCx) |
2349 | 3 | { |
2350 | 3 | CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get(); |
2351 | 3 | MOZ_ASSERT(ccjscx->Context() == aCx); |
2352 | 3 | |
2353 | 3 | return ccjscx->IsSystemCaller(); |
2354 | 3 | } |
2355 | | |
2356 | | // static |
2357 | | bool |
2358 | | nsContentUtils::LookupBindingMember(JSContext* aCx, nsIContent *aContent, |
2359 | | JS::Handle<jsid> aId, |
2360 | | JS::MutableHandle<JS::PropertyDescriptor> aDesc) |
2361 | 0 | { |
2362 | 0 | nsXBLBinding* binding = aContent->GetXBLBinding(); |
2363 | 0 | if (!binding) |
2364 | 0 | return true; |
2365 | 0 | return binding->LookupMember(aCx, aId, aDesc); |
2366 | 0 | } |
2367 | | |
2368 | | // static |
2369 | | nsINode* |
2370 | | nsContentUtils::GetCrossDocParentNode(nsINode* aChild) |
2371 | 0 | { |
2372 | 0 | MOZ_ASSERT(aChild, "The child is null!"); |
2373 | 0 |
|
2374 | 0 | nsINode* parent = aChild->GetParentNode(); |
2375 | 0 | if (parent && parent->IsContent() && aChild->IsContent()) { |
2376 | 0 | parent = aChild->AsContent()->GetFlattenedTreeParent(); |
2377 | 0 | } |
2378 | 0 |
|
2379 | 0 | if (parent || !aChild->IsDocument()) { |
2380 | 0 | return parent; |
2381 | 0 | } |
2382 | 0 | |
2383 | 0 | nsIDocument* doc = aChild->AsDocument(); |
2384 | 0 | nsIDocument* parentDoc = doc->GetParentDocument(); |
2385 | 0 | return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr; |
2386 | 0 | } |
2387 | | |
2388 | | // static |
2389 | | bool |
2390 | | nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant, |
2391 | | const nsINode* aPossibleAncestor) |
2392 | 0 | { |
2393 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2394 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2395 | 0 |
|
2396 | 0 | do { |
2397 | 0 | if (aPossibleDescendant == aPossibleAncestor) |
2398 | 0 | return true; |
2399 | 0 | aPossibleDescendant = aPossibleDescendant->GetParentNode(); |
2400 | 0 | } while (aPossibleDescendant); |
2401 | 0 |
|
2402 | 0 | return false; |
2403 | 0 | } |
2404 | | |
2405 | | bool |
2406 | | nsContentUtils::ContentIsHostIncludingDescendantOf( |
2407 | | const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) |
2408 | 0 | { |
2409 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2410 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2411 | 0 |
|
2412 | 0 | do { |
2413 | 0 | if (aPossibleDescendant == aPossibleAncestor) |
2414 | 0 | return true; |
2415 | 0 | if (aPossibleDescendant->IsDocumentFragment()) { |
2416 | 0 | aPossibleDescendant = |
2417 | 0 | aPossibleDescendant->AsDocumentFragment()->GetHost(); |
2418 | 0 | } else { |
2419 | 0 | aPossibleDescendant = aPossibleDescendant->GetParentNode(); |
2420 | 0 | } |
2421 | 0 | } while (aPossibleDescendant); |
2422 | 0 |
|
2423 | 0 | return false; |
2424 | 0 | } |
2425 | | |
2426 | | bool |
2427 | | nsContentUtils::ContentIsShadowIncludingDescendantOf( |
2428 | | const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) |
2429 | 0 | { |
2430 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2431 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2432 | 0 |
|
2433 | 0 | if (aPossibleAncestor == aPossibleDescendant->GetComposedDoc()) { |
2434 | 0 | return true; |
2435 | 0 | } |
2436 | 0 | |
2437 | 0 | do { |
2438 | 0 | if (aPossibleDescendant == aPossibleAncestor) { |
2439 | 0 | return true; |
2440 | 0 | } |
2441 | 0 | |
2442 | 0 | if (aPossibleDescendant->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) { |
2443 | 0 | ShadowRoot* shadowRoot = |
2444 | 0 | ShadowRoot::FromNode(const_cast<nsINode*>(aPossibleDescendant)); |
2445 | 0 | aPossibleDescendant = shadowRoot ? shadowRoot->GetHost() : nullptr; |
2446 | 0 | } else { |
2447 | 0 | aPossibleDescendant = aPossibleDescendant->GetParentNode(); |
2448 | 0 | } |
2449 | 0 | } while (aPossibleDescendant); |
2450 | 0 |
|
2451 | 0 | return false; |
2452 | 0 | } |
2453 | | |
2454 | | // static |
2455 | | bool |
2456 | | nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant, |
2457 | | nsINode* aPossibleAncestor) |
2458 | 0 | { |
2459 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2460 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2461 | 0 |
|
2462 | 0 | do { |
2463 | 0 | if (aPossibleDescendant == aPossibleAncestor) |
2464 | 0 | return true; |
2465 | 0 | |
2466 | 0 | aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant); |
2467 | 0 | } while (aPossibleDescendant); |
2468 | 0 |
|
2469 | 0 | return false; |
2470 | 0 | } |
2471 | | |
2472 | | // static |
2473 | | bool |
2474 | | nsContentUtils::ContentIsFlattenedTreeDescendantOf( |
2475 | | const nsINode* aPossibleDescendant, |
2476 | | const nsINode* aPossibleAncestor) |
2477 | 0 | { |
2478 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2479 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2480 | 0 |
|
2481 | 0 | do { |
2482 | 0 | if (aPossibleDescendant == aPossibleAncestor) { |
2483 | 0 | return true; |
2484 | 0 | } |
2485 | 0 | aPossibleDescendant = aPossibleDescendant->GetFlattenedTreeParentNode(); |
2486 | 0 | } while (aPossibleDescendant); |
2487 | 0 |
|
2488 | 0 | return false; |
2489 | 0 | } |
2490 | | |
2491 | | // static |
2492 | | bool |
2493 | | nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle( |
2494 | | const nsINode* aPossibleDescendant, |
2495 | | const nsINode* aPossibleAncestor) |
2496 | 0 | { |
2497 | 0 | MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!"); |
2498 | 0 | MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!"); |
2499 | 0 |
|
2500 | 0 | do { |
2501 | 0 | if (aPossibleDescendant == aPossibleAncestor) { |
2502 | 0 | return true; |
2503 | 0 | } |
2504 | 0 | aPossibleDescendant = |
2505 | 0 | aPossibleDescendant->GetFlattenedTreeParentNodeForStyle(); |
2506 | 0 | } while (aPossibleDescendant); |
2507 | 0 |
|
2508 | 0 | return false; |
2509 | 0 | } |
2510 | | |
2511 | | // static |
2512 | | nsINode* |
2513 | | nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB) |
2514 | 0 | { |
2515 | 0 | while (true && aTargetA) { |
2516 | 0 | // If A's root is not a shadow root... |
2517 | 0 | nsINode* root = aTargetA->SubtreeRoot(); |
2518 | 0 | if (!root->IsShadowRoot()) { |
2519 | 0 | // ...then return A. |
2520 | 0 | return aTargetA; |
2521 | 0 | } |
2522 | 0 | |
2523 | 0 | // or A's root is a shadow-including inclusive ancestor of B... |
2524 | 0 | if (nsContentUtils::ContentIsShadowIncludingDescendantOf(aTargetB, root)) { |
2525 | 0 | // ...then return A. |
2526 | 0 | return aTargetA; |
2527 | 0 | } |
2528 | 0 | |
2529 | 0 | aTargetA = ShadowRoot::FromNode(root)->GetHost(); |
2530 | 0 | } |
2531 | 0 |
|
2532 | 0 | return nullptr; |
2533 | 0 | } |
2534 | | |
2535 | | // static |
2536 | | nsresult |
2537 | | nsContentUtils::GetAncestors(nsINode* aNode, |
2538 | | nsTArray<nsINode*>& aArray) |
2539 | 0 | { |
2540 | 0 | while (aNode) { |
2541 | 0 | aArray.AppendElement(aNode); |
2542 | 0 | aNode = aNode->GetParentNode(); |
2543 | 0 | } |
2544 | 0 | return NS_OK; |
2545 | 0 | } |
2546 | | |
2547 | | // static |
2548 | | nsresult |
2549 | | nsContentUtils::GetAncestorsAndOffsets(nsINode* aNode, |
2550 | | int32_t aOffset, |
2551 | | nsTArray<nsIContent*>* aAncestorNodes, |
2552 | | nsTArray<int32_t>* aAncestorOffsets) |
2553 | 0 | { |
2554 | 0 | NS_ENSURE_ARG_POINTER(aNode); |
2555 | 0 |
|
2556 | 0 | if (!aNode->IsContent()) { |
2557 | 0 | return NS_ERROR_FAILURE; |
2558 | 0 | } |
2559 | 0 | nsIContent* content = aNode->AsContent(); |
2560 | 0 |
|
2561 | 0 | if (!aAncestorNodes->IsEmpty()) { |
2562 | 0 | NS_WARNING("aAncestorNodes is not empty"); |
2563 | 0 | aAncestorNodes->Clear(); |
2564 | 0 | } |
2565 | 0 |
|
2566 | 0 | if (!aAncestorOffsets->IsEmpty()) { |
2567 | 0 | NS_WARNING("aAncestorOffsets is not empty"); |
2568 | 0 | aAncestorOffsets->Clear(); |
2569 | 0 | } |
2570 | 0 |
|
2571 | 0 | // insert the node itself |
2572 | 0 | aAncestorNodes->AppendElement(content); |
2573 | 0 | aAncestorOffsets->AppendElement(aOffset); |
2574 | 0 |
|
2575 | 0 | // insert all the ancestors |
2576 | 0 | nsIContent* child = content; |
2577 | 0 | nsIContent* parent = child->GetParent(); |
2578 | 0 | while (parent) { |
2579 | 0 | aAncestorNodes->AppendElement(parent); |
2580 | 0 | aAncestorOffsets->AppendElement(parent->ComputeIndexOf(child)); |
2581 | 0 | child = parent; |
2582 | 0 | parent = parent->GetParent(); |
2583 | 0 | } |
2584 | 0 |
|
2585 | 0 | return NS_OK; |
2586 | 0 | } |
2587 | | |
2588 | | template <typename Node, typename GetParentFunc> |
2589 | | static Node* |
2590 | | GetCommonAncestorInternal(Node* aNode1, |
2591 | | Node* aNode2, |
2592 | | GetParentFunc aGetParentFunc) |
2593 | 0 | { |
2594 | 0 | MOZ_ASSERT(aNode1 != aNode2); |
2595 | 0 |
|
2596 | 0 | // Build the chain of parents |
2597 | 0 | AutoTArray<Node*, 30> parents1, parents2; |
2598 | 0 | do { |
2599 | 0 | parents1.AppendElement(aNode1); |
2600 | 0 | aNode1 = aGetParentFunc(aNode1); |
2601 | 0 | } while (aNode1); |
2602 | 0 | do { |
2603 | 0 | parents2.AppendElement(aNode2); |
2604 | 0 | aNode2 = aGetParentFunc(aNode2); |
2605 | 0 | } while (aNode2); |
2606 | 0 |
|
2607 | 0 | // Find where the parent chain differs |
2608 | 0 | uint32_t pos1 = parents1.Length(); |
2609 | 0 | uint32_t pos2 = parents2.Length(); |
2610 | 0 | Node* parent = nullptr; |
2611 | 0 | uint32_t len; |
2612 | 0 | for (len = std::min(pos1, pos2); len > 0; --len) { |
2613 | 0 | Node* child1 = parents1.ElementAt(--pos1); |
2614 | 0 | Node* child2 = parents2.ElementAt(--pos2); |
2615 | 0 | if (child1 != child2) { |
2616 | 0 | break; |
2617 | 0 | } |
2618 | 0 | parent = child1; |
2619 | 0 | } |
2620 | 0 |
|
2621 | 0 | return parent; |
2622 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:nsINode* GetCommonAncestorInternal<nsINode, nsContentUtils::GetCommonAncestorHelper(nsINode*, nsINode*)::$_0>(nsINode*, nsINode*, nsContentUtils::GetCommonAncestorHelper(nsINode*, nsINode*)::$_0) Unexecuted instantiation: nsContentUtils.cpp:nsIContent* GetCommonAncestorInternal<nsIContent, nsContentUtils::GetCommonFlattenedTreeAncestorHelper(nsIContent*, nsIContent*)::$_1>(nsIContent*, nsIContent*, nsContentUtils::GetCommonFlattenedTreeAncestorHelper(nsIContent*, nsIContent*)::$_1) Unexecuted instantiation: nsContentUtils.cpp:mozilla::dom::Element* GetCommonAncestorInternal<mozilla::dom::Element, nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(mozilla::dom::Element*, mozilla::dom::Element*)::$_2>(mozilla::dom::Element*, mozilla::dom::Element*, nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(mozilla::dom::Element*, mozilla::dom::Element*)::$_2) |
2623 | | |
2624 | | /* static */ |
2625 | | nsINode* |
2626 | | nsContentUtils::GetCommonAncestorHelper(nsINode* aNode1, nsINode* aNode2) |
2627 | 0 | { |
2628 | 0 | return GetCommonAncestorInternal(aNode1, aNode2, [](nsINode* aNode) { |
2629 | 0 | return aNode->GetParentNode(); |
2630 | 0 | }); |
2631 | 0 | } |
2632 | | |
2633 | | /* static */ |
2634 | | nsIContent* |
2635 | | nsContentUtils::GetCommonFlattenedTreeAncestorHelper(nsIContent* aContent1, |
2636 | | nsIContent* aContent2) |
2637 | 0 | { |
2638 | 0 | return GetCommonAncestorInternal(aContent1, aContent2, [](nsIContent* aContent) { |
2639 | 0 | return aContent->GetFlattenedTreeParent(); |
2640 | 0 | }); |
2641 | 0 | } |
2642 | | |
2643 | | /* static */ |
2644 | | Element* |
2645 | | nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(Element* aElement1, |
2646 | | Element* aElement2) |
2647 | 0 | { |
2648 | 0 | return GetCommonAncestorInternal(aElement1, aElement2, [](Element* aElement) { |
2649 | 0 | return aElement->GetFlattenedTreeParentElementForStyle(); |
2650 | 0 | }); |
2651 | 0 | } |
2652 | | |
2653 | | /* static */ |
2654 | | bool |
2655 | | nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2, |
2656 | | int32_t* aNode1Index, |
2657 | | int32_t* aNode2Index) |
2658 | 0 | { |
2659 | 0 | // Note, CompareDocumentPosition takes the latter params in different order. |
2660 | 0 | return (aNode2->CompareDocumentPosition(*aNode1, aNode2Index, aNode1Index) & |
2661 | 0 | (Node_Binding::DOCUMENT_POSITION_PRECEDING | |
2662 | 0 | Node_Binding::DOCUMENT_POSITION_DISCONNECTED)) == |
2663 | 0 | Node_Binding::DOCUMENT_POSITION_PRECEDING; |
2664 | 0 | } |
2665 | | |
2666 | | /* static */ |
2667 | | int32_t |
2668 | | nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1, |
2669 | | nsINode* aParent2, int32_t aOffset2, |
2670 | | bool* aDisconnected) |
2671 | 0 | { |
2672 | 0 | if (aParent1 == aParent2) { |
2673 | 0 | // XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result |
2674 | 0 | // of nsINode::ComputeIndexOf(), but this compares such invalid |
2675 | 0 | // offset with valid offset. |
2676 | 0 | return aOffset1 < aOffset2 ? -1 : |
2677 | 0 | aOffset1 > aOffset2 ? 1 : |
2678 | 0 | 0; |
2679 | 0 | } |
2680 | 0 |
|
2681 | 0 | AutoTArray<nsINode*, 32> parents1, parents2; |
2682 | 0 | nsINode* node1 = aParent1; |
2683 | 0 | nsINode* node2 = aParent2; |
2684 | 0 | do { |
2685 | 0 | parents1.AppendElement(node1); |
2686 | 0 | node1 = node1->GetParentNode(); |
2687 | 0 | } while (node1); |
2688 | 0 | do { |
2689 | 0 | parents2.AppendElement(node2); |
2690 | 0 | node2 = node2->GetParentNode(); |
2691 | 0 | } while (node2); |
2692 | 0 |
|
2693 | 0 | uint32_t pos1 = parents1.Length() - 1; |
2694 | 0 | uint32_t pos2 = parents2.Length() - 1; |
2695 | 0 |
|
2696 | 0 | bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2); |
2697 | 0 | if (aDisconnected) { |
2698 | 0 | *aDisconnected = disconnected; |
2699 | 0 | } |
2700 | 0 | if (disconnected) { |
2701 | 0 | NS_ASSERTION(aDisconnected, "unexpected disconnected nodes"); |
2702 | 0 | return 1; |
2703 | 0 | } |
2704 | 0 |
|
2705 | 0 | // Find where the parent chains differ |
2706 | 0 | nsINode* parent = parents1.ElementAt(pos1); |
2707 | 0 | uint32_t len; |
2708 | 0 | for (len = std::min(pos1, pos2); len > 0; --len) { |
2709 | 0 | nsINode* child1 = parents1.ElementAt(--pos1); |
2710 | 0 | nsINode* child2 = parents2.ElementAt(--pos2); |
2711 | 0 | if (child1 != child2) { |
2712 | 0 | return parent->ComputeIndexOf(child1) < parent->ComputeIndexOf(child2) ? -1 : 1; |
2713 | 0 | } |
2714 | 0 | parent = child1; |
2715 | 0 | } |
2716 | 0 |
|
2717 | 0 |
|
2718 | 0 | // The parent chains never differed, so one of the nodes is an ancestor of |
2719 | 0 | // the other |
2720 | 0 |
|
2721 | 0 | NS_ASSERTION(!pos1 || !pos2, |
2722 | 0 | "should have run out of parent chain for one of the nodes"); |
2723 | 0 |
|
2724 | 0 | if (!pos1) { |
2725 | 0 | nsINode* child2 = parents2.ElementAt(--pos2); |
2726 | 0 | // XXX aOffset1 may be -1 as mentioned above. So, why does this return |
2727 | 0 | // it's *before* of the valid DOM point? |
2728 | 0 | return aOffset1 <= parent->ComputeIndexOf(child2) ? -1 : 1; |
2729 | 0 | } |
2730 | 0 |
|
2731 | 0 | nsINode* child1 = parents1.ElementAt(--pos1); |
2732 | 0 | // XXX aOffset2 may be -1 as mentioned above. So, why does this return it's |
2733 | 0 | // *after* of the valid DOM point? |
2734 | 0 | return parent->ComputeIndexOf(child1) < aOffset2 ? -1 : 1; |
2735 | 0 | } |
2736 | | |
2737 | | /* static */ |
2738 | | int32_t |
2739 | | nsContentUtils::ComparePoints(const RawRangeBoundary& aFirst, |
2740 | | const RawRangeBoundary& aSecond, |
2741 | | bool* aDisconnected) |
2742 | 0 | { |
2743 | 0 | if (NS_WARN_IF(!aFirst.IsSet()) || NS_WARN_IF(!aSecond.IsSet())) { |
2744 | 0 | return -1; |
2745 | 0 | } |
2746 | 0 | return ComparePoints(aFirst.Container(), aFirst.Offset(), |
2747 | 0 | aSecond.Container(), aSecond.Offset(), |
2748 | 0 | aDisconnected); |
2749 | 0 | } |
2750 | | |
2751 | | inline bool |
2752 | | IsCharInSet(const char* aSet, |
2753 | | const char16_t aChar) |
2754 | 0 | { |
2755 | 0 | char16_t ch; |
2756 | 0 | while ((ch = *aSet)) { |
2757 | 0 | if (aChar == char16_t(ch)) { |
2758 | 0 | return true; |
2759 | 0 | } |
2760 | 0 | ++aSet; |
2761 | 0 | } |
2762 | 0 | return false; |
2763 | 0 | } |
2764 | | |
2765 | | /** |
2766 | | * This method strips leading/trailing chars, in given set, from string. |
2767 | | */ |
2768 | | |
2769 | | // static |
2770 | | const nsDependentSubstring |
2771 | | nsContentUtils::TrimCharsInSet(const char* aSet, |
2772 | | const nsAString& aValue) |
2773 | 0 | { |
2774 | 0 | nsAString::const_iterator valueCurrent, valueEnd; |
2775 | 0 |
|
2776 | 0 | aValue.BeginReading(valueCurrent); |
2777 | 0 | aValue.EndReading(valueEnd); |
2778 | 0 |
|
2779 | 0 | // Skip characters in the beginning |
2780 | 0 | while (valueCurrent != valueEnd) { |
2781 | 0 | if (!IsCharInSet(aSet, *valueCurrent)) { |
2782 | 0 | break; |
2783 | 0 | } |
2784 | 0 | ++valueCurrent; |
2785 | 0 | } |
2786 | 0 |
|
2787 | 0 | if (valueCurrent != valueEnd) { |
2788 | 0 | for (;;) { |
2789 | 0 | --valueEnd; |
2790 | 0 | if (!IsCharInSet(aSet, *valueEnd)) { |
2791 | 0 | break; |
2792 | 0 | } |
2793 | 0 | } |
2794 | 0 | ++valueEnd; // Step beyond the last character we want in the value. |
2795 | 0 | } |
2796 | 0 |
|
2797 | 0 | // valueEnd should point to the char after the last to copy |
2798 | 0 | return Substring(valueCurrent, valueEnd); |
2799 | 0 | } |
2800 | | |
2801 | | /** |
2802 | | * This method strips leading and trailing whitespace from a string. |
2803 | | */ |
2804 | | |
2805 | | // static |
2806 | | template<bool IsWhitespace(char16_t)> |
2807 | | const nsDependentSubstring |
2808 | | nsContentUtils::TrimWhitespace(const nsAString& aStr, bool aTrimTrailing) |
2809 | 0 | { |
2810 | 0 | nsAString::const_iterator start, end; |
2811 | 0 |
|
2812 | 0 | aStr.BeginReading(start); |
2813 | 0 | aStr.EndReading(end); |
2814 | 0 |
|
2815 | 0 | // Skip whitespace characters in the beginning |
2816 | 0 | while (start != end && IsWhitespace(*start)) { |
2817 | 0 | ++start; |
2818 | 0 | } |
2819 | 0 |
|
2820 | 0 | if (aTrimTrailing) { |
2821 | 0 | // Skip whitespace characters in the end. |
2822 | 0 | while (end != start) { |
2823 | 0 | --end; |
2824 | 0 |
|
2825 | 0 | if (!IsWhitespace(*end)) { |
2826 | 0 | // Step back to the last non-whitespace character. |
2827 | 0 | ++end; |
2828 | 0 |
|
2829 | 0 | break; |
2830 | 0 | } |
2831 | 0 | } |
2832 | 0 | } |
2833 | 0 |
|
2834 | 0 | // Return a substring for the string w/o leading and/or trailing |
2835 | 0 | // whitespace |
2836 | 0 |
|
2837 | 0 | return Substring(start, end); |
2838 | 0 | } Unexecuted instantiation: nsTDependentSubstring<char16_t> const nsContentUtils::TrimWhitespace<&nsCRT::IsAsciiSpace>(nsTSubstring<char16_t> const&, bool) Unexecuted instantiation: nsTDependentSubstring<char16_t> const nsContentUtils::TrimWhitespace<&nsContentUtils::IsHTMLWhitespace>(nsTSubstring<char16_t> const&, bool) Unexecuted instantiation: nsTDependentSubstring<char16_t> const nsContentUtils::TrimWhitespace<&nsContentUtils::IsHTMLWhitespaceOrNBSP>(nsTSubstring<char16_t> const&, bool) |
2839 | | |
2840 | | // Declaring the templates we are going to use avoid linking issues without |
2841 | | // inlining the method. Considering there is not so much spaces checking |
2842 | | // methods we can consider this to be better than inlining. |
2843 | | template |
2844 | | const nsDependentSubstring |
2845 | | nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool); |
2846 | | template |
2847 | | const nsDependentSubstring |
2848 | | nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool); |
2849 | | template |
2850 | | const nsDependentSubstring |
2851 | | nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool); |
2852 | | |
2853 | | static inline void KeyAppendSep(nsACString& aKey) |
2854 | 0 | { |
2855 | 0 | if (!aKey.IsEmpty()) { |
2856 | 0 | aKey.Append('>'); |
2857 | 0 | } |
2858 | 0 | } |
2859 | | |
2860 | | static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) |
2861 | 0 | { |
2862 | 0 | KeyAppendSep(aKey); |
2863 | 0 |
|
2864 | 0 | // Could escape separator here if collisions happen. > is not a legal char |
2865 | 0 | // for a name or type attribute, so we should be safe avoiding that extra work. |
2866 | 0 |
|
2867 | 0 | AppendUTF16toUTF8(aString, aKey); |
2868 | 0 | } |
2869 | | |
2870 | | static inline void KeyAppendString(const nsACString& aString, nsACString& aKey) |
2871 | 0 | { |
2872 | 0 | KeyAppendSep(aKey); |
2873 | 0 |
|
2874 | 0 | // Could escape separator here if collisions happen. > is not a legal char |
2875 | 0 | // for a name or type attribute, so we should be safe avoiding that extra work. |
2876 | 0 |
|
2877 | 0 | aKey.Append(aString); |
2878 | 0 | } |
2879 | | |
2880 | | static inline void KeyAppendInt(int32_t aInt, nsACString& aKey) |
2881 | 0 | { |
2882 | 0 | KeyAppendSep(aKey); |
2883 | 0 |
|
2884 | 0 | aKey.Append(nsPrintfCString("%d", aInt)); |
2885 | 0 | } |
2886 | | |
2887 | | static inline bool IsAutocompleteOff(const nsIContent* aContent) |
2888 | 0 | { |
2889 | 0 | return aContent->IsElement() && |
2890 | 0 | aContent->AsElement()->AttrValueIs(kNameSpaceID_None, |
2891 | 0 | nsGkAtoms::autocomplete, |
2892 | 0 | NS_LITERAL_STRING("off"), |
2893 | 0 | eIgnoreCase); |
2894 | 0 | } |
2895 | | |
2896 | | /*static*/ nsresult |
2897 | | nsContentUtils::GenerateStateKey(nsIContent* aContent, |
2898 | | nsIDocument* aDocument, |
2899 | | nsACString& aKey) |
2900 | 0 | { |
2901 | 0 | aKey.Truncate(); |
2902 | 0 |
|
2903 | 0 | uint32_t partID = aDocument ? aDocument->GetPartID() : 0; |
2904 | 0 |
|
2905 | 0 | // We must have content if we're not using a special state id |
2906 | 0 | NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE); |
2907 | 0 |
|
2908 | 0 | // Don't capture state for anonymous content |
2909 | 0 | if (aContent->IsInAnonymousSubtree()) { |
2910 | 0 | return NS_OK; |
2911 | 0 | } |
2912 | 0 | |
2913 | 0 | if (IsAutocompleteOff(aContent)) { |
2914 | 0 | return NS_OK; |
2915 | 0 | } |
2916 | 0 | |
2917 | 0 | nsCOMPtr<nsIHTMLDocument> htmlDocument = |
2918 | 0 | do_QueryInterface(aContent->GetUncomposedDoc()); |
2919 | 0 |
|
2920 | 0 | KeyAppendInt(partID, aKey); // first append a partID |
2921 | 0 | bool generatedUniqueKey = false; |
2922 | 0 |
|
2923 | 0 | if (htmlDocument) { |
2924 | 0 | nsHTMLDocument* htmlDoc = static_cast<nsHTMLDocument*> (htmlDocument.get()); |
2925 | 0 | RefPtr<nsContentList> htmlForms; |
2926 | 0 | RefPtr<nsContentList> htmlFormControls; |
2927 | 0 | htmlDoc->GetFormsAndFormControls(getter_AddRefs(htmlForms), |
2928 | 0 | getter_AddRefs(htmlFormControls)); |
2929 | 0 |
|
2930 | 0 | // If we have a form control and can calculate form information, use that |
2931 | 0 | // as the key - it is more reliable than just recording position in the |
2932 | 0 | // DOM. |
2933 | 0 | // XXXbz Is it, really? We have bugs on this, I think... |
2934 | 0 | // Important to have a unique key, and tag/type/name may not be. |
2935 | 0 | // |
2936 | 0 | // If the control has a form, the format of the key is: |
2937 | 0 | // f>type>IndOfFormInDoc>IndOfControlInForm>FormName>name |
2938 | 0 | // else: |
2939 | 0 | // d>type>IndOfControlInDoc>name |
2940 | 0 | // |
2941 | 0 | // XXX We don't need to use index if name is there |
2942 | 0 | // XXXbz We don't? Why not? I don't follow. |
2943 | 0 | // |
2944 | 0 | nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent)); |
2945 | 0 | if (control) { |
2946 | 0 |
|
2947 | 0 | // Append the control type |
2948 | 0 | KeyAppendInt(control->ControlType(), aKey); |
2949 | 0 |
|
2950 | 0 | // If in a form, add form name / index of form / index in form |
2951 | 0 | Element *formElement = control->GetFormElement(); |
2952 | 0 | if (formElement) { |
2953 | 0 | if (IsAutocompleteOff(formElement)) { |
2954 | 0 | aKey.Truncate(); |
2955 | 0 | return NS_OK; |
2956 | 0 | } |
2957 | 0 | |
2958 | 0 | KeyAppendString(NS_LITERAL_CSTRING("f"), aKey); |
2959 | 0 |
|
2960 | 0 | // Append the index of the form in the document |
2961 | 0 | int32_t index = htmlForms->IndexOf(formElement, false); |
2962 | 0 | if (index <= -1) { |
2963 | 0 | // |
2964 | 0 | // XXX HACK this uses some state that was dumped into the document |
2965 | 0 | // specifically to fix bug 138892. What we are trying to do is *guess* |
2966 | 0 | // which form this control's state is found in, with the highly likely |
2967 | 0 | // guess that the highest form parsed so far is the one. |
2968 | 0 | // This code should not be on trunk, only branch. |
2969 | 0 | // |
2970 | 0 | index = htmlDocument->GetNumFormsSynchronous() - 1; |
2971 | 0 | } |
2972 | 0 | if (index > -1) { |
2973 | 0 | KeyAppendInt(index, aKey); |
2974 | 0 |
|
2975 | 0 | // Append the index of the control in the form |
2976 | 0 | nsCOMPtr<nsIForm> form(do_QueryInterface(formElement)); |
2977 | 0 | index = form->IndexOfControl(control); |
2978 | 0 |
|
2979 | 0 | if (index > -1) { |
2980 | 0 | KeyAppendInt(index, aKey); |
2981 | 0 | generatedUniqueKey = true; |
2982 | 0 | } |
2983 | 0 | } |
2984 | 0 |
|
2985 | 0 | // Append the form name |
2986 | 0 | nsAutoString formName; |
2987 | 0 | formElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, formName); |
2988 | 0 | KeyAppendString(formName, aKey); |
2989 | 0 |
|
2990 | 0 | } else { |
2991 | 0 |
|
2992 | 0 | KeyAppendString(NS_LITERAL_CSTRING("d"), aKey); |
2993 | 0 |
|
2994 | 0 | // If not in a form, add index of control in document |
2995 | 0 | // Less desirable than indexing by form info. |
2996 | 0 |
|
2997 | 0 | // Hash by index of control in doc (we are not in a form) |
2998 | 0 | // These are important as they are unique, and type/name may not be. |
2999 | 0 |
|
3000 | 0 | // We have to flush sink notifications at this point to make |
3001 | 0 | // sure that htmlFormControls is up to date. |
3002 | 0 | int32_t index = htmlFormControls->IndexOf(aContent, true); |
3003 | 0 | if (index > -1) { |
3004 | 0 | KeyAppendInt(index, aKey); |
3005 | 0 | generatedUniqueKey = true; |
3006 | 0 | } |
3007 | 0 | } |
3008 | 0 |
|
3009 | 0 | // Append the control name |
3010 | 0 | nsAutoString name; |
3011 | 0 | aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); |
3012 | 0 | KeyAppendString(name, aKey); |
3013 | 0 | } |
3014 | 0 | } |
3015 | 0 |
|
3016 | 0 | if (!generatedUniqueKey) { |
3017 | 0 | // Either we didn't have a form control or we aren't in an HTML document so |
3018 | 0 | // we can't figure out form info. Append the tag name if it's an element |
3019 | 0 | // to avoid restoring state for one type of element on another type. |
3020 | 0 | if (aContent->IsElement()) { |
3021 | 0 | KeyAppendString(nsDependentAtomString(aContent->NodeInfo()->NameAtom()), |
3022 | 0 | aKey); |
3023 | 0 | } |
3024 | 0 | else { |
3025 | 0 | // Append a character that is not "d" or "f" to disambiguate from |
3026 | 0 | // the case when we were a form control in an HTML document. |
3027 | 0 | KeyAppendString(NS_LITERAL_CSTRING("o"), aKey); |
3028 | 0 | } |
3029 | 0 |
|
3030 | 0 | // Now start at aContent and append the indices of it and all its ancestors |
3031 | 0 | // in their containers. That should at least pin down its position in the |
3032 | 0 | // DOM... |
3033 | 0 | nsINode* parent = aContent->GetParentNode(); |
3034 | 0 | nsINode* content = aContent; |
3035 | 0 | while (parent) { |
3036 | 0 | KeyAppendInt(parent->ComputeIndexOf(content), aKey); |
3037 | 0 | content = parent; |
3038 | 0 | parent = content->GetParentNode(); |
3039 | 0 | } |
3040 | 0 | } |
3041 | 0 |
|
3042 | 0 | return NS_OK; |
3043 | 0 | } |
3044 | | |
3045 | | // static |
3046 | | nsIPrincipal* |
3047 | | nsContentUtils::SubjectPrincipal(JSContext* aCx) |
3048 | 4.87M | { |
3049 | 4.87M | MOZ_ASSERT(NS_IsMainThread()); |
3050 | 4.87M | |
3051 | 4.87M | // As opposed to SubjectPrincipal(), we do in fact assume that |
3052 | 4.87M | // we're in a realm here; anyone who calls this function in |
3053 | 4.87M | // situations where that's not the case is doing it wrong. |
3054 | 4.87M | JS::Realm* realm = js::GetContextRealm(aCx); |
3055 | 4.87M | MOZ_ASSERT(realm); |
3056 | 4.87M | |
3057 | 4.87M | JSPrincipals* principals = JS::GetRealmPrincipals(realm); |
3058 | 4.87M | return nsJSPrincipals::get(principals); |
3059 | 4.87M | } |
3060 | | |
3061 | | // static |
3062 | | nsIPrincipal* |
3063 | | nsContentUtils::SubjectPrincipal() |
3064 | 4.87M | { |
3065 | 4.87M | MOZ_ASSERT(IsInitialized()); |
3066 | 4.87M | MOZ_ASSERT(NS_IsMainThread()); |
3067 | 4.87M | JSContext* cx = GetCurrentJSContext(); |
3068 | 4.87M | if (!cx) { |
3069 | 0 | MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden"); |
3070 | 0 | } |
3071 | 4.87M | |
3072 | 4.87M | JS::Realm* realm = js::GetContextRealm(cx); |
3073 | 4.87M | |
3074 | 4.87M | // When an AutoJSAPI is instantiated, we are in a null realm until the |
3075 | 4.87M | // first JSAutoRealm, which is kind of a purgatory as far as permissions |
3076 | 4.87M | // go. It would be nice to just hard-abort if somebody does a security check |
3077 | 4.87M | // in this purgatory zone, but that would be too fragile, since it could be |
3078 | 4.87M | // triggered by random IsCallerChrome() checks 20-levels deep. |
3079 | 4.87M | // |
3080 | 4.87M | // So we want to return _something_ here - and definitely not the System |
3081 | 4.87M | // Principal, since that would make an AutoJSAPI a very dangerous thing to |
3082 | 4.87M | // instantiate. |
3083 | 4.87M | // |
3084 | 4.87M | // The natural thing to return is a null principal. Ideally, we'd return a |
3085 | 4.87M | // different null principal each time, to avoid any unexpected interactions |
3086 | 4.87M | // when the principal accidentally gets inherited somewhere. But |
3087 | 4.87M | // SubjectPrincipal doesn't return strong references, so there's no way to |
3088 | 4.87M | // sanely manage the lifetime of multiple null principals. |
3089 | 4.87M | // |
3090 | 4.87M | // So we use a singleton null principal. To avoid it being accidentally |
3091 | 4.87M | // inherited and becoming a "real" subject or object principal, we do a |
3092 | 4.87M | // release-mode assert during realm creation against using this principal on |
3093 | 4.87M | // an actual global. |
3094 | 4.87M | if (!realm) { |
3095 | 0 | return sNullSubjectPrincipal; |
3096 | 0 | } |
3097 | 4.87M | |
3098 | 4.87M | return SubjectPrincipal(cx); |
3099 | 4.87M | } |
3100 | | |
3101 | | // static |
3102 | | nsIPrincipal* |
3103 | | nsContentUtils::ObjectPrincipal(JSObject* aObj) |
3104 | 0 | { |
3105 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3106 | 0 |
|
3107 | | #ifdef DEBUG |
3108 | | JS::AssertObjectBelongsToCurrentThread(aObj); |
3109 | | #endif |
3110 | |
|
3111 | 0 | MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(aObj)); |
3112 | 0 |
|
3113 | 0 | JS::Realm* realm = js::GetNonCCWObjectRealm(aObj); |
3114 | 0 | JSPrincipals* principals = JS::GetRealmPrincipals(realm); |
3115 | 0 | return nsJSPrincipals::get(principals); |
3116 | 0 | } |
3117 | | |
3118 | | // static |
3119 | | nsresult |
3120 | | nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult, |
3121 | | const nsAString& aSpec, |
3122 | | nsIDocument* aDocument, |
3123 | | nsIURI* aBaseURI) |
3124 | 0 | { |
3125 | 0 | if (aDocument) { |
3126 | 0 | return NS_NewURI(aResult, aSpec, |
3127 | 0 | aDocument->GetDocumentCharacterSet(), |
3128 | 0 | aBaseURI, sIOService); |
3129 | 0 | } |
3130 | 0 | return NS_NewURI(aResult, aSpec, nullptr, aBaseURI, sIOService); |
3131 | 0 | } |
3132 | | |
3133 | | // static |
3134 | | bool |
3135 | | nsContentUtils::IsNameWithDash(nsAtom* aName) |
3136 | 0 | { |
3137 | 0 | // A valid custom element name is a sequence of characters name which |
3138 | 0 | // must match the PotentialCustomElementName production: |
3139 | 0 | // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)* |
3140 | 0 | const char16_t* name = aName->GetUTF16String(); |
3141 | 0 | uint32_t len = aName->GetLength(); |
3142 | 0 | bool hasDash = false; |
3143 | 0 |
|
3144 | 0 | if (!len || name[0] < 'a' || name[0] > 'z') { |
3145 | 0 | return false; |
3146 | 0 | } |
3147 | 0 | |
3148 | 0 | uint32_t i = 1; |
3149 | 0 | while (i < len) { |
3150 | 0 | if (NS_IS_HIGH_SURROGATE(name[i]) && i + 1 < len && |
3151 | 0 | NS_IS_LOW_SURROGATE(name[i + 1])) { |
3152 | 0 | // Merged two 16-bit surrogate pairs into code point. |
3153 | 0 | char32_t code = SURROGATE_TO_UCS4(name[i], name[i + 1]); |
3154 | 0 |
|
3155 | 0 | if (code < 0x10000 || code > 0xEFFFF) { |
3156 | 0 | return false; |
3157 | 0 | } |
3158 | 0 | |
3159 | 0 | i += 2; |
3160 | 0 | } else { |
3161 | 0 | if (name[i] == '-') { |
3162 | 0 | hasDash = true; |
3163 | 0 | } |
3164 | 0 |
|
3165 | 0 | if (name[i] != '-' && name[i] != '.' && |
3166 | 0 | name[i] != '_' && name[i] != 0xB7 && |
3167 | 0 | (name[i] < '0' || name[i] > '9') && |
3168 | 0 | (name[i] < 'a' || name[i] > 'z') && |
3169 | 0 | (name[i] < 0xC0 || name[i] > 0xD6) && |
3170 | 0 | (name[i] < 0xF8 || name[i] > 0x37D) && |
3171 | 0 | (name[i] < 0x37F || name[i] > 0x1FFF) && |
3172 | 0 | (name[i] < 0x200C || name[i] > 0x200D) && |
3173 | 0 | (name[i] < 0x203F || name[i] > 0x2040) && |
3174 | 0 | (name[i] < 0x2070 || name[i] > 0x218F) && |
3175 | 0 | (name[i] < 0x2C00 || name[i] > 0x2FEF) && |
3176 | 0 | (name[i] < 0x3001 || name[i] > 0xD7FF) && |
3177 | 0 | (name[i] < 0xF900 || name[i] > 0xFDCF) && |
3178 | 0 | (name[i] < 0xFDF0 || name[i] > 0xFFFD)) { |
3179 | 0 | return false; |
3180 | 0 | } |
3181 | 0 | |
3182 | 0 | i++; |
3183 | 0 | } |
3184 | 0 | } |
3185 | 0 |
|
3186 | 0 | return hasDash; |
3187 | 0 | } |
3188 | | |
3189 | | // static |
3190 | | bool |
3191 | | nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID) |
3192 | 0 | { |
3193 | 0 | // Allow non-dashed names in XUL for XBL to Custom Element migrations. |
3194 | 0 | if (aNameSpaceID == kNameSpaceID_XUL) { |
3195 | 0 | return true; |
3196 | 0 | } |
3197 | 0 | |
3198 | 0 | bool hasDash = IsNameWithDash(aName); |
3199 | 0 | if (!hasDash) { |
3200 | 0 | return false; |
3201 | 0 | } |
3202 | 0 | |
3203 | 0 | // The custom element name must not be one of the following values: |
3204 | 0 | // annotation-xml |
3205 | 0 | // color-profile |
3206 | 0 | // font-face |
3207 | 0 | // font-face-src |
3208 | 0 | // font-face-uri |
3209 | 0 | // font-face-format |
3210 | 0 | // font-face-name |
3211 | 0 | // missing-glyph |
3212 | 0 | return aName != nsGkAtoms::annotation_xml_ && |
3213 | 0 | aName != nsGkAtoms::colorProfile && |
3214 | 0 | aName != nsGkAtoms::font_face && |
3215 | 0 | aName != nsGkAtoms::font_face_src && |
3216 | 0 | aName != nsGkAtoms::font_face_uri && |
3217 | 0 | aName != nsGkAtoms::font_face_format && |
3218 | 0 | aName != nsGkAtoms::font_face_name && |
3219 | 0 | aName != nsGkAtoms::missingGlyph; |
3220 | 0 | } |
3221 | | |
3222 | | // static |
3223 | | nsresult |
3224 | | nsContentUtils::CheckQName(const nsAString& aQualifiedName, |
3225 | | bool aNamespaceAware, |
3226 | | const char16_t** aColon) |
3227 | 0 | { |
3228 | 0 | const char* colon = nullptr; |
3229 | 0 | const char16_t* begin = aQualifiedName.BeginReading(); |
3230 | 0 | const char16_t* end = aQualifiedName.EndReading(); |
3231 | 0 |
|
3232 | 0 | int result = MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin), |
3233 | 0 | reinterpret_cast<const char*>(end), |
3234 | 0 | aNamespaceAware, &colon); |
3235 | 0 |
|
3236 | 0 | if (!result) { |
3237 | 0 | if (aColon) { |
3238 | 0 | *aColon = reinterpret_cast<const char16_t*>(colon); |
3239 | 0 | } |
3240 | 0 |
|
3241 | 0 | return NS_OK; |
3242 | 0 | } |
3243 | 0 |
|
3244 | 0 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; |
3245 | 0 | } |
3246 | | |
3247 | | //static |
3248 | | nsresult |
3249 | | nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, |
3250 | | const nsString& aQName, |
3251 | | int32_t *aNamespace, nsAtom **aLocalName) |
3252 | 0 | { |
3253 | 0 | const char16_t* colon; |
3254 | 0 | nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon); |
3255 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3256 | 0 |
|
3257 | 0 | if (colon) { |
3258 | 0 | const char16_t* end; |
3259 | 0 | aQName.EndReading(end); |
3260 | 0 | nsAutoString nameSpace; |
3261 | 0 | rv = aNamespaceResolver->LookupNamespaceURIInternal(Substring(aQName.get(), |
3262 | 0 | colon), |
3263 | 0 | nameSpace); |
3264 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3265 | 0 |
|
3266 | 0 | *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace, |
3267 | 0 | nsContentUtils::IsChromeDoc(aNamespaceResolver->OwnerDoc())); |
3268 | 0 | if (*aNamespace == kNameSpaceID_Unknown) |
3269 | 0 | return NS_ERROR_FAILURE; |
3270 | 0 | |
3271 | 0 | *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take(); |
3272 | 0 | } |
3273 | 0 | else { |
3274 | 0 | *aNamespace = kNameSpaceID_None; |
3275 | 0 | *aLocalName = NS_AtomizeMainThread(aQName).take(); |
3276 | 0 | } |
3277 | 0 | NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY); |
3278 | 0 | return NS_OK; |
3279 | 0 | } |
3280 | | |
3281 | | // static |
3282 | | nsresult |
3283 | | nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI, |
3284 | | const nsAString& aQualifiedName, |
3285 | | nsNodeInfoManager* aNodeInfoManager, |
3286 | | uint16_t aNodeType, |
3287 | | mozilla::dom::NodeInfo** aNodeInfo) |
3288 | 0 | { |
3289 | 0 | const nsString& qName = PromiseFlatString(aQualifiedName); |
3290 | 0 | const char16_t* colon; |
3291 | 0 | nsresult rv = nsContentUtils::CheckQName(qName, true, &colon); |
3292 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3293 | 0 |
|
3294 | 0 | int32_t nsID; |
3295 | 0 | sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID); |
3296 | 0 | if (colon) { |
3297 | 0 | const char16_t* end; |
3298 | 0 | qName.EndReading(end); |
3299 | 0 |
|
3300 | 0 | RefPtr<nsAtom> prefix = |
3301 | 0 | NS_AtomizeMainThread(Substring(qName.get(), colon)); |
3302 | 0 |
|
3303 | 0 | rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, |
3304 | 0 | nsID, aNodeType, aNodeInfo); |
3305 | 0 | } |
3306 | 0 | else { |
3307 | 0 | rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nullptr, nsID, |
3308 | 0 | aNodeType, aNodeInfo); |
3309 | 0 | } |
3310 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3311 | 0 |
|
3312 | 0 | return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(), |
3313 | 0 | (*aNodeInfo)->GetPrefixAtom(), |
3314 | 0 | (*aNodeInfo)->NamespaceID()) ? |
3315 | 0 | NS_OK : NS_ERROR_DOM_NAMESPACE_ERR; |
3316 | 0 | } |
3317 | | |
3318 | | // static |
3319 | | void |
3320 | | nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsAtom **aPrefix, |
3321 | | nsAtom **aLocalName, int32_t* aNameSpaceID) |
3322 | 0 | { |
3323 | 0 | /** |
3324 | 0 | * Expat can send the following: |
3325 | 0 | * localName |
3326 | 0 | * namespaceURI<separator>localName |
3327 | 0 | * namespaceURI<separator>localName<separator>prefix |
3328 | 0 | * |
3329 | 0 | * and we use 0xFFFF for the <separator>. |
3330 | 0 | * |
3331 | 0 | */ |
3332 | 0 |
|
3333 | 0 | const char16_t *uriEnd = nullptr; |
3334 | 0 | const char16_t *nameEnd = nullptr; |
3335 | 0 | const char16_t *pos; |
3336 | 0 | for (pos = aExpatName; *pos; ++pos) { |
3337 | 0 | if (*pos == 0xFFFF) { |
3338 | 0 | if (uriEnd) { |
3339 | 0 | nameEnd = pos; |
3340 | 0 | } |
3341 | 0 | else { |
3342 | 0 | uriEnd = pos; |
3343 | 0 | } |
3344 | 0 | } |
3345 | 0 | } |
3346 | 0 |
|
3347 | 0 | const char16_t *nameStart; |
3348 | 0 | if (uriEnd) { |
3349 | 0 | if (sNameSpaceManager) { |
3350 | 0 | sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName, |
3351 | 0 | uriEnd), |
3352 | 0 | *aNameSpaceID); |
3353 | 0 | } |
3354 | 0 | else { |
3355 | 0 | *aNameSpaceID = kNameSpaceID_Unknown; |
3356 | 0 | } |
3357 | 0 |
|
3358 | 0 | nameStart = (uriEnd + 1); |
3359 | 0 | if (nameEnd) { |
3360 | 0 | const char16_t *prefixStart = nameEnd + 1; |
3361 | 0 | *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take(); |
3362 | 0 | } |
3363 | 0 | else { |
3364 | 0 | nameEnd = pos; |
3365 | 0 | *aPrefix = nullptr; |
3366 | 0 | } |
3367 | 0 | } |
3368 | 0 | else { |
3369 | 0 | *aNameSpaceID = kNameSpaceID_None; |
3370 | 0 | nameStart = aExpatName; |
3371 | 0 | nameEnd = pos; |
3372 | 0 | *aPrefix = nullptr; |
3373 | 0 | } |
3374 | 0 | *aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take(); |
3375 | 0 | } |
3376 | | |
3377 | | // static |
3378 | | nsIPresShell* |
3379 | | nsContentUtils::GetPresShellForContent(const nsIContent* aContent) |
3380 | 0 | { |
3381 | 0 | nsIDocument* doc = aContent->GetComposedDoc(); |
3382 | 0 | if (!doc) { |
3383 | 0 | return nullptr; |
3384 | 0 | } |
3385 | 0 | |
3386 | 0 | return doc->GetShell(); |
3387 | 0 | } |
3388 | | |
3389 | | // static |
3390 | | nsPresContext* |
3391 | | nsContentUtils::GetContextForContent(const nsIContent* aContent) |
3392 | 0 | { |
3393 | 0 | nsIPresShell* presShell = GetPresShellForContent(aContent); |
3394 | 0 |
|
3395 | 0 | if (!presShell) { |
3396 | 0 | return nullptr; |
3397 | 0 | } |
3398 | 0 | |
3399 | 0 | return presShell->GetPresContext(); |
3400 | 0 | } |
3401 | | |
3402 | | // static |
3403 | | bool |
3404 | | nsContentUtils::CanLoadImage(nsIURI* aURI, nsINode* aNode, |
3405 | | nsIDocument* aLoadingDocument, |
3406 | | nsIPrincipal* aLoadingPrincipal) |
3407 | 0 | { |
3408 | 0 | MOZ_ASSERT(aURI, "Must have a URI"); |
3409 | 0 | MOZ_ASSERT(aLoadingDocument, "Must have a document"); |
3410 | 0 | MOZ_ASSERT(aLoadingPrincipal, "Must have a loading principal"); |
3411 | 0 |
|
3412 | 0 | nsresult rv; |
3413 | 0 |
|
3414 | 0 | uint32_t appType = nsIDocShell::APP_TYPE_UNKNOWN; |
3415 | 0 |
|
3416 | 0 | { |
3417 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aLoadingDocument->GetDocShell(); |
3418 | 0 | if (docShellTreeItem) { |
3419 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
3420 | 0 | docShellTreeItem->GetRootTreeItem(getter_AddRefs(root)); |
3421 | 0 |
|
3422 | 0 | nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root)); |
3423 | 0 |
|
3424 | 0 | if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) { |
3425 | 0 | appType = nsIDocShell::APP_TYPE_UNKNOWN; |
3426 | 0 | } |
3427 | 0 | } |
3428 | 0 | } |
3429 | 0 |
|
3430 | 0 | if (appType != nsIDocShell::APP_TYPE_EDITOR) { |
3431 | 0 | // Editor apps get special treatment here, editors can load images |
3432 | 0 | // from anywhere. This allows editor to insert images from file:// |
3433 | 0 | // into documents that are being edited. |
3434 | 0 | rv = sSecurityManager-> |
3435 | 0 | CheckLoadURIWithPrincipal(aLoadingPrincipal, aURI, |
3436 | 0 | nsIScriptSecurityManager::ALLOW_CHROME); |
3437 | 0 | if (NS_FAILED(rv)) { |
3438 | 0 | return false; |
3439 | 0 | } |
3440 | 0 | } |
3441 | 0 | |
3442 | 0 | nsCOMPtr<nsILoadInfo> secCheckLoadInfo = |
3443 | 0 | new mozilla::net::LoadInfo(aLoadingPrincipal, |
3444 | 0 | aLoadingPrincipal, // triggering principal |
3445 | 0 | aNode, |
3446 | 0 | nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, |
3447 | 0 | nsIContentPolicy::TYPE_INTERNAL_IMAGE); |
3448 | 0 |
|
3449 | 0 | int16_t decision = nsIContentPolicy::ACCEPT; |
3450 | 0 |
|
3451 | 0 | rv = NS_CheckContentLoadPolicy(aURI, secCheckLoadInfo, |
3452 | 0 | EmptyCString(), //mime guess |
3453 | 0 | &decision, |
3454 | 0 | GetContentPolicy()); |
3455 | 0 |
|
3456 | 0 | return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision); |
3457 | 0 | } |
3458 | | |
3459 | | // static |
3460 | | mozilla::OriginAttributes |
3461 | | nsContentUtils::GetOriginAttributes(nsIDocument* aDocument) |
3462 | 0 | { |
3463 | 0 | if (!aDocument) { |
3464 | 0 | return mozilla::OriginAttributes(); |
3465 | 0 | } |
3466 | 0 | |
3467 | 0 | nsCOMPtr<nsILoadGroup> loadGroup = aDocument->GetDocumentLoadGroup(); |
3468 | 0 | if (loadGroup) { |
3469 | 0 | return GetOriginAttributes(loadGroup); |
3470 | 0 | } |
3471 | 0 | |
3472 | 0 | mozilla::OriginAttributes attrs; |
3473 | 0 | nsCOMPtr<nsIChannel> channel = aDocument->GetChannel(); |
3474 | 0 | if (channel) { |
3475 | 0 | NS_GetOriginAttributes(channel, attrs); |
3476 | 0 | } |
3477 | 0 | return attrs; |
3478 | 0 | } |
3479 | | |
3480 | | // static |
3481 | | mozilla::OriginAttributes |
3482 | | nsContentUtils::GetOriginAttributes(nsILoadGroup* aLoadGroup) |
3483 | 0 | { |
3484 | 0 | if (!aLoadGroup) { |
3485 | 0 | return mozilla::OriginAttributes(); |
3486 | 0 | } |
3487 | 0 | mozilla::OriginAttributes attrs; |
3488 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
3489 | 0 | aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
3490 | 0 | if (callbacks) { |
3491 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); |
3492 | 0 | if (loadContext) { |
3493 | 0 | loadContext->GetOriginAttributes(attrs); |
3494 | 0 | } |
3495 | 0 | } |
3496 | 0 | return attrs; |
3497 | 0 | } |
3498 | | |
3499 | | // static |
3500 | | bool |
3501 | | nsContentUtils::IsInPrivateBrowsing(nsIDocument* aDoc) |
3502 | 0 | { |
3503 | 0 | if (!aDoc) { |
3504 | 0 | return false; |
3505 | 0 | } |
3506 | 0 | |
3507 | 0 | nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup(); |
3508 | 0 | if (loadGroup) { |
3509 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
3510 | 0 | loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
3511 | 0 | if (callbacks) { |
3512 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); |
3513 | 0 | if (loadContext) { |
3514 | 0 | return loadContext->UsePrivateBrowsing(); |
3515 | 0 | } |
3516 | 0 | } |
3517 | 0 | } |
3518 | 0 | |
3519 | 0 | nsCOMPtr<nsIChannel> channel = aDoc->GetChannel(); |
3520 | 0 | return channel && NS_UsePrivateBrowsing(channel); |
3521 | 0 | } |
3522 | | |
3523 | | // static |
3524 | | bool |
3525 | | nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup) |
3526 | 0 | { |
3527 | 0 | if (!aLoadGroup) { |
3528 | 0 | return false; |
3529 | 0 | } |
3530 | 0 | bool isPrivate = false; |
3531 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
3532 | 0 | aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
3533 | 0 | if (callbacks) { |
3534 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); |
3535 | 0 | isPrivate = loadContext && loadContext->UsePrivateBrowsing(); |
3536 | 0 | } |
3537 | 0 | return isPrivate; |
3538 | 0 | } |
3539 | | |
3540 | | bool |
3541 | | nsContentUtils::DocumentInactiveForImageLoads(nsIDocument* aDocument) |
3542 | 0 | { |
3543 | 0 | if (aDocument && !IsChromeDoc(aDocument) && !aDocument->IsResourceDoc()) { |
3544 | 0 | nsCOMPtr<nsPIDOMWindowInner> win = |
3545 | 0 | do_QueryInterface(aDocument->GetScopeObject()); |
3546 | 0 | return !win || !win->GetDocShell(); |
3547 | 0 | } |
3548 | 0 | return false; |
3549 | 0 | } |
3550 | | |
3551 | | imgLoader* |
3552 | | nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc) |
3553 | 0 | { |
3554 | 0 | NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc), nullptr); |
3555 | 0 |
|
3556 | 0 | if (!aDoc) { |
3557 | 0 | return imgLoader::NormalLoader(); |
3558 | 0 | } |
3559 | 0 | bool isPrivate = IsInPrivateBrowsing(aDoc); |
3560 | 0 | return isPrivate ? imgLoader::PrivateBrowsingLoader() |
3561 | 0 | : imgLoader::NormalLoader(); |
3562 | 0 | } |
3563 | | |
3564 | | // static |
3565 | | imgLoader* |
3566 | | nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel, |
3567 | | nsIDocument* aContext) |
3568 | 0 | { |
3569 | 0 | NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext), nullptr); |
3570 | 0 |
|
3571 | 0 | if (!aChannel) { |
3572 | 0 | return imgLoader::NormalLoader(); |
3573 | 0 | } |
3574 | 0 | nsCOMPtr<nsILoadContext> context; |
3575 | 0 | NS_QueryNotificationCallbacks(aChannel, context); |
3576 | 0 | return context && context->UsePrivateBrowsing() ? |
3577 | 0 | imgLoader::PrivateBrowsingLoader() : |
3578 | 0 | imgLoader::NormalLoader(); |
3579 | 0 | } |
3580 | | |
3581 | | // static |
3582 | | bool |
3583 | | nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument) |
3584 | 0 | { |
3585 | 0 | imgILoader* loader = GetImgLoaderForDocument(aDocument); |
3586 | 0 | nsCOMPtr<imgICache> cache = do_QueryInterface(loader); |
3587 | 0 |
|
3588 | 0 | // If something unexpected happened we return false, otherwise if props |
3589 | 0 | // is set, the image is cached and we return true |
3590 | 0 | nsCOMPtr<nsIProperties> props; |
3591 | 0 | nsresult rv = cache->FindEntryProperties(aURI, aDocument, getter_AddRefs(props)); |
3592 | 0 | return (NS_SUCCEEDED(rv) && props); |
3593 | 0 | } |
3594 | | |
3595 | | // static |
3596 | | int32_t |
3597 | | nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode) |
3598 | | { |
3599 | | switch (aMode) { |
3600 | | case CORS_ANONYMOUS: |
3601 | | return imgILoader::LOAD_CORS_ANONYMOUS; |
3602 | | case CORS_USE_CREDENTIALS: |
3603 | | return imgILoader::LOAD_CORS_USE_CREDENTIALS; |
3604 | | default: |
3605 | | return 0; |
3606 | | } |
3607 | | } |
3608 | | |
3609 | | // static |
3610 | | nsresult |
3611 | | nsContentUtils::LoadImage(nsIURI* aURI, nsINode* aContext, |
3612 | | nsIDocument* aLoadingDocument, |
3613 | | nsIPrincipal* aLoadingPrincipal, |
3614 | | uint64_t aRequestContextID, |
3615 | | nsIURI* aReferrer, |
3616 | | net::ReferrerPolicy aReferrerPolicy, |
3617 | | imgINotificationObserver* aObserver, int32_t aLoadFlags, |
3618 | | const nsAString& initiatorType, |
3619 | | imgRequestProxy** aRequest, |
3620 | | uint32_t aContentPolicyType, |
3621 | | bool aUseUrgentStartForChannel) |
3622 | 0 | { |
3623 | 0 | MOZ_ASSERT(aURI, "Must have a URI"); |
3624 | 0 | MOZ_ASSERT(aContext, "Must have a context"); |
3625 | 0 | MOZ_ASSERT(aLoadingDocument, "Must have a document"); |
3626 | 0 | MOZ_ASSERT(aLoadingPrincipal, "Must have a principal"); |
3627 | 0 | MOZ_ASSERT(aRequest, "Null out param"); |
3628 | 0 |
|
3629 | 0 | imgLoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument); |
3630 | 0 | if (!imgLoader) { |
3631 | 0 | // nothing we can do here |
3632 | 0 | return NS_ERROR_FAILURE; |
3633 | 0 | } |
3634 | 0 | |
3635 | 0 | nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup(); |
3636 | 0 |
|
3637 | 0 | nsIURI *documentURI = aLoadingDocument->GetDocumentURI(); |
3638 | 0 |
|
3639 | 0 | NS_ASSERTION(loadGroup || IsFontTableURI(documentURI), |
3640 | 0 | "Could not get loadgroup; onload may fire too early"); |
3641 | 0 |
|
3642 | 0 | // XXXbz using "documentURI" for the initialDocumentURI is not quite |
3643 | 0 | // right, but the best we can do here... |
3644 | 0 | return imgLoader->LoadImage(aURI, /* uri to load */ |
3645 | 0 | documentURI, /* initialDocumentURI */ |
3646 | 0 | aReferrer, /* referrer */ |
3647 | 0 | aReferrerPolicy, /* referrer policy */ |
3648 | 0 | aLoadingPrincipal, /* loading principal */ |
3649 | 0 | aRequestContextID, /* request context ID */ |
3650 | 0 | loadGroup, /* loadgroup */ |
3651 | 0 | aObserver, /* imgINotificationObserver */ |
3652 | 0 | aContext, /* loading context */ |
3653 | 0 | aLoadingDocument, /* uniquification key */ |
3654 | 0 | aLoadFlags, /* load flags */ |
3655 | 0 | nullptr, /* cache key */ |
3656 | 0 | aContentPolicyType, /* content policy type */ |
3657 | 0 | initiatorType, /* the load initiator */ |
3658 | 0 | aUseUrgentStartForChannel, /* urgent-start flag */ |
3659 | 0 | aRequest); |
3660 | 0 | } |
3661 | | |
3662 | | // static |
3663 | | already_AddRefed<imgIContainer> |
3664 | | nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent, |
3665 | | imgIRequest **aRequest) |
3666 | 0 | { |
3667 | 0 | if (aRequest) { |
3668 | 0 | *aRequest = nullptr; |
3669 | 0 | } |
3670 | 0 |
|
3671 | 0 | NS_ENSURE_TRUE(aContent, nullptr); |
3672 | 0 |
|
3673 | 0 | nsCOMPtr<imgIRequest> imgRequest; |
3674 | 0 | aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, |
3675 | 0 | getter_AddRefs(imgRequest)); |
3676 | 0 | if (!imgRequest) { |
3677 | 0 | return nullptr; |
3678 | 0 | } |
3679 | 0 | |
3680 | 0 | nsCOMPtr<imgIContainer> imgContainer; |
3681 | 0 | imgRequest->GetImage(getter_AddRefs(imgContainer)); |
3682 | 0 |
|
3683 | 0 | if (!imgContainer) { |
3684 | 0 | return nullptr; |
3685 | 0 | } |
3686 | 0 | |
3687 | 0 | if (aRequest) { |
3688 | 0 | imgRequest.swap(*aRequest); |
3689 | 0 | } |
3690 | 0 |
|
3691 | 0 | return imgContainer.forget(); |
3692 | 0 | } |
3693 | | |
3694 | | //static |
3695 | | already_AddRefed<imgRequestProxy> |
3696 | | nsContentUtils::GetStaticRequest(nsIDocument* aLoadingDocument, |
3697 | | imgRequestProxy* aRequest) |
3698 | 0 | { |
3699 | 0 | NS_ENSURE_TRUE(aRequest, nullptr); |
3700 | 0 | RefPtr<imgRequestProxy> retval; |
3701 | 0 | aRequest->GetStaticRequest(aLoadingDocument, getter_AddRefs(retval)); |
3702 | 0 | return retval.forget(); |
3703 | 0 | } |
3704 | | |
3705 | | // static |
3706 | | bool |
3707 | | nsContentUtils::ContentIsDraggable(nsIContent* aContent) |
3708 | 0 | { |
3709 | 0 | MOZ_ASSERT(aContent); |
3710 | 0 |
|
3711 | 0 | if (auto htmlElement = nsGenericHTMLElement::FromNode(aContent)) { |
3712 | 0 | if (htmlElement->Draggable()) { |
3713 | 0 | return true; |
3714 | 0 | } |
3715 | 0 | |
3716 | 0 | if (htmlElement->AttrValueIs(kNameSpaceID_None, |
3717 | 0 | nsGkAtoms::draggable, |
3718 | 0 | nsGkAtoms::_false, |
3719 | 0 | eIgnoreCase)) { |
3720 | 0 | return false; |
3721 | 0 | } |
3722 | 0 | } |
3723 | 0 | |
3724 | 0 | // special handling for content area image and link dragging |
3725 | 0 | return IsDraggableImage(aContent) || IsDraggableLink(aContent); |
3726 | 0 | } |
3727 | | |
3728 | | // static |
3729 | | bool |
3730 | | nsContentUtils::IsDraggableImage(nsIContent* aContent) |
3731 | 0 | { |
3732 | 0 | MOZ_ASSERT(aContent, "Must have content node to test"); |
3733 | 0 |
|
3734 | 0 | nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent)); |
3735 | 0 | if (!imageContent) { |
3736 | 0 | return false; |
3737 | 0 | } |
3738 | 0 | |
3739 | 0 | nsCOMPtr<imgIRequest> imgRequest; |
3740 | 0 | imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, |
3741 | 0 | getter_AddRefs(imgRequest)); |
3742 | 0 |
|
3743 | 0 | // XXXbz It may be draggable even if the request resulted in an error. Why? |
3744 | 0 | // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did. |
3745 | 0 | return imgRequest != nullptr; |
3746 | 0 | } |
3747 | | |
3748 | | // static |
3749 | | bool |
3750 | 0 | nsContentUtils::IsDraggableLink(const nsIContent* aContent) { |
3751 | 0 | nsCOMPtr<nsIURI> absURI; |
3752 | 0 | return aContent->IsLink(getter_AddRefs(absURI)); |
3753 | 0 | } |
3754 | | |
3755 | | // static |
3756 | | nsresult |
3757 | | nsContentUtils::QNameChanged(mozilla::dom::NodeInfo* aNodeInfo, nsAtom* aName, |
3758 | | mozilla::dom::NodeInfo** aResult) |
3759 | 0 | { |
3760 | 0 | nsNodeInfoManager *niMgr = aNodeInfo->NodeInfoManager(); |
3761 | 0 |
|
3762 | 0 | *aResult = niMgr->GetNodeInfo(aName, nullptr, |
3763 | 0 | aNodeInfo->NamespaceID(), |
3764 | 0 | aNodeInfo->NodeType(), |
3765 | 0 | aNodeInfo->GetExtraName()).take(); |
3766 | 0 | return NS_OK; |
3767 | 0 | } |
3768 | | |
3769 | | |
3770 | | static bool |
3771 | | TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool aExactHostMatch) |
3772 | 0 | { |
3773 | 0 | if (!aPrincipal) { |
3774 | 0 | // We always deny (i.e. don't allow) the permission if we don't have a |
3775 | 0 | // principal. |
3776 | 0 | return aPerm != nsIPermissionManager::ALLOW_ACTION; |
3777 | 0 | } |
3778 | 0 | |
3779 | 0 | nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); |
3780 | 0 | NS_ENSURE_TRUE(permMgr, false); |
3781 | 0 |
|
3782 | 0 | uint32_t perm; |
3783 | 0 | nsresult rv; |
3784 | 0 | if (aExactHostMatch) { |
3785 | 0 | rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm); |
3786 | 0 | } else { |
3787 | 0 | rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm); |
3788 | 0 | } |
3789 | 0 | NS_ENSURE_SUCCESS(rv, false); |
3790 | 0 |
|
3791 | 0 | return perm == aPerm; |
3792 | 0 | } |
3793 | | |
3794 | | bool |
3795 | | nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType) |
3796 | 0 | { |
3797 | 0 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, false); |
3798 | 0 | } |
3799 | | |
3800 | | bool |
3801 | | nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType) |
3802 | 0 | { |
3803 | 0 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, false); |
3804 | 0 | } |
3805 | | |
3806 | | bool |
3807 | | nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, const char* aType) |
3808 | 0 | { |
3809 | 0 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, true); |
3810 | 0 | } |
3811 | | |
3812 | | bool |
3813 | | nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, const char* aType) |
3814 | 0 | { |
3815 | 0 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, true); |
3816 | 0 | } |
3817 | | |
3818 | | static const char *gEventNames[] = {"event"}; |
3819 | | static const char *gSVGEventNames[] = {"evt"}; |
3820 | | // for b/w compat, the first name to onerror is still 'event', even though it |
3821 | | // is actually the error message |
3822 | | static const char *gOnErrorNames[] = {"event", "source", "lineno", |
3823 | | "colno", "error"}; |
3824 | | |
3825 | | // static |
3826 | | void |
3827 | | nsContentUtils::GetEventArgNames(int32_t aNameSpaceID, |
3828 | | nsAtom *aEventName, |
3829 | | bool aIsForWindow, |
3830 | | uint32_t *aArgCount, |
3831 | | const char*** aArgArray) |
3832 | 0 | { |
3833 | 0 | #define SET_EVENT_ARG_NAMES(names) \ |
3834 | 0 | *aArgCount = sizeof(names)/sizeof(names[0]); \ |
3835 | 0 | *aArgArray = names; |
3836 | 0 |
|
3837 | 0 | // JSEventHandler is what does the arg magic for onerror, and it does |
3838 | 0 | // not seem to take the namespace into account. So we let onerror in all |
3839 | 0 | // namespaces get the 3 arg names. |
3840 | 0 | if (aEventName == nsGkAtoms::onerror && aIsForWindow) { |
3841 | 0 | SET_EVENT_ARG_NAMES(gOnErrorNames); |
3842 | 0 | } else if (aNameSpaceID == kNameSpaceID_SVG) { |
3843 | 0 | SET_EVENT_ARG_NAMES(gSVGEventNames); |
3844 | 0 | } else { |
3845 | 0 | SET_EVENT_ARG_NAMES(gEventNames); |
3846 | 0 | } |
3847 | 0 | } |
3848 | | |
3849 | | // Note: The list of content bundles in nsStringBundle.cpp should be updated |
3850 | | // whenever entries are added or removed from this list. |
3851 | | static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = { |
3852 | | // Must line up with the enum values in |PropertiesFile| enum. |
3853 | | "chrome://global/locale/css.properties", |
3854 | | "chrome://global/locale/xbl.properties", |
3855 | | "chrome://global/locale/xul.properties", |
3856 | | "chrome://global/locale/layout_errors.properties", |
3857 | | "chrome://global/locale/layout/HtmlForm.properties", |
3858 | | "chrome://global/locale/printing.properties", |
3859 | | "chrome://global/locale/dom/dom.properties", |
3860 | | "chrome://global/locale/layout/htmlparser.properties", |
3861 | | "chrome://global/locale/svg/svg.properties", |
3862 | | "chrome://branding/locale/brand.properties", |
3863 | | "chrome://global/locale/commonDialogs.properties", |
3864 | | "chrome://global/locale/mathml/mathml.properties", |
3865 | | "chrome://global/locale/security/security.properties", |
3866 | | "chrome://necko/locale/necko.properties" |
3867 | | }; |
3868 | | |
3869 | | /* static */ nsresult |
3870 | | nsContentUtils::EnsureStringBundle(PropertiesFile aFile) |
3871 | 0 | { |
3872 | 0 | if (!sStringBundles[aFile]) { |
3873 | 0 | if (!sStringBundleService) { |
3874 | 0 | nsresult rv = |
3875 | 0 | CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService); |
3876 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3877 | 0 | } |
3878 | 0 | nsIStringBundle *bundle; |
3879 | 0 | nsresult rv = |
3880 | 0 | sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle); |
3881 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3882 | 0 | sStringBundles[aFile] = bundle; // transfer ownership |
3883 | 0 | } |
3884 | 0 | return NS_OK; |
3885 | 0 | } |
3886 | | |
3887 | | /* static */ |
3888 | | void |
3889 | | nsContentUtils::AsyncPrecreateStringBundles() |
3890 | 3 | { |
3891 | 3 | // We only ever want to pre-create bundles in the parent process. |
3892 | 3 | // |
3893 | 3 | // All nsContentUtils bundles are shared between the parent and child |
3894 | 3 | // precesses, and the shared memory regions that back them *must* be created |
3895 | 3 | // in the parent, and then sent to all children. |
3896 | 3 | // |
3897 | 3 | // If we attempt to create a bundle in the child before its memory region is |
3898 | 3 | // available, we need to create a temporary non-shared bundle, and later |
3899 | 3 | // replace that with the shared memory copy. So attempting to pre-load in the |
3900 | 3 | // child is wasteful and unnecessary. |
3901 | 3 | MOZ_ASSERT(XRE_IsParentProcess()); |
3902 | 3 | |
3903 | 45 | for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT; ++bundleIndex) { |
3904 | 42 | nsresult rv = NS_IdleDispatchToCurrentThread( |
3905 | 42 | NS_NewRunnableFunction("AsyncPrecreateStringBundles", |
3906 | 42 | [bundleIndex]() { |
3907 | 0 | PropertiesFile file = static_cast<PropertiesFile>(bundleIndex); |
3908 | 0 | EnsureStringBundle(file); |
3909 | 0 | nsIStringBundle *bundle = sStringBundles[file]; |
3910 | 0 | bundle->AsyncPreload(); |
3911 | 0 | })); |
3912 | 42 | Unused << NS_WARN_IF(NS_FAILED(rv)); |
3913 | 42 | } |
3914 | 3 | } |
3915 | | |
3916 | | /* static */ |
3917 | | nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile, |
3918 | | const char* aKey, |
3919 | | nsAString& aResult) |
3920 | 0 | { |
3921 | 0 | nsresult rv = EnsureStringBundle(aFile); |
3922 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3923 | 0 | nsIStringBundle *bundle = sStringBundles[aFile]; |
3924 | 0 | return bundle->GetStringFromName(aKey, aResult); |
3925 | 0 | } |
3926 | | |
3927 | | /* static */ |
3928 | | nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile, |
3929 | | const char* aKey, |
3930 | | const char16_t **aParams, |
3931 | | uint32_t aParamsLength, |
3932 | | nsAString& aResult) |
3933 | 0 | { |
3934 | 0 | nsresult rv = EnsureStringBundle(aFile); |
3935 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3936 | 0 | nsIStringBundle *bundle = sStringBundles[aFile]; |
3937 | 0 |
|
3938 | 0 | if (!aParams || !aParamsLength) { |
3939 | 0 | return bundle->GetStringFromName(aKey, aResult); |
3940 | 0 | } |
3941 | 0 | |
3942 | 0 | return bundle->FormatStringFromName(aKey, aParams, aParamsLength, aResult); |
3943 | 0 | } |
3944 | | |
3945 | | /* static */ |
3946 | | nsresult nsContentUtils::FormatLocalizedString( |
3947 | | PropertiesFile aFile, |
3948 | | const char* aKey, |
3949 | | const nsTArray<nsString>& aParamArray, |
3950 | | nsAString& aResult) |
3951 | 0 | { |
3952 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3953 | 0 |
|
3954 | 0 | UniquePtr<const char16_t*[]> params; |
3955 | 0 | uint32_t paramsLength = aParamArray.Length(); |
3956 | 0 | if (paramsLength > 0) { |
3957 | 0 | params = MakeUnique<const char16_t*[]>(paramsLength); |
3958 | 0 | for (uint32_t i = 0; i < paramsLength; ++i) { |
3959 | 0 | params[i] = aParamArray[i].get(); |
3960 | 0 | } |
3961 | 0 | } |
3962 | 0 | return FormatLocalizedString(aFile, aKey, params.get(), paramsLength, |
3963 | 0 | aResult); |
3964 | 0 | } |
3965 | | |
3966 | | |
3967 | | /* static */ void |
3968 | | nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText, |
3969 | | const char * classification, |
3970 | | bool aFromPrivateWindow) |
3971 | 0 | { |
3972 | 0 | nsCOMPtr<nsIScriptError> scriptError = |
3973 | 0 | do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); |
3974 | 0 | if (scriptError) { |
3975 | 0 | nsCOMPtr<nsIConsoleService> console = |
3976 | 0 | do_GetService(NS_CONSOLESERVICE_CONTRACTID); |
3977 | 0 | if (console && NS_SUCCEEDED(scriptError->Init(aErrorText, EmptyString(), |
3978 | 0 | EmptyString(), 0, 0, |
3979 | 0 | nsIScriptError::errorFlag, |
3980 | 0 | classification, |
3981 | 0 | aFromPrivateWindow))) { |
3982 | 0 | console->LogMessage(scriptError); |
3983 | 0 | } |
3984 | 0 | } |
3985 | 0 | } |
3986 | | |
3987 | | /* static */ nsresult |
3988 | | nsContentUtils::ReportToConsole(uint32_t aErrorFlags, |
3989 | | const nsACString& aCategory, |
3990 | | const nsIDocument* aDocument, |
3991 | | PropertiesFile aFile, |
3992 | | const char *aMessageName, |
3993 | | const char16_t **aParams, |
3994 | | uint32_t aParamsLength, |
3995 | | nsIURI* aURI, |
3996 | | const nsString& aSourceLine, |
3997 | | uint32_t aLineNumber, |
3998 | | uint32_t aColumnNumber) |
3999 | 0 | { |
4000 | 0 | NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength), |
4001 | 0 | "Supply either both parameters and their number or no" |
4002 | 0 | "parameters and 0."); |
4003 | 0 |
|
4004 | 0 | nsresult rv; |
4005 | 0 | nsAutoString errorText; |
4006 | 0 | if (aParams) { |
4007 | 0 | rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength, |
4008 | 0 | errorText); |
4009 | 0 | } |
4010 | 0 | else { |
4011 | 0 | rv = GetLocalizedString(aFile, aMessageName, errorText); |
4012 | 0 | } |
4013 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4014 | 0 |
|
4015 | 0 | return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory, |
4016 | 0 | aDocument, aURI, aSourceLine, |
4017 | 0 | aLineNumber, aColumnNumber); |
4018 | 0 | } |
4019 | | |
4020 | | /* static */ void |
4021 | | nsContentUtils::ReportEmptyGetElementByIdArg(const nsIDocument* aDoc) |
4022 | 0 | { |
4023 | 0 | ReportToConsole(nsIScriptError::warningFlag, |
4024 | 0 | NS_LITERAL_CSTRING("DOM"), aDoc, |
4025 | 0 | nsContentUtils::eDOM_PROPERTIES, |
4026 | 0 | "EmptyGetElementByIdParam"); |
4027 | 0 | } |
4028 | | |
4029 | | /* static */ nsresult |
4030 | | nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText, |
4031 | | uint32_t aErrorFlags, |
4032 | | const nsACString& aCategory, |
4033 | | const nsIDocument* aDocument, |
4034 | | nsIURI* aURI, |
4035 | | const nsString& aSourceLine, |
4036 | | uint32_t aLineNumber, |
4037 | | uint32_t aColumnNumber, |
4038 | | MissingErrorLocationMode aLocationMode) |
4039 | 0 | { |
4040 | 0 | uint64_t innerWindowID = 0; |
4041 | 0 | if (aDocument) { |
4042 | 0 | if (!aURI) { |
4043 | 0 | aURI = aDocument->GetDocumentURI(); |
4044 | 0 | } |
4045 | 0 | innerWindowID = aDocument->InnerWindowID(); |
4046 | 0 | } |
4047 | 0 |
|
4048 | 0 | return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory, |
4049 | 0 | innerWindowID, aURI, aSourceLine, |
4050 | 0 | aLineNumber, aColumnNumber, aLocationMode); |
4051 | 0 | } |
4052 | | |
4053 | | /* static */ nsresult |
4054 | | nsContentUtils::ReportToConsoleByWindowID(const nsAString& aErrorText, |
4055 | | uint32_t aErrorFlags, |
4056 | | const nsACString& aCategory, |
4057 | | uint64_t aInnerWindowID, |
4058 | | nsIURI* aURI, |
4059 | | const nsString& aSourceLine, |
4060 | | uint32_t aLineNumber, |
4061 | | uint32_t aColumnNumber, |
4062 | | MissingErrorLocationMode aLocationMode) |
4063 | 0 | { |
4064 | 0 | nsresult rv; |
4065 | 0 | if (!sConsoleService) { // only need to bother null-checking here |
4066 | 0 | rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService); |
4067 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4068 | 0 | } |
4069 | 0 |
|
4070 | 0 | nsAutoCString spec; |
4071 | 0 | if (!aLineNumber && aLocationMode == eUSE_CALLING_LOCATION) { |
4072 | 0 | JSContext *cx = GetCurrentJSContext(); |
4073 | 0 | if (cx) { |
4074 | 0 | nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber); |
4075 | 0 | } |
4076 | 0 | } |
4077 | 0 |
|
4078 | 0 | nsCOMPtr<nsIScriptError> errorObject = |
4079 | 0 | do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv); |
4080 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4081 | 0 |
|
4082 | 0 | if (!spec.IsEmpty()) { |
4083 | 0 | rv = errorObject->InitWithWindowID(aErrorText, |
4084 | 0 | NS_ConvertUTF8toUTF16(spec), // file name |
4085 | 0 | aSourceLine, |
4086 | 0 | aLineNumber, aColumnNumber, |
4087 | 0 | aErrorFlags, aCategory, |
4088 | 0 | aInnerWindowID); |
4089 | 0 | } else { |
4090 | 0 | rv = errorObject->InitWithSourceURI(aErrorText, |
4091 | 0 | aURI, |
4092 | 0 | aSourceLine, |
4093 | 0 | aLineNumber, aColumnNumber, |
4094 | 0 | aErrorFlags, aCategory, |
4095 | 0 | aInnerWindowID); |
4096 | 0 | } |
4097 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4098 | 0 |
|
4099 | 0 | return sConsoleService->LogMessage(errorObject); |
4100 | 0 | } |
4101 | | |
4102 | | void |
4103 | | nsContentUtils::LogMessageToConsole(const char* aMsg) |
4104 | 0 | { |
4105 | 0 | if (!sConsoleService) { // only need to bother null-checking here |
4106 | 0 | CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService); |
4107 | 0 | if (!sConsoleService) { |
4108 | 0 | return; |
4109 | 0 | } |
4110 | 0 | } |
4111 | 0 | sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get()); |
4112 | 0 | } |
4113 | | |
4114 | | bool |
4115 | | nsContentUtils::IsChromeDoc(nsIDocument *aDocument) |
4116 | 0 | { |
4117 | 0 | if (!aDocument) { |
4118 | 0 | return false; |
4119 | 0 | } |
4120 | 0 | return aDocument->NodePrincipal() == sSystemPrincipal; |
4121 | 0 | } |
4122 | | |
4123 | | bool |
4124 | | nsContentUtils::IsChildOfSameType(nsIDocument* aDoc) |
4125 | 0 | { |
4126 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(aDoc->GetDocShell()); |
4127 | 0 | nsCOMPtr<nsIDocShellTreeItem> sameTypeParent; |
4128 | 0 | if (docShellAsItem) { |
4129 | 0 | docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent)); |
4130 | 0 | } |
4131 | 0 | return sameTypeParent != nullptr; |
4132 | 0 | } |
4133 | | |
4134 | | bool |
4135 | | nsContentUtils::IsPlainTextType(const nsACString& aContentType) |
4136 | 0 | { |
4137 | 0 | // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES |
4138 | 0 | // define in nsContentDLF.h as well. |
4139 | 0 | return aContentType.EqualsLiteral(TEXT_PLAIN) || |
4140 | 0 | aContentType.EqualsLiteral(TEXT_CSS) || |
4141 | 0 | aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) || |
4142 | 0 | aContentType.EqualsLiteral(TEXT_VTT) || |
4143 | 0 | aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) || |
4144 | 0 | aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) || |
4145 | 0 | aContentType.EqualsLiteral(TEXT_ECMASCRIPT) || |
4146 | 0 | aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) || |
4147 | 0 | aContentType.EqualsLiteral(TEXT_JAVASCRIPT) || |
4148 | 0 | aContentType.EqualsLiteral(APPLICATION_JSON) || |
4149 | 0 | aContentType.EqualsLiteral(TEXT_JSON); |
4150 | 0 | } |
4151 | | |
4152 | | bool |
4153 | | nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString& aContentType) |
4154 | 0 | { |
4155 | 0 | // NOTE: This must be a subset of the list in IsPlainTextType(). |
4156 | 0 | return aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) || |
4157 | 0 | aContentType.EqualsLiteral(APPLICATION_JSON) || |
4158 | 0 | aContentType.EqualsLiteral(TEXT_JSON) || |
4159 | 0 | aContentType.EqualsLiteral(TEXT_VTT); |
4160 | 0 | } |
4161 | | |
4162 | | bool |
4163 | | nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument* aDocument, |
4164 | | nsIURI* aURI, |
4165 | | nsACString& aScriptURI, |
4166 | | nsresult* aRv) |
4167 | 0 | { |
4168 | 0 | MOZ_ASSERT(aRv); |
4169 | 0 | bool scriptFileNameModified = false; |
4170 | 0 | *aRv = NS_OK; |
4171 | 0 |
|
4172 | 0 | *aRv = aURI->GetSpec(aScriptURI); |
4173 | 0 | NS_ENSURE_SUCCESS(*aRv, false); |
4174 | 0 |
|
4175 | 0 | if (IsChromeDoc(aDocument)) { |
4176 | 0 | nsCOMPtr<nsIChromeRegistry> chromeReg = |
4177 | 0 | mozilla::services::GetChromeRegistryService(); |
4178 | 0 |
|
4179 | 0 | if (!chromeReg) { |
4180 | 0 | // If we're running w/o a chrome registry we won't modify any |
4181 | 0 | // script file names. |
4182 | 0 |
|
4183 | 0 | return scriptFileNameModified; |
4184 | 0 | } |
4185 | 0 | |
4186 | 0 | bool docWrappersEnabled = |
4187 | 0 | chromeReg->WrappersEnabled(aDocument->GetDocumentURI()); |
4188 | 0 |
|
4189 | 0 | bool uriWrappersEnabled = chromeReg->WrappersEnabled(aURI); |
4190 | 0 |
|
4191 | 0 | nsIURI *docURI = aDocument->GetDocumentURI(); |
4192 | 0 |
|
4193 | 0 | if (docURI && docWrappersEnabled && !uriWrappersEnabled) { |
4194 | 0 | // aURI is a script from a URL that doesn't get wrapper |
4195 | 0 | // automation. aDocument is a chrome document that does get |
4196 | 0 | // wrapper automation. Prepend the chrome document's URI |
4197 | 0 | // followed by the string " -> " to the URI of the script we're |
4198 | 0 | // loading here so that script in that URI gets the same wrapper |
4199 | 0 | // automation that the chrome document expects. |
4200 | 0 | nsAutoCString spec; |
4201 | 0 | *aRv = docURI->GetSpec(spec); |
4202 | 0 | if (NS_WARN_IF(NS_FAILED(*aRv))) { |
4203 | 0 | return false; |
4204 | 0 | } |
4205 | 0 | |
4206 | 0 | spec.AppendLiteral(" -> "); |
4207 | 0 | spec.Append(aScriptURI); |
4208 | 0 |
|
4209 | 0 | aScriptURI = spec; |
4210 | 0 |
|
4211 | 0 | scriptFileNameModified = true; |
4212 | 0 | } |
4213 | 0 | } |
4214 | 0 |
|
4215 | 0 | return scriptFileNameModified; |
4216 | 0 | } |
4217 | | |
4218 | | // static |
4219 | | bool |
4220 | | nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument) |
4221 | 0 | { |
4222 | 0 | if (!aDocument) { |
4223 | 0 | return false; |
4224 | 0 | } |
4225 | 0 | |
4226 | 0 | if (aDocument->GetDisplayDocument()) { |
4227 | 0 | return IsInChromeDocshell(aDocument->GetDisplayDocument()); |
4228 | 0 | } |
4229 | 0 | |
4230 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShell = aDocument->GetDocShell(); |
4231 | 0 | if (!docShell) { |
4232 | 0 | return false; |
4233 | 0 | } |
4234 | 0 | |
4235 | 0 | return docShell->ItemType() == nsIDocShellTreeItem::typeChrome; |
4236 | 0 | } |
4237 | | |
4238 | | // static |
4239 | | nsIContentPolicy* |
4240 | | nsContentUtils::GetContentPolicy() |
4241 | 5 | { |
4242 | 5 | if (!sTriedToGetContentPolicy) { |
4243 | 1 | CallGetService(NS_CONTENTPOLICY_CONTRACTID, &sContentPolicyService); |
4244 | 1 | // It's OK to not have a content policy service |
4245 | 1 | sTriedToGetContentPolicy = true; |
4246 | 1 | } |
4247 | 5 | |
4248 | 5 | return sContentPolicyService; |
4249 | 5 | } |
4250 | | |
4251 | | // static |
4252 | | bool |
4253 | | nsContentUtils::IsEventAttributeName(nsAtom* aName, int32_t aType) |
4254 | 0 | { |
4255 | 0 | const char16_t* name = aName->GetUTF16String(); |
4256 | 0 | if (name[0] != 'o' || name[1] != 'n') |
4257 | 0 | return false; |
4258 | 0 | |
4259 | 0 | EventNameMapping mapping; |
4260 | 0 | return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType); |
4261 | 0 | } |
4262 | | |
4263 | | // static |
4264 | | EventMessage |
4265 | | nsContentUtils::GetEventMessage(nsAtom* aName) |
4266 | 0 | { |
4267 | 0 | MOZ_ASSERT(NS_IsMainThread(), "sAtomEventTable is not threadsafe"); |
4268 | 0 | if (aName) { |
4269 | 0 | EventNameMapping mapping; |
4270 | 0 | if (sAtomEventTable->Get(aName, &mapping)) { |
4271 | 0 | return mapping.mMessage; |
4272 | 0 | } |
4273 | 0 | } |
4274 | 0 | |
4275 | 0 | return eUnidentifiedEvent; |
4276 | 0 | } |
4277 | | |
4278 | | // static |
4279 | | mozilla::EventClassID |
4280 | | nsContentUtils::GetEventClassID(const nsAString& aName) |
4281 | 0 | { |
4282 | 0 | EventNameMapping mapping; |
4283 | 0 | if (sStringEventTable->Get(aName, &mapping)) |
4284 | 0 | return mapping.mEventClassID; |
4285 | 0 | |
4286 | 0 | return eBasicEventClass; |
4287 | 0 | } |
4288 | | |
4289 | | nsAtom* |
4290 | | nsContentUtils::GetEventMessageAndAtom(const nsAString& aName, |
4291 | | mozilla::EventClassID aEventClassID, |
4292 | | EventMessage* aEventMessage) |
4293 | 0 | { |
4294 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe"); |
4295 | 0 | EventNameMapping mapping; |
4296 | 0 | if (sStringEventTable->Get(aName, &mapping)) { |
4297 | 0 | *aEventMessage = |
4298 | 0 | mapping.mEventClassID == aEventClassID ? mapping.mMessage : |
4299 | 0 | eUnidentifiedEvent; |
4300 | 0 | return mapping.mAtom; |
4301 | 0 | } |
4302 | 0 |
|
4303 | 0 | // If we have cached lots of user defined event names, clear some of them. |
4304 | 0 | if (sUserDefinedEvents->Length() > 127) { |
4305 | 0 | while (sUserDefinedEvents->Length() > 64) { |
4306 | 0 | nsAtom* first = sUserDefinedEvents->ElementAt(0); |
4307 | 0 | sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2)); |
4308 | 0 | sUserDefinedEvents->RemoveElementAt(0); |
4309 | 0 | } |
4310 | 0 | } |
4311 | 0 |
|
4312 | 0 | *aEventMessage = eUnidentifiedEvent; |
4313 | 0 | RefPtr<nsAtom> atom = |
4314 | 0 | NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); |
4315 | 0 | sUserDefinedEvents->AppendElement(atom); |
4316 | 0 | mapping.mAtom = atom; |
4317 | 0 | mapping.mMessage = eUnidentifiedEvent; |
4318 | 0 | mapping.mType = EventNameType_None; |
4319 | 0 | mapping.mEventClassID = eBasicEventClass; |
4320 | 0 | // This is a slow hashtable call, but at least we cache the result for the |
4321 | 0 | // following calls. Because GetEventMessageAndAtomForListener utilizes |
4322 | 0 | // sStringEventTable, it needs to know in which cases sStringEventTable |
4323 | 0 | // doesn't contain the information it needs so that it can use |
4324 | 0 | // sAtomEventTable instead. |
4325 | 0 | mapping.mMaybeSpecialSVGorSMILEvent = |
4326 | 0 | GetEventMessage(atom) != eUnidentifiedEvent; |
4327 | 0 | sStringEventTable->Put(aName, mapping); |
4328 | 0 | return mapping.mAtom; |
4329 | 0 | } |
4330 | | |
4331 | | // static |
4332 | | EventMessage |
4333 | | nsContentUtils::GetEventMessageAndAtomForListener(const nsAString& aName, |
4334 | | nsAtom** aOnName) |
4335 | 0 | { |
4336 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe"); |
4337 | 0 |
|
4338 | 0 | // Because of SVG/SMIL sStringEventTable contains a subset of the event names |
4339 | 0 | // comparing to the sAtomEventTable. However, usually sStringEventTable |
4340 | 0 | // contains the information we need, so in order to reduce hashtable |
4341 | 0 | // lookups, start from it. |
4342 | 0 | EventNameMapping mapping; |
4343 | 0 | EventMessage msg = eUnidentifiedEvent; |
4344 | 0 | RefPtr<nsAtom> atom; |
4345 | 0 | if (sStringEventTable->Get(aName, &mapping)) { |
4346 | 0 | if (mapping.mMaybeSpecialSVGorSMILEvent) { |
4347 | 0 | // Try the atom version so that we should get the right message for |
4348 | 0 | // SVG/SMIL. |
4349 | 0 | atom = NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); |
4350 | 0 | msg = GetEventMessage(atom); |
4351 | 0 | } else { |
4352 | 0 | atom = mapping.mAtom; |
4353 | 0 | msg = mapping.mMessage; |
4354 | 0 | } |
4355 | 0 | atom.forget(aOnName); |
4356 | 0 | return msg; |
4357 | 0 | } |
4358 | 0 |
|
4359 | 0 | // GetEventMessageAndAtom will cache the event type for the future usage... |
4360 | 0 | GetEventMessageAndAtom(aName, eBasicEventClass, &msg); |
4361 | 0 |
|
4362 | 0 | // ...and then call this method recursively to get the message and atom from |
4363 | 0 | // now updated sStringEventTable. |
4364 | 0 | return GetEventMessageAndAtomForListener(aName, aOnName); |
4365 | 0 | } |
4366 | | |
4367 | | static |
4368 | | nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget, |
4369 | | const nsAString& aEventName, |
4370 | | CanBubble aCanBubble, |
4371 | | Cancelable aCancelable, |
4372 | | Composed aComposed, |
4373 | | Trusted aTrusted, |
4374 | | Event** aEvent, |
4375 | | EventTarget** aTargetOut) |
4376 | 0 | { |
4377 | 0 | nsCOMPtr<EventTarget> target(do_QueryInterface(aTarget)); |
4378 | 0 | NS_ENSURE_TRUE(aDoc && target, NS_ERROR_INVALID_ARG); |
4379 | 0 |
|
4380 | 0 | ErrorResult err; |
4381 | 0 | RefPtr<Event> event = aDoc->CreateEvent(NS_LITERAL_STRING("Events"), |
4382 | 0 | CallerType::System, err); |
4383 | 0 | if (NS_WARN_IF(err.Failed())) { |
4384 | 0 | return err.StealNSResult(); |
4385 | 0 | } |
4386 | 0 | |
4387 | 0 | event->InitEvent(aEventName, aCanBubble, aCancelable, aComposed); |
4388 | 0 | event->SetTrusted(aTrusted == Trusted::eYes); |
4389 | 0 |
|
4390 | 0 | event->SetTarget(target); |
4391 | 0 |
|
4392 | 0 | event.forget(aEvent); |
4393 | 0 | target.forget(aTargetOut); |
4394 | 0 | return NS_OK; |
4395 | 0 | } |
4396 | | |
4397 | | // static |
4398 | | nsresult |
4399 | | nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget, |
4400 | | const nsAString& aEventName, |
4401 | | CanBubble aCanBubble, |
4402 | | Cancelable aCancelable, |
4403 | | Composed aComposed, |
4404 | | bool* aDefaultAction) |
4405 | 0 | { |
4406 | 0 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, |
4407 | 0 | aComposed, Trusted::eYes, aDefaultAction); |
4408 | 0 | } |
4409 | | |
4410 | | // static |
4411 | | nsresult |
4412 | | nsContentUtils::DispatchUntrustedEvent(nsIDocument* aDoc, nsISupports* aTarget, |
4413 | | const nsAString& aEventName, |
4414 | | CanBubble aCanBubble, |
4415 | | Cancelable aCancelable, |
4416 | | bool* aDefaultAction) |
4417 | 0 | { |
4418 | 0 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, |
4419 | 0 | Composed::eDefault, Trusted::eNo, aDefaultAction); |
4420 | 0 | } |
4421 | | |
4422 | | // static |
4423 | | nsresult |
4424 | | nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget, |
4425 | | const nsAString& aEventName, |
4426 | | CanBubble aCanBubble, |
4427 | | Cancelable aCancelable, |
4428 | | Composed aComposed, |
4429 | | Trusted aTrusted, |
4430 | | bool* aDefaultAction, |
4431 | | ChromeOnlyDispatch aOnlyChromeDispatch) |
4432 | 0 | { |
4433 | 0 | RefPtr<Event> event; |
4434 | 0 | nsCOMPtr<EventTarget> target; |
4435 | 0 | nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble, |
4436 | 0 | aCancelable, aComposed, aTrusted, |
4437 | 0 | getter_AddRefs(event), |
4438 | 0 | getter_AddRefs(target)); |
4439 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4440 | 0 | event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = |
4441 | 0 | aOnlyChromeDispatch == ChromeOnlyDispatch::eYes; |
4442 | 0 |
|
4443 | 0 | ErrorResult err; |
4444 | 0 | bool doDefault = target->DispatchEvent(*event, CallerType::System, err); |
4445 | 0 | if (aDefaultAction) { |
4446 | 0 | *aDefaultAction = doDefault; |
4447 | 0 | } |
4448 | 0 | return err.StealNSResult(); |
4449 | 0 | } |
4450 | | |
4451 | | // static |
4452 | | nsresult |
4453 | | nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget, |
4454 | | WidgetEvent& aEvent, |
4455 | | EventMessage aEventMessage, |
4456 | | CanBubble aCanBubble, |
4457 | | Cancelable aCancelable, |
4458 | | Trusted aTrusted, |
4459 | | bool* aDefaultAction, |
4460 | | ChromeOnlyDispatch aOnlyChromeDispatch) |
4461 | 0 | { |
4462 | 0 | MOZ_ASSERT_IF(aOnlyChromeDispatch == ChromeOnlyDispatch::eYes, |
4463 | 0 | aTrusted == Trusted::eYes); |
4464 | 0 |
|
4465 | 0 | nsCOMPtr<EventTarget> target(do_QueryInterface(aTarget)); |
4466 | 0 |
|
4467 | 0 | aEvent.mTime = PR_Now(); |
4468 | 0 |
|
4469 | 0 | aEvent.mSpecifiedEventType = GetEventTypeFromMessage(aEventMessage); |
4470 | 0 | aEvent.SetDefaultComposed(); |
4471 | 0 | aEvent.SetDefaultComposedInNativeAnonymousContent(); |
4472 | 0 |
|
4473 | 0 | aEvent.mFlags.mBubbles = aCanBubble == CanBubble::eYes; |
4474 | 0 | aEvent.mFlags.mCancelable = aCancelable == Cancelable::eYes; |
4475 | 0 | aEvent.mFlags.mOnlyChromeDispatch = |
4476 | 0 | aOnlyChromeDispatch == ChromeOnlyDispatch::eYes; |
4477 | 0 |
|
4478 | 0 | aEvent.mTarget = target; |
4479 | 0 |
|
4480 | 0 | nsEventStatus status = nsEventStatus_eIgnore; |
4481 | 0 | nsresult rv = EventDispatcher::DispatchDOMEvent(target, &aEvent, nullptr, |
4482 | 0 | nullptr, &status); |
4483 | 0 | if (aDefaultAction) { |
4484 | 0 | *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault); |
4485 | 0 | } |
4486 | 0 | return rv; |
4487 | 0 | } |
4488 | | |
4489 | | nsresult |
4490 | | nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc, |
4491 | | nsISupports *aTarget, |
4492 | | const nsAString& aEventName, |
4493 | | CanBubble aCanBubble, |
4494 | | Cancelable aCancelable, |
4495 | | bool* aDefaultAction) |
4496 | 0 | { |
4497 | 0 |
|
4498 | 0 | RefPtr<Event> event; |
4499 | 0 | nsCOMPtr<EventTarget> target; |
4500 | 0 | nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble, |
4501 | 0 | aCancelable, Composed::eDefault, |
4502 | 0 | Trusted::eYes, |
4503 | 0 | getter_AddRefs(event), |
4504 | 0 | getter_AddRefs(target)); |
4505 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4506 | 0 |
|
4507 | 0 | NS_ASSERTION(aDoc, "GetEventAndTarget lied?"); |
4508 | 0 | if (!aDoc->GetWindow()) |
4509 | 0 | return NS_ERROR_INVALID_ARG; |
4510 | 0 | |
4511 | 0 | EventTarget* piTarget = aDoc->GetWindow()->GetParentTarget(); |
4512 | 0 | if (!piTarget) |
4513 | 0 | return NS_ERROR_INVALID_ARG; |
4514 | 0 | |
4515 | 0 | ErrorResult err; |
4516 | 0 | bool defaultActionEnabled = |
4517 | 0 | piTarget->DispatchEvent(*event, CallerType::System, err); |
4518 | 0 | if (aDefaultAction) { |
4519 | 0 | *aDefaultAction = defaultActionEnabled; |
4520 | 0 | } |
4521 | 0 | return err.StealNSResult(); |
4522 | 0 | } |
4523 | | |
4524 | | /* static */ |
4525 | | nsresult |
4526 | | nsContentUtils::DispatchFocusChromeEvent(nsPIDOMWindowOuter* aWindow) |
4527 | 0 | { |
4528 | 0 | MOZ_ASSERT(aWindow); |
4529 | 0 |
|
4530 | 0 | nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc(); |
4531 | 0 | if (!doc) { |
4532 | 0 | return NS_ERROR_FAILURE; |
4533 | 0 | } |
4534 | 0 | |
4535 | 0 | return DispatchChromeEvent(doc, aWindow, |
4536 | 0 | NS_LITERAL_STRING("DOMWindowFocus"), |
4537 | 0 | CanBubble::eYes, Cancelable::eYes); |
4538 | 0 | } |
4539 | | |
4540 | | nsresult |
4541 | | nsContentUtils::DispatchEventOnlyToChrome(nsIDocument* aDoc, |
4542 | | nsISupports* aTarget, |
4543 | | const nsAString& aEventName, |
4544 | | CanBubble aCanBubble, |
4545 | | Cancelable aCancelable, |
4546 | | bool* aDefaultAction) |
4547 | 0 | { |
4548 | 0 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, |
4549 | 0 | Composed::eDefault, Trusted::eYes, aDefaultAction, |
4550 | 0 | ChromeOnlyDispatch::eYes); |
4551 | 0 | } |
4552 | | |
4553 | | /* static */ |
4554 | | Element* |
4555 | | nsContentUtils::MatchElementId(nsIContent *aContent, const nsAtom* aId) |
4556 | 0 | { |
4557 | 0 | for (nsIContent* cur = aContent; |
4558 | 0 | cur; |
4559 | 0 | cur = cur->GetNextNode(aContent)) { |
4560 | 0 | if (aId == cur->GetID()) { |
4561 | 0 | return cur->AsElement(); |
4562 | 0 | } |
4563 | 0 | } |
4564 | 0 |
|
4565 | 0 | return nullptr; |
4566 | 0 | } |
4567 | | |
4568 | | /* static */ |
4569 | | Element * |
4570 | | nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId) |
4571 | 0 | { |
4572 | 0 | MOZ_ASSERT(!aId.IsEmpty(), "Will match random elements"); |
4573 | 0 |
|
4574 | 0 | // ID attrs are generally stored as atoms, so just atomize this up front |
4575 | 0 | RefPtr<nsAtom> id(NS_Atomize(aId)); |
4576 | 0 | if (!id) { |
4577 | 0 | // OOM, so just bail |
4578 | 0 | return nullptr; |
4579 | 0 | } |
4580 | 0 | |
4581 | 0 | return MatchElementId(aContent, id); |
4582 | 0 | } |
4583 | | |
4584 | | /* static */ |
4585 | | nsIDocument* |
4586 | | nsContentUtils::GetSubdocumentWithOuterWindowId(nsIDocument *aDocument, |
4587 | | uint64_t aOuterWindowId) |
4588 | 0 | { |
4589 | 0 | if (!aDocument || !aOuterWindowId) { |
4590 | 0 | return nullptr; |
4591 | 0 | } |
4592 | 0 | |
4593 | 0 | RefPtr<nsGlobalWindowOuter> window = |
4594 | 0 | nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowId); |
4595 | 0 | if (!window) { |
4596 | 0 | return nullptr; |
4597 | 0 | } |
4598 | 0 | |
4599 | 0 | nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->AsOuter(); |
4600 | 0 | nsCOMPtr<nsIDocument> foundDoc = outerWindow->GetDoc(); |
4601 | 0 | if (nsContentUtils::ContentIsCrossDocDescendantOf(foundDoc, aDocument)) { |
4602 | 0 | // Note that ContentIsCrossDocDescendantOf will return true if |
4603 | 0 | // foundDoc == aDocument. |
4604 | 0 | return foundDoc; |
4605 | 0 | } |
4606 | 0 | |
4607 | 0 | return nullptr; |
4608 | 0 | } |
4609 | | |
4610 | | /* static */ |
4611 | | void |
4612 | | nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver) |
4613 | 3 | { |
4614 | 3 | nsCOMPtr<nsIObserverService> observerService = |
4615 | 3 | mozilla::services::GetObserverService(); |
4616 | 3 | if (observerService) { |
4617 | 3 | observerService->AddObserver(aObserver, |
4618 | 3 | NS_XPCOM_SHUTDOWN_OBSERVER_ID, |
4619 | 3 | false); |
4620 | 3 | } |
4621 | 3 | } |
4622 | | |
4623 | | /* static */ |
4624 | | void |
4625 | | nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver) |
4626 | 0 | { |
4627 | 0 | nsCOMPtr<nsIObserverService> observerService = |
4628 | 0 | mozilla::services::GetObserverService(); |
4629 | 0 | if (observerService) { |
4630 | 0 | observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID); |
4631 | 0 | } |
4632 | 0 | } |
4633 | | |
4634 | | /* static */ |
4635 | | bool |
4636 | | nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent, |
4637 | | int32_t aNameSpaceID, |
4638 | | nsAtom* aName) |
4639 | 0 | { |
4640 | 0 | static Element::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nullptr}; |
4641 | 0 | return aContent->IsElement() && |
4642 | 0 | aContent->AsElement()->FindAttrValueIn(aNameSpaceID, aName, strings, eCaseMatters) |
4643 | 0 | == Element::ATTR_VALUE_NO_MATCH; |
4644 | 0 | } |
4645 | | |
4646 | | /* static */ |
4647 | | bool |
4648 | | nsContentUtils::HasMutationListeners(nsINode* aNode, |
4649 | | uint32_t aType, |
4650 | | nsINode* aTargetForSubtreeModified) |
4651 | 0 | { |
4652 | 0 | nsIDocument* doc = aNode->OwnerDoc(); |
4653 | 0 |
|
4654 | 0 | // global object will be null for documents that don't have windows. |
4655 | 0 | nsPIDOMWindowInner* window = doc->GetInnerWindow(); |
4656 | 0 | // This relies on EventListenerManager::AddEventListener, which sets |
4657 | 0 | // all mutation bits when there is a listener for DOMSubtreeModified event. |
4658 | 0 | if (window && !window->HasMutationListeners(aType)) { |
4659 | 0 | return false; |
4660 | 0 | } |
4661 | 0 | |
4662 | 0 | if (aNode->IsContent() && aNode->AsContent()->ChromeOnlyAccess()) { |
4663 | 0 | return false; |
4664 | 0 | } |
4665 | 0 | |
4666 | 0 | doc->MayDispatchMutationEvent(aTargetForSubtreeModified); |
4667 | 0 |
|
4668 | 0 | // If we have a window, we can check it for mutation listeners now. |
4669 | 0 | if (aNode->IsInUncomposedDoc()) { |
4670 | 0 | nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window)); |
4671 | 0 | if (piTarget) { |
4672 | 0 | EventListenerManager* manager = piTarget->GetExistingListenerManager(); |
4673 | 0 | if (manager && manager->HasMutationListeners()) { |
4674 | 0 | return true; |
4675 | 0 | } |
4676 | 0 | } |
4677 | 0 | } |
4678 | 0 | |
4679 | 0 | // If we have a window, we know a mutation listener is registered, but it |
4680 | 0 | // might not be in our chain. If we don't have a window, we might have a |
4681 | 0 | // mutation listener. Check quickly to see. |
4682 | 0 | while (aNode) { |
4683 | 0 | EventListenerManager* manager = aNode->GetExistingListenerManager(); |
4684 | 0 | if (manager && manager->HasMutationListeners()) { |
4685 | 0 | return true; |
4686 | 0 | } |
4687 | 0 | |
4688 | 0 | if (aNode->IsContent()) { |
4689 | 0 | nsIContent* insertionPoint = aNode->AsContent()->GetXBLInsertionPoint(); |
4690 | 0 | if (insertionPoint) { |
4691 | 0 | aNode = insertionPoint->GetParent(); |
4692 | 0 | MOZ_ASSERT(aNode); |
4693 | 0 | continue; |
4694 | 0 | } |
4695 | 0 | } |
4696 | 0 | aNode = aNode->GetParentNode(); |
4697 | 0 | } |
4698 | 0 |
|
4699 | 0 | return false; |
4700 | 0 | } |
4701 | | |
4702 | | /* static */ |
4703 | | bool |
4704 | | nsContentUtils::HasMutationListeners(nsIDocument* aDocument, |
4705 | | uint32_t aType) |
4706 | 0 | { |
4707 | 0 | nsPIDOMWindowInner* window = aDocument ? |
4708 | 0 | aDocument->GetInnerWindow() : nullptr; |
4709 | 0 |
|
4710 | 0 | // This relies on EventListenerManager::AddEventListener, which sets |
4711 | 0 | // all mutation bits when there is a listener for DOMSubtreeModified event. |
4712 | 0 | return !window || window->HasMutationListeners(aType); |
4713 | 0 | } |
4714 | | |
4715 | | void |
4716 | | nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent) |
4717 | 0 | { |
4718 | 0 | MOZ_ASSERT(aChild, "Missing child"); |
4719 | 0 | MOZ_ASSERT(aChild->GetParentNode() == aParent, "Wrong parent"); |
4720 | 0 | MOZ_ASSERT(aChild->OwnerDoc() == aParent->OwnerDoc(), "Wrong owner-doc"); |
4721 | 0 |
|
4722 | 0 | // Having an explicit check here since it's an easy mistake to fall into, |
4723 | 0 | // and there might be existing code with problems. We'd rather be safe |
4724 | 0 | // than fire DOMNodeRemoved in all corner cases. We also rely on it for |
4725 | 0 | // nsAutoScriptBlockerSuppressNodeRemoved. |
4726 | 0 | if (!IsSafeToRunScript()) { |
4727 | 0 | // This checks that IsSafeToRunScript is true since we don't want to fire |
4728 | 0 | // events when that is false. We can't rely on EventDispatcher to assert |
4729 | 0 | // this in this situation since most of the time there are no mutation |
4730 | 0 | // event listeners, in which case we won't even attempt to dispatch events. |
4731 | 0 | // However this also allows for two exceptions. First off, we don't assert |
4732 | 0 | // if the mutation happens to native anonymous content since we never fire |
4733 | 0 | // mutation events on such content anyway. |
4734 | 0 | // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since |
4735 | 0 | // that is a know case when we'd normally fire a mutation event, but can't |
4736 | 0 | // make that safe and so we suppress it at this time. Ideally this should |
4737 | 0 | // go away eventually. |
4738 | 0 | if (!(aChild->IsContent() && aChild->AsContent()->IsInNativeAnonymousSubtree()) && |
4739 | 0 | !sDOMNodeRemovedSuppressCount) { |
4740 | 0 | NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe"); |
4741 | 0 | WarnScriptWasIgnored(aChild->OwnerDoc()); |
4742 | 0 | } |
4743 | 0 | return; |
4744 | 0 | } |
4745 | 0 |
|
4746 | 0 | if (HasMutationListeners(aChild, |
4747 | 0 | NS_EVENT_BITS_MUTATION_NODEREMOVED, aParent)) { |
4748 | 0 | InternalMutationEvent mutation(true, eLegacyNodeRemoved); |
4749 | 0 | mutation.mRelatedNode = aParent; |
4750 | 0 |
|
4751 | 0 | mozAutoSubtreeModified subtree(aParent->OwnerDoc(), aParent); |
4752 | 0 | EventDispatcher::Dispatch(aChild, nullptr, &mutation); |
4753 | 0 | } |
4754 | 0 | } |
4755 | | |
4756 | | void |
4757 | | nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() |
4758 | 0 | { |
4759 | 0 | if (!sEventListenerManagersHash) { |
4760 | 0 | return; |
4761 | 0 | } |
4762 | 0 | |
4763 | 0 | for (auto i = sEventListenerManagersHash->Iter(); !i.Done(); i.Next()) { |
4764 | 0 | auto entry = static_cast<EventListenerManagerMapEntry*>(i.Get()); |
4765 | 0 | nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget()); |
4766 | 0 | if (n && n->IsInComposedDoc() && |
4767 | 0 | nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) { |
4768 | 0 | entry->mListenerManager->MarkForCC(); |
4769 | 0 | } |
4770 | 0 | } |
4771 | 0 | } |
4772 | | |
4773 | | /* static */ |
4774 | | void |
4775 | | nsContentUtils::TraverseListenerManager(nsINode *aNode, |
4776 | | nsCycleCollectionTraversalCallback &cb) |
4777 | 0 | { |
4778 | 0 | if (!sEventListenerManagersHash) { |
4779 | 0 | // We're already shut down, just return. |
4780 | 0 | return; |
4781 | 0 | } |
4782 | 0 | |
4783 | 0 | auto entry = static_cast<EventListenerManagerMapEntry*> |
4784 | 0 | (sEventListenerManagersHash->Search(aNode)); |
4785 | 0 | if (entry) { |
4786 | 0 | CycleCollectionNoteChild(cb, entry->mListenerManager.get(), |
4787 | 0 | "[via hash] mListenerManager"); |
4788 | 0 | } |
4789 | 0 | } |
4790 | | |
4791 | | EventListenerManager* |
4792 | | nsContentUtils::GetListenerManagerForNode(nsINode *aNode) |
4793 | 0 | { |
4794 | 0 | if (!sEventListenerManagersHash) { |
4795 | 0 | // We're already shut down, don't bother creating an event listener |
4796 | 0 | // manager. |
4797 | 0 |
|
4798 | 0 | return nullptr; |
4799 | 0 | } |
4800 | 0 | |
4801 | 0 | auto entry = |
4802 | 0 | static_cast<EventListenerManagerMapEntry*> |
4803 | 0 | (sEventListenerManagersHash->Add(aNode, fallible)); |
4804 | 0 |
|
4805 | 0 | if (!entry) { |
4806 | 0 | return nullptr; |
4807 | 0 | } |
4808 | 0 | |
4809 | 0 | if (!entry->mListenerManager) { |
4810 | 0 | entry->mListenerManager = new EventListenerManager(aNode); |
4811 | 0 |
|
4812 | 0 | aNode->SetFlags(NODE_HAS_LISTENERMANAGER); |
4813 | 0 | } |
4814 | 0 |
|
4815 | 0 | return entry->mListenerManager; |
4816 | 0 | } |
4817 | | |
4818 | | EventListenerManager* |
4819 | | nsContentUtils::GetExistingListenerManagerForNode(const nsINode *aNode) |
4820 | 0 | { |
4821 | 0 | if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) { |
4822 | 0 | return nullptr; |
4823 | 0 | } |
4824 | 0 | |
4825 | 0 | if (!sEventListenerManagersHash) { |
4826 | 0 | // We're already shut down, don't bother creating an event listener |
4827 | 0 | // manager. |
4828 | 0 |
|
4829 | 0 | return nullptr; |
4830 | 0 | } |
4831 | 0 | |
4832 | 0 | auto entry = static_cast<EventListenerManagerMapEntry*> |
4833 | 0 | (sEventListenerManagersHash->Search(aNode)); |
4834 | 0 | if (entry) { |
4835 | 0 | return entry->mListenerManager; |
4836 | 0 | } |
4837 | 0 | |
4838 | 0 | return nullptr; |
4839 | 0 | } |
4840 | | |
4841 | | /* static */ |
4842 | | void |
4843 | | nsContentUtils::RemoveListenerManager(nsINode *aNode) |
4844 | 0 | { |
4845 | 0 | if (sEventListenerManagersHash) { |
4846 | 0 | auto entry = static_cast<EventListenerManagerMapEntry*> |
4847 | 0 | (sEventListenerManagersHash->Search(aNode)); |
4848 | 0 | if (entry) { |
4849 | 0 | RefPtr<EventListenerManager> listenerManager; |
4850 | 0 | listenerManager.swap(entry->mListenerManager); |
4851 | 0 | // Remove the entry and *then* do operations that could cause further |
4852 | 0 | // modification of sEventListenerManagersHash. See bug 334177. |
4853 | 0 | sEventListenerManagersHash->RawRemove(entry); |
4854 | 0 | if (listenerManager) { |
4855 | 0 | listenerManager->Disconnect(); |
4856 | 0 | } |
4857 | 0 | } |
4858 | 0 | } |
4859 | 0 | } |
4860 | | |
4861 | | /* static */ |
4862 | | bool |
4863 | | nsContentUtils::IsValidNodeName(nsAtom *aLocalName, nsAtom *aPrefix, |
4864 | | int32_t aNamespaceID) |
4865 | 0 | { |
4866 | 0 | if (aNamespaceID == kNameSpaceID_Unknown) { |
4867 | 0 | return false; |
4868 | 0 | } |
4869 | 0 | |
4870 | 0 | if (!aPrefix) { |
4871 | 0 | // If the prefix is null, then either the QName must be xmlns or the |
4872 | 0 | // namespace must not be XMLNS. |
4873 | 0 | return (aLocalName == nsGkAtoms::xmlns) == |
4874 | 0 | (aNamespaceID == kNameSpaceID_XMLNS); |
4875 | 0 | } |
4876 | 0 |
|
4877 | 0 | // If the prefix is non-null then the namespace must not be null. |
4878 | 0 | if (aNamespaceID == kNameSpaceID_None) { |
4879 | 0 | return false; |
4880 | 0 | } |
4881 | 0 | |
4882 | 0 | // If the namespace is the XMLNS namespace then the prefix must be xmlns, |
4883 | 0 | // but the localname must not be xmlns. |
4884 | 0 | if (aNamespaceID == kNameSpaceID_XMLNS) { |
4885 | 0 | return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns; |
4886 | 0 | } |
4887 | 0 |
|
4888 | 0 | // If the namespace is not the XMLNS namespace then the prefix must not be |
4889 | 0 | // xmlns. |
4890 | 0 | // If the namespace is the XML namespace then the prefix can be anything. |
4891 | 0 | // If the namespace is not the XML namespace then the prefix must not be xml. |
4892 | 0 | return aPrefix != nsGkAtoms::xmlns && |
4893 | 0 | (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml); |
4894 | 0 | } |
4895 | | |
4896 | | already_AddRefed<DocumentFragment> |
4897 | | nsContentUtils::CreateContextualFragment(nsINode* aContextNode, |
4898 | | const nsAString& aFragment, |
4899 | | bool aPreventScriptExecution, |
4900 | | ErrorResult& aRv) |
4901 | 0 | { |
4902 | 0 | if (!aContextNode) { |
4903 | 0 | aRv.Throw(NS_ERROR_INVALID_ARG); |
4904 | 0 | return nullptr; |
4905 | 0 | } |
4906 | 0 | |
4907 | 0 | // If we don't have a document here, we can't get the right security context |
4908 | 0 | // for compiling event handlers... so just bail out. |
4909 | 0 | nsCOMPtr<nsIDocument> document = aContextNode->OwnerDoc(); |
4910 | 0 | bool isHTML = document->IsHTMLDocument(); |
4911 | | #ifdef DEBUG |
4912 | | nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document); |
4913 | | NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!"); |
4914 | | #endif |
4915 | |
|
4916 | 0 | if (isHTML) { |
4917 | 0 | RefPtr<DocumentFragment> frag = |
4918 | 0 | new DocumentFragment(document->NodeInfoManager()); |
4919 | 0 |
|
4920 | 0 | nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode); |
4921 | 0 | if (contextAsContent && !contextAsContent->IsElement()) { |
4922 | 0 | contextAsContent = contextAsContent->GetParent(); |
4923 | 0 | if (contextAsContent && !contextAsContent->IsElement()) { |
4924 | 0 | // can this even happen? |
4925 | 0 | contextAsContent = nullptr; |
4926 | 0 | } |
4927 | 0 | } |
4928 | 0 |
|
4929 | 0 | if (contextAsContent && !contextAsContent->IsHTMLElement(nsGkAtoms::html)) { |
4930 | 0 | aRv = ParseFragmentHTML(aFragment, frag, |
4931 | 0 | contextAsContent->NodeInfo()->NameAtom(), |
4932 | 0 | contextAsContent->GetNameSpaceID(), |
4933 | 0 | (document->GetCompatibilityMode() == |
4934 | 0 | eCompatibility_NavQuirks), |
4935 | 0 | aPreventScriptExecution); |
4936 | 0 | } else { |
4937 | 0 | aRv = ParseFragmentHTML(aFragment, frag, |
4938 | 0 | nsGkAtoms::body, |
4939 | 0 | kNameSpaceID_XHTML, |
4940 | 0 | (document->GetCompatibilityMode() == |
4941 | 0 | eCompatibility_NavQuirks), |
4942 | 0 | aPreventScriptExecution); |
4943 | 0 | } |
4944 | 0 |
|
4945 | 0 | return frag.forget(); |
4946 | 0 | } |
4947 | 0 |
|
4948 | 0 | AutoTArray<nsString, 32> tagStack; |
4949 | 0 | nsAutoString uriStr, nameStr; |
4950 | 0 | nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode); |
4951 | 0 | // just in case we have a text node |
4952 | 0 | if (content && !content->IsElement()) |
4953 | 0 | content = content->GetParent(); |
4954 | 0 |
|
4955 | 0 | while (content && content->IsElement()) { |
4956 | 0 | nsString& tagName = *tagStack.AppendElement(); |
4957 | 0 | tagName = content->NodeInfo()->QualifiedName(); |
4958 | 0 |
|
4959 | 0 | // see if we need to add xmlns declarations |
4960 | 0 | uint32_t count = content->AsElement()->GetAttrCount(); |
4961 | 0 | bool setDefaultNamespace = false; |
4962 | 0 | if (count > 0) { |
4963 | 0 | uint32_t index; |
4964 | 0 |
|
4965 | 0 | for (index = 0; index < count; index++) { |
4966 | 0 | const BorrowedAttrInfo info = content->AsElement()->GetAttrInfoAt(index); |
4967 | 0 | const nsAttrName* name = info.mName; |
4968 | 0 | if (name->NamespaceEquals(kNameSpaceID_XMLNS)) { |
4969 | 0 | info.mValue->ToString(uriStr); |
4970 | 0 |
|
4971 | 0 | // really want something like nsXMLContentSerializer::SerializeAttr |
4972 | 0 | tagName.AppendLiteral(" xmlns"); // space important |
4973 | 0 | if (name->GetPrefix()) { |
4974 | 0 | tagName.Append(char16_t(':')); |
4975 | 0 | name->LocalName()->ToString(nameStr); |
4976 | 0 | tagName.Append(nameStr); |
4977 | 0 | } else { |
4978 | 0 | setDefaultNamespace = true; |
4979 | 0 | } |
4980 | 0 | tagName.AppendLiteral(R"(=")"); |
4981 | 0 | tagName.Append(uriStr); |
4982 | 0 | tagName.Append('"'); |
4983 | 0 | } |
4984 | 0 | } |
4985 | 0 | } |
4986 | 0 |
|
4987 | 0 | if (!setDefaultNamespace) { |
4988 | 0 | mozilla::dom::NodeInfo* info = content->NodeInfo(); |
4989 | 0 | if (!info->GetPrefixAtom() && |
4990 | 0 | info->NamespaceID() != kNameSpaceID_None) { |
4991 | 0 | // We have no namespace prefix, but have a namespace ID. Push |
4992 | 0 | // default namespace attr in, so that our kids will be in our |
4993 | 0 | // namespace. |
4994 | 0 | info->GetNamespaceURI(uriStr); |
4995 | 0 | tagName.AppendLiteral(R"( xmlns=")"); |
4996 | 0 | tagName.Append(uriStr); |
4997 | 0 | tagName.Append('"'); |
4998 | 0 | } |
4999 | 0 | } |
5000 | 0 |
|
5001 | 0 | content = content->GetParent(); |
5002 | 0 | } |
5003 | 0 |
|
5004 | 0 | RefPtr<DocumentFragment> frag; |
5005 | 0 | aRv = ParseFragmentXML(aFragment, document, tagStack, |
5006 | 0 | aPreventScriptExecution, getter_AddRefs(frag)); |
5007 | 0 | return frag.forget(); |
5008 | 0 | } |
5009 | | |
5010 | | /* static */ |
5011 | | void |
5012 | | nsContentUtils::DropFragmentParsers() |
5013 | 0 | { |
5014 | 0 | NS_IF_RELEASE(sHTMLFragmentParser); |
5015 | 0 | NS_IF_RELEASE(sXMLFragmentParser); |
5016 | 0 | NS_IF_RELEASE(sXMLFragmentSink); |
5017 | 0 | } |
5018 | | |
5019 | | /* static */ |
5020 | | void |
5021 | | nsContentUtils::XPCOMShutdown() |
5022 | 0 | { |
5023 | 0 | nsContentUtils::DropFragmentParsers(); |
5024 | 0 | } |
5025 | | |
5026 | | /* static */ |
5027 | | nsresult |
5028 | | nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer, |
5029 | | nsIContent* aTargetNode, |
5030 | | nsAtom* aContextLocalName, |
5031 | | int32_t aContextNamespace, |
5032 | | bool aQuirks, |
5033 | | bool aPreventScriptExecution) |
5034 | 0 | { |
5035 | 0 | AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML"); |
5036 | 0 |
|
5037 | 0 | if (nsContentUtils::sFragmentParsingActive) { |
5038 | 0 | MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted."); |
5039 | 0 | return NS_ERROR_DOM_INVALID_STATE_ERR; |
5040 | 0 | } |
5041 | 0 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); |
5042 | 0 | nsContentUtils::sFragmentParsingActive = true; |
5043 | 0 | if (!sHTMLFragmentParser) { |
5044 | 0 | NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser()); |
5045 | 0 | // Now sHTMLFragmentParser owns the object |
5046 | 0 | } |
5047 | 0 |
|
5048 | 0 | nsIContent* target = aTargetNode; |
5049 | 0 |
|
5050 | 0 | // If this is a chrome-privileged document, create a fragment first, and |
5051 | 0 | // sanitize it before insertion. |
5052 | 0 | RefPtr<DocumentFragment> fragment; |
5053 | 0 | if (IsSystemPrincipal(aTargetNode->NodePrincipal())) { |
5054 | 0 | fragment = new DocumentFragment(aTargetNode->OwnerDoc()->NodeInfoManager()); |
5055 | 0 | target = fragment; |
5056 | 0 | } |
5057 | 0 |
|
5058 | 0 | nsresult rv = |
5059 | 0 | sHTMLFragmentParser->ParseFragment(aSourceBuffer, |
5060 | 0 | target, |
5061 | 0 | aContextLocalName, |
5062 | 0 | aContextNamespace, |
5063 | 0 | aQuirks, |
5064 | 0 | aPreventScriptExecution); |
5065 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5066 | 0 |
|
5067 | 0 | if (fragment) { |
5068 | 0 | // Don't fire mutation events for nodes removed by the sanitizer. |
5069 | 0 | nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker; |
5070 | 0 |
|
5071 | 0 | nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle | |
5072 | 0 | nsIParserUtils::SanitizerAllowComments | |
5073 | 0 | nsIParserUtils::SanitizerDropForms | |
5074 | 0 | nsIParserUtils::SanitizerLogRemovals); |
5075 | 0 | sanitizer.Sanitize(fragment); |
5076 | 0 |
|
5077 | 0 | ErrorResult error; |
5078 | 0 | aTargetNode->AppendChild(*fragment, error); |
5079 | 0 | rv = error.StealNSResult(); |
5080 | 0 | } |
5081 | 0 |
|
5082 | 0 | return rv; |
5083 | 0 | } |
5084 | | |
5085 | | /* static */ |
5086 | | nsresult |
5087 | | nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer, |
5088 | | nsIDocument* aTargetDocument, |
5089 | | bool aScriptingEnabledForNoscriptParsing) |
5090 | 0 | { |
5091 | 0 | AutoTimelineMarker m(aTargetDocument->GetDocShell(), "Parse HTML"); |
5092 | 0 |
|
5093 | 0 | if (nsContentUtils::sFragmentParsingActive) { |
5094 | 0 | MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted."); |
5095 | 0 | return NS_ERROR_DOM_INVALID_STATE_ERR; |
5096 | 0 | } |
5097 | 0 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); |
5098 | 0 | nsContentUtils::sFragmentParsingActive = true; |
5099 | 0 | if (!sHTMLFragmentParser) { |
5100 | 0 | NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser()); |
5101 | 0 | // Now sHTMLFragmentParser owns the object |
5102 | 0 | } |
5103 | 0 | nsresult rv = |
5104 | 0 | sHTMLFragmentParser->ParseDocument(aSourceBuffer, |
5105 | 0 | aTargetDocument, |
5106 | 0 | aScriptingEnabledForNoscriptParsing); |
5107 | 0 | return rv; |
5108 | 0 | } |
5109 | | |
5110 | | /* static */ |
5111 | | nsresult |
5112 | | nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer, |
5113 | | nsIDocument* aDocument, |
5114 | | nsTArray<nsString>& aTagStack, |
5115 | | bool aPreventScriptExecution, |
5116 | | DocumentFragment** aReturn) |
5117 | 0 | { |
5118 | 0 | AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML"); |
5119 | 0 |
|
5120 | 0 | if (nsContentUtils::sFragmentParsingActive) { |
5121 | 0 | MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted."); |
5122 | 0 | return NS_ERROR_DOM_INVALID_STATE_ERR; |
5123 | 0 | } |
5124 | 0 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); |
5125 | 0 | nsContentUtils::sFragmentParsingActive = true; |
5126 | 0 | if (!sXMLFragmentParser) { |
5127 | 0 | nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID); |
5128 | 0 | parser.forget(&sXMLFragmentParser); |
5129 | 0 | // sXMLFragmentParser now owns the parser |
5130 | 0 | } |
5131 | 0 | if (!sXMLFragmentSink) { |
5132 | 0 | NS_NewXMLFragmentContentSink(&sXMLFragmentSink); |
5133 | 0 | // sXMLFragmentSink now owns the sink |
5134 | 0 | } |
5135 | 0 | nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink); |
5136 | 0 | MOZ_ASSERT(contentsink, "Sink doesn't QI to nsIContentSink!"); |
5137 | 0 | sXMLFragmentParser->SetContentSink(contentsink); |
5138 | 0 |
|
5139 | 0 | sXMLFragmentSink->SetTargetDocument(aDocument); |
5140 | 0 | sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution); |
5141 | 0 |
|
5142 | 0 | nsresult rv = |
5143 | 0 | sXMLFragmentParser->ParseFragment(aSourceBuffer, |
5144 | 0 | aTagStack); |
5145 | 0 | if (NS_FAILED(rv)) { |
5146 | 0 | // Drop the fragment parser and sink that might be in an inconsistent state |
5147 | 0 | NS_IF_RELEASE(sXMLFragmentParser); |
5148 | 0 | NS_IF_RELEASE(sXMLFragmentSink); |
5149 | 0 | return rv; |
5150 | 0 | } |
5151 | 0 |
|
5152 | 0 | rv = sXMLFragmentSink->FinishFragmentParsing(aReturn); |
5153 | 0 |
|
5154 | 0 | sXMLFragmentParser->Reset(); |
5155 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5156 | 0 |
|
5157 | 0 | // If this is a chrome-privileged document, sanitize the fragment before |
5158 | 0 | // returning. |
5159 | 0 | if (IsSystemPrincipal(aDocument->NodePrincipal())) { |
5160 | 0 | // Don't fire mutation events for nodes removed by the sanitizer. |
5161 | 0 | nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker; |
5162 | 0 |
|
5163 | 0 | nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle | |
5164 | 0 | nsIParserUtils::SanitizerAllowComments | |
5165 | 0 | nsIParserUtils::SanitizerDropForms | |
5166 | 0 | nsIParserUtils::SanitizerLogRemovals); |
5167 | 0 | sanitizer.Sanitize(*aReturn); |
5168 | 0 | } |
5169 | 0 |
|
5170 | 0 | return rv; |
5171 | 0 | } |
5172 | | |
5173 | | /* static */ |
5174 | | nsresult |
5175 | | nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, |
5176 | | nsAString& aResultBuffer, |
5177 | | uint32_t aFlags, |
5178 | | uint32_t aWrapCol) |
5179 | 0 | { |
5180 | 0 | nsCOMPtr<nsIURI> uri; |
5181 | 0 | NS_NewURI(getter_AddRefs(uri), "about:blank"); |
5182 | 0 | nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithoutOriginAttributes(); |
5183 | 0 | nsCOMPtr<nsIDocument> document; |
5184 | 0 | nsresult rv = NS_NewDOMDocument(getter_AddRefs(document), |
5185 | 0 | EmptyString(), |
5186 | 0 | EmptyString(), |
5187 | 0 | nullptr, |
5188 | 0 | uri, |
5189 | 0 | uri, |
5190 | 0 | principal, |
5191 | 0 | true, |
5192 | 0 | nullptr, |
5193 | 0 | DocumentFlavorHTML); |
5194 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5195 | 0 |
|
5196 | 0 | rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document, |
5197 | 0 | !(aFlags & nsIDocumentEncoder::OutputNoScriptContent)); |
5198 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5199 | 0 |
|
5200 | 0 | nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance( |
5201 | 0 | "@mozilla.org/layout/documentEncoder;1?type=text/plain"); |
5202 | 0 |
|
5203 | 0 | rv = encoder->Init(document, NS_LITERAL_STRING("text/plain"), aFlags); |
5204 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5205 | 0 |
|
5206 | 0 | encoder->SetWrapColumn(aWrapCol); |
5207 | 0 |
|
5208 | 0 | return encoder->EncodeToString(aResultBuffer); |
5209 | 0 | } |
5210 | | |
5211 | | /* static */ |
5212 | | nsresult |
5213 | | nsContentUtils::SetNodeTextContent(nsIContent* aContent, |
5214 | | const nsAString& aValue, |
5215 | | bool aTryReuse) |
5216 | 0 | { |
5217 | 0 | // Fire DOMNodeRemoved mutation events before we do anything else. |
5218 | 0 | nsCOMPtr<nsIContent> owningContent; |
5219 | 0 |
|
5220 | 0 | // Batch possible DOMSubtreeModified events. |
5221 | 0 | mozAutoSubtreeModified subtree(nullptr, nullptr); |
5222 | 0 |
|
5223 | 0 | // Scope firing mutation events so that we don't carry any state that |
5224 | 0 | // might be stale |
5225 | 0 | { |
5226 | 0 | // We're relying on mozAutoSubtreeModified to keep a strong reference if |
5227 | 0 | // needed. |
5228 | 0 | nsIDocument* doc = aContent->OwnerDoc(); |
5229 | 0 |
|
5230 | 0 | // Optimize the common case of there being no observers |
5231 | 0 | if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) { |
5232 | 0 | subtree.UpdateTarget(doc, nullptr); |
5233 | 0 | owningContent = aContent; |
5234 | 0 | nsCOMPtr<nsINode> child; |
5235 | 0 | bool skipFirst = aTryReuse; |
5236 | 0 | for (child = aContent->GetFirstChild(); |
5237 | 0 | child && child->GetParentNode() == aContent; |
5238 | 0 | child = child->GetNextSibling()) { |
5239 | 0 | if (skipFirst && child->IsText()) { |
5240 | 0 | skipFirst = false; |
5241 | 0 | continue; |
5242 | 0 | } |
5243 | 0 | nsContentUtils::MaybeFireNodeRemoved(child, aContent); |
5244 | 0 | } |
5245 | 0 | } |
5246 | 0 | } |
5247 | 0 |
|
5248 | 0 | // Might as well stick a batch around this since we're performing several |
5249 | 0 | // mutations. |
5250 | 0 | mozAutoDocUpdate updateBatch(aContent->GetComposedDoc(), true); |
5251 | 0 | nsAutoMutationBatch mb; |
5252 | 0 |
|
5253 | 0 | if (aTryReuse && !aValue.IsEmpty()) { |
5254 | 0 | // Let's remove nodes until we find a eTEXT. |
5255 | 0 | while (aContent->HasChildren()) { |
5256 | 0 | nsIContent* child = aContent->GetFirstChild(); |
5257 | 0 | if (child->IsText()) { |
5258 | 0 | break; |
5259 | 0 | } |
5260 | 0 | aContent->RemoveChildNode(child, true); |
5261 | 0 | } |
5262 | 0 |
|
5263 | 0 | // If we have a node, it must be a eTEXT and we reuse it. |
5264 | 0 | if (aContent->HasChildren()) { |
5265 | 0 | nsIContent* child = aContent->GetFirstChild(); |
5266 | 0 | nsresult rv = child->AsText()->SetText(aValue, true); |
5267 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5268 | 0 |
|
5269 | 0 | // All the following nodes, if they exist, must be deleted. |
5270 | 0 | while (nsIContent* nextChild = child->GetNextSibling()) { |
5271 | 0 | aContent->RemoveChildNode(nextChild, true); |
5272 | 0 | } |
5273 | 0 | } |
5274 | 0 |
|
5275 | 0 | if (aContent->HasChildren()) { |
5276 | 0 | return NS_OK; |
5277 | 0 | } |
5278 | 0 | } |
5279 | 0 | else { |
5280 | 0 | mb.Init(aContent, true, false); |
5281 | 0 | while (aContent->HasChildren()) { |
5282 | 0 | aContent->RemoveChildNode(aContent->GetFirstChild(), true); |
5283 | 0 | } |
5284 | 0 | } |
5285 | 0 | mb.RemovalDone(); |
5286 | 0 |
|
5287 | 0 | if (aValue.IsEmpty()) { |
5288 | 0 | return NS_OK; |
5289 | 0 | } |
5290 | 0 | |
5291 | 0 | RefPtr<nsTextNode> textContent = |
5292 | 0 | new nsTextNode(aContent->NodeInfo()->NodeInfoManager()); |
5293 | 0 |
|
5294 | 0 | textContent->SetText(aValue, true); |
5295 | 0 |
|
5296 | 0 | nsresult rv = aContent->AppendChildTo(textContent, true); |
5297 | 0 | mb.NodesAdded(); |
5298 | 0 | return rv; |
5299 | 0 | } |
5300 | | |
5301 | | static bool |
5302 | | AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult, |
5303 | | const fallible_t& aFallible) |
5304 | 0 | { |
5305 | 0 | for (nsIContent* child = aNode->GetFirstChild(); |
5306 | 0 | child; |
5307 | 0 | child = child->GetNextSibling()) { |
5308 | 0 | if (child->IsElement()) { |
5309 | 0 | bool ok = AppendNodeTextContentsRecurse(child, aResult, |
5310 | 0 | aFallible); |
5311 | 0 | if (!ok) { |
5312 | 0 | return false; |
5313 | 0 | } |
5314 | 0 | } |
5315 | 0 | else if (Text* text = child->GetAsText()) { |
5316 | 0 | bool ok = text->AppendTextTo(aResult, aFallible); |
5317 | 0 | if (!ok) { |
5318 | 0 | return false; |
5319 | 0 | } |
5320 | 0 | } |
5321 | 0 | } |
5322 | 0 |
|
5323 | 0 | return true; |
5324 | 0 | } |
5325 | | |
5326 | | /* static */ |
5327 | | bool |
5328 | | nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep, |
5329 | | nsAString& aResult, |
5330 | | const fallible_t& aFallible) |
5331 | 0 | { |
5332 | 0 | if (Text* text = aNode->GetAsText()) { |
5333 | 0 | return text->AppendTextTo(aResult, aFallible); |
5334 | 0 | } |
5335 | 0 | if (aDeep) { |
5336 | 0 | return AppendNodeTextContentsRecurse(aNode, aResult, aFallible); |
5337 | 0 | } |
5338 | 0 | |
5339 | 0 | for (nsIContent* child = aNode->GetFirstChild(); |
5340 | 0 | child; |
5341 | 0 | child = child->GetNextSibling()) { |
5342 | 0 | if (Text* text = child->GetAsText()) { |
5343 | 0 | bool ok = text->AppendTextTo(aResult, fallible); |
5344 | 0 | if (!ok) { |
5345 | 0 | return false; |
5346 | 0 | } |
5347 | 0 | } |
5348 | 0 | } |
5349 | 0 | return true; |
5350 | 0 | } |
5351 | | |
5352 | | bool |
5353 | | nsContentUtils::HasNonEmptyTextContent(nsINode* aNode, |
5354 | | TextContentDiscoverMode aDiscoverMode) |
5355 | 0 | { |
5356 | 0 | for (nsIContent* child = aNode->GetFirstChild(); |
5357 | 0 | child; |
5358 | 0 | child = child->GetNextSibling()) { |
5359 | 0 | if (child->IsText() && |
5360 | 0 | child->TextLength() > 0) { |
5361 | 0 | return true; |
5362 | 0 | } |
5363 | 0 | |
5364 | 0 | if (aDiscoverMode == eRecurseIntoChildren && |
5365 | 0 | HasNonEmptyTextContent(child, aDiscoverMode)) { |
5366 | 0 | return true; |
5367 | 0 | } |
5368 | 0 | } |
5369 | 0 |
|
5370 | 0 | return false; |
5371 | 0 | } |
5372 | | |
5373 | | /* static */ |
5374 | | bool |
5375 | | nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode, |
5376 | | const nsIContent* aContent) |
5377 | 0 | { |
5378 | 0 | MOZ_ASSERT(aNode, "Must have a node to work with"); |
5379 | 0 | MOZ_ASSERT(aContent, "Must have a content to work with"); |
5380 | 0 |
|
5381 | 0 | if (!aNode->IsContent()) { |
5382 | 0 | /** |
5383 | 0 | * The root isn't an nsIContent, so it's a document or attribute. The only |
5384 | 0 | * nodes in the same anonymous subtree as it will have a null |
5385 | 0 | * bindingParent. |
5386 | 0 | * |
5387 | 0 | * XXXbz strictly speaking, that's not true for attribute nodes. |
5388 | 0 | */ |
5389 | 0 | return aContent->GetBindingParent() == nullptr; |
5390 | 0 | } |
5391 | 0 | |
5392 | 0 | return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent(); |
5393 | 0 | } |
5394 | | |
5395 | | /* static */ |
5396 | | void |
5397 | | nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) |
5398 | 0 | { |
5399 | 0 | IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); |
5400 | 0 | } |
5401 | | |
5402 | | /* static */ bool |
5403 | | nsContentUtils::SchemeIs(nsIURI* aURI, const char* aScheme) |
5404 | 0 | { |
5405 | 0 | nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); |
5406 | 0 | NS_ENSURE_TRUE(baseURI, false); |
5407 | 0 |
|
5408 | 0 | bool isScheme = false; |
5409 | 0 | return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme; |
5410 | 0 | } |
5411 | | |
5412 | | bool |
5413 | | nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal) |
5414 | 16 | { |
5415 | 16 | MOZ_ASSERT(IsInitialized()); |
5416 | 16 | return aPrincipal == sSystemPrincipal; |
5417 | 16 | } |
5418 | | |
5419 | | bool |
5420 | | nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) |
5421 | 0 | { |
5422 | 0 | nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal); |
5423 | 0 | return !!ep; |
5424 | 0 | } |
5425 | | |
5426 | | nsIPrincipal* |
5427 | | nsContentUtils::GetSystemPrincipal() |
5428 | 11 | { |
5429 | 11 | MOZ_ASSERT(IsInitialized()); |
5430 | 11 | return sSystemPrincipal; |
5431 | 11 | } |
5432 | | |
5433 | | bool |
5434 | | nsContentUtils::CombineResourcePrincipals(nsCOMPtr<nsIPrincipal>* aResourcePrincipal, |
5435 | | nsIPrincipal* aExtraPrincipal) |
5436 | 0 | { |
5437 | 0 | if (!aExtraPrincipal) { |
5438 | 0 | return false; |
5439 | 0 | } |
5440 | 0 | if (!*aResourcePrincipal) { |
5441 | 0 | *aResourcePrincipal = aExtraPrincipal; |
5442 | 0 | return true; |
5443 | 0 | } |
5444 | 0 | if (*aResourcePrincipal == aExtraPrincipal) { |
5445 | 0 | return false; |
5446 | 0 | } |
5447 | 0 | bool subsumes; |
5448 | 0 | if (NS_SUCCEEDED((*aResourcePrincipal)->Subsumes(aExtraPrincipal, &subsumes)) && |
5449 | 0 | subsumes) { |
5450 | 0 | return false; |
5451 | 0 | } |
5452 | 0 | *aResourcePrincipal = sSystemPrincipal; |
5453 | 0 | return true; |
5454 | 0 | } |
5455 | | |
5456 | | /* static */ |
5457 | | void |
5458 | | nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, |
5459 | | nsIURI *aLinkURI, const nsString &aTargetSpec, |
5460 | | bool aClick, bool aIsTrusted) |
5461 | 0 | { |
5462 | 0 | NS_ASSERTION(aPresContext, "Need a nsPresContext"); |
5463 | 0 | MOZ_ASSERT(aLinkURI, "No link URI"); |
5464 | 0 |
|
5465 | 0 | if (aContent->IsEditable()) { |
5466 | 0 | return; |
5467 | 0 | } |
5468 | 0 | |
5469 | 0 | nsILinkHandler *handler = aPresContext->GetLinkHandler(); |
5470 | 0 | if (!handler) { |
5471 | 0 | return; |
5472 | 0 | } |
5473 | 0 | |
5474 | 0 | if (!aClick) { |
5475 | 0 | handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get()); |
5476 | 0 | return; |
5477 | 0 | } |
5478 | 0 | |
5479 | 0 | // Check that this page is allowed to load this URI. |
5480 | 0 | nsresult proceed = NS_OK; |
5481 | 0 |
|
5482 | 0 | if (sSecurityManager) { |
5483 | 0 | uint32_t flag = static_cast<uint32_t>(nsIScriptSecurityManager::STANDARD); |
5484 | 0 | proceed = |
5485 | 0 | sSecurityManager->CheckLoadURIWithPrincipal(aContent->NodePrincipal(), |
5486 | 0 | aLinkURI, flag); |
5487 | 0 | } |
5488 | 0 |
|
5489 | 0 | // Only pass off the click event if the script security manager says it's ok. |
5490 | 0 | // We need to rest aTargetSpec for forced downloads. |
5491 | 0 | if (NS_SUCCEEDED(proceed)) { |
5492 | 0 |
|
5493 | 0 | // A link/area element with a download attribute is allowed to set |
5494 | 0 | // a pseudo Content-Disposition header. |
5495 | 0 | // For security reasons we only allow websites to declare same-origin resources |
5496 | 0 | // as downloadable. If this check fails we will just do the normal thing |
5497 | 0 | // (i.e. navigate to the resource). |
5498 | 0 | nsAutoString fileName; |
5499 | 0 | if ((!aContent->IsHTMLElement(nsGkAtoms::a) && |
5500 | 0 | !aContent->IsHTMLElement(nsGkAtoms::area) && |
5501 | 0 | !aContent->IsSVGElement(nsGkAtoms::a)) || |
5502 | 0 | !aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::download, fileName) || |
5503 | 0 | NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, false, true))) { |
5504 | 0 | fileName.SetIsVoid(true); // No actionable download attribute was found. |
5505 | 0 | } |
5506 | 0 |
|
5507 | 0 | handler->OnLinkClick(aContent, aLinkURI, |
5508 | 0 | fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(), |
5509 | 0 | fileName, nullptr, nullptr, EventStateManager::IsHandlingUserInput(), |
5510 | 0 | aIsTrusted, aContent->NodePrincipal()); |
5511 | 0 | } |
5512 | 0 | } |
5513 | | |
5514 | | /* static */ |
5515 | | void |
5516 | | nsContentUtils::GetLinkLocation(Element* aElement, nsString& aLocationString) |
5517 | 0 | { |
5518 | 0 | nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI(); |
5519 | 0 | if (hrefURI) { |
5520 | 0 | nsAutoCString specUTF8; |
5521 | 0 | nsresult rv = hrefURI->GetSpec(specUTF8); |
5522 | 0 | if (NS_SUCCEEDED(rv)) |
5523 | 0 | CopyUTF8toUTF16(specUTF8, aLocationString); |
5524 | 0 | } |
5525 | 0 | } |
5526 | | |
5527 | | /* static */ |
5528 | | nsIWidget* |
5529 | | nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget) |
5530 | 0 | { |
5531 | 0 | if (!aWidget) |
5532 | 0 | return nullptr; |
5533 | 0 | |
5534 | 0 | return aWidget->GetTopLevelWidget(); |
5535 | 0 | } |
5536 | | |
5537 | | /* static */ |
5538 | | const nsDependentString |
5539 | | nsContentUtils::GetLocalizedEllipsis() |
5540 | 0 | { |
5541 | 0 | static char16_t sBuf[4] = { 0, 0, 0, 0 }; |
5542 | 0 | if (!sBuf[0]) { |
5543 | 0 | nsAutoString tmp; |
5544 | 0 | Preferences::GetLocalizedString("intl.ellipsis", tmp); |
5545 | 0 | uint32_t len = std::min(uint32_t(tmp.Length()), |
5546 | 0 | uint32_t(ArrayLength(sBuf) - 1)); |
5547 | 0 | CopyUnicodeTo(tmp, 0, sBuf, len); |
5548 | 0 | if (!sBuf[0]) |
5549 | 0 | sBuf[0] = char16_t(0x2026); |
5550 | 0 | } |
5551 | 0 | return nsDependentString(sBuf); |
5552 | 0 | } |
5553 | | |
5554 | | /* static */ |
5555 | | void |
5556 | | nsContentUtils::AddScriptBlocker() |
5557 | 0 | { |
5558 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5559 | 0 | if (!sScriptBlockerCount) { |
5560 | 0 | MOZ_ASSERT(sRunnersCountAtFirstBlocker == 0, |
5561 | 0 | "Should not already have a count"); |
5562 | 0 | sRunnersCountAtFirstBlocker = sBlockedScriptRunners ? sBlockedScriptRunners->Length() : 0; |
5563 | 0 | } |
5564 | 0 | ++sScriptBlockerCount; |
5565 | 0 | } |
5566 | | |
5567 | | #ifdef DEBUG |
5568 | | static bool sRemovingScriptBlockers = false; |
5569 | | #endif |
5570 | | |
5571 | | /* static */ |
5572 | | void |
5573 | | nsContentUtils::RemoveScriptBlocker() |
5574 | 0 | { |
5575 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5576 | 0 | MOZ_ASSERT(!sRemovingScriptBlockers); |
5577 | 0 | NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers"); |
5578 | 0 | --sScriptBlockerCount; |
5579 | 0 | if (sScriptBlockerCount) { |
5580 | 0 | return; |
5581 | 0 | } |
5582 | 0 | |
5583 | 0 | if (!sBlockedScriptRunners) { |
5584 | 0 | return; |
5585 | 0 | } |
5586 | 0 | |
5587 | 0 | uint32_t firstBlocker = sRunnersCountAtFirstBlocker; |
5588 | 0 | uint32_t lastBlocker = sBlockedScriptRunners->Length(); |
5589 | 0 | uint32_t originalFirstBlocker = firstBlocker; |
5590 | 0 | uint32_t blockersCount = lastBlocker - firstBlocker; |
5591 | 0 | sRunnersCountAtFirstBlocker = 0; |
5592 | 0 | NS_ASSERTION(firstBlocker <= lastBlocker, |
5593 | 0 | "bad sRunnersCountAtFirstBlocker"); |
5594 | 0 |
|
5595 | 0 | while (firstBlocker < lastBlocker) { |
5596 | 0 | nsCOMPtr<nsIRunnable> runnable; |
5597 | 0 | runnable.swap((*sBlockedScriptRunners)[firstBlocker]); |
5598 | 0 | ++firstBlocker; |
5599 | 0 |
|
5600 | 0 | // Calling the runnable can reenter us |
5601 | 0 | runnable->Run(); |
5602 | 0 | // So can dropping the reference to the runnable |
5603 | 0 | runnable = nullptr; |
5604 | 0 |
|
5605 | 0 | NS_ASSERTION(sRunnersCountAtFirstBlocker == 0, |
5606 | 0 | "Bad count"); |
5607 | 0 | NS_ASSERTION(!sScriptBlockerCount, "This is really bad"); |
5608 | 0 | } |
5609 | | #ifdef DEBUG |
5610 | | AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers); |
5611 | | sRemovingScriptBlockers = true; |
5612 | | #endif |
5613 | | sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount); |
5614 | 0 | } |
5615 | | |
5616 | | /* static */ |
5617 | | nsIWindowProvider* |
5618 | | nsContentUtils::GetWindowProviderForContentProcess() |
5619 | 0 | { |
5620 | 0 | MOZ_ASSERT(XRE_IsContentProcess()); |
5621 | 0 | return ContentChild::GetSingleton(); |
5622 | 0 | } |
5623 | | |
5624 | | /* static */ |
5625 | | already_AddRefed<nsPIDOMWindowOuter> |
5626 | | nsContentUtils::GetMostRecentNonPBWindow() |
5627 | 0 | { |
5628 | 0 | nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); |
5629 | 0 |
|
5630 | 0 | nsCOMPtr<mozIDOMWindowProxy> window; |
5631 | 0 | wm->GetMostRecentNonPBWindow(u"navigator:browser", |
5632 | 0 | getter_AddRefs(window)); |
5633 | 0 | nsCOMPtr<nsPIDOMWindowOuter> pwindow; |
5634 | 0 | pwindow = do_QueryInterface(window); |
5635 | 0 |
|
5636 | 0 | return pwindow.forget(); |
5637 | 0 | } |
5638 | | |
5639 | | /* static */ |
5640 | | void |
5641 | | nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument) |
5642 | 0 | { |
5643 | 0 | nsAutoString msg; |
5644 | 0 | bool privateBrowsing = false; |
5645 | 0 |
|
5646 | 0 | if (aDocument) { |
5647 | 0 | nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI(); |
5648 | 0 | if (uri) { |
5649 | 0 | msg.Append(NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault())); |
5650 | 0 | msg.AppendLiteral(" : "); |
5651 | 0 | } |
5652 | 0 | privateBrowsing = |
5653 | 0 | !!aDocument->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId; |
5654 | 0 | } |
5655 | 0 |
|
5656 | 0 | msg.AppendLiteral("Unable to run script because scripts are blocked internally."); |
5657 | 0 | LogSimpleConsoleError(msg, "DOM", privateBrowsing); |
5658 | 0 | } |
5659 | | |
5660 | | /* static */ |
5661 | | void |
5662 | | nsContentUtils::AddScriptRunner(already_AddRefed<nsIRunnable> aRunnable) |
5663 | 0 | { |
5664 | 0 | nsCOMPtr<nsIRunnable> runnable = aRunnable; |
5665 | 0 | if (!runnable) { |
5666 | 0 | return; |
5667 | 0 | } |
5668 | 0 | |
5669 | 0 | if (sScriptBlockerCount) { |
5670 | 0 | sBlockedScriptRunners->AppendElement(runnable.forget()); |
5671 | 0 | return; |
5672 | 0 | } |
5673 | 0 | |
5674 | 0 | runnable->Run(); |
5675 | 0 | } |
5676 | | |
5677 | | /* static */ |
5678 | | void |
5679 | 0 | nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) { |
5680 | 0 | nsCOMPtr<nsIRunnable> runnable = aRunnable; |
5681 | 0 | AddScriptRunner(runnable.forget()); |
5682 | 0 | } |
5683 | | |
5684 | | /* static */ |
5685 | | void |
5686 | | nsContentUtils::RunInStableState(already_AddRefed<nsIRunnable> aRunnable) |
5687 | 0 | { |
5688 | 0 | MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!"); |
5689 | 0 | CycleCollectedJSContext::Get()->RunInStableState(std::move(aRunnable)); |
5690 | 0 | } |
5691 | | |
5692 | | /* static */ |
5693 | | void |
5694 | | nsContentUtils::AddPendingIDBTransaction(already_AddRefed<nsIRunnable> aTransaction) |
5695 | 0 | { |
5696 | 0 | MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!"); |
5697 | 0 | CycleCollectedJSContext::Get()->AddPendingIDBTransaction(std::move(aTransaction)); |
5698 | 0 | } |
5699 | | |
5700 | | /* static */ |
5701 | | bool |
5702 | | nsContentUtils::IsInStableOrMetaStableState() |
5703 | 0 | { |
5704 | 0 | MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!"); |
5705 | 0 | return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState(); |
5706 | 0 | } |
5707 | | |
5708 | | /* |
5709 | | * Helper function for nsContentUtils::ProcessViewportInfo. |
5710 | | * |
5711 | | * Handles a single key=value pair. If it corresponds to a valid viewport |
5712 | | * attribute, add it to the document header data. No validation is done on the |
5713 | | * value itself (this is done at display time). |
5714 | | */ |
5715 | | static void ProcessViewportToken(nsIDocument *aDocument, |
5716 | 0 | const nsAString &token) { |
5717 | 0 |
|
5718 | 0 | /* Iterators. */ |
5719 | 0 | nsAString::const_iterator tip, tail, end; |
5720 | 0 | token.BeginReading(tip); |
5721 | 0 | tail = tip; |
5722 | 0 | token.EndReading(end); |
5723 | 0 |
|
5724 | 0 | /* Move tip to the '='. */ |
5725 | 0 | while ((tip != end) && (*tip != '=')) |
5726 | 0 | ++tip; |
5727 | 0 |
|
5728 | 0 | /* If we didn't find an '=', punt. */ |
5729 | 0 | if (tip == end) |
5730 | 0 | return; |
5731 | 0 | |
5732 | 0 | /* Extract the key and value. */ |
5733 | 0 | const nsAString &key = |
5734 | 0 | nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(tail, tip), |
5735 | 0 | true); |
5736 | 0 | const nsAString &value = |
5737 | 0 | nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(++tip, end), |
5738 | 0 | true); |
5739 | 0 |
|
5740 | 0 | /* Check for known keys. If we find a match, insert the appropriate |
5741 | 0 | * information into the document header. */ |
5742 | 0 | RefPtr<nsAtom> key_atom = NS_Atomize(key); |
5743 | 0 | if (key_atom == nsGkAtoms::height) |
5744 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_height, value); |
5745 | 0 | else if (key_atom == nsGkAtoms::width) |
5746 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_width, value); |
5747 | 0 | else if (key_atom == nsGkAtoms::initial_scale) |
5748 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_initial_scale, value); |
5749 | 0 | else if (key_atom == nsGkAtoms::minimum_scale) |
5750 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value); |
5751 | 0 | else if (key_atom == nsGkAtoms::maximum_scale) |
5752 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value); |
5753 | 0 | else if (key_atom == nsGkAtoms::user_scalable) |
5754 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value); |
5755 | 0 | } |
5756 | | |
5757 | 0 | #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \ |
5758 | 0 | (c == '\t') || (c == '\n') || (c == '\r')) |
5759 | | |
5760 | | /* static */ |
5761 | | nsresult |
5762 | | nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument, |
5763 | 0 | const nsAString &viewportInfo) { |
5764 | 0 |
|
5765 | 0 | /* We never fail. */ |
5766 | 0 | nsresult rv = NS_OK; |
5767 | 0 |
|
5768 | 0 | aDocument->SetHeaderData(nsGkAtoms::viewport, viewportInfo); |
5769 | 0 |
|
5770 | 0 | /* Iterators. */ |
5771 | 0 | nsAString::const_iterator tip, tail, end; |
5772 | 0 | viewportInfo.BeginReading(tip); |
5773 | 0 | tail = tip; |
5774 | 0 | viewportInfo.EndReading(end); |
5775 | 0 |
|
5776 | 0 | /* Read the tip to the first non-separator character. */ |
5777 | 0 | while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) |
5778 | 0 | ++tip; |
5779 | 0 |
|
5780 | 0 | /* Read through and find tokens separated by separators. */ |
5781 | 0 | while (tip != end) { |
5782 | 0 |
|
5783 | 0 | /* Synchronize tip and tail. */ |
5784 | 0 | tail = tip; |
5785 | 0 |
|
5786 | 0 | /* Advance tip past non-separator characters. */ |
5787 | 0 | while ((tip != end) && !IS_SEPARATOR(*tip)) |
5788 | 0 | ++tip; |
5789 | 0 |
|
5790 | 0 | /* Allow white spaces that surround the '=' character */ |
5791 | 0 | if ((tip != end) && (*tip == '=')) { |
5792 | 0 | ++tip; |
5793 | 0 |
|
5794 | 0 | while ((tip != end) && nsCRT::IsAsciiSpace(*tip)) |
5795 | 0 | ++tip; |
5796 | 0 |
|
5797 | 0 | while ((tip != end) && !(IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) |
5798 | 0 | ++tip; |
5799 | 0 | } |
5800 | 0 |
|
5801 | 0 | /* Our token consists of the characters between tail and tip. */ |
5802 | 0 | ProcessViewportToken(aDocument, Substring(tail, tip)); |
5803 | 0 |
|
5804 | 0 | /* Skip separators. */ |
5805 | 0 | while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) |
5806 | 0 | ++tip; |
5807 | 0 | } |
5808 | 0 |
|
5809 | 0 | return rv; |
5810 | 0 |
|
5811 | 0 | } |
5812 | | |
5813 | | #undef IS_SEPARATOR |
5814 | | |
5815 | | /* static */ |
5816 | | void |
5817 | | nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument) |
5818 | 0 | { |
5819 | 0 | #ifdef MOZ_XUL |
5820 | 0 | nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
5821 | 0 | if (pm && aDocument) { |
5822 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell(); |
5823 | 0 | if (docShellToHide) |
5824 | 0 | pm->HidePopupsInDocShell(docShellToHide); |
5825 | 0 | } |
5826 | 0 | #endif |
5827 | 0 | } |
5828 | | |
5829 | | /* static */ |
5830 | | already_AddRefed<nsIDragSession> |
5831 | | nsContentUtils::GetDragSession() |
5832 | 0 | { |
5833 | 0 | nsCOMPtr<nsIDragSession> dragSession; |
5834 | 0 | nsCOMPtr<nsIDragService> dragService = |
5835 | 0 | do_GetService("@mozilla.org/widget/dragservice;1"); |
5836 | 0 | if (dragService) |
5837 | 0 | dragService->GetCurrentSession(getter_AddRefs(dragSession)); |
5838 | 0 | return dragSession.forget(); |
5839 | 0 | } |
5840 | | |
5841 | | /* static */ |
5842 | | nsresult |
5843 | | nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) |
5844 | 0 | { |
5845 | 0 | if (aDragEvent->mDataTransfer || !aDragEvent->IsTrusted()) { |
5846 | 0 | return NS_OK; |
5847 | 0 | } |
5848 | 0 | |
5849 | 0 | // For dragstart events, the data transfer object is |
5850 | 0 | // created before the event fires, so it should already be set. For other |
5851 | 0 | // drag events, get the object from the drag session. |
5852 | 0 | NS_ASSERTION(aDragEvent->mMessage != eDragStart, |
5853 | 0 | "draggesture event created without a dataTransfer"); |
5854 | 0 |
|
5855 | 0 | nsCOMPtr<nsIDragSession> dragSession = GetDragSession(); |
5856 | 0 | NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress |
5857 | 0 |
|
5858 | 0 | RefPtr<DataTransfer> initialDataTransfer = |
5859 | 0 | dragSession->GetDataTransfer(); |
5860 | 0 | if (!initialDataTransfer) { |
5861 | 0 | // A dataTransfer won't exist when a drag was started by some other |
5862 | 0 | // means, for instance calling the drag service directly, or a drag |
5863 | 0 | // from another application. In either case, a new dataTransfer should |
5864 | 0 | // be created that reflects the data. |
5865 | 0 | initialDataTransfer = |
5866 | 0 | new DataTransfer(aDragEvent->mTarget, aDragEvent->mMessage, true, -1); |
5867 | 0 |
|
5868 | 0 | // now set it in the drag session so we don't need to create it again |
5869 | 0 | dragSession->SetDataTransfer(initialDataTransfer); |
5870 | 0 | } |
5871 | 0 |
|
5872 | 0 | bool isCrossDomainSubFrameDrop = false; |
5873 | 0 | if (aDragEvent->mMessage == eDrop) { |
5874 | 0 | isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent); |
5875 | 0 | } |
5876 | 0 |
|
5877 | 0 | // each event should use a clone of the original dataTransfer. |
5878 | 0 | initialDataTransfer->Clone(aDragEvent->mTarget, aDragEvent->mMessage, |
5879 | 0 | aDragEvent->mUserCancelled, |
5880 | 0 | isCrossDomainSubFrameDrop, |
5881 | 0 | getter_AddRefs(aDragEvent->mDataTransfer)); |
5882 | 0 | if (NS_WARN_IF(!aDragEvent->mDataTransfer)) { |
5883 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
5884 | 0 | } |
5885 | 0 | |
5886 | 0 | // for the dragenter and dragover events, initialize the drop effect |
5887 | 0 | // from the drop action, which platform specific widget code sets before |
5888 | 0 | // the event is fired based on the keyboard state. |
5889 | 0 | if (aDragEvent->mMessage == eDragEnter || aDragEvent->mMessage == eDragOver) { |
5890 | 0 | uint32_t action; |
5891 | 0 | dragSession->GetDragAction(&action); |
5892 | 0 | uint32_t effectAllowed = aDragEvent->mDataTransfer->EffectAllowedInt(); |
5893 | 0 | aDragEvent->mDataTransfer->SetDropEffectInt( |
5894 | 0 | FilterDropEffect(action, effectAllowed)); |
5895 | 0 | } |
5896 | 0 | else if (aDragEvent->mMessage == eDrop || |
5897 | 0 | aDragEvent->mMessage == eDragEnd) { |
5898 | 0 | // For the drop and dragend events, set the drop effect based on the |
5899 | 0 | // last value that the dropEffect had. This will have been set in |
5900 | 0 | // EventStateManager::PostHandleEvent for the last dragenter or |
5901 | 0 | // dragover event. |
5902 | 0 | aDragEvent->mDataTransfer->SetDropEffectInt( |
5903 | 0 | initialDataTransfer->DropEffectInt()); |
5904 | 0 | } |
5905 | 0 |
|
5906 | 0 | return NS_OK; |
5907 | 0 | } |
5908 | | |
5909 | | /* static */ |
5910 | | uint32_t |
5911 | | nsContentUtils::FilterDropEffect(uint32_t aAction, uint32_t aEffectAllowed) |
5912 | 0 | { |
5913 | 0 | // It is possible for the drag action to include more than one action, but |
5914 | 0 | // the widget code which sets the action from the keyboard state should only |
5915 | 0 | // be including one. If multiple actions were set, we just consider them in |
5916 | 0 | // the following order: |
5917 | 0 | // copy, link, move |
5918 | 0 | if (aAction & nsIDragService::DRAGDROP_ACTION_COPY) |
5919 | 0 | aAction = nsIDragService::DRAGDROP_ACTION_COPY; |
5920 | 0 | else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK) |
5921 | 0 | aAction = nsIDragService::DRAGDROP_ACTION_LINK; |
5922 | 0 | else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE) |
5923 | 0 | aAction = nsIDragService::DRAGDROP_ACTION_MOVE; |
5924 | 0 |
|
5925 | 0 | // Filter the action based on the effectAllowed. If the effectAllowed |
5926 | 0 | // doesn't include the action, then that action cannot be done, so adjust |
5927 | 0 | // the action to something that is allowed. For a copy, adjust to move or |
5928 | 0 | // link. For a move, adjust to copy or link. For a link, adjust to move or |
5929 | 0 | // link. Otherwise, use none. |
5930 | 0 | if (aAction & aEffectAllowed || |
5931 | 0 | aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) |
5932 | 0 | return aAction; |
5933 | 0 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE) |
5934 | 0 | return nsIDragService::DRAGDROP_ACTION_MOVE; |
5935 | 0 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY) |
5936 | 0 | return nsIDragService::DRAGDROP_ACTION_COPY; |
5937 | 0 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK) |
5938 | 0 | return nsIDragService::DRAGDROP_ACTION_LINK; |
5939 | 0 | return nsIDragService::DRAGDROP_ACTION_NONE; |
5940 | 0 | } |
5941 | | |
5942 | | /* static */ |
5943 | | bool |
5944 | | nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession, |
5945 | | WidgetDragEvent* aDropEvent) |
5946 | 0 | { |
5947 | 0 | nsCOMPtr<nsIContent> target = do_QueryInterface(aDropEvent->mOriginalTarget); |
5948 | 0 | if (!target) { |
5949 | 0 | return true; |
5950 | 0 | } |
5951 | 0 | |
5952 | 0 | nsIDocument* targetDoc = target->OwnerDoc(); |
5953 | 0 | nsPIDOMWindowOuter* targetWin = targetDoc->GetWindow(); |
5954 | 0 | if (!targetWin) { |
5955 | 0 | return true; |
5956 | 0 | } |
5957 | 0 | |
5958 | 0 | nsCOMPtr<nsIDocShellTreeItem> tdsti = targetWin->GetDocShell(); |
5959 | 0 | if (!tdsti) { |
5960 | 0 | return true; |
5961 | 0 | } |
5962 | 0 | |
5963 | 0 | // Always allow dropping onto chrome shells. |
5964 | 0 | if (tdsti->ItemType() == nsIDocShellTreeItem::typeChrome) { |
5965 | 0 | return false; |
5966 | 0 | } |
5967 | 0 | |
5968 | 0 | // If there is no source node, then this is a drag from another |
5969 | 0 | // application, which should be allowed. |
5970 | 0 | nsCOMPtr<nsIDocument> doc; |
5971 | 0 | aDragSession->GetSourceDocument(getter_AddRefs(doc)); |
5972 | 0 | if (doc) { |
5973 | 0 | // Get each successive parent of the source document and compare it to |
5974 | 0 | // the drop document. If they match, then this is a drag from a child frame. |
5975 | 0 | do { |
5976 | 0 | doc = doc->GetParentDocument(); |
5977 | 0 | if (doc == targetDoc) { |
5978 | 0 | // The drag is from a child frame. |
5979 | 0 | return true; |
5980 | 0 | } |
5981 | 0 | } while (doc); |
5982 | 0 | } |
5983 | 0 |
|
5984 | 0 | return false; |
5985 | 0 | } |
5986 | | |
5987 | | /* static */ |
5988 | | bool |
5989 | | nsContentUtils::URIIsLocalFile(nsIURI *aURI) |
5990 | 0 | { |
5991 | 0 | bool isFile; |
5992 | 0 | nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService); |
5993 | 0 |
|
5994 | 0 | // Important: we do NOT test the entire URI chain here! |
5995 | 0 | return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI, |
5996 | 0 | nsIProtocolHandler::URI_IS_LOCAL_FILE, |
5997 | 0 | &isFile)) && |
5998 | 0 | isFile; |
5999 | 0 | } |
6000 | | |
6001 | | /* static */ |
6002 | | JSContext * |
6003 | | nsContentUtils::GetCurrentJSContext() |
6004 | 4.87M | { |
6005 | 4.87M | MOZ_ASSERT(IsInitialized()); |
6006 | 4.87M | if (!IsJSAPIActive()) { |
6007 | 0 | return nullptr; |
6008 | 0 | } |
6009 | 4.87M | return danger::GetJSContext(); |
6010 | 4.87M | } |
6011 | | |
6012 | | template<typename StringType, typename CharType> |
6013 | | void |
6014 | | _ASCIIToLowerInSitu(StringType& aStr) |
6015 | 0 | { |
6016 | 0 | CharType* iter = aStr.BeginWriting(); |
6017 | 0 | CharType* end = aStr.EndWriting(); |
6018 | 0 | MOZ_ASSERT(iter && end); |
6019 | 0 |
|
6020 | 0 | while (iter != end) { |
6021 | 0 | CharType c = *iter; |
6022 | 0 | if (c >= 'A' && c <= 'Z') { |
6023 | 0 | *iter = c + ('a' - 'A'); |
6024 | 0 | } |
6025 | 0 | ++iter; |
6026 | 0 | } |
6027 | 0 | } Unexecuted instantiation: void _ASCIIToLowerInSitu<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t>&) Unexecuted instantiation: void _ASCIIToLowerInSitu<nsTSubstring<char>, char>(nsTSubstring<char>&) |
6028 | | |
6029 | | /* static */ |
6030 | | void |
6031 | | nsContentUtils::ASCIIToLower(nsAString& aStr) |
6032 | 0 | { |
6033 | 0 | return _ASCIIToLowerInSitu<nsAString, char16_t>(aStr); |
6034 | 0 | } |
6035 | | |
6036 | | /* static */ |
6037 | | void |
6038 | | nsContentUtils::ASCIIToLower(nsACString& aStr) |
6039 | 0 | { |
6040 | 0 | return _ASCIIToLowerInSitu<nsACString, char>(aStr); |
6041 | 0 | } |
6042 | | |
6043 | | template<typename StringType, typename CharType> |
6044 | | void |
6045 | | _ASCIIToLowerCopy(const StringType& aSource, StringType& aDest) |
6046 | 0 | { |
6047 | 0 | uint32_t len = aSource.Length(); |
6048 | 0 | aDest.SetLength(len); |
6049 | 0 | MOZ_ASSERT(aDest.Length() == len); |
6050 | 0 |
|
6051 | 0 | CharType* dest = aDest.BeginWriting(); |
6052 | 0 | MOZ_ASSERT(dest); |
6053 | 0 |
|
6054 | 0 | const CharType* iter = aSource.BeginReading(); |
6055 | 0 | const CharType* end = aSource.EndReading(); |
6056 | 0 | while (iter != end) { |
6057 | 0 | CharType c = *iter; |
6058 | 0 | *dest = (c >= 'A' && c <= 'Z') ? |
6059 | 0 | c + ('a' - 'A') : c; |
6060 | 0 | ++iter; |
6061 | 0 | ++dest; |
6062 | 0 | } |
6063 | 0 | } Unexecuted instantiation: void _ASCIIToLowerCopy<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t> const&, nsTSubstring<char16_t>&) Unexecuted instantiation: void _ASCIIToLowerCopy<nsTSubstring<char>, char>(nsTSubstring<char> const&, nsTSubstring<char>&) |
6064 | | |
6065 | | /* static */ |
6066 | | void |
6067 | 0 | nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest) { |
6068 | 0 | return _ASCIIToLowerCopy<nsAString, char16_t>(aSource, aDest); |
6069 | 0 | } |
6070 | | |
6071 | | /* static */ |
6072 | | void |
6073 | 0 | nsContentUtils::ASCIIToLower(const nsACString& aSource, nsACString& aDest) { |
6074 | 0 | return _ASCIIToLowerCopy<nsACString, char>(aSource, aDest); |
6075 | 0 | } |
6076 | | |
6077 | | |
6078 | | template<typename StringType, typename CharType> |
6079 | | void |
6080 | | _ASCIIToUpperInSitu(StringType& aStr) |
6081 | 0 | { |
6082 | 0 | CharType* iter = aStr.BeginWriting(); |
6083 | 0 | CharType* end = aStr.EndWriting(); |
6084 | 0 | MOZ_ASSERT(iter && end); |
6085 | 0 |
|
6086 | 0 | while (iter != end) { |
6087 | 0 | CharType c = *iter; |
6088 | 0 | if (c >= 'a' && c <= 'z') { |
6089 | 0 | *iter = c + ('A' - 'a'); |
6090 | 0 | } |
6091 | 0 | ++iter; |
6092 | 0 | } |
6093 | 0 | } Unexecuted instantiation: void _ASCIIToUpperInSitu<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t>&) Unexecuted instantiation: void _ASCIIToUpperInSitu<nsTSubstring<char>, char>(nsTSubstring<char>&) |
6094 | | |
6095 | | /* static */ |
6096 | | void |
6097 | | nsContentUtils::ASCIIToUpper(nsAString& aStr) |
6098 | 0 | { |
6099 | 0 | return _ASCIIToUpperInSitu<nsAString, char16_t>(aStr); |
6100 | 0 | } |
6101 | | |
6102 | | /* static */ |
6103 | | void |
6104 | | nsContentUtils::ASCIIToUpper(nsACString& aStr) |
6105 | 0 | { |
6106 | 0 | return _ASCIIToUpperInSitu<nsACString, char>(aStr); |
6107 | 0 | } |
6108 | | |
6109 | | template<typename StringType, typename CharType> |
6110 | | void |
6111 | | _ASCIIToUpperCopy(const StringType& aSource, StringType& aDest) |
6112 | 0 | { |
6113 | 0 | uint32_t len = aSource.Length(); |
6114 | 0 | aDest.SetLength(len); |
6115 | 0 | MOZ_ASSERT(aDest.Length() == len); |
6116 | 0 |
|
6117 | 0 | CharType* dest = aDest.BeginWriting(); |
6118 | 0 | MOZ_ASSERT(dest); |
6119 | 0 |
|
6120 | 0 | const CharType* iter = aSource.BeginReading(); |
6121 | 0 | const CharType* end = aSource.EndReading(); |
6122 | 0 | while (iter != end) { |
6123 | 0 | CharType c = *iter; |
6124 | 0 | *dest = (c >= 'a' && c <= 'z') ? |
6125 | 0 | c + ('A' - 'a') : c; |
6126 | 0 | ++iter; |
6127 | 0 | ++dest; |
6128 | 0 | } |
6129 | 0 | } Unexecuted instantiation: void _ASCIIToUpperCopy<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t> const&, nsTSubstring<char16_t>&) Unexecuted instantiation: void _ASCIIToUpperCopy<nsTSubstring<char>, char>(nsTSubstring<char> const&, nsTSubstring<char>&) |
6130 | | |
6131 | | /* static */ |
6132 | | void |
6133 | | nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest) |
6134 | 0 | { |
6135 | 0 | return _ASCIIToUpperCopy<nsAString, char16_t>(aSource, aDest); |
6136 | 0 | } |
6137 | | |
6138 | | /* static */ |
6139 | | void |
6140 | | nsContentUtils::ASCIIToUpper(const nsACString& aSource, nsACString& aDest) |
6141 | 0 | { |
6142 | 0 | return _ASCIIToUpperCopy<nsACString, char>(aSource, aDest); |
6143 | 0 | } |
6144 | | |
6145 | | /* static */ |
6146 | | bool |
6147 | | nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1, |
6148 | | const nsAString& aStr2) |
6149 | 191k | { |
6150 | 191k | uint32_t len = aStr1.Length(); |
6151 | 191k | if (len != aStr2.Length()) { |
6152 | 188k | return false; |
6153 | 188k | } |
6154 | 3.66k | |
6155 | 3.66k | const char16_t* str1 = aStr1.BeginReading(); |
6156 | 3.66k | const char16_t* str2 = aStr2.BeginReading(); |
6157 | 3.66k | const char16_t* end = str1 + len; |
6158 | 3.66k | |
6159 | 35.6k | while (str1 < end) { |
6160 | 34.3k | char16_t c1 = *str1++; |
6161 | 34.3k | char16_t c2 = *str2++; |
6162 | 34.3k | |
6163 | 34.3k | // First check if any bits other than the 0x0020 differs |
6164 | 34.3k | if ((c1 ^ c2) & 0xffdf) { |
6165 | 2.29k | return false; |
6166 | 2.29k | } |
6167 | 32.0k | |
6168 | 32.0k | // We know they can only differ in the 0x0020 bit. |
6169 | 32.0k | // Likely the two chars are the same, so check that first |
6170 | 32.0k | if (c1 != c2) { |
6171 | 470 | // They do differ, but since it's only in the 0x0020 bit, check if it's |
6172 | 470 | // the same ascii char, but just differing in case |
6173 | 470 | char16_t c1Upper = c1 & 0xffdf; |
6174 | 470 | if (!('A' <= c1Upper && c1Upper <= 'Z')) { |
6175 | 0 | return false; |
6176 | 0 | } |
6177 | 470 | } |
6178 | 32.0k | } |
6179 | 3.66k | |
6180 | 3.66k | return true; |
6181 | 3.66k | } |
6182 | | |
6183 | | /* static */ |
6184 | | bool |
6185 | | nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr) |
6186 | 0 | { |
6187 | 0 | const char16_t* iter = aStr.BeginReading(); |
6188 | 0 | const char16_t* end = aStr.EndReading(); |
6189 | 0 | while (iter != end) { |
6190 | 0 | char16_t c = *iter; |
6191 | 0 | if (c >= 'A' && c <= 'Z') { |
6192 | 0 | return true; |
6193 | 0 | } |
6194 | 0 | ++iter; |
6195 | 0 | } |
6196 | 0 |
|
6197 | 0 | return false; |
6198 | 0 | } |
6199 | | |
6200 | | /* static */ |
6201 | | nsIInterfaceRequestor* |
6202 | | nsContentUtils::SameOriginChecker() |
6203 | 0 | { |
6204 | 0 | if (!sSameOriginChecker) { |
6205 | 0 | sSameOriginChecker = new SameOriginCheckerImpl(); |
6206 | 0 | NS_ADDREF(sSameOriginChecker); |
6207 | 0 | } |
6208 | 0 | return sSameOriginChecker; |
6209 | 0 | } |
6210 | | |
6211 | | /* static */ |
6212 | | nsresult |
6213 | | nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel) |
6214 | 0 | { |
6215 | 0 | if (!nsContentUtils::GetSecurityManager()) |
6216 | 0 | return NS_ERROR_NOT_AVAILABLE; |
6217 | 0 | |
6218 | 0 | nsCOMPtr<nsIPrincipal> oldPrincipal; |
6219 | 0 | nsContentUtils::GetSecurityManager()-> |
6220 | 0 | GetChannelResultPrincipal(aOldChannel, getter_AddRefs(oldPrincipal)); |
6221 | 0 |
|
6222 | 0 | nsCOMPtr<nsIURI> newURI; |
6223 | 0 | aNewChannel->GetURI(getter_AddRefs(newURI)); |
6224 | 0 | nsCOMPtr<nsIURI> newOriginalURI; |
6225 | 0 | aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); |
6226 | 0 |
|
6227 | 0 | NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI); |
6228 | 0 |
|
6229 | 0 | nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false); |
6230 | 0 | if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) { |
6231 | 0 | rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false); |
6232 | 0 | } |
6233 | 0 |
|
6234 | 0 | return rv; |
6235 | 0 | } |
6236 | | |
6237 | | NS_IMPL_ISUPPORTS(SameOriginCheckerImpl, |
6238 | | nsIChannelEventSink, |
6239 | | nsIInterfaceRequestor) |
6240 | | |
6241 | | NS_IMETHODIMP |
6242 | | SameOriginCheckerImpl::AsyncOnChannelRedirect(nsIChannel* aOldChannel, |
6243 | | nsIChannel* aNewChannel, |
6244 | | uint32_t aFlags, |
6245 | | nsIAsyncVerifyRedirectCallback* cb) |
6246 | 0 | { |
6247 | 0 | MOZ_ASSERT(aNewChannel, "Redirecting to null channel?"); |
6248 | 0 |
|
6249 | 0 | nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel); |
6250 | 0 | if (NS_SUCCEEDED(rv)) { |
6251 | 0 | cb->OnRedirectVerifyCallback(NS_OK); |
6252 | 0 | } |
6253 | 0 |
|
6254 | 0 | return rv; |
6255 | 0 | } |
6256 | | |
6257 | | NS_IMETHODIMP |
6258 | | SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult) |
6259 | 0 | { |
6260 | 0 | return QueryInterface(aIID, aResult); |
6261 | 0 | } |
6262 | | |
6263 | | /* static */ |
6264 | | nsresult |
6265 | | nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsACString& aOrigin) |
6266 | 0 | { |
6267 | 0 | MOZ_ASSERT(aPrincipal, "missing principal"); |
6268 | 0 |
|
6269 | 0 | aOrigin.Truncate(); |
6270 | 0 |
|
6271 | 0 | nsCOMPtr<nsIURI> uri; |
6272 | 0 | nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); |
6273 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6274 | 0 |
|
6275 | 0 | if (uri) { |
6276 | 0 | return GetASCIIOrigin(uri, aOrigin); |
6277 | 0 | } |
6278 | 0 | |
6279 | 0 | aOrigin.AssignLiteral("null"); |
6280 | 0 |
|
6281 | 0 | return NS_OK; |
6282 | 0 | } |
6283 | | |
6284 | | /* static */ |
6285 | | nsresult |
6286 | | nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin) |
6287 | 0 | { |
6288 | 0 | MOZ_ASSERT(aURI, "missing uri"); |
6289 | 0 |
|
6290 | 0 | bool isBlobURL = false; |
6291 | 0 | nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL); |
6292 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6293 | 0 |
|
6294 | 0 | // For Blob URI, the path is the URL of the owning page. |
6295 | 0 | if (isBlobURL) { |
6296 | 0 | nsAutoCString path; |
6297 | 0 | rv = aURI->GetPathQueryRef(path); |
6298 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6299 | 0 |
|
6300 | 0 | nsCOMPtr<nsIURI> uri; |
6301 | 0 | nsresult rv = NS_NewURI(getter_AddRefs(uri), path); |
6302 | 0 | if (NS_FAILED(rv)) { |
6303 | 0 | aOrigin.AssignLiteral("null"); |
6304 | 0 | return NS_OK; |
6305 | 0 | } |
6306 | 0 | |
6307 | 0 | return GetASCIIOrigin(uri, aOrigin); |
6308 | 0 | } |
6309 | 0 | |
6310 | 0 | aOrigin.Truncate(); |
6311 | 0 |
|
6312 | 0 | nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); |
6313 | 0 | NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); |
6314 | 0 |
|
6315 | 0 | nsCString host; |
6316 | 0 | rv = uri->GetAsciiHost(host); |
6317 | 0 |
|
6318 | 0 | if (NS_SUCCEEDED(rv) && !host.IsEmpty()) { |
6319 | 0 | nsCString scheme; |
6320 | 0 | rv = uri->GetScheme(scheme); |
6321 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6322 | 0 |
|
6323 | 0 | int32_t port = -1; |
6324 | 0 | uri->GetPort(&port); |
6325 | 0 | if (port != -1 && port == NS_GetDefaultPort(scheme.get())) |
6326 | 0 | port = -1; |
6327 | 0 |
|
6328 | 0 | nsCString hostPort; |
6329 | 0 | rv = NS_GenerateHostPort(host, port, hostPort); |
6330 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6331 | 0 |
|
6332 | 0 | aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort; |
6333 | 0 | } |
6334 | 0 | else { |
6335 | 0 | aOrigin.AssignLiteral("null"); |
6336 | 0 | } |
6337 | 0 |
|
6338 | 0 | return NS_OK; |
6339 | 0 | } |
6340 | | |
6341 | | /* static */ |
6342 | | nsresult |
6343 | | nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin) |
6344 | 0 | { |
6345 | 0 | MOZ_ASSERT(aPrincipal, "missing principal"); |
6346 | 0 |
|
6347 | 0 | aOrigin.Truncate(); |
6348 | 0 |
|
6349 | 0 | nsCOMPtr<nsIURI> uri; |
6350 | 0 | nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); |
6351 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6352 | 0 |
|
6353 | 0 | if (uri) { |
6354 | 0 | return GetUTFOrigin(uri, aOrigin); |
6355 | 0 | } |
6356 | 0 | |
6357 | 0 | aOrigin.AssignLiteral("null"); |
6358 | 0 |
|
6359 | 0 | return NS_OK; |
6360 | 0 | } |
6361 | | |
6362 | | /* static */ |
6363 | | nsresult |
6364 | | nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin) |
6365 | 0 | { |
6366 | 0 | MOZ_ASSERT(aURI, "missing uri"); |
6367 | 0 | nsresult rv; |
6368 | 0 |
|
6369 | | #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) |
6370 | | // Check if either URI has a special origin. |
6371 | | nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin = do_QueryInterface(aURI); |
6372 | | if (uriWithSpecialOrigin) { |
6373 | | nsCOMPtr<nsIURI> origin; |
6374 | | rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin)); |
6375 | | NS_ENSURE_SUCCESS(rv, rv); |
6376 | | |
6377 | | return GetUTFOrigin(origin, aOrigin); |
6378 | | } |
6379 | | #endif |
6380 | |
|
6381 | 0 | bool isBlobURL = false; |
6382 | 0 | rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL); |
6383 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6384 | 0 |
|
6385 | 0 | // For Blob URI, the path is the URL of the owning page. |
6386 | 0 | if (isBlobURL) { |
6387 | 0 | nsAutoCString path; |
6388 | 0 | rv = aURI->GetPathQueryRef(path); |
6389 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6390 | 0 |
|
6391 | 0 | nsCOMPtr<nsIURI> uri; |
6392 | 0 | nsresult rv = NS_NewURI(getter_AddRefs(uri), path); |
6393 | 0 | if (NS_FAILED(rv)) { |
6394 | 0 | aOrigin.AssignLiteral("null"); |
6395 | 0 | return NS_OK; |
6396 | 0 | } |
6397 | 0 | |
6398 | 0 | return GetUTFOrigin(uri, aOrigin); |
6399 | 0 | } |
6400 | 0 | |
6401 | 0 | aOrigin.Truncate(); |
6402 | 0 |
|
6403 | 0 | nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); |
6404 | 0 | NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); |
6405 | 0 |
|
6406 | 0 | nsCString host; |
6407 | 0 | rv = uri->GetHost(host); |
6408 | 0 |
|
6409 | 0 | if (NS_SUCCEEDED(rv) && !host.IsEmpty()) { |
6410 | 0 | nsCString scheme; |
6411 | 0 | rv = uri->GetScheme(scheme); |
6412 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6413 | 0 |
|
6414 | 0 | int32_t port = -1; |
6415 | 0 | uri->GetPort(&port); |
6416 | 0 | if (port != -1 && port == NS_GetDefaultPort(scheme.get())) |
6417 | 0 | port = -1; |
6418 | 0 |
|
6419 | 0 | nsCString hostPort; |
6420 | 0 | rv = NS_GenerateHostPort(host, port, hostPort); |
6421 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6422 | 0 |
|
6423 | 0 | aOrigin = NS_ConvertUTF8toUTF16( |
6424 | 0 | scheme + NS_LITERAL_CSTRING("://") + hostPort); |
6425 | 0 | } |
6426 | 0 | else { |
6427 | 0 | aOrigin.AssignLiteral("null"); |
6428 | 0 | } |
6429 | 0 |
|
6430 | 0 | return NS_OK; |
6431 | 0 | } |
6432 | | |
6433 | | /* static */ |
6434 | | bool |
6435 | | nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal) |
6436 | 0 | { |
6437 | 0 | nsCOMPtr<nsIURI> channelURI; |
6438 | 0 | nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); |
6439 | 0 | NS_ENSURE_SUCCESS(rv, false); |
6440 | 0 |
|
6441 | 0 | return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false, aAllowIfInheritsPrincipal)); |
6442 | 0 | } |
6443 | | |
6444 | | /* static */ |
6445 | | bool |
6446 | | nsContentUtils::CanAccessNativeAnon() |
6447 | 0 | { |
6448 | 0 | return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL(); |
6449 | 0 | } |
6450 | | |
6451 | | /* static */ nsresult |
6452 | | nsContentUtils::DispatchXULCommand(nsIContent* aTarget, |
6453 | | bool aTrusted, |
6454 | | Event* aSourceEvent, |
6455 | | nsIPresShell* aShell, |
6456 | | bool aCtrl, |
6457 | | bool aAlt, |
6458 | | bool aShift, |
6459 | | bool aMeta, |
6460 | | uint16_t aInputSource) |
6461 | 0 | { |
6462 | 0 | NS_ENSURE_STATE(aTarget); |
6463 | 0 | nsIDocument* doc = aTarget->OwnerDoc(); |
6464 | 0 | nsPresContext* presContext = doc->GetPresContext(); |
6465 | 0 |
|
6466 | 0 | RefPtr<XULCommandEvent> xulCommand = new XULCommandEvent(doc, presContext, |
6467 | 0 | nullptr); |
6468 | 0 | xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"), true, true, |
6469 | 0 | nsGlobalWindowInner::Cast(doc->GetInnerWindow()), |
6470 | 0 | 0, aCtrl, aAlt, aShift, |
6471 | 0 | aMeta, |
6472 | 0 | aSourceEvent, |
6473 | 0 | aInputSource, IgnoreErrors()); |
6474 | 0 |
|
6475 | 0 | if (aShell) { |
6476 | 0 | nsEventStatus status = nsEventStatus_eIgnore; |
6477 | 0 | nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell; |
6478 | 0 | return aShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status); |
6479 | 0 | } |
6480 | 0 | |
6481 | 0 | ErrorResult rv; |
6482 | 0 | aTarget->DispatchEvent(*xulCommand, rv); |
6483 | 0 | return rv.StealNSResult(); |
6484 | 0 | } |
6485 | | |
6486 | | // static |
6487 | | nsresult |
6488 | | nsContentUtils::WrapNative(JSContext *cx, nsISupports *native, |
6489 | | nsWrapperCache *cache, const nsIID* aIID, |
6490 | | JS::MutableHandle<JS::Value> vp, bool aAllowWrapping) |
6491 | 1.62M | { |
6492 | 1.62M | MOZ_ASSERT(cx == GetCurrentJSContext()); |
6493 | 1.62M | |
6494 | 1.62M | if (!native) { |
6495 | 0 | vp.setNull(); |
6496 | 0 |
|
6497 | 0 | return NS_OK; |
6498 | 0 | } |
6499 | 1.62M | |
6500 | 1.62M | JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp); |
6501 | 1.62M | if (wrapper) { |
6502 | 0 | return NS_OK; |
6503 | 0 | } |
6504 | 1.62M | |
6505 | 1.62M | NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED); |
6506 | 1.62M | |
6507 | 1.62M | if (!NS_IsMainThread()) { |
6508 | 0 | MOZ_CRASH(); |
6509 | 0 | } |
6510 | 1.62M | |
6511 | 1.62M | JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx)); |
6512 | 1.62M | nsresult rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID, |
6513 | 1.62M | aAllowWrapping, vp); |
6514 | 1.62M | return rv; |
6515 | 1.62M | } |
6516 | | |
6517 | | nsresult |
6518 | | nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData, |
6519 | | JSObject** aResult) |
6520 | 0 | { |
6521 | 0 | if (!aCx) { |
6522 | 0 | return NS_ERROR_FAILURE; |
6523 | 0 | } |
6524 | 0 | |
6525 | 0 | int32_t dataLen = aData.Length(); |
6526 | 0 | *aResult = JS_NewArrayBuffer(aCx, dataLen); |
6527 | 0 | if (!*aResult) { |
6528 | 0 | return NS_ERROR_FAILURE; |
6529 | 0 | } |
6530 | 0 | |
6531 | 0 | if (dataLen > 0) { |
6532 | 0 | NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?"); |
6533 | 0 | JS::AutoCheckCannotGC nogc; |
6534 | 0 | bool isShared; |
6535 | 0 | memcpy(JS_GetArrayBufferData(*aResult, &isShared, nogc), aData.BeginReading(), dataLen); |
6536 | 0 | MOZ_ASSERT(!isShared); |
6537 | 0 | } |
6538 | 0 |
|
6539 | 0 | return NS_OK; |
6540 | 0 | } |
6541 | | |
6542 | | void |
6543 | | nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr) |
6544 | 0 | { |
6545 | 0 | // In common cases where we don't have nulls in the |
6546 | 0 | // string we can simple simply bypass the checking code. |
6547 | 0 | int32_t firstNullPos = aInStr.FindChar('\0'); |
6548 | 0 | if (firstNullPos == kNotFound) { |
6549 | 0 | aOutStr.Assign(aInStr); |
6550 | 0 | return; |
6551 | 0 | } |
6552 | 0 | |
6553 | 0 | aOutStr.SetCapacity(aInStr.Length() - 1); |
6554 | 0 | nsAString::const_iterator start, end; |
6555 | 0 | aInStr.BeginReading(start); |
6556 | 0 | aInStr.EndReading(end); |
6557 | 0 | while (start != end) { |
6558 | 0 | if (*start != '\0') |
6559 | 0 | aOutStr.Append(*start); |
6560 | 0 | ++start; |
6561 | 0 | } |
6562 | 0 | } |
6563 | | |
6564 | | struct ClassMatchingInfo { |
6565 | | AtomArray mClasses; |
6566 | | nsCaseTreatment mCaseTreatment; |
6567 | | }; |
6568 | | |
6569 | | // static |
6570 | | bool |
6571 | | nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID, |
6572 | | nsAtom* aAtom, void* aData) |
6573 | 0 | { |
6574 | 0 | // We can't match if there are no class names |
6575 | 0 | const nsAttrValue* classAttr = aElement->GetClasses(); |
6576 | 0 | if (!classAttr) { |
6577 | 0 | return false; |
6578 | 0 | } |
6579 | 0 | |
6580 | 0 | // need to match *all* of the classes |
6581 | 0 | ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); |
6582 | 0 | uint32_t length = info->mClasses.Length(); |
6583 | 0 | if (!length) { |
6584 | 0 | // If we actually had no classes, don't match. |
6585 | 0 | return false; |
6586 | 0 | } |
6587 | 0 | uint32_t i; |
6588 | 0 | for (i = 0; i < length; ++i) { |
6589 | 0 | if (!classAttr->Contains(info->mClasses[i], |
6590 | 0 | info->mCaseTreatment)) { |
6591 | 0 | return false; |
6592 | 0 | } |
6593 | 0 | } |
6594 | 0 |
|
6595 | 0 | return true; |
6596 | 0 | } |
6597 | | |
6598 | | // static |
6599 | | void |
6600 | | nsContentUtils::DestroyClassNameArray(void* aData) |
6601 | 0 | { |
6602 | 0 | ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); |
6603 | 0 | delete info; |
6604 | 0 | } |
6605 | | |
6606 | | // static |
6607 | | void* |
6608 | | nsContentUtils::AllocClassMatchingInfo(nsINode* aRootNode, |
6609 | | const nsString* aClasses) |
6610 | 0 | { |
6611 | 0 | nsAttrValue attrValue; |
6612 | 0 | attrValue.ParseAtomArray(*aClasses); |
6613 | 0 | // nsAttrValue::Equals is sensitive to order, so we'll send an array |
6614 | 0 | auto* info = new ClassMatchingInfo; |
6615 | 0 | if (attrValue.Type() == nsAttrValue::eAtomArray) { |
6616 | 0 | info->mClasses.SwapElements(*(attrValue.GetAtomArrayValue())); |
6617 | 0 | } else if (attrValue.Type() == nsAttrValue::eAtom) { |
6618 | 0 | info->mClasses.AppendElement(attrValue.GetAtomValue()); |
6619 | 0 | } |
6620 | 0 |
|
6621 | 0 | info->mCaseTreatment = |
6622 | 0 | aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ? |
6623 | 0 | eIgnoreCase : eCaseMatters; |
6624 | 0 | return info; |
6625 | 0 | } |
6626 | | |
6627 | | // static |
6628 | | bool |
6629 | | nsContentUtils::IsFocusedContent(const nsIContent* aContent) |
6630 | 0 | { |
6631 | 0 | nsFocusManager* fm = nsFocusManager::GetFocusManager(); |
6632 | 0 |
|
6633 | 0 | return fm && fm->GetFocusedElement() == aContent; |
6634 | 0 | } |
6635 | | |
6636 | | bool |
6637 | | nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent) |
6638 | 0 | { |
6639 | 0 | nsIDocument* doc = aContent->GetComposedDoc(); |
6640 | 0 | if (!doc) { |
6641 | 0 | return false; |
6642 | 0 | } |
6643 | 0 | |
6644 | 0 | // If the subdocument lives in another process, the frame is |
6645 | 0 | // tabbable. |
6646 | 0 | if (EventStateManager::IsRemoteTarget(aContent)) { |
6647 | 0 | return true; |
6648 | 0 | } |
6649 | 0 | |
6650 | 0 | // XXXbz should this use OwnerDoc() for GetSubDocumentFor? |
6651 | 0 | // sXBL/XBL2 issue! |
6652 | 0 | nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); |
6653 | 0 | if (!subDoc) { |
6654 | 0 | return false; |
6655 | 0 | } |
6656 | 0 | |
6657 | 0 | nsCOMPtr<nsIDocShell> docShell = subDoc->GetDocShell(); |
6658 | 0 | if (!docShell) { |
6659 | 0 | return false; |
6660 | 0 | } |
6661 | 0 | |
6662 | 0 | nsCOMPtr<nsIContentViewer> contentViewer; |
6663 | 0 | docShell->GetContentViewer(getter_AddRefs(contentViewer)); |
6664 | 0 | if (!contentViewer) { |
6665 | 0 | return false; |
6666 | 0 | } |
6667 | 0 | |
6668 | 0 | nsCOMPtr<nsIContentViewer> zombieViewer; |
6669 | 0 | contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer)); |
6670 | 0 |
|
6671 | 0 | // If there are 2 viewers for the current docshell, that |
6672 | 0 | // means the current document may be a zombie document. |
6673 | 0 | // While load and pageshow events are dispatched, zombie viewer is the old, |
6674 | 0 | // to be hidden document. |
6675 | 0 | if (zombieViewer) { |
6676 | 0 | bool inOnLoad = false; |
6677 | 0 | docShell->GetIsExecutingOnLoadHandler(&inOnLoad); |
6678 | 0 | return inOnLoad; |
6679 | 0 | } |
6680 | 0 | |
6681 | 0 | return true; |
6682 | 0 | } |
6683 | | |
6684 | | bool |
6685 | | nsContentUtils::IsUserFocusIgnored(nsINode* aNode) |
6686 | 0 | { |
6687 | 0 | if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) { |
6688 | 0 | return false; |
6689 | 0 | } |
6690 | 0 | |
6691 | 0 | // Check if our mozbrowser iframe ancestors has ignoreuserfocus attribute. |
6692 | 0 | while (aNode) { |
6693 | 0 | nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aNode); |
6694 | 0 | if (browserFrame && |
6695 | 0 | aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::ignoreuserfocus) && |
6696 | 0 | browserFrame->GetReallyIsBrowser()) { |
6697 | 0 | return true; |
6698 | 0 | } |
6699 | 0 | nsPIDOMWindowOuter* win = aNode->OwnerDoc()->GetWindow(); |
6700 | 0 | aNode = win ? win->GetFrameElementInternal() : nullptr; |
6701 | 0 | } |
6702 | 0 |
|
6703 | 0 | return false; |
6704 | 0 | } |
6705 | | |
6706 | | bool |
6707 | | nsContentUtils::HasScrollgrab(nsIContent* aContent) |
6708 | 0 | { |
6709 | 0 | // If we ever standardize this feature we'll want to hook this up properly |
6710 | 0 | // again. For now we're removing all the DOM-side code related to it but |
6711 | 0 | // leaving the layout and APZ handling for it in place. |
6712 | 0 | return false; |
6713 | 0 | } |
6714 | | |
6715 | | void |
6716 | | nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter* aWindow) |
6717 | 0 | { |
6718 | 0 | if (!aWindow) { |
6719 | 0 | return; |
6720 | 0 | } |
6721 | 0 | |
6722 | 0 | // Note that because FlushPendingNotifications flushes parents, this |
6723 | 0 | // is O(N^2) in docshell tree depth. However, the docshell tree is |
6724 | 0 | // usually pretty shallow. |
6725 | 0 | |
6726 | 0 | if (nsCOMPtr<nsIDocument> doc = aWindow->GetDoc()) { |
6727 | 0 | doc->FlushPendingNotifications(FlushType::Layout); |
6728 | 0 | } |
6729 | 0 |
|
6730 | 0 | if (nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell()) { |
6731 | 0 | int32_t i = 0, i_end; |
6732 | 0 | docShell->GetChildCount(&i_end); |
6733 | 0 | for (; i < i_end; ++i) { |
6734 | 0 | nsCOMPtr<nsIDocShellTreeItem> item; |
6735 | 0 | if (docShell->GetChildAt(i, getter_AddRefs(item)) == NS_OK && item) { |
6736 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> win = item->GetWindow()) { |
6737 | 0 | FlushLayoutForTree(win); |
6738 | 0 | } |
6739 | 0 | } |
6740 | 0 | } |
6741 | 0 | } |
6742 | 0 | } |
6743 | | |
6744 | | void nsContentUtils::RemoveNewlines(nsString &aString) |
6745 | 0 | { |
6746 | 0 | aString.StripCRLF(); |
6747 | 0 | } |
6748 | | |
6749 | | void |
6750 | | nsContentUtils::PlatformToDOMLineBreaks(nsString &aString) |
6751 | 0 | { |
6752 | 0 | if (!PlatformToDOMLineBreaks(aString, fallible)) { |
6753 | 0 | aString.AllocFailed(aString.Length()); |
6754 | 0 | } |
6755 | 0 | } |
6756 | | |
6757 | | bool |
6758 | | nsContentUtils::PlatformToDOMLineBreaks(nsString& aString, const fallible_t& aFallible) |
6759 | 0 | { |
6760 | 0 | if (aString.FindChar(char16_t('\r')) != -1) { |
6761 | 0 | // Windows linebreaks: Map CRLF to LF: |
6762 | 0 | if (!aString.ReplaceSubstring(u"\r\n", u"\n", aFallible)) { |
6763 | 0 | return false; |
6764 | 0 | } |
6765 | 0 | |
6766 | 0 | // Mac linebreaks: Map any remaining CR to LF: |
6767 | 0 | if (!aString.ReplaceSubstring(u"\r", u"\n", aFallible)) { |
6768 | 0 | return false; |
6769 | 0 | } |
6770 | 0 | } |
6771 | 0 | |
6772 | 0 | return true; |
6773 | 0 | } |
6774 | | |
6775 | | void |
6776 | | nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer* aBuf, |
6777 | | nsAString& aResultString) |
6778 | 0 | { |
6779 | 0 | MOZ_ASSERT(aBuf, "Expecting a non-null string buffer"); |
6780 | 0 |
|
6781 | 0 | uint32_t stringLen = NS_strlen(static_cast<char16_t*>(aBuf->Data())); |
6782 | 0 |
|
6783 | 0 | // SANITY CHECK: In case the nsStringBuffer isn't correctly |
6784 | 0 | // null-terminated, let's clamp its length using the allocated size, to be |
6785 | 0 | // sure the resulting string doesn't sample past the end of the the buffer. |
6786 | 0 | // (Note that StorageSize() is in units of bytes, so we have to convert that |
6787 | 0 | // to units of PRUnichars, and subtract 1 for the null-terminator.) |
6788 | 0 | uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1; |
6789 | 0 | MOZ_ASSERT(stringLen <= allocStringLen, |
6790 | 0 | "string buffer lacks null terminator!"); |
6791 | 0 | stringLen = std::min(stringLen, allocStringLen); |
6792 | 0 |
|
6793 | 0 | aBuf->ToString(stringLen, aResultString); |
6794 | 0 | } |
6795 | | |
6796 | | nsIPresShell* |
6797 | | nsContentUtils::FindPresShellForDocument(const nsIDocument* aDoc) |
6798 | 0 | { |
6799 | 0 | const nsIDocument* doc = aDoc; |
6800 | 0 | nsIDocument* displayDoc = doc->GetDisplayDocument(); |
6801 | 0 | if (displayDoc) { |
6802 | 0 | doc = displayDoc; |
6803 | 0 | } |
6804 | 0 |
|
6805 | 0 | nsIPresShell* shell = doc->GetShell(); |
6806 | 0 | if (shell) { |
6807 | 0 | return shell; |
6808 | 0 | } |
6809 | 0 | |
6810 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell(); |
6811 | 0 | while (docShellTreeItem) { |
6812 | 0 | // We may be in a display:none subdocument, or we may not have a presshell |
6813 | 0 | // created yet. |
6814 | 0 | // Walk the docshell tree to find the nearest container that has a presshell, |
6815 | 0 | // and return that. |
6816 | 0 | nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem); |
6817 | 0 | nsIPresShell* presShell = docShell->GetPresShell(); |
6818 | 0 | if (presShell) { |
6819 | 0 | return presShell; |
6820 | 0 | } |
6821 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
6822 | 0 | docShellTreeItem->GetParent(getter_AddRefs(parent)); |
6823 | 0 | docShellTreeItem = parent; |
6824 | 0 | } |
6825 | 0 |
|
6826 | 0 | return nullptr; |
6827 | 0 | } |
6828 | | |
6829 | | nsIWidget* |
6830 | | nsContentUtils::WidgetForDocument(const nsIDocument* aDoc) |
6831 | 0 | { |
6832 | 0 | nsIPresShell* shell = FindPresShellForDocument(aDoc); |
6833 | 0 | if (shell) { |
6834 | 0 | nsViewManager* VM = shell->GetViewManager(); |
6835 | 0 | if (VM) { |
6836 | 0 | nsView* rootView = VM->GetRootView(); |
6837 | 0 | if (rootView) { |
6838 | 0 | nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView); |
6839 | 0 | if (displayRoot) { |
6840 | 0 | return displayRoot->GetNearestWidget(nullptr); |
6841 | 0 | } |
6842 | 0 | } |
6843 | 0 | } |
6844 | 0 | } |
6845 | 0 | |
6846 | 0 | return nullptr; |
6847 | 0 | } |
6848 | | |
6849 | | nsIWidget* |
6850 | | nsContentUtils::WidgetForContent(const nsIContent* aContent) |
6851 | 0 | { |
6852 | 0 | nsIFrame* frame = aContent->GetPrimaryFrame(); |
6853 | 0 | if (frame) { |
6854 | 0 | frame = nsLayoutUtils::GetDisplayRootFrame(frame); |
6855 | 0 |
|
6856 | 0 | nsView* view = frame->GetView(); |
6857 | 0 | if (view) { |
6858 | 0 | return view->GetWidget(); |
6859 | 0 | } |
6860 | 0 | } |
6861 | 0 | |
6862 | 0 | return nullptr; |
6863 | 0 | } |
6864 | | |
6865 | | already_AddRefed<LayerManager> |
6866 | | nsContentUtils::LayerManagerForContent(const nsIContent *aContent) |
6867 | 0 | { |
6868 | 0 | nsIWidget* widget = nsContentUtils::WidgetForContent(aContent); |
6869 | 0 | if (widget) { |
6870 | 0 | RefPtr<LayerManager> manager = widget->GetLayerManager(); |
6871 | 0 | return manager.forget(); |
6872 | 0 | } |
6873 | 0 | |
6874 | 0 | return nullptr; |
6875 | 0 | } |
6876 | | |
6877 | | static already_AddRefed<LayerManager> |
6878 | | LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent) |
6879 | 0 | { |
6880 | 0 | nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc); |
6881 | 0 | if (widget) { |
6882 | 0 | RefPtr<LayerManager> manager = |
6883 | 0 | widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : |
6884 | 0 | nsIWidget::LAYER_MANAGER_CURRENT); |
6885 | 0 | return manager.forget(); |
6886 | 0 | } |
6887 | 0 |
|
6888 | 0 | return nullptr; |
6889 | 0 | } |
6890 | | |
6891 | | already_AddRefed<LayerManager> |
6892 | | nsContentUtils::LayerManagerForDocument(const nsIDocument *aDoc) |
6893 | 0 | { |
6894 | 0 | return LayerManagerForDocumentInternal(aDoc, false); |
6895 | 0 | } |
6896 | | |
6897 | | already_AddRefed<LayerManager> |
6898 | | nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc) |
6899 | 0 | { |
6900 | 0 | return LayerManagerForDocumentInternal(aDoc, true); |
6901 | 0 | } |
6902 | | |
6903 | | bool |
6904 | | nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal) |
6905 | 0 | { |
6906 | 0 | if (!aPrincipal) { |
6907 | 0 | return false; |
6908 | 0 | } |
6909 | 0 | |
6910 | 0 | if (IsSystemPrincipal(aPrincipal)) { |
6911 | 0 | return true; |
6912 | 0 | } |
6913 | 0 | |
6914 | 0 | nsCOMPtr<nsIURI> princURI; |
6915 | 0 | aPrincipal->GetURI(getter_AddRefs(princURI)); |
6916 | 0 |
|
6917 | 0 | return princURI && |
6918 | 0 | ((sAllowXULXBL_for_file && SchemeIs(princURI, "file")) || |
6919 | 0 | IsSitePermAllow(aPrincipal, "allowXULXBL")); |
6920 | 0 | } |
6921 | | |
6922 | | bool |
6923 | | nsContentUtils::IsPDFJSEnabled() |
6924 | 0 | { |
6925 | 0 | nsCOMPtr<nsIStreamConverter> conv = do_CreateInstance( |
6926 | 0 | "@mozilla.org/streamconv;1?from=application/pdf&to=text/html"); |
6927 | 0 | return conv; |
6928 | 0 | } |
6929 | | |
6930 | | already_AddRefed<nsIDocumentLoaderFactory> |
6931 | | nsContentUtils::FindInternalContentViewer(const nsACString& aType, |
6932 | | ContentViewerType* aLoaderType) |
6933 | 0 | { |
6934 | 0 | if (aLoaderType) { |
6935 | 0 | *aLoaderType = TYPE_UNSUPPORTED; |
6936 | 0 | } |
6937 | 0 |
|
6938 | 0 | // one helper factory, please |
6939 | 0 | nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); |
6940 | 0 | if (!catMan) |
6941 | 0 | return nullptr; |
6942 | 0 | |
6943 | 0 | nsCOMPtr<nsIDocumentLoaderFactory> docFactory; |
6944 | 0 |
|
6945 | 0 | nsCString contractID; |
6946 | 0 | nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", |
6947 | 0 | aType, contractID); |
6948 | 0 | if (NS_SUCCEEDED(rv)) { |
6949 | 0 | docFactory = do_GetService(contractID.get()); |
6950 | 0 | if (docFactory && aLoaderType) { |
6951 | 0 | if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID)) |
6952 | 0 | *aLoaderType = TYPE_CONTENT; |
6953 | 0 | else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID)) |
6954 | 0 | *aLoaderType = TYPE_PLUGIN; |
6955 | 0 | else |
6956 | 0 | *aLoaderType = TYPE_UNKNOWN; |
6957 | 0 | } |
6958 | 0 | return docFactory.forget(); |
6959 | 0 | } |
6960 | 0 |
|
6961 | 0 | if (DecoderTraits::IsSupportedInVideoDocument(aType)) { |
6962 | 0 | docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1"); |
6963 | 0 | if (docFactory && aLoaderType) { |
6964 | 0 | *aLoaderType = TYPE_CONTENT; |
6965 | 0 | } |
6966 | 0 | return docFactory.forget(); |
6967 | 0 | } |
6968 | 0 |
|
6969 | 0 | return nullptr; |
6970 | 0 | } |
6971 | | |
6972 | | static void |
6973 | | ReportPatternCompileFailure(nsAString& aPattern, nsIDocument* aDocument, |
6974 | | JSContext* cx) |
6975 | 0 | { |
6976 | 0 | MOZ_ASSERT(JS_IsExceptionPending(cx)); |
6977 | 0 |
|
6978 | 0 | JS::RootedValue exn(cx); |
6979 | 0 | if (!JS_GetPendingException(cx, &exn)) { |
6980 | 0 | return; |
6981 | 0 | } |
6982 | 0 | if (!exn.isObject()) { |
6983 | 0 | // If pending exception is not an object, it should be OOM. |
6984 | 0 | return; |
6985 | 0 | } |
6986 | 0 | |
6987 | 0 | JS::AutoSaveExceptionState savedExc(cx); |
6988 | 0 | JS::RootedObject exnObj(cx, &exn.toObject()); |
6989 | 0 | JS::RootedValue messageVal(cx); |
6990 | 0 | if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) { |
6991 | 0 | return; |
6992 | 0 | } |
6993 | 0 | MOZ_ASSERT(messageVal.isString()); |
6994 | 0 |
|
6995 | 0 | JS::RootedString messageStr(cx, messageVal.toString()); |
6996 | 0 | MOZ_ASSERT(messageStr); |
6997 | 0 |
|
6998 | 0 | nsAutoString wideMessage; |
6999 | 0 | if (!AssignJSString(cx, wideMessage, messageStr)) { |
7000 | 0 | return; |
7001 | 0 | } |
7002 | 0 | |
7003 | 0 | const nsString& pattern = PromiseFlatString(aPattern); |
7004 | 0 | const char16_t *strings[] = { pattern.get(), wideMessage.get() }; |
7005 | 0 | nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, |
7006 | 0 | NS_LITERAL_CSTRING("DOM"), |
7007 | 0 | aDocument, |
7008 | 0 | nsContentUtils::eDOM_PROPERTIES, |
7009 | 0 | "PatternAttributeCompileFailure", |
7010 | 0 | strings, ArrayLength(strings)); |
7011 | 0 | savedExc.drop(); |
7012 | 0 | } |
7013 | | |
7014 | | // static |
7015 | | bool |
7016 | | nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern, |
7017 | | nsIDocument* aDocument) |
7018 | 0 | { |
7019 | 0 | NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)"); |
7020 | 0 |
|
7021 | 0 | AutoJSContext cx; |
7022 | 0 | AutoDisableJSInterruptCallback disabler(cx); |
7023 | 0 |
|
7024 | 0 | // We can use the junk scope here, because we're just using it for |
7025 | 0 | // regexp evaluation, not actual script execution. |
7026 | 0 | JSAutoRealm ar(cx, xpc::UnprivilegedJunkScope()); |
7027 | 0 |
|
7028 | 0 | // The pattern has to match the entire value. |
7029 | 0 | aPattern.InsertLiteral(u"^(?:", 0); |
7030 | 0 | aPattern.AppendLiteral(")$"); |
7031 | 0 |
|
7032 | 0 | JS::Rooted<JSObject*> re(cx, |
7033 | 0 | JS_NewUCRegExpObject(cx, |
7034 | 0 | static_cast<char16_t*>(aPattern.BeginWriting()), |
7035 | 0 | aPattern.Length(), JSREG_UNICODE)); |
7036 | 0 | if (!re) { |
7037 | 0 | // Remove extra patterns added above to report with the original pattern. |
7038 | 0 | aPattern.Cut(0, 4); |
7039 | 0 | aPattern.Cut(aPattern.Length() - 2, 2); |
7040 | 0 | ReportPatternCompileFailure(aPattern, aDocument, cx); |
7041 | 0 | return true; |
7042 | 0 | } |
7043 | 0 | |
7044 | 0 | JS::Rooted<JS::Value> rval(cx, JS::NullValue()); |
7045 | 0 | size_t idx = 0; |
7046 | 0 | if (!JS_ExecuteRegExpNoStatics(cx, re, |
7047 | 0 | static_cast<char16_t*>(aValue.BeginWriting()), |
7048 | 0 | aValue.Length(), &idx, true, &rval)) { |
7049 | 0 | return true; |
7050 | 0 | } |
7051 | 0 | |
7052 | 0 | return !rval.isNull(); |
7053 | 0 | } |
7054 | | |
7055 | | // static |
7056 | | nsresult |
7057 | | nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, bool *aResult) |
7058 | 0 | { |
7059 | 0 | // Note: about:blank URIs do NOT inherit the security context from the |
7060 | 0 | // current document, which is what this function tests for... |
7061 | 0 | return NS_URIChainHasFlags(aURI, |
7062 | 0 | nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, |
7063 | 0 | aResult); |
7064 | 0 | } |
7065 | | |
7066 | | // static |
7067 | | bool |
7068 | | nsContentUtils::ChannelShouldInheritPrincipal(nsIPrincipal* aLoadingPrincipal, |
7069 | | nsIURI* aURI, |
7070 | | bool aInheritForAboutBlank, |
7071 | | bool aForceInherit) |
7072 | 0 | { |
7073 | 0 | MOZ_ASSERT(aLoadingPrincipal, "Can not check inheritance without a principal"); |
7074 | 0 |
|
7075 | 0 | // Only tell the channel to inherit if it can't provide its own security context. |
7076 | 0 | // |
7077 | 0 | // XXX: If this is ever changed, check all callers for what owners |
7078 | 0 | // they're passing in. In particular, see the code and |
7079 | 0 | // comments in nsDocShell::LoadURI where we fall back on |
7080 | 0 | // inheriting the owner if called from chrome. That would be |
7081 | 0 | // very wrong if this code changed anything but channels that |
7082 | 0 | // can't provide their own security context! |
7083 | 0 | // |
7084 | 0 | // If aForceInherit is true, we will inherit, even for a channel that |
7085 | 0 | // can provide its own security context. This is used for srcdoc loads. |
7086 | 0 | bool inherit = aForceInherit; |
7087 | 0 | if (!inherit) { |
7088 | 0 | bool uriInherits; |
7089 | 0 | // We expect URIInheritsSecurityContext to return success for an |
7090 | 0 | // about:blank URI, so don't call NS_IsAboutBlank() if this call fails. |
7091 | 0 | // This condition needs to match the one in nsDocShell::InternalLoad where |
7092 | 0 | // we're checking for things that will use the owner. |
7093 | 0 | inherit = |
7094 | 0 | (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &uriInherits)) && |
7095 | 0 | (uriInherits || (aInheritForAboutBlank && NS_IsAboutBlank(aURI)))) || |
7096 | 0 | // |
7097 | 0 | // file: uri special-casing |
7098 | 0 | // |
7099 | 0 | // If this is a file: load opened from another file: then it may need |
7100 | 0 | // to inherit the owner from the referrer so they can script each other. |
7101 | 0 | // If we don't set the owner explicitly then each file: gets an owner |
7102 | 0 | // based on its own codebase later. |
7103 | 0 | // |
7104 | 0 | (URIIsLocalFile(aURI) && |
7105 | 0 | NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) && |
7106 | 0 | // One more check here. CheckMayLoad will always return true for the |
7107 | 0 | // system principal, but we do NOT want to inherit in that case. |
7108 | 0 | !IsSystemPrincipal(aLoadingPrincipal)); |
7109 | 0 | } |
7110 | 0 | return inherit; |
7111 | 0 | } |
7112 | | |
7113 | | /* static */ |
7114 | | bool |
7115 | | nsContentUtils::IsFullscreenApiEnabled() |
7116 | 0 | { |
7117 | 0 | return sIsFullscreenApiEnabled; |
7118 | 0 | } |
7119 | | |
7120 | | /* static */ |
7121 | | bool |
7122 | | nsContentUtils::IsRequestFullscreenAllowed(CallerType aCallerType) |
7123 | 0 | { |
7124 | 0 | // If more time has elapsed since the user input than is specified by the |
7125 | 0 | // dom.event.handling-user-input-time-limit pref (default 1 second), this |
7126 | 0 | // function also returns false. |
7127 | 0 |
|
7128 | 0 | if (!sTrustedFullscreenOnly || aCallerType == CallerType::System) { |
7129 | 0 | return true; |
7130 | 0 | } |
7131 | 0 | |
7132 | 0 | if (EventStateManager::IsHandlingUserInput()) { |
7133 | 0 | TimeDuration timeout = HandlingUserInputTimeout(); |
7134 | 0 | return timeout <= TimeDuration(nullptr) || |
7135 | 0 | (TimeStamp::Now() - |
7136 | 0 | EventStateManager::GetHandlingInputStart()) <= timeout; |
7137 | 0 | } |
7138 | 0 |
|
7139 | 0 | return false; |
7140 | 0 | } |
7141 | | |
7142 | | /* static */ |
7143 | | bool |
7144 | | nsContentUtils::IsCutCopyAllowed(nsIPrincipal* aSubjectPrincipal) |
7145 | 0 | { |
7146 | 0 | if (!IsCutCopyRestricted() && EventStateManager::IsHandlingUserInput()) { |
7147 | 0 | return true; |
7148 | 0 | } |
7149 | 0 | |
7150 | 0 | return PrincipalHasPermission(aSubjectPrincipal, nsGkAtoms::clipboardWrite); |
7151 | 0 | } |
7152 | | |
7153 | | /* static */ |
7154 | | bool |
7155 | | nsContentUtils::IsFrameTimingEnabled() |
7156 | 0 | { |
7157 | 0 | return sIsFrameTimingPrefEnabled; |
7158 | 0 | } |
7159 | | |
7160 | | /* static */ |
7161 | | bool |
7162 | | nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2) |
7163 | 0 | { |
7164 | 0 | if (!aDoc1 || !aDoc2) { |
7165 | 0 | return false; |
7166 | 0 | } |
7167 | 0 | bool principalsEqual = false; |
7168 | 0 | aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual); |
7169 | 0 | return principalsEqual; |
7170 | 0 | } |
7171 | | |
7172 | | /* static */ |
7173 | | bool |
7174 | | nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) |
7175 | 0 | { |
7176 | | #ifdef XP_MACOSX |
7177 | | // We control dispatch to all mac plugins. |
7178 | | return false; |
7179 | | #else |
7180 | 0 | if (!aContent || !aContent->IsInComposedDoc()) { |
7181 | 0 | return false; |
7182 | 0 | } |
7183 | 0 | |
7184 | 0 | nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aContent); |
7185 | 0 | if (!olc) { |
7186 | 0 | return false; |
7187 | 0 | } |
7188 | 0 | |
7189 | 0 | RefPtr<nsNPAPIPluginInstance> plugin; |
7190 | 0 | olc->GetPluginInstance(getter_AddRefs(plugin)); |
7191 | 0 | if (!plugin) { |
7192 | 0 | return false; |
7193 | 0 | } |
7194 | 0 | |
7195 | 0 | bool isWindowless = false; |
7196 | 0 | nsresult res = plugin->IsWindowless(&isWindowless); |
7197 | 0 | if (NS_FAILED(res)) { |
7198 | 0 | return false; |
7199 | 0 | } |
7200 | 0 | |
7201 | 0 | return !isWindowless; |
7202 | 0 | #endif |
7203 | 0 | } |
7204 | | |
7205 | | /* static */ |
7206 | | void |
7207 | | nsContentUtils::FireMutationEventsForDirectParsing(nsIDocument* aDoc, |
7208 | | nsIContent* aDest, |
7209 | | int32_t aOldChildCount) |
7210 | 0 | { |
7211 | 0 | // Fire mutation events. Optimize for the case when there are no listeners |
7212 | 0 | int32_t newChildCount = aDest->GetChildCount(); |
7213 | 0 | if (newChildCount && nsContentUtils:: |
7214 | 0 | HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) { |
7215 | 0 | AutoTArray<nsCOMPtr<nsIContent>, 50> childNodes; |
7216 | 0 | NS_ASSERTION(newChildCount - aOldChildCount >= 0, |
7217 | 0 | "What, some unexpected dom mutation has happened?"); |
7218 | 0 | childNodes.SetCapacity(newChildCount - aOldChildCount); |
7219 | 0 | for (nsIContent* child = aDest->GetFirstChild(); |
7220 | 0 | child; |
7221 | 0 | child = child->GetNextSibling()) { |
7222 | 0 | childNodes.AppendElement(child); |
7223 | 0 | } |
7224 | 0 | FragmentOrElement::FireNodeInserted(aDoc, aDest, childNodes); |
7225 | 0 | } |
7226 | 0 | } |
7227 | | |
7228 | | /* static */ |
7229 | | nsIDocument* |
7230 | | nsContentUtils::GetRootDocument(nsIDocument* aDoc) |
7231 | 0 | { |
7232 | 0 | if (!aDoc) { |
7233 | 0 | return nullptr; |
7234 | 0 | } |
7235 | 0 | nsIDocument* doc = aDoc; |
7236 | 0 | while (doc->GetParentDocument()) { |
7237 | 0 | doc = doc->GetParentDocument(); |
7238 | 0 | } |
7239 | 0 | return doc; |
7240 | 0 | } |
7241 | | |
7242 | | /* static */ |
7243 | | bool |
7244 | | nsContentUtils::IsInPointerLockContext(nsPIDOMWindowOuter* aWin) |
7245 | 0 | { |
7246 | 0 | if (!aWin) { |
7247 | 0 | return false; |
7248 | 0 | } |
7249 | 0 | |
7250 | 0 | nsCOMPtr<nsIDocument> pointerLockedDoc = |
7251 | 0 | do_QueryReferent(EventStateManager::sPointerLockedDoc); |
7252 | 0 | if (!pointerLockedDoc || !pointerLockedDoc->GetWindow()) { |
7253 | 0 | return false; |
7254 | 0 | } |
7255 | 0 | |
7256 | 0 | nsCOMPtr<nsPIDOMWindowOuter> lockTop = |
7257 | 0 | pointerLockedDoc->GetWindow()->GetScriptableTop(); |
7258 | 0 | nsCOMPtr<nsPIDOMWindowOuter> top = aWin->GetScriptableTop(); |
7259 | 0 |
|
7260 | 0 | return top == lockTop; |
7261 | 0 | } |
7262 | | |
7263 | | // static |
7264 | | int32_t |
7265 | | nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame, |
7266 | | int32_t aOffset) |
7267 | 0 | { |
7268 | 0 | // The structure of the anonymous frames within a text control frame is |
7269 | 0 | // an optional block frame, followed by an optional br frame. |
7270 | 0 |
|
7271 | 0 | // If the offset frame has a child, then this frame is the block which |
7272 | 0 | // has the text frames (containing the content) as its children. This will |
7273 | 0 | // be the case if we click to the right of any of the text frames, or at the |
7274 | 0 | // bottom of the text area. |
7275 | 0 | nsIFrame* firstChild = aOffsetFrame->PrincipalChildList().FirstChild(); |
7276 | 0 | if (firstChild) { |
7277 | 0 | // In this case, the passed-in offset is incorrect, and we want the length |
7278 | 0 | // of the entire content in the text control frame. |
7279 | 0 | return firstChild->GetContent()->Length(); |
7280 | 0 | } |
7281 | 0 | |
7282 | 0 | if (aOffsetFrame->GetPrevSibling() && |
7283 | 0 | !aOffsetFrame->GetNextSibling()) { |
7284 | 0 | // In this case, we're actually within the last frame, which is a br |
7285 | 0 | // frame. Our offset should therefore be the length of the first child of |
7286 | 0 | // our parent. |
7287 | 0 | int32_t aOutOffset = |
7288 | 0 | aOffsetFrame->GetParent()->PrincipalChildList().FirstChild()->GetContent()->Length(); |
7289 | 0 | return aOutOffset; |
7290 | 0 | } |
7291 | 0 | |
7292 | 0 | // Otherwise, we're within one of the text frames, in which case our offset |
7293 | 0 | // has already been correctly calculated. |
7294 | 0 | return aOffset; |
7295 | 0 | } |
7296 | | |
7297 | | // static |
7298 | | void |
7299 | | nsContentUtils::GetSelectionInTextControl(Selection* aSelection, |
7300 | | Element* aRoot, |
7301 | | uint32_t& aOutStartOffset, |
7302 | | uint32_t& aOutEndOffset) |
7303 | 0 | { |
7304 | 0 | MOZ_ASSERT(aSelection && aRoot); |
7305 | 0 |
|
7306 | 0 | // We don't care which end of this selection is anchor and which is focus. In |
7307 | 0 | // fact, we explicitly want to know which is the _start_ and which is the |
7308 | 0 | // _end_, not anchor vs focus. |
7309 | 0 | const nsRange* range = aSelection->GetAnchorFocusRange(); |
7310 | 0 | if (!range) { |
7311 | 0 | // Nothing selected |
7312 | 0 | aOutStartOffset = aOutEndOffset = 0; |
7313 | 0 | return; |
7314 | 0 | } |
7315 | 0 | |
7316 | 0 | // All the node pointers here are raw pointers for performance. We shouldn't |
7317 | 0 | // be doing anything in this function that invalidates the node tree. |
7318 | 0 | nsINode* startContainer = range->GetStartContainer(); |
7319 | 0 | uint32_t startOffset = range->StartOffset(); |
7320 | 0 | nsINode* endContainer = range->GetEndContainer(); |
7321 | 0 | uint32_t endOffset = range->EndOffset(); |
7322 | 0 |
|
7323 | 0 | // We have at most two children, consisting of an optional text node followed |
7324 | 0 | // by an optional <br>. |
7325 | 0 | NS_ASSERTION(aRoot->GetChildCount() <= 2, "Unexpected children"); |
7326 | 0 | nsIContent* firstChild = aRoot->GetFirstChild(); |
7327 | | #ifdef DEBUG |
7328 | | nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild(); |
7329 | | NS_ASSERTION(startContainer == aRoot || startContainer == firstChild || |
7330 | | startContainer == lastChild, "Unexpected startContainer"); |
7331 | | NS_ASSERTION(endContainer == aRoot || endContainer == firstChild || |
7332 | | endContainer == lastChild, "Unexpected endContainer"); |
7333 | | // firstChild is either text or a <br> (hence an element). |
7334 | | MOZ_ASSERT_IF(firstChild, |
7335 | | firstChild->IsText() || firstChild->IsElement()); |
7336 | | #endif |
7337 | | // Testing IsElement() is faster than testing IsNodeOfType(), since it's |
7338 | 0 | // non-virtual. |
7339 | 0 | if (!firstChild || firstChild->IsElement()) { |
7340 | 0 | // No text node, so everything is 0 |
7341 | 0 | startOffset = endOffset = 0; |
7342 | 0 | } else { |
7343 | 0 | // First child is text. If the start/end is already in the text node, |
7344 | 0 | // or the start of the root node, no change needed. If it's in the root |
7345 | 0 | // node but not the start, or in the trailing <br>, we need to set the |
7346 | 0 | // offset to the end. |
7347 | 0 | if ((startContainer == aRoot && startOffset != 0) || |
7348 | 0 | (startContainer != aRoot && startContainer != firstChild)) { |
7349 | 0 | startOffset = firstChild->Length(); |
7350 | 0 | } |
7351 | 0 | if ((endContainer == aRoot && endOffset != 0) || |
7352 | 0 | (endContainer != aRoot && endContainer != firstChild)) { |
7353 | 0 | endOffset = firstChild->Length(); |
7354 | 0 | } |
7355 | 0 | } |
7356 | 0 |
|
7357 | 0 | MOZ_ASSERT(startOffset <= endOffset); |
7358 | 0 | aOutStartOffset = startOffset; |
7359 | 0 | aOutEndOffset = endOffset; |
7360 | 0 | } |
7361 | | |
7362 | | |
7363 | | HTMLEditor* |
7364 | | nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext) |
7365 | 0 | { |
7366 | 0 | nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell()); |
7367 | 0 | bool isEditable; |
7368 | 0 | if (!docShell || |
7369 | 0 | NS_FAILED(docShell->GetEditable(&isEditable)) || !isEditable) |
7370 | 0 | return nullptr; |
7371 | 0 | |
7372 | 0 | return docShell->GetHTMLEditor(); |
7373 | 0 | } |
7374 | | |
7375 | | // static |
7376 | | bool |
7377 | | nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader) |
7378 | 0 | { |
7379 | 0 | if (IsForbiddenSystemRequestHeader(aHeader)) { |
7380 | 0 | return true; |
7381 | 0 | } |
7382 | 0 | |
7383 | 0 | return StringBeginsWith(aHeader, NS_LITERAL_CSTRING("proxy-"), |
7384 | 0 | nsCaseInsensitiveCStringComparator()) || |
7385 | 0 | StringBeginsWith(aHeader, NS_LITERAL_CSTRING("sec-"), |
7386 | 0 | nsCaseInsensitiveCStringComparator()); |
7387 | 0 | } |
7388 | | |
7389 | | // static |
7390 | | bool |
7391 | | nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader) |
7392 | 0 | { |
7393 | 0 | static const char *kInvalidHeaders[] = { |
7394 | 0 | "accept-charset", "accept-encoding", "access-control-request-headers", |
7395 | 0 | "access-control-request-method", "connection", "content-length", |
7396 | 0 | "cookie", "cookie2", "date", "dnt", "expect", "host", "keep-alive", |
7397 | 0 | "origin", "referer", "te", "trailer", "transfer-encoding", "upgrade", "via" |
7398 | 0 | }; |
7399 | 0 | for (auto& kInvalidHeader : kInvalidHeaders) { |
7400 | 0 | if (aHeader.LowerCaseEqualsASCII(kInvalidHeader)) { |
7401 | 0 | return true; |
7402 | 0 | } |
7403 | 0 | } |
7404 | 0 | return false; |
7405 | 0 | } |
7406 | | |
7407 | | // static |
7408 | | bool |
7409 | | nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) |
7410 | 0 | { |
7411 | 0 | return (aHeader.LowerCaseEqualsASCII("set-cookie") || |
7412 | 0 | aHeader.LowerCaseEqualsASCII("set-cookie2")); |
7413 | 0 | } |
7414 | | |
7415 | | // static |
7416 | | bool |
7417 | | nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue) |
7418 | 0 | { |
7419 | 0 | nsAutoCString contentType; |
7420 | 0 | nsAutoCString unused; |
7421 | 0 |
|
7422 | 0 | nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused); |
7423 | 0 | if (NS_FAILED(rv)) { |
7424 | 0 | return false; |
7425 | 0 | } |
7426 | 0 | |
7427 | 0 | return contentType.LowerCaseEqualsLiteral("text/plain") || |
7428 | 0 | contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") || |
7429 | 0 | contentType.LowerCaseEqualsLiteral("multipart/form-data"); |
7430 | 0 | } |
7431 | | |
7432 | | bool |
7433 | | nsContentUtils::DoNotTrackEnabled() |
7434 | 0 | { |
7435 | 0 | return nsContentUtils::sDoNotTrackEnabled; |
7436 | 0 | } |
7437 | | |
7438 | | mozilla::LogModule* |
7439 | | nsContentUtils::DOMDumpLog() |
7440 | 0 | { |
7441 | 0 | return sDOMDumpLog; |
7442 | 0 | } |
7443 | | |
7444 | | bool |
7445 | | nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult, |
7446 | | const fallible_t& aFallible) |
7447 | 0 | { |
7448 | 0 | aResult.Truncate(); |
7449 | 0 | return AppendNodeTextContent(aNode, aDeep, aResult, aFallible); |
7450 | 0 | } |
7451 | | |
7452 | | void |
7453 | | nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult) |
7454 | 0 | { |
7455 | 0 | if (!GetNodeTextContent(aNode, aDeep, aResult, fallible)) { |
7456 | 0 | NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size |
7457 | 0 | } |
7458 | 0 | } |
7459 | | |
7460 | | void |
7461 | | nsContentUtils::DestroyMatchString(void* aData) |
7462 | 0 | { |
7463 | 0 | if (aData) { |
7464 | 0 | nsString* matchString = static_cast<nsString*>(aData); |
7465 | 0 | delete matchString; |
7466 | 0 | } |
7467 | 0 | } |
7468 | | |
7469 | | bool |
7470 | | nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) |
7471 | 0 | { |
7472 | 0 | // Table ordered from most to least likely JS MIME types. |
7473 | 0 | static const char* jsTypes[] = { |
7474 | 0 | "text/javascript", |
7475 | 0 | "text/ecmascript", |
7476 | 0 | "application/javascript", |
7477 | 0 | "application/ecmascript", |
7478 | 0 | "application/x-javascript", |
7479 | 0 | "application/x-ecmascript", |
7480 | 0 | "text/javascript1.0", |
7481 | 0 | "text/javascript1.1", |
7482 | 0 | "text/javascript1.2", |
7483 | 0 | "text/javascript1.3", |
7484 | 0 | "text/javascript1.4", |
7485 | 0 | "text/javascript1.5", |
7486 | 0 | "text/jscript", |
7487 | 0 | "text/livescript", |
7488 | 0 | "text/x-ecmascript", |
7489 | 0 | "text/x-javascript", |
7490 | 0 | nullptr |
7491 | 0 | }; |
7492 | 0 |
|
7493 | 0 | for (uint32_t i = 0; jsTypes[i]; ++i) { |
7494 | 0 | if (aMIMEType.LowerCaseEqualsASCII(jsTypes[i])) { |
7495 | 0 | return true; |
7496 | 0 | } |
7497 | 0 | } |
7498 | 0 |
|
7499 | 0 | return false; |
7500 | 0 | } |
7501 | | |
7502 | | nsresult |
7503 | | nsContentUtils::GenerateUUIDInPlace(nsID& aUUID) |
7504 | 0 | { |
7505 | 0 | MOZ_ASSERT(sUUIDGenerator); |
7506 | 0 |
|
7507 | 0 | nsresult rv = sUUIDGenerator->GenerateUUIDInPlace(&aUUID); |
7508 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
7509 | 0 | return rv; |
7510 | 0 | } |
7511 | 0 | |
7512 | 0 | return NS_OK; |
7513 | 0 | } |
7514 | | |
7515 | | bool |
7516 | | nsContentUtils::PrefetchPreloadEnabled(nsIDocShell* aDocShell) |
7517 | 0 | { |
7518 | 0 | // |
7519 | 0 | // SECURITY CHECK: disable prefetching and preloading from mailnews! |
7520 | 0 | // |
7521 | 0 | // walk up the docshell tree to see if any containing |
7522 | 0 | // docshell are of type MAIL. |
7523 | 0 | // |
7524 | 0 |
|
7525 | 0 | if (!aDocShell) { |
7526 | 0 | return false; |
7527 | 0 | } |
7528 | 0 | |
7529 | 0 | nsCOMPtr<nsIDocShell> docshell = aDocShell; |
7530 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentItem; |
7531 | 0 |
|
7532 | 0 | do { |
7533 | 0 | uint32_t appType = 0; |
7534 | 0 | nsresult rv = docshell->GetAppType(&appType); |
7535 | 0 | if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL) { |
7536 | 0 | return false; // do not prefetch, preload, preconnect from mailnews |
7537 | 0 | } |
7538 | 0 | |
7539 | 0 | docshell->GetParent(getter_AddRefs(parentItem)); |
7540 | 0 | if (parentItem) { |
7541 | 0 | docshell = do_QueryInterface(parentItem); |
7542 | 0 | if (!docshell) { |
7543 | 0 | NS_ERROR("cannot get a docshell from a treeItem!"); |
7544 | 0 | return false; |
7545 | 0 | } |
7546 | 0 | } |
7547 | 0 | } while (parentItem); |
7548 | 0 |
|
7549 | 0 | return true; |
7550 | 0 | } |
7551 | | |
7552 | | uint64_t |
7553 | | nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) |
7554 | 0 | { |
7555 | 0 | // can't do anything if there's no nsIRequest! |
7556 | 0 | if (!aRequest) { |
7557 | 0 | return 0; |
7558 | 0 | } |
7559 | 0 | |
7560 | 0 | nsCOMPtr<nsILoadGroup> loadGroup; |
7561 | 0 | nsresult rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup)); |
7562 | 0 |
|
7563 | 0 | if (NS_FAILED(rv) || !loadGroup) { |
7564 | 0 | return 0; |
7565 | 0 | } |
7566 | 0 | |
7567 | 0 | return GetInnerWindowID(loadGroup); |
7568 | 0 | } |
7569 | | |
7570 | | uint64_t |
7571 | | nsContentUtils::GetInnerWindowID(nsILoadGroup* aLoadGroup) |
7572 | 0 | { |
7573 | 0 | if (!aLoadGroup) { |
7574 | 0 | return 0; |
7575 | 0 | } |
7576 | 0 | |
7577 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
7578 | 0 | nsresult rv = aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
7579 | 0 | if (NS_FAILED(rv) || !callbacks) { |
7580 | 0 | return 0; |
7581 | 0 | } |
7582 | 0 | |
7583 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); |
7584 | 0 | if (!loadContext) { |
7585 | 0 | return 0; |
7586 | 0 | } |
7587 | 0 | |
7588 | 0 | nsCOMPtr<mozIDOMWindowProxy> window; |
7589 | 0 | rv = loadContext->GetAssociatedWindow(getter_AddRefs(window)); |
7590 | 0 | if (NS_FAILED(rv) || !window) { |
7591 | 0 | return 0; |
7592 | 0 | } |
7593 | 0 | |
7594 | 0 | auto* pwindow = nsPIDOMWindowOuter::From(window); |
7595 | 0 | if (!pwindow) { |
7596 | 0 | return 0; |
7597 | 0 | } |
7598 | 0 | |
7599 | 0 | nsPIDOMWindowInner* inner = pwindow->GetCurrentInnerWindow(); |
7600 | 0 | return inner ? inner->WindowID() : 0; |
7601 | 0 | } |
7602 | | |
7603 | | nsresult |
7604 | | nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost) |
7605 | 0 | { |
7606 | 0 | aHost.Truncate(); |
7607 | 0 | nsresult rv = aURI->GetHost(aHost); |
7608 | 0 | if (NS_FAILED(rv)) { // Some URIs do not have a host |
7609 | 0 | return rv; |
7610 | 0 | } |
7611 | 0 | |
7612 | 0 | if (aHost.FindChar(':') != -1) { // Escape IPv6 address |
7613 | 0 | MOZ_ASSERT(!aHost.Length() || |
7614 | 0 | (aHost[0] !='[' && aHost[aHost.Length() - 1] != ']')); |
7615 | 0 | aHost.Insert('[', 0); |
7616 | 0 | aHost.Append(']'); |
7617 | 0 | } |
7618 | 0 |
|
7619 | 0 | return NS_OK; |
7620 | 0 | } |
7621 | | |
7622 | | nsresult |
7623 | | nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost) |
7624 | 0 | { |
7625 | 0 | nsAutoCString hostname; |
7626 | 0 | nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname); |
7627 | 0 | if (NS_FAILED(rv)) { |
7628 | 0 | return rv; |
7629 | 0 | } |
7630 | 0 | CopyUTF8toUTF16(hostname, aHost); |
7631 | 0 | return NS_OK; |
7632 | 0 | } |
7633 | | |
7634 | | bool |
7635 | | nsContentUtils::CallOnAllRemoteChildren(MessageBroadcaster* aManager, |
7636 | | CallOnRemoteChildFunction aCallback, |
7637 | | void* aArg) |
7638 | 0 | { |
7639 | 0 | uint32_t tabChildCount = aManager->ChildCount(); |
7640 | 0 | for (uint32_t j = 0; j < tabChildCount; ++j) { |
7641 | 0 | RefPtr<MessageListenerManager> childMM = aManager->GetChildAt(j); |
7642 | 0 | if (!childMM) { |
7643 | 0 | continue; |
7644 | 0 | } |
7645 | 0 | |
7646 | 0 | RefPtr<MessageBroadcaster> nonLeafMM = MessageBroadcaster::From(childMM); |
7647 | 0 | if (nonLeafMM) { |
7648 | 0 | if (CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg)) { |
7649 | 0 | return true; |
7650 | 0 | } |
7651 | 0 | continue; |
7652 | 0 | } |
7653 | 0 | |
7654 | 0 | mozilla::dom::ipc::MessageManagerCallback* cb = childMM->GetCallback(); |
7655 | 0 | if (cb) { |
7656 | 0 | nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb); |
7657 | 0 | TabParent* remote = TabParent::GetFrom(fl); |
7658 | 0 | if (remote && aCallback) { |
7659 | 0 | if (aCallback(remote, aArg)) { |
7660 | 0 | return true; |
7661 | 0 | } |
7662 | 0 | } |
7663 | 0 | } |
7664 | 0 | } |
7665 | 0 |
|
7666 | 0 | return false; |
7667 | 0 | } |
7668 | | |
7669 | | void |
7670 | | nsContentUtils::CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow, |
7671 | | CallOnRemoteChildFunction aCallback, |
7672 | | void* aArg) |
7673 | 0 | { |
7674 | 0 | nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow); |
7675 | 0 | if (window->IsChromeWindow()) { |
7676 | 0 | RefPtr<MessageBroadcaster> windowMM = window->GetMessageManager(); |
7677 | 0 | if (windowMM) { |
7678 | 0 | CallOnAllRemoteChildren(windowMM, aCallback, aArg); |
7679 | 0 | } |
7680 | 0 | } |
7681 | 0 | } |
7682 | | |
7683 | | struct UIStateChangeInfo { |
7684 | | UIStateChangeType mShowAccelerators; |
7685 | | UIStateChangeType mShowFocusRings; |
7686 | | |
7687 | | UIStateChangeInfo(UIStateChangeType aShowAccelerators, |
7688 | | UIStateChangeType aShowFocusRings) |
7689 | | : mShowAccelerators(aShowAccelerators), |
7690 | | mShowFocusRings(aShowFocusRings) |
7691 | 0 | {} |
7692 | | }; |
7693 | | |
7694 | | bool |
7695 | | SetKeyboardIndicatorsChild(TabParent* aParent, void* aArg) |
7696 | 0 | { |
7697 | 0 | UIStateChangeInfo* stateInfo = static_cast<UIStateChangeInfo*>(aArg); |
7698 | 0 | Unused << aParent->SendSetKeyboardIndicators(stateInfo->mShowAccelerators, |
7699 | 0 | stateInfo->mShowFocusRings); |
7700 | 0 | return false; |
7701 | 0 | } |
7702 | | |
7703 | | void |
7704 | | nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(nsPIDOMWindowOuter* aWindow, |
7705 | | UIStateChangeType aShowAccelerators, |
7706 | | UIStateChangeType aShowFocusRings) |
7707 | 0 | { |
7708 | 0 | UIStateChangeInfo stateInfo(aShowAccelerators, aShowFocusRings); |
7709 | 0 | CallOnAllRemoteChildren(aWindow, SetKeyboardIndicatorsChild, |
7710 | 0 | (void *)&stateInfo); |
7711 | 0 | } |
7712 | | |
7713 | | nsresult |
7714 | | nsContentUtils::IPCTransferableToTransferable(const IPCDataTransfer& aDataTransfer, |
7715 | | const bool& aIsPrivateData, |
7716 | | nsIPrincipal* aRequestingPrincipal, |
7717 | | const nsContentPolicyType& aContentPolicyType, |
7718 | | nsITransferable* aTransferable, |
7719 | | mozilla::dom::nsIContentParent* aContentParent, |
7720 | | mozilla::dom::TabChild* aTabChild) |
7721 | 0 | { |
7722 | 0 | nsresult rv; |
7723 | 0 |
|
7724 | 0 | const nsTArray<IPCDataTransferItem>& items = aDataTransfer.items(); |
7725 | 0 | for (const auto& item : items) { |
7726 | 0 | aTransferable->AddDataFlavor(item.flavor().get()); |
7727 | 0 |
|
7728 | 0 | if (item.data().type() == IPCDataTransferData::TnsString) { |
7729 | 0 | nsCOMPtr<nsISupportsString> dataWrapper = |
7730 | 0 | do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); |
7731 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7732 | 0 |
|
7733 | 0 | const nsString& text = item.data().get_nsString(); |
7734 | 0 | rv = dataWrapper->SetData(text); |
7735 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7736 | 0 |
|
7737 | 0 | rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper, |
7738 | 0 | text.Length() * sizeof(char16_t)); |
7739 | 0 |
|
7740 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7741 | 0 | } else if (item.data().type() == IPCDataTransferData::TShmem) { |
7742 | 0 | if (nsContentUtils::IsFlavorImage(item.flavor())) { |
7743 | 0 | nsCOMPtr<imgIContainer> imageContainer; |
7744 | 0 | rv = nsContentUtils::DataTransferItemToImage(item, |
7745 | 0 | getter_AddRefs(imageContainer)); |
7746 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7747 | 0 |
|
7748 | 0 | nsCOMPtr<nsISupportsInterfacePointer> imgPtr = |
7749 | 0 | do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID); |
7750 | 0 | NS_ENSURE_TRUE(imgPtr, NS_ERROR_FAILURE); |
7751 | 0 |
|
7752 | 0 | rv = imgPtr->SetData(imageContainer); |
7753 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7754 | 0 |
|
7755 | 0 | aTransferable->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*)); |
7756 | 0 | } else { |
7757 | 0 | nsCOMPtr<nsISupportsCString> dataWrapper = |
7758 | 0 | do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv); |
7759 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7760 | 0 |
|
7761 | 0 | // The buffer contains the terminating null. |
7762 | 0 | Shmem itemData = item.data().get_Shmem(); |
7763 | 0 | const nsDependentCSubstring text(itemData.get<char>(), |
7764 | 0 | itemData.Size<char>()); |
7765 | 0 | rv = dataWrapper->SetData(text); |
7766 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7767 | 0 |
|
7768 | 0 | rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper, text.Length()); |
7769 | 0 |
|
7770 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7771 | 0 | } |
7772 | 0 |
|
7773 | 0 | if (aContentParent) { |
7774 | 0 | Unused << aContentParent->DeallocShmem(item.data().get_Shmem()); |
7775 | 0 | } else if (aTabChild) { |
7776 | 0 | Unused << aTabChild->DeallocShmem(item.data().get_Shmem()); |
7777 | 0 | } |
7778 | 0 | } |
7779 | 0 | } |
7780 | 0 |
|
7781 | 0 | aTransferable->SetIsPrivateData(aIsPrivateData); |
7782 | 0 | aTransferable->SetRequestingPrincipal(aRequestingPrincipal); |
7783 | 0 | aTransferable->SetContentPolicyType(aContentPolicyType); |
7784 | 0 | return NS_OK; |
7785 | 0 | } |
7786 | | |
7787 | | void |
7788 | | nsContentUtils::TransferablesToIPCTransferables(nsIArray* aTransferables, |
7789 | | nsTArray<IPCDataTransfer>& aIPC, |
7790 | | bool aInSyncMessage, |
7791 | | mozilla::dom::nsIContentChild* aChild, |
7792 | | mozilla::dom::nsIContentParent* aParent) |
7793 | 0 | { |
7794 | 0 | aIPC.Clear(); |
7795 | 0 | if (aTransferables) { |
7796 | 0 | uint32_t transferableCount = 0; |
7797 | 0 | aTransferables->GetLength(&transferableCount); |
7798 | 0 | for (uint32_t i = 0; i < transferableCount; ++i) { |
7799 | 0 | IPCDataTransfer* dt = aIPC.AppendElement(); |
7800 | 0 | nsCOMPtr<nsITransferable> transferable = do_QueryElementAt(aTransferables, i); |
7801 | 0 | TransferableToIPCTransferable(transferable, dt, aInSyncMessage, aChild, aParent); |
7802 | 0 | } |
7803 | 0 | } |
7804 | 0 | } |
7805 | | |
7806 | | nsresult |
7807 | | nsContentUtils::SlurpFileToString(nsIFile* aFile, nsACString& aString) |
7808 | 0 | { |
7809 | 0 | aString.Truncate(); |
7810 | 0 |
|
7811 | 0 | nsCOMPtr<nsIURI> fileURI; |
7812 | 0 | nsresult rv = NS_NewFileURI(getter_AddRefs(fileURI), aFile); |
7813 | 0 | if (NS_FAILED(rv)) { |
7814 | 0 | return rv; |
7815 | 0 | } |
7816 | 0 | |
7817 | 0 | nsCOMPtr<nsIChannel> channel; |
7818 | 0 | rv = NS_NewChannel(getter_AddRefs(channel), |
7819 | 0 | fileURI, |
7820 | 0 | nsContentUtils::GetSystemPrincipal(), |
7821 | 0 | nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, |
7822 | 0 | nsIContentPolicy::TYPE_OTHER); |
7823 | 0 | if (NS_FAILED(rv)) { |
7824 | 0 | return rv; |
7825 | 0 | } |
7826 | 0 | |
7827 | 0 | nsCOMPtr<nsIInputStream> stream; |
7828 | 0 | rv = channel->Open2(getter_AddRefs(stream)); |
7829 | 0 | if (NS_FAILED(rv)) { |
7830 | 0 | return rv; |
7831 | 0 | } |
7832 | 0 | |
7833 | 0 | rv = NS_ConsumeStream(stream, UINT32_MAX, aString); |
7834 | 0 | if (NS_FAILED(rv)) { |
7835 | 0 | return rv; |
7836 | 0 | } |
7837 | 0 | |
7838 | 0 | rv = stream->Close(); |
7839 | 0 | if (NS_FAILED(rv)) { |
7840 | 0 | return rv; |
7841 | 0 | } |
7842 | 0 | |
7843 | 0 | return NS_OK; |
7844 | 0 | } |
7845 | | |
7846 | | bool |
7847 | | nsContentUtils::IsFileImage(nsIFile* aFile, nsACString& aType) |
7848 | 0 | { |
7849 | 0 | nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1"); |
7850 | 0 | if (!mime) { |
7851 | 0 | return false; |
7852 | 0 | } |
7853 | 0 | |
7854 | 0 | nsresult rv = mime->GetTypeFromFile(aFile, aType); |
7855 | 0 | if (NS_FAILED(rv)) { |
7856 | 0 | return false; |
7857 | 0 | } |
7858 | 0 | |
7859 | 0 | return StringBeginsWith(aType, NS_LITERAL_CSTRING("image/")); |
7860 | 0 | } |
7861 | | |
7862 | | nsresult |
7863 | | nsContentUtils::CalculateBufferSizeForImage(const uint32_t& aStride, |
7864 | | const IntSize& aImageSize, |
7865 | | const SurfaceFormat& aFormat, |
7866 | | size_t* aMaxBufferSize, |
7867 | | size_t* aUsedBufferSize) |
7868 | 0 | { |
7869 | 0 | CheckedInt32 requiredBytes = |
7870 | 0 | CheckedInt32(aStride) * CheckedInt32(aImageSize.height); |
7871 | 0 | if (!requiredBytes.isValid()) { |
7872 | 0 | return NS_ERROR_FAILURE; |
7873 | 0 | } |
7874 | 0 | *aMaxBufferSize = requiredBytes.value(); |
7875 | 0 | *aUsedBufferSize = *aMaxBufferSize - aStride + (aImageSize.width * BytesPerPixel(aFormat)); |
7876 | 0 | return NS_OK; |
7877 | 0 | } |
7878 | | |
7879 | | nsresult |
7880 | | nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem, |
7881 | | imgIContainer** aContainer) |
7882 | 0 | { |
7883 | 0 | MOZ_ASSERT(aItem.data().type() == IPCDataTransferData::TShmem); |
7884 | 0 | MOZ_ASSERT(IsFlavorImage(aItem.flavor())); |
7885 | 0 |
|
7886 | 0 | const IPCDataTransferImage& imageDetails = aItem.imageDetails(); |
7887 | 0 | const IntSize size(imageDetails.width(), imageDetails.height()); |
7888 | 0 | if (!size.width || !size.height) { |
7889 | 0 | return NS_ERROR_FAILURE; |
7890 | 0 | } |
7891 | 0 | |
7892 | 0 | Shmem data = aItem.data().get_Shmem(); |
7893 | 0 |
|
7894 | 0 | // Validate shared memory buffer size |
7895 | 0 | size_t imageBufLen = 0; |
7896 | 0 | size_t maxBufLen = 0; |
7897 | 0 | nsresult rv = CalculateBufferSizeForImage(imageDetails.stride(), |
7898 | 0 | size, |
7899 | 0 | imageDetails.format(), |
7900 | 0 | &maxBufLen, |
7901 | 0 | &imageBufLen); |
7902 | 0 | if (NS_FAILED(rv)) { |
7903 | 0 | return rv; |
7904 | 0 | } |
7905 | 0 | if (imageBufLen > data.Size<uint8_t>()) { |
7906 | 0 | return NS_ERROR_FAILURE; |
7907 | 0 | } |
7908 | 0 | |
7909 | 0 | RefPtr<DataSourceSurface> image = |
7910 | 0 | CreateDataSourceSurfaceFromData(size, |
7911 | 0 | imageDetails.format(), |
7912 | 0 | data.get<uint8_t>(), |
7913 | 0 | imageDetails.stride()); |
7914 | 0 |
|
7915 | 0 | RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size); |
7916 | 0 | nsCOMPtr<imgIContainer> imageContainer = |
7917 | 0 | image::ImageOps::CreateFromDrawable(drawable); |
7918 | 0 | imageContainer.forget(aContainer); |
7919 | 0 |
|
7920 | 0 | return NS_OK; |
7921 | 0 | } |
7922 | | |
7923 | | bool |
7924 | | nsContentUtils::IsFlavorImage(const nsACString& aFlavor) |
7925 | 0 | { |
7926 | 0 | return aFlavor.EqualsLiteral(kNativeImageMime) || |
7927 | 0 | aFlavor.EqualsLiteral(kJPEGImageMime) || |
7928 | 0 | aFlavor.EqualsLiteral(kJPGImageMime) || |
7929 | 0 | aFlavor.EqualsLiteral(kPNGImageMime) || |
7930 | 0 | aFlavor.EqualsLiteral(kGIFImageMime); |
7931 | 0 | } |
7932 | | |
7933 | | static Shmem |
7934 | | ConvertToShmem(mozilla::dom::nsIContentChild* aChild, |
7935 | | mozilla::dom::nsIContentParent* aParent, |
7936 | | const nsACString& aInput) |
7937 | 0 | { |
7938 | 0 | MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent)); |
7939 | 0 |
|
7940 | 0 | IShmemAllocator* allocator = |
7941 | 0 | aChild ? static_cast<IShmemAllocator*>(aChild) |
7942 | 0 | : static_cast<IShmemAllocator*>(aParent); |
7943 | 0 |
|
7944 | 0 | Shmem result; |
7945 | 0 | if (!allocator->AllocShmem(aInput.Length(), |
7946 | 0 | SharedMemory::TYPE_BASIC, |
7947 | 0 | &result)) { |
7948 | 0 | return result; |
7949 | 0 | } |
7950 | 0 | |
7951 | 0 | memcpy(result.get<char>(), |
7952 | 0 | aInput.BeginReading(), |
7953 | 0 | aInput.Length()); |
7954 | 0 |
|
7955 | 0 | return result; |
7956 | 0 | } |
7957 | | |
7958 | | void |
7959 | | nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable, |
7960 | | IPCDataTransfer* aIPCDataTransfer, |
7961 | | bool aInSyncMessage, |
7962 | | mozilla::dom::nsIContentChild* aChild, |
7963 | | mozilla::dom::nsIContentParent* aParent) |
7964 | 0 | { |
7965 | 0 | MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent)); |
7966 | 0 |
|
7967 | 0 | if (aTransferable) { |
7968 | 0 | nsCOMPtr<nsIArray> flavorList; |
7969 | 0 | aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); |
7970 | 0 | if (flavorList) { |
7971 | 0 | uint32_t flavorCount = 0; |
7972 | 0 | flavorList->GetLength(&flavorCount); |
7973 | 0 | for (uint32_t j = 0; j < flavorCount; ++j) { |
7974 | 0 | nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j); |
7975 | 0 | if (!flavor) { |
7976 | 0 | continue; |
7977 | 0 | } |
7978 | 0 | |
7979 | 0 | nsAutoCString flavorStr; |
7980 | 0 | flavor->GetData(flavorStr); |
7981 | 0 | if (!flavorStr.Length()) { |
7982 | 0 | continue; |
7983 | 0 | } |
7984 | 0 | |
7985 | 0 | nsCOMPtr<nsISupports> data; |
7986 | 0 | uint32_t dataLen = 0; |
7987 | 0 | aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen); |
7988 | 0 |
|
7989 | 0 | nsCOMPtr<nsISupportsString> text = do_QueryInterface(data); |
7990 | 0 | nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data); |
7991 | 0 | if (text) { |
7992 | 0 | nsAutoString dataAsString; |
7993 | 0 | text->GetData(dataAsString); |
7994 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
7995 | 0 | item->flavor() = flavorStr; |
7996 | 0 | item->data() = dataAsString; |
7997 | 0 | } else if (ctext) { |
7998 | 0 | nsAutoCString dataAsString; |
7999 | 0 | ctext->GetData(dataAsString); |
8000 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8001 | 0 | item->flavor() = flavorStr; |
8002 | 0 |
|
8003 | 0 | Shmem dataAsShmem = ConvertToShmem(aChild, aParent, dataAsString); |
8004 | 0 | if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) { |
8005 | 0 | continue; |
8006 | 0 | } |
8007 | 0 | |
8008 | 0 | item->data() = dataAsShmem; |
8009 | 0 | } else { |
8010 | 0 | nsCOMPtr<nsISupportsInterfacePointer> sip = |
8011 | 0 | do_QueryInterface(data); |
8012 | 0 | if (sip) { |
8013 | 0 | sip->GetData(getter_AddRefs(data)); |
8014 | 0 | } |
8015 | 0 |
|
8016 | 0 | // Images to be pasted on the clipboard are nsIInputStreams |
8017 | 0 | nsCOMPtr<nsIInputStream> stream(do_QueryInterface(data)); |
8018 | 0 | if (stream) { |
8019 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8020 | 0 | item->flavor() = flavorStr; |
8021 | 0 |
|
8022 | 0 | nsCString imageData; |
8023 | 0 | NS_ConsumeStream(stream, UINT32_MAX, imageData); |
8024 | 0 |
|
8025 | 0 | Shmem imageDataShmem = ConvertToShmem(aChild, aParent, imageData); |
8026 | 0 | if (!imageDataShmem.IsReadable() || !imageDataShmem.Size<char>()) { |
8027 | 0 | continue; |
8028 | 0 | } |
8029 | 0 | |
8030 | 0 | item->data() = imageDataShmem; |
8031 | 0 | continue; |
8032 | 0 | } |
8033 | 0 | |
8034 | 0 | // Images to be placed on the clipboard are imgIContainers. |
8035 | 0 | nsCOMPtr<imgIContainer> image(do_QueryInterface(data)); |
8036 | 0 | if (image) { |
8037 | 0 | RefPtr<mozilla::gfx::SourceSurface> surface = |
8038 | 0 | image->GetFrame(imgIContainer::FRAME_CURRENT, |
8039 | 0 | imgIContainer::FLAG_SYNC_DECODE); |
8040 | 0 | if (!surface) { |
8041 | 0 | continue; |
8042 | 0 | } |
8043 | 0 | RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = |
8044 | 0 | surface->GetDataSurface(); |
8045 | 0 | if (!dataSurface) { |
8046 | 0 | continue; |
8047 | 0 | } |
8048 | 0 | size_t length; |
8049 | 0 | int32_t stride; |
8050 | 0 | IShmemAllocator* allocator = aChild ? static_cast<IShmemAllocator*>(aChild) |
8051 | 0 | : static_cast<IShmemAllocator*>(aParent); |
8052 | 0 | Maybe<Shmem> surfaceData = GetSurfaceData(dataSurface, &length, &stride, |
8053 | 0 | allocator); |
8054 | 0 |
|
8055 | 0 | if (surfaceData.isNothing()) { |
8056 | 0 | continue; |
8057 | 0 | } |
8058 | 0 | |
8059 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8060 | 0 | item->flavor() = flavorStr; |
8061 | 0 | // Turn item->data() into an nsCString prior to accessing it. |
8062 | 0 | item->data() = surfaceData.ref(); |
8063 | 0 |
|
8064 | 0 | IPCDataTransferImage& imageDetails = item->imageDetails(); |
8065 | 0 | mozilla::gfx::IntSize size = dataSurface->GetSize(); |
8066 | 0 | imageDetails.width() = size.width; |
8067 | 0 | imageDetails.height() = size.height; |
8068 | 0 | imageDetails.stride() = stride; |
8069 | 0 | imageDetails.format() = dataSurface->GetFormat(); |
8070 | 0 |
|
8071 | 0 | continue; |
8072 | 0 | } |
8073 | 0 | |
8074 | 0 | // Otherwise, handle this as a file. |
8075 | 0 | nsCOMPtr<BlobImpl> blobImpl; |
8076 | 0 | nsCOMPtr<nsIFile> file = do_QueryInterface(data); |
8077 | 0 | if (file) { |
8078 | 0 | // If we can send this over as a blob, do so. Otherwise, we're |
8079 | 0 | // responding to a sync message and the child can't process the blob |
8080 | 0 | // constructor before processing our response, which would crash. In |
8081 | 0 | // that case, hope that the caller is nsClipboardProxy::GetData, |
8082 | 0 | // called from editor and send over images as raw data. |
8083 | 0 | if (aInSyncMessage) { |
8084 | 0 | nsAutoCString type; |
8085 | 0 | if (IsFileImage(file, type)) { |
8086 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8087 | 0 | item->flavor() = type; |
8088 | 0 | nsAutoCString data; |
8089 | 0 | SlurpFileToString(file, data); |
8090 | 0 |
|
8091 | 0 | Shmem dataAsShmem = ConvertToShmem(aChild, aParent, data); |
8092 | 0 | item->data() = dataAsShmem; |
8093 | 0 | } |
8094 | 0 |
|
8095 | 0 | continue; |
8096 | 0 | } |
8097 | 0 |
|
8098 | 0 | if (aParent) { |
8099 | 0 | bool isDir = false; |
8100 | 0 | if (NS_SUCCEEDED(file->IsDirectory(&isDir)) && isDir) { |
8101 | 0 | nsAutoString path; |
8102 | 0 | if (NS_WARN_IF(NS_FAILED(file->GetPath(path)))) { |
8103 | 0 | continue; |
8104 | 0 | } |
8105 | 0 | |
8106 | 0 | RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate(); |
8107 | 0 | fss->GrantAccessToContentProcess(aParent->ChildID(), path); |
8108 | 0 | } |
8109 | 0 | } |
8110 | 0 |
|
8111 | 0 | blobImpl = new FileBlobImpl(file); |
8112 | 0 |
|
8113 | 0 | IgnoredErrorResult rv; |
8114 | 0 |
|
8115 | 0 | // Ensure that file data is cached no that the content process |
8116 | 0 | // has this data available to it when passed over: |
8117 | 0 | blobImpl->GetSize(rv); |
8118 | 0 | if (NS_WARN_IF(rv.Failed())) { |
8119 | 0 | continue; |
8120 | 0 | } |
8121 | 0 | |
8122 | 0 | blobImpl->GetLastModified(rv); |
8123 | 0 | if (NS_WARN_IF(rv.Failed())) { |
8124 | 0 | continue; |
8125 | 0 | } |
8126 | 0 | } else { |
8127 | 0 | if (aInSyncMessage) { |
8128 | 0 | // Can't do anything. |
8129 | 0 | continue; |
8130 | 0 | } |
8131 | 0 | blobImpl = do_QueryInterface(data); |
8132 | 0 | } |
8133 | 0 | if (blobImpl) { |
8134 | 0 | IPCDataTransferData data; |
8135 | 0 | IPCBlob ipcBlob; |
8136 | 0 |
|
8137 | 0 | // If we failed to create the blob actor, then this blob probably |
8138 | 0 | // can't get the file size for the underlying file, ignore it for |
8139 | 0 | // now. TODO pass this through anyway. |
8140 | 0 | if (aChild) { |
8141 | 0 | nsresult rv = IPCBlobUtils::Serialize(blobImpl, aChild, ipcBlob); |
8142 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
8143 | 0 | continue; |
8144 | 0 | } |
8145 | 0 | |
8146 | 0 | data = ipcBlob; |
8147 | 0 | } else if (aParent) { |
8148 | 0 | nsresult rv = IPCBlobUtils::Serialize(blobImpl, aParent, ipcBlob); |
8149 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
8150 | 0 | continue; |
8151 | 0 | } |
8152 | 0 | |
8153 | 0 | data = ipcBlob; |
8154 | 0 | } |
8155 | 0 |
|
8156 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8157 | 0 | item->flavor() = flavorStr; |
8158 | 0 | item->data() = data; |
8159 | 0 | } else { |
8160 | 0 | // This is a hack to support kFilePromiseMime. |
8161 | 0 | // On Windows there just needs to be an entry for it, |
8162 | 0 | // and for OSX we need to create |
8163 | 0 | // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider. |
8164 | 0 | if (flavorStr.EqualsLiteral(kFilePromiseMime)) { |
8165 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8166 | 0 | item->flavor() = flavorStr; |
8167 | 0 | item->data() = NS_ConvertUTF8toUTF16(flavorStr); |
8168 | 0 | } else if (!data) { |
8169 | 0 | // Empty element, transfer only the flavor |
8170 | 0 | IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); |
8171 | 0 | item->flavor() = flavorStr; |
8172 | 0 | item->data() = nsString(); |
8173 | 0 | continue; |
8174 | 0 | } |
8175 | 0 | } |
8176 | 0 | } |
8177 | 0 | } |
8178 | 0 | } |
8179 | 0 | } |
8180 | 0 | } |
8181 | | |
8182 | | namespace { |
8183 | | // The default type used for calling GetSurfaceData(). Gets surface data as |
8184 | | // raw buffer. |
8185 | | struct GetSurfaceDataRawBuffer |
8186 | | { |
8187 | | using ReturnType = mozilla::UniquePtr<char[]>; |
8188 | | using BufferType = char*; |
8189 | | |
8190 | | ReturnType Allocate(size_t aSize) |
8191 | 0 | { |
8192 | 0 | return ReturnType(new char[aSize]); |
8193 | 0 | } |
8194 | | |
8195 | | static BufferType |
8196 | | GetBuffer(const ReturnType& aReturnValue) |
8197 | 0 | { |
8198 | 0 | return aReturnValue.get(); |
8199 | 0 | } |
8200 | | |
8201 | | static ReturnType |
8202 | | NullValue() |
8203 | 0 | { |
8204 | 0 | return ReturnType(); |
8205 | 0 | } |
8206 | | }; |
8207 | | |
8208 | | // The type used for calling GetSurfaceData() that allocates and writes to |
8209 | | // a shared memory buffer. |
8210 | | struct GetSurfaceDataShmem |
8211 | | { |
8212 | | using ReturnType = Maybe<Shmem>; |
8213 | | using BufferType = char*; |
8214 | | |
8215 | | explicit GetSurfaceDataShmem(IShmemAllocator* aAllocator) |
8216 | | : mAllocator(aAllocator) |
8217 | 0 | { } |
8218 | | |
8219 | | ReturnType Allocate(size_t aSize) |
8220 | 0 | { |
8221 | 0 | Shmem shmem; |
8222 | 0 | if (!mAllocator->AllocShmem(aSize, SharedMemory::TYPE_BASIC, &shmem)) { |
8223 | 0 | return Nothing(); |
8224 | 0 | } |
8225 | 0 | |
8226 | 0 | return Some(shmem); |
8227 | 0 | } |
8228 | | |
8229 | | static BufferType |
8230 | | GetBuffer(const ReturnType& aReturnValue) |
8231 | 0 | { |
8232 | 0 | return aReturnValue.isSome() ? aReturnValue.ref().get<char>() : nullptr; |
8233 | 0 | } |
8234 | | |
8235 | | static ReturnType |
8236 | | NullValue() |
8237 | 0 | { |
8238 | 0 | return ReturnType(); |
8239 | 0 | } |
8240 | | private: |
8241 | | IShmemAllocator* mAllocator; |
8242 | | }; |
8243 | | |
8244 | | /* |
8245 | | * Get the pixel data from the given source surface and return it as a buffer. |
8246 | | * The length and stride will be assigned from the surface. |
8247 | | */ |
8248 | | template <typename GetSurfaceDataContext = GetSurfaceDataRawBuffer> |
8249 | | typename GetSurfaceDataContext::ReturnType |
8250 | | GetSurfaceDataImpl(mozilla::gfx::DataSourceSurface* aSurface, |
8251 | | size_t* aLength, int32_t* aStride, |
8252 | | GetSurfaceDataContext aContext = GetSurfaceDataContext()) |
8253 | 0 | { |
8254 | 0 | mozilla::gfx::DataSourceSurface::MappedSurface map; |
8255 | 0 | if (!aSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map)) { |
8256 | 0 | return GetSurfaceDataContext::NullValue(); |
8257 | 0 | } |
8258 | 0 | |
8259 | 0 | size_t bufLen = 0; |
8260 | 0 | size_t maxBufLen = 0; |
8261 | 0 | nsresult rv = nsContentUtils::CalculateBufferSizeForImage(map.mStride, |
8262 | 0 | aSurface->GetSize(), |
8263 | 0 | aSurface->GetFormat(), |
8264 | 0 | &maxBufLen, |
8265 | 0 | &bufLen); |
8266 | 0 | if (NS_FAILED(rv)) { |
8267 | 0 | aSurface->Unmap(); |
8268 | 0 | return GetSurfaceDataContext::NullValue(); |
8269 | 0 | } |
8270 | 0 | |
8271 | 0 | // nsDependentCString wants null-terminated string. |
8272 | 0 | typename GetSurfaceDataContext::ReturnType surfaceData = aContext.Allocate(maxBufLen + 1); |
8273 | 0 | if (GetSurfaceDataContext::GetBuffer(surfaceData)) { |
8274 | 0 | memcpy(GetSurfaceDataContext::GetBuffer(surfaceData), |
8275 | 0 | reinterpret_cast<char*>(map.mData), |
8276 | 0 | bufLen); |
8277 | 0 | memset(GetSurfaceDataContext::GetBuffer(surfaceData) + bufLen, |
8278 | 0 | 0, |
8279 | 0 | maxBufLen - bufLen + 1); |
8280 | 0 | } |
8281 | 0 |
|
8282 | 0 | *aLength = maxBufLen; |
8283 | 0 | *aStride = map.mStride; |
8284 | 0 |
|
8285 | 0 | aSurface->Unmap(); |
8286 | 0 | return surfaceData; |
8287 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:(anonymous namespace)::GetSurfaceDataRawBuffer::ReturnType (anonymous namespace)::GetSurfaceDataImpl<(anonymous namespace)::GetSurfaceDataRawBuffer>(mozilla::gfx::DataSourceSurface*, unsigned long*, int*, (anonymous namespace)::GetSurfaceDataRawBuffer) Unexecuted instantiation: nsContentUtils.cpp:(anonymous namespace)::GetSurfaceDataShmem::ReturnType (anonymous namespace)::GetSurfaceDataImpl<(anonymous namespace)::GetSurfaceDataShmem>(mozilla::gfx::DataSourceSurface*, unsigned long*, int*, (anonymous namespace)::GetSurfaceDataShmem) |
8288 | | } // Anonymous namespace. |
8289 | | |
8290 | | mozilla::UniquePtr<char[]> |
8291 | | nsContentUtils::GetSurfaceData( |
8292 | | NotNull<mozilla::gfx::DataSourceSurface*> aSurface, |
8293 | | size_t* aLength, int32_t* aStride) |
8294 | 0 | { |
8295 | 0 | return GetSurfaceDataImpl(aSurface, aLength, aStride); |
8296 | 0 | } |
8297 | | |
8298 | | Maybe<Shmem> |
8299 | | nsContentUtils::GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface, |
8300 | | size_t* aLength, int32_t* aStride, |
8301 | | IShmemAllocator* aAllocator) |
8302 | 0 | { |
8303 | 0 | return GetSurfaceDataImpl(aSurface, aLength, aStride, |
8304 | 0 | GetSurfaceDataShmem(aAllocator)); |
8305 | 0 | } |
8306 | | |
8307 | | mozilla::Modifiers |
8308 | | nsContentUtils::GetWidgetModifiers(int32_t aModifiers) |
8309 | 0 | { |
8310 | 0 | Modifiers result = 0; |
8311 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SHIFT) { |
8312 | 0 | result |= mozilla::MODIFIER_SHIFT; |
8313 | 0 | } |
8314 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_CONTROL) { |
8315 | 0 | result |= mozilla::MODIFIER_CONTROL; |
8316 | 0 | } |
8317 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALT) { |
8318 | 0 | result |= mozilla::MODIFIER_ALT; |
8319 | 0 | } |
8320 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_META) { |
8321 | 0 | result |= mozilla::MODIFIER_META; |
8322 | 0 | } |
8323 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALTGRAPH) { |
8324 | 0 | result |= mozilla::MODIFIER_ALTGRAPH; |
8325 | 0 | } |
8326 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_CAPSLOCK) { |
8327 | 0 | result |= mozilla::MODIFIER_CAPSLOCK; |
8328 | 0 | } |
8329 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_FN) { |
8330 | 0 | result |= mozilla::MODIFIER_FN; |
8331 | 0 | } |
8332 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_FNLOCK) { |
8333 | 0 | result |= mozilla::MODIFIER_FNLOCK; |
8334 | 0 | } |
8335 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_NUMLOCK) { |
8336 | 0 | result |= mozilla::MODIFIER_NUMLOCK; |
8337 | 0 | } |
8338 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SCROLLLOCK) { |
8339 | 0 | result |= mozilla::MODIFIER_SCROLLLOCK; |
8340 | 0 | } |
8341 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOL) { |
8342 | 0 | result |= mozilla::MODIFIER_SYMBOL; |
8343 | 0 | } |
8344 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK) { |
8345 | 0 | result |= mozilla::MODIFIER_SYMBOLLOCK; |
8346 | 0 | } |
8347 | 0 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_OS) { |
8348 | 0 | result |= mozilla::MODIFIER_OS; |
8349 | 0 | } |
8350 | 0 | return result; |
8351 | 0 | } |
8352 | | |
8353 | | nsIWidget* |
8354 | 0 | nsContentUtils::GetWidget(nsIPresShell* aPresShell, nsPoint* aOffset) { |
8355 | 0 | if (aPresShell) { |
8356 | 0 | nsIFrame* frame = aPresShell->GetRootFrame(); |
8357 | 0 | if (frame) |
8358 | 0 | return frame->GetView()->GetNearestWidget(aOffset); |
8359 | 0 | } |
8360 | 0 | return nullptr; |
8361 | 0 | } |
8362 | | |
8363 | | int16_t |
8364 | | nsContentUtils::GetButtonsFlagForButton(int32_t aButton) |
8365 | 0 | { |
8366 | 0 | switch (aButton) { |
8367 | 0 | case -1: |
8368 | 0 | return WidgetMouseEvent::eNoButtonFlag; |
8369 | 0 | case WidgetMouseEvent::eLeftButton: |
8370 | 0 | return WidgetMouseEvent::eLeftButtonFlag; |
8371 | 0 | case WidgetMouseEvent::eMiddleButton: |
8372 | 0 | return WidgetMouseEvent::eMiddleButtonFlag; |
8373 | 0 | case WidgetMouseEvent::eRightButton: |
8374 | 0 | return WidgetMouseEvent::eRightButtonFlag; |
8375 | 0 | case 4: |
8376 | 0 | return WidgetMouseEvent::e4thButtonFlag; |
8377 | 0 | case 5: |
8378 | 0 | return WidgetMouseEvent::e5thButtonFlag; |
8379 | 0 | default: |
8380 | 0 | NS_ERROR("Button not known."); |
8381 | 0 | return 0; |
8382 | 0 | } |
8383 | 0 | } |
8384 | | |
8385 | | LayoutDeviceIntPoint |
8386 | | nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint, |
8387 | | const nsPoint& aOffset, |
8388 | | nsPresContext* aPresContext) |
8389 | 0 | { |
8390 | 0 | return LayoutDeviceIntPoint::FromAppUnitsRounded( |
8391 | 0 | (CSSPoint::ToAppUnits(aPoint) + |
8392 | 0 | aOffset).ApplyResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(aPresContext->PresShell())), |
8393 | 0 | aPresContext->AppUnitsPerDevPixel()); |
8394 | 0 | } |
8395 | | |
8396 | | nsView* |
8397 | | nsContentUtils::GetViewToDispatchEvent(nsPresContext* presContext, |
8398 | | nsIPresShell** presShell) |
8399 | 0 | { |
8400 | 0 | if (presContext && presShell) { |
8401 | 0 | *presShell = presContext->PresShell(); |
8402 | 0 | if (*presShell) { |
8403 | 0 | NS_ADDREF(*presShell); |
8404 | 0 | if (nsViewManager* viewManager = (*presShell)->GetViewManager()) { |
8405 | 0 | if (nsView* view = viewManager->GetRootView()) { |
8406 | 0 | return view; |
8407 | 0 | } |
8408 | 0 | } |
8409 | 0 | } |
8410 | 0 | } |
8411 | 0 | return nullptr; |
8412 | 0 | } |
8413 | | |
8414 | | nsresult |
8415 | | nsContentUtils::SendMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell, |
8416 | | const nsAString& aType, |
8417 | | float aX, |
8418 | | float aY, |
8419 | | int32_t aButton, |
8420 | | int32_t aButtons, |
8421 | | int32_t aClickCount, |
8422 | | int32_t aModifiers, |
8423 | | bool aIgnoreRootScrollFrame, |
8424 | | float aPressure, |
8425 | | unsigned short aInputSourceArg, |
8426 | | uint32_t aIdentifier, |
8427 | | bool aToWindow, |
8428 | | bool *aPreventDefault, |
8429 | | bool aIsDOMEventSynthesized, |
8430 | | bool aIsWidgetEventSynthesized) |
8431 | 0 | { |
8432 | 0 | nsPoint offset; |
8433 | 0 | nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset); |
8434 | 0 | if (!widget) |
8435 | 0 | return NS_ERROR_FAILURE; |
8436 | 0 | |
8437 | 0 | EventMessage msg; |
8438 | 0 | WidgetMouseEvent::ExitFrom exitFrom = WidgetMouseEvent::eChild; |
8439 | 0 | bool contextMenuKey = false; |
8440 | 0 | if (aType.EqualsLiteral("mousedown")) { |
8441 | 0 | msg = eMouseDown; |
8442 | 0 | } else if (aType.EqualsLiteral("mouseup")) { |
8443 | 0 | msg = eMouseUp; |
8444 | 0 | } else if (aType.EqualsLiteral("mousemove")) { |
8445 | 0 | msg = eMouseMove; |
8446 | 0 | } else if (aType.EqualsLiteral("mouseover")) { |
8447 | 0 | msg = eMouseEnterIntoWidget; |
8448 | 0 | } else if (aType.EqualsLiteral("mouseout")) { |
8449 | 0 | msg = eMouseExitFromWidget; |
8450 | 0 | } else if (aType.EqualsLiteral("mousecancel")) { |
8451 | 0 | msg = eMouseExitFromWidget; |
8452 | 0 | exitFrom = WidgetMouseEvent::eTopLevel; |
8453 | 0 | } else if (aType.EqualsLiteral("mouselongtap")) { |
8454 | 0 | msg = eMouseLongTap; |
8455 | 0 | } else if (aType.EqualsLiteral("contextmenu")) { |
8456 | 0 | msg = eContextMenu; |
8457 | 0 | contextMenuKey = (aButton == 0); |
8458 | 0 | } else if (aType.EqualsLiteral("MozMouseHittest")) { |
8459 | 0 | msg = eMouseHitTest; |
8460 | 0 | } else { |
8461 | 0 | return NS_ERROR_FAILURE; |
8462 | 0 | } |
8463 | 0 | |
8464 | 0 | if (aInputSourceArg == MouseEvent_Binding::MOZ_SOURCE_UNKNOWN) { |
8465 | 0 | aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE; |
8466 | 0 | } |
8467 | 0 |
|
8468 | 0 | WidgetMouseEvent event(true, msg, widget, |
8469 | 0 | aIsWidgetEventSynthesized ? |
8470 | 0 | WidgetMouseEvent::eSynthesized : |
8471 | 0 | WidgetMouseEvent::eReal, |
8472 | 0 | contextMenuKey ? WidgetMouseEvent::eContextMenuKey : |
8473 | 0 | WidgetMouseEvent::eNormal); |
8474 | 0 | event.pointerId = aIdentifier; |
8475 | 0 | event.mModifiers = GetWidgetModifiers(aModifiers); |
8476 | 0 | event.button = aButton; |
8477 | 0 | event.buttons = aButtons != nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED ? |
8478 | 0 | aButtons : |
8479 | 0 | msg == eMouseUp ? 0 : GetButtonsFlagForButton(aButton); |
8480 | 0 | event.pressure = aPressure; |
8481 | 0 | event.inputSource = aInputSourceArg; |
8482 | 0 | event.mClickCount = aClickCount; |
8483 | 0 | event.mTime = PR_IntervalNow(); |
8484 | 0 | event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; |
8485 | 0 | event.mExitFrom = exitFrom; |
8486 | 0 |
|
8487 | 0 | nsPresContext* presContext = aPresShell->GetPresContext(); |
8488 | 0 | if (!presContext) |
8489 | 0 | return NS_ERROR_FAILURE; |
8490 | 0 | |
8491 | 0 | event.mRefPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); |
8492 | 0 | event.mIgnoreRootScrollFrame = aIgnoreRootScrollFrame; |
8493 | 0 |
|
8494 | 0 | nsEventStatus status = nsEventStatus_eIgnore; |
8495 | 0 | if (aToWindow) { |
8496 | 0 | nsCOMPtr<nsIPresShell> presShell; |
8497 | 0 | nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell)); |
8498 | 0 | if (!presShell || !view) { |
8499 | 0 | return NS_ERROR_FAILURE; |
8500 | 0 | } |
8501 | 0 | return presShell->HandleEvent(view->GetFrame(), &event, false, &status); |
8502 | 0 | } |
8503 | 0 | if (gfxPrefs::TestEventsAsyncEnabled()) { |
8504 | 0 | status = widget->DispatchInputEvent(&event); |
8505 | 0 | } else { |
8506 | 0 | nsresult rv = widget->DispatchEvent(&event, status); |
8507 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
8508 | 0 | } |
8509 | 0 | if (aPreventDefault) { |
8510 | 0 | *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); |
8511 | 0 | } |
8512 | 0 |
|
8513 | 0 | return NS_OK; |
8514 | 0 | } |
8515 | | |
8516 | | /* static */ |
8517 | | void |
8518 | | nsContentUtils::FirePageHideEvent(nsIDocShellTreeItem* aItem, |
8519 | | EventTarget* aChromeEventHandler, |
8520 | | bool aOnlySystemGroup) |
8521 | 0 | { |
8522 | 0 | nsCOMPtr<nsIDocument> doc = aItem->GetDocument(); |
8523 | 0 | NS_ASSERTION(doc, "What happened here?"); |
8524 | 0 | doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup); |
8525 | 0 |
|
8526 | 0 | int32_t childCount = 0; |
8527 | 0 | aItem->GetChildCount(&childCount); |
8528 | 0 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; |
8529 | 0 | kids.AppendElements(childCount); |
8530 | 0 | for (int32_t i = 0; i < childCount; ++i) { |
8531 | 0 | aItem->GetChildAt(i, getter_AddRefs(kids[i])); |
8532 | 0 | } |
8533 | 0 |
|
8534 | 0 | for (uint32_t i = 0; i < kids.Length(); ++i) { |
8535 | 0 | if (kids[i]) { |
8536 | 0 | FirePageHideEvent(kids[i], aChromeEventHandler, aOnlySystemGroup); |
8537 | 0 | } |
8538 | 0 | } |
8539 | 0 | } |
8540 | | |
8541 | | // The pageshow event is fired for a given document only if IsShowing() returns |
8542 | | // the same thing as aFireIfShowing. This gives us a way to fire pageshow only |
8543 | | // on documents that are still loading or only on documents that are already |
8544 | | // loaded. |
8545 | | /* static */ |
8546 | | void |
8547 | | nsContentUtils::FirePageShowEvent(nsIDocShellTreeItem* aItem, |
8548 | | EventTarget* aChromeEventHandler, |
8549 | | bool aFireIfShowing, |
8550 | | bool aOnlySystemGroup) |
8551 | 0 | { |
8552 | 0 | int32_t childCount = 0; |
8553 | 0 | aItem->GetChildCount(&childCount); |
8554 | 0 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; |
8555 | 0 | kids.AppendElements(childCount); |
8556 | 0 | for (int32_t i = 0; i < childCount; ++i) { |
8557 | 0 | aItem->GetChildAt(i, getter_AddRefs(kids[i])); |
8558 | 0 | } |
8559 | 0 |
|
8560 | 0 | for (uint32_t i = 0; i < kids.Length(); ++i) { |
8561 | 0 | if (kids[i]) { |
8562 | 0 | FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing, |
8563 | 0 | aOnlySystemGroup); |
8564 | 0 | } |
8565 | 0 | } |
8566 | 0 |
|
8567 | 0 | nsCOMPtr<nsIDocument> doc = aItem->GetDocument(); |
8568 | 0 | NS_ASSERTION(doc, "What happened here?"); |
8569 | 0 | if (doc->IsShowing() == aFireIfShowing) { |
8570 | 0 | doc->OnPageShow(true, aChromeEventHandler, aOnlySystemGroup); |
8571 | 0 | } |
8572 | 0 | } |
8573 | | |
8574 | | /* static */ |
8575 | | already_AddRefed<nsPIWindowRoot> |
8576 | | nsContentUtils::GetWindowRoot(nsIDocument* aDoc) |
8577 | 0 | { |
8578 | 0 | if (aDoc) { |
8579 | 0 | if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) { |
8580 | 0 | return win->GetTopWindowRoot(); |
8581 | 0 | } |
8582 | 0 | } |
8583 | 0 | return nullptr; |
8584 | 0 | } |
8585 | | |
8586 | | /* static */ |
8587 | | bool |
8588 | | nsContentUtils::IsPreloadType(nsContentPolicyType aType) |
8589 | 5 | { |
8590 | 5 | return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || |
8591 | 5 | aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || |
8592 | 5 | aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD); |
8593 | 5 | } |
8594 | | |
8595 | | /* static */ |
8596 | | bool |
8597 | | nsContentUtils::IsUpgradableDisplayType(nsContentPolicyType aType) |
8598 | 0 | { |
8599 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
8600 | 0 | return (aType == nsIContentPolicy::TYPE_IMAGE || |
8601 | 0 | aType == nsIContentPolicy::TYPE_MEDIA); |
8602 | 0 | } |
8603 | | |
8604 | | nsresult |
8605 | | nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal, |
8606 | | nsIDocument* aDoc, |
8607 | | nsIHttpChannel* aChannel, |
8608 | | mozilla::net::ReferrerPolicy aReferrerPolicy) |
8609 | 0 | { |
8610 | 0 | NS_ENSURE_ARG_POINTER(aPrincipal); |
8611 | 0 | NS_ENSURE_ARG_POINTER(aChannel); |
8612 | 0 |
|
8613 | 0 | nsCOMPtr<nsIURI> principalURI; |
8614 | 0 |
|
8615 | 0 | if (IsSystemPrincipal(aPrincipal)) { |
8616 | 0 | return NS_OK; |
8617 | 0 | } |
8618 | 0 | |
8619 | 0 | aPrincipal->GetURI(getter_AddRefs(principalURI)); |
8620 | 0 |
|
8621 | 0 | if (!aDoc) { |
8622 | 0 | return aChannel->SetReferrerWithPolicy(principalURI, aReferrerPolicy); |
8623 | 0 | } |
8624 | 0 | |
8625 | 0 | // If it weren't for history.push/replaceState, we could just use the |
8626 | 0 | // principal's URI here. But since we want changes to the URI effected |
8627 | 0 | // by push/replaceState to be reflected in the XHR referrer, we have to |
8628 | 0 | // be more clever. |
8629 | 0 | // |
8630 | 0 | // If the document's original URI (before any push/replaceStates) matches |
8631 | 0 | // our principal, then we use the document's current URI (after |
8632 | 0 | // push/replaceStates). Otherwise (if the document is, say, a data: |
8633 | 0 | // URI), we just use the principal's URI. |
8634 | 0 | nsCOMPtr<nsIURI> docCurURI = aDoc->GetDocumentURI(); |
8635 | 0 | nsCOMPtr<nsIURI> docOrigURI = aDoc->GetOriginalURI(); |
8636 | 0 |
|
8637 | 0 | nsCOMPtr<nsIURI> referrerURI; |
8638 | 0 |
|
8639 | 0 | if (principalURI && docCurURI && docOrigURI) { |
8640 | 0 | bool equal = false; |
8641 | 0 | principalURI->Equals(docOrigURI, &equal); |
8642 | 0 | if (equal) { |
8643 | 0 | referrerURI = docCurURI; |
8644 | 0 | } |
8645 | 0 | } |
8646 | 0 |
|
8647 | 0 | if (!referrerURI) { |
8648 | 0 | referrerURI = principalURI; |
8649 | 0 | } |
8650 | 0 |
|
8651 | 0 | return aChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy); |
8652 | 0 | } |
8653 | | |
8654 | | // static |
8655 | | net::ReferrerPolicy |
8656 | | nsContentUtils::GetReferrerPolicyFromHeader(const nsAString& aHeader) |
8657 | 0 | { |
8658 | 0 | // Multiple headers could be concatenated into one comma-separated |
8659 | 0 | // list of policies. Need to tokenize the multiple headers. |
8660 | 0 | nsCharSeparatedTokenizer tokenizer(aHeader, ','); |
8661 | 0 | nsAutoString token; |
8662 | 0 | net::ReferrerPolicy referrerPolicy = mozilla::net::RP_Unset; |
8663 | 0 | while (tokenizer.hasMoreTokens()) { |
8664 | 0 | token = tokenizer.nextToken(); |
8665 | 0 | if (token.IsEmpty()) { |
8666 | 0 | continue; |
8667 | 0 | } |
8668 | 0 | net::ReferrerPolicy policy = net::ReferrerPolicyFromString(token); |
8669 | 0 | if (policy != net::RP_Unset) { |
8670 | 0 | referrerPolicy = policy; |
8671 | 0 | } |
8672 | 0 | } |
8673 | 0 | return referrerPolicy; |
8674 | 0 | } |
8675 | | |
8676 | | // static |
8677 | | net::ReferrerPolicy |
8678 | | nsContentUtils::GetReferrerPolicyFromChannel(nsIChannel* aChannel) |
8679 | 0 | { |
8680 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); |
8681 | 0 | if (!httpChannel) { |
8682 | 0 | return net::RP_Unset; |
8683 | 0 | } |
8684 | 0 | |
8685 | 0 | nsresult rv; |
8686 | 0 | nsAutoCString headerValue; |
8687 | 0 | rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"), |
8688 | 0 | headerValue); |
8689 | 0 | if (NS_FAILED(rv) || headerValue.IsEmpty()) { |
8690 | 0 | return net::RP_Unset; |
8691 | 0 | } |
8692 | 0 | |
8693 | 0 | return GetReferrerPolicyFromHeader(NS_ConvertUTF8toUTF16(headerValue)); |
8694 | 0 | } |
8695 | | |
8696 | | // static |
8697 | | bool |
8698 | | nsContentUtils::IsNonSubresourceRequest(nsIChannel* aChannel) |
8699 | 0 | { |
8700 | 0 | nsLoadFlags loadFlags = 0; |
8701 | 0 | aChannel->GetLoadFlags(&loadFlags); |
8702 | 0 | if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) { |
8703 | 0 | return true; |
8704 | 0 | } |
8705 | 0 | |
8706 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); |
8707 | 0 | if (!loadInfo) { |
8708 | 0 | return false; |
8709 | 0 | } |
8710 | 0 | nsContentPolicyType type = loadInfo->InternalContentPolicyType(); |
8711 | 0 | return IsNonSubresourceInternalPolicyType(type); |
8712 | 0 | } |
8713 | | |
8714 | | // static |
8715 | | bool |
8716 | | nsContentUtils::IsNonSubresourceInternalPolicyType(nsContentPolicyType aType) |
8717 | 0 | { |
8718 | 0 | return aType == nsIContentPolicy::TYPE_DOCUMENT || |
8719 | 0 | aType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || |
8720 | 0 | aType == nsIContentPolicy::TYPE_INTERNAL_FRAME || |
8721 | 0 | aType == nsIContentPolicy::TYPE_INTERNAL_WORKER || |
8722 | 0 | aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER; |
8723 | 0 | } |
8724 | | |
8725 | | // static, public |
8726 | | nsContentUtils::StorageAccess |
8727 | | nsContentUtils::StorageAllowedForWindow(nsPIDOMWindowInner* aWindow) |
8728 | 0 | { |
8729 | 0 | if (nsIDocument* document = aWindow->GetExtantDoc()) { |
8730 | 0 | nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal(); |
8731 | 0 | // Note that GetChannel() below may return null, but that's OK, since the |
8732 | 0 | // callee is able to deal with a null channel argument, and if passed null, |
8733 | 0 | // will only fail to notify the UI in case storage gets blocked. |
8734 | 0 | nsIChannel* channel = document->GetChannel(); |
8735 | 0 | return InternalStorageAllowedForPrincipal(principal, aWindow, nullptr, |
8736 | 0 | channel); |
8737 | 0 | } |
8738 | 0 | |
8739 | 0 | return StorageAccess::eDeny; |
8740 | 0 | } |
8741 | | |
8742 | | // static, public |
8743 | | nsContentUtils::StorageAccess |
8744 | | nsContentUtils::StorageAllowedForDocument(nsIDocument* aDoc) |
8745 | 0 | { |
8746 | 0 | MOZ_ASSERT(aDoc); |
8747 | 0 |
|
8748 | 0 | if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) { |
8749 | 0 | nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal(); |
8750 | 0 | // Note that GetChannel() below may return null, but that's OK, since the |
8751 | 0 | // callee is able to deal with a null channel argument, and if passed null, |
8752 | 0 | // will only fail to notify the UI in case storage gets blocked. |
8753 | 0 | nsIChannel* channel = aDoc->GetChannel(); |
8754 | 0 | return InternalStorageAllowedForPrincipal(principal, inner, nullptr, |
8755 | 0 | channel); |
8756 | 0 | } |
8757 | 0 | |
8758 | 0 | return StorageAccess::eDeny; |
8759 | 0 | } |
8760 | | |
8761 | | // static, public |
8762 | | nsContentUtils::StorageAccess |
8763 | | nsContentUtils::StorageAllowedForNewWindow(nsIPrincipal* aPrincipal, |
8764 | | nsIURI* aURI, |
8765 | | nsPIDOMWindowInner* aParent) |
8766 | 0 | { |
8767 | 0 | MOZ_ASSERT(aPrincipal); |
8768 | 0 | MOZ_ASSERT(aURI); |
8769 | 0 | // parent may be nullptr |
8770 | 0 |
|
8771 | 0 | return InternalStorageAllowedForPrincipal(aPrincipal, aParent, aURI, nullptr); |
8772 | 0 | } |
8773 | | |
8774 | | // static, public |
8775 | | nsContentUtils::StorageAccess |
8776 | | nsContentUtils::StorageAllowedForChannel(nsIChannel* aChannel) |
8777 | 0 | { |
8778 | 0 | MOZ_DIAGNOSTIC_ASSERT(sSecurityManager); |
8779 | 0 | MOZ_DIAGNOSTIC_ASSERT(aChannel); |
8780 | 0 |
|
8781 | 0 | nsCOMPtr<nsIPrincipal> principal; |
8782 | 0 | Unused << sSecurityManager->GetChannelResultPrincipal(aChannel, |
8783 | 0 | getter_AddRefs(principal)); |
8784 | 0 | NS_ENSURE_TRUE(principal, nsContentUtils::StorageAccess::eDeny); |
8785 | 0 |
|
8786 | 0 | nsContentUtils::StorageAccess result = |
8787 | 0 | InternalStorageAllowedForPrincipal(principal, nullptr, nullptr, aChannel); |
8788 | 0 |
|
8789 | 0 | return result; |
8790 | 0 | } |
8791 | | |
8792 | | // static, public |
8793 | | nsContentUtils::StorageAccess |
8794 | | nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal) |
8795 | 0 | { |
8796 | 0 | return InternalStorageAllowedForPrincipal(aPrincipal, nullptr, nullptr, |
8797 | 0 | nullptr); |
8798 | 0 | } |
8799 | | |
8800 | | // static, private |
8801 | | void |
8802 | | nsContentUtils::GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal, |
8803 | | uint32_t* aLifetimePolicy) |
8804 | 0 | { |
8805 | 0 | *aLifetimePolicy = sCookiesLifetimePolicy; |
8806 | 0 |
|
8807 | 0 | // Any permissions set for the given principal will override our default |
8808 | 0 | // settings from preferences. |
8809 | 0 | nsCOMPtr<nsIPermissionManager> permissionManager = |
8810 | 0 | services::GetPermissionManager(); |
8811 | 0 | if (!permissionManager) { |
8812 | 0 | return; |
8813 | 0 | } |
8814 | 0 | |
8815 | 0 | uint32_t perm; |
8816 | 0 | permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm); |
8817 | 0 | switch (perm) { |
8818 | 0 | case nsICookiePermission::ACCESS_ALLOW: |
8819 | 0 | *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
8820 | 0 | break; |
8821 | 0 | case nsICookiePermission::ACCESS_DENY: |
8822 | 0 | *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
8823 | 0 | break; |
8824 | 0 | case nsICookiePermission::ACCESS_SESSION: |
8825 | 0 | *aLifetimePolicy = nsICookieService::ACCEPT_SESSION; |
8826 | 0 | break; |
8827 | 0 | case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY: |
8828 | 0 | // NOTE: The decision was made here to override the lifetime policy to be |
8829 | 0 | // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does |
8830 | 0 | // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a |
8831 | 0 | // specific domain. As BEHAVIOR_REJECT_FOREIGN isn't visible in our UI, |
8832 | 0 | // this is probably not an issue. |
8833 | 0 | *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
8834 | 0 | break; |
8835 | 0 | case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY: |
8836 | 0 | // NOTE: The decision was made here to override the lifetime policy to be |
8837 | 0 | // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does |
8838 | 0 | // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a |
8839 | 0 | // specific domain. As BEHAVIOR_LIMIT_FOREIGN isn't visible in our UI, |
8840 | 0 | // this is probably not an issue. |
8841 | 0 | *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
8842 | 0 | break; |
8843 | 0 | } |
8844 | 0 | } |
8845 | | |
8846 | | // static public |
8847 | | bool |
8848 | | nsContentUtils::IsThirdPartyWindowOrChannel(nsPIDOMWindowInner* aWindow, |
8849 | | nsIChannel* aChannel, |
8850 | | nsIURI* aURI) |
8851 | 0 | { |
8852 | 0 | MOZ_ASSERT(!aWindow || !aChannel, |
8853 | 0 | "A window and channel should not both be provided."); |
8854 | 0 |
|
8855 | 0 | nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); |
8856 | 0 | if (!thirdPartyUtil) { |
8857 | 0 | return false; |
8858 | 0 | } |
8859 | 0 | |
8860 | 0 | // In the absence of a window or channel, we assume that we are first-party. |
8861 | 0 | bool thirdParty = false; |
8862 | 0 |
|
8863 | 0 | if (aWindow) { |
8864 | 0 | Unused << thirdPartyUtil->IsThirdPartyWindow(aWindow->GetOuterWindow(), |
8865 | 0 | aURI, |
8866 | 0 | &thirdParty); |
8867 | 0 | } |
8868 | 0 |
|
8869 | 0 | if (aChannel) { |
8870 | 0 | // Note, we must call IsThirdPartyChannel() here and not just try to |
8871 | 0 | // use nsILoadInfo.isThirdPartyContext. That nsILoadInfo property only |
8872 | 0 | // indicates if the parent loading window is third party or not. We |
8873 | 0 | // want to check the channel URI against the loading principal as well. |
8874 | 0 | Unused << thirdPartyUtil->IsThirdPartyChannel(aChannel, |
8875 | 0 | nullptr, |
8876 | 0 | &thirdParty); |
8877 | 0 | } |
8878 | 0 |
|
8879 | 0 | return thirdParty; |
8880 | 0 | } |
8881 | | |
8882 | | // static public |
8883 | | bool |
8884 | | nsContentUtils::IsTrackingResourceWindow(nsPIDOMWindowInner* aWindow) |
8885 | 0 | { |
8886 | 0 | MOZ_ASSERT(aWindow); |
8887 | 0 |
|
8888 | 0 | nsIDocument* document = aWindow->GetExtantDoc(); |
8889 | 0 | if (!document) { |
8890 | 0 | return false; |
8891 | 0 | } |
8892 | 0 | |
8893 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = |
8894 | 0 | do_QueryInterface(document->GetChannel()); |
8895 | 0 | if (!httpChannel) { |
8896 | 0 | return false; |
8897 | 0 | } |
8898 | 0 | |
8899 | 0 | return httpChannel->GetIsTrackingResource(); |
8900 | 0 | } |
8901 | | |
8902 | | static bool |
8903 | | StorageDisabledByAntiTrackingInternal(nsPIDOMWindowInner* aWindow, |
8904 | | nsIChannel* aChannel, |
8905 | | nsIPrincipal* aPrincipal, |
8906 | | nsIURI* aURI, |
8907 | | uint32_t* aRejectedReason) |
8908 | 0 | { |
8909 | 0 | MOZ_ASSERT(aWindow || aChannel || aPrincipal); |
8910 | 0 |
|
8911 | 0 | if (aWindow) { |
8912 | 0 | nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI(); |
8913 | 0 | return !documentURI || |
8914 | 0 | !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow, |
8915 | 0 | documentURI, |
8916 | 0 | aRejectedReason); |
8917 | 0 | } |
8918 | 0 |
|
8919 | 0 | if (aChannel) { |
8920 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); |
8921 | 0 | if (!httpChannel) { |
8922 | 0 | return false; |
8923 | 0 | } |
8924 | 0 | |
8925 | 0 | nsCOMPtr<nsIURI> uri; |
8926 | 0 | nsresult rv = httpChannel->GetURI(getter_AddRefs(uri)); |
8927 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
8928 | 0 | return false; |
8929 | 0 | } |
8930 | 0 | |
8931 | 0 | return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, |
8932 | 0 | uri, |
8933 | 0 | aRejectedReason); |
8934 | 0 | } |
8935 | 0 | |
8936 | 0 | MOZ_ASSERT(aPrincipal); |
8937 | 0 | return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aPrincipal); |
8938 | 0 | } |
8939 | | |
8940 | | // static public |
8941 | | bool |
8942 | | nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, |
8943 | | nsIChannel* aChannel, |
8944 | | nsIPrincipal* aPrincipal, |
8945 | | nsIURI* aURI) |
8946 | 0 | { |
8947 | 0 | uint32_t rejectedReason = 0; |
8948 | 0 | bool disabled = |
8949 | 0 | StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI, |
8950 | 0 | &rejectedReason); |
8951 | 0 | if (disabled && sAntiTrackingControlCenterUIEnabled && rejectedReason) { |
8952 | 0 | if (aWindow) { |
8953 | 0 | AntiTrackingCommon::NotifyRejection(aWindow, rejectedReason); |
8954 | 0 | } else if (aChannel) { |
8955 | 0 | AntiTrackingCommon::NotifyRejection(aChannel, rejectedReason); |
8956 | 0 | } |
8957 | 0 | } |
8958 | 0 | return disabled; |
8959 | 0 | } |
8960 | | |
8961 | | // static, private |
8962 | | nsContentUtils::StorageAccess |
8963 | | nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal, |
8964 | | nsPIDOMWindowInner* aWindow, |
8965 | | nsIURI* aURI, |
8966 | | nsIChannel* aChannel) |
8967 | 0 | { |
8968 | 0 | MOZ_ASSERT(aPrincipal); |
8969 | 0 |
|
8970 | 0 | StorageAccess access = StorageAccess::eAllow; |
8971 | 0 |
|
8972 | 0 | // We don't allow storage on the null principal, in general. Even if the |
8973 | 0 | // calling context is chrome. |
8974 | 0 | if (aPrincipal->GetIsNullPrincipal()) { |
8975 | 0 | return StorageAccess::eDeny; |
8976 | 0 | } |
8977 | 0 | |
8978 | 0 | if (aWindow) { |
8979 | 0 | // If the document is sandboxed, then it is not permitted to use storage |
8980 | 0 | nsIDocument* document = aWindow->GetExtantDoc(); |
8981 | 0 | if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) { |
8982 | 0 | return StorageAccess::eDeny; |
8983 | 0 | } |
8984 | 0 | |
8985 | 0 | // Check if we are in private browsing, and record that fact |
8986 | 0 | if (IsInPrivateBrowsing(document)) { |
8987 | 0 | access = StorageAccess::ePrivateBrowsing; |
8988 | 0 | } |
8989 | 0 | } |
8990 | 0 |
|
8991 | 0 | uint32_t lifetimePolicy; |
8992 | 0 |
|
8993 | 0 | // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior |
8994 | 0 | // and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale). |
8995 | 0 | auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy(); |
8996 | 0 |
|
8997 | 0 | if (policy) { |
8998 | 0 | lifetimePolicy = nsICookieService::ACCEPT_NORMALLY; |
8999 | 0 | } else { |
9000 | 0 | GetCookieLifetimePolicyForPrincipal(aPrincipal, &lifetimePolicy); |
9001 | 0 | } |
9002 | 0 |
|
9003 | 0 | // Check if we should only allow storage for the session, and record that fact |
9004 | 0 | if (lifetimePolicy == nsICookieService::ACCEPT_SESSION) { |
9005 | 0 | // Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow |
9006 | 0 | // so perform a std::min comparison to make sure we preserve ePrivateBrowsing |
9007 | 0 | // if it has been set. |
9008 | 0 | access = std::min(StorageAccess::eSessionScoped, access); |
9009 | 0 | } |
9010 | 0 |
|
9011 | 0 | // About URIs are allowed to access storage, even if they don't have chrome |
9012 | 0 | // privileges. If this is not desired, than the consumer will have to |
9013 | 0 | // implement their own restriction functionality. |
9014 | 0 | // |
9015 | 0 | // This is due to backwards-compatibility and the state of storage access before |
9016 | 0 | // the introducton of nsContentUtils::InternalStorageAllowedForPrincipal: |
9017 | 0 | // |
9018 | 0 | // BEFORE: |
9019 | 0 | // localStorage, caches: allowed in 3rd-party iframes always |
9020 | 0 | // IndexedDB: allowed in 3rd-party iframes only if 3rd party URI is an about: |
9021 | 0 | // URI within a specific whitelist |
9022 | 0 | // |
9023 | 0 | // AFTER: |
9024 | 0 | // localStorage, caches: allowed in 3rd-party iframes by default. Preference |
9025 | 0 | // can be set to disable in 3rd-party, which will not disallow in about: URIs. |
9026 | 0 | // IndexedDB: allowed in 3rd-party iframes by default. Preference can be set to |
9027 | 0 | // disable in 3rd-party, which will disallow in about: URIs, unless they are |
9028 | 0 | // within a specific whitelist. |
9029 | 0 | // |
9030 | 0 | // This means that behavior for storage with internal about: URIs should not be |
9031 | 0 | // affected, which is desireable due to the lack of automated testing for about: |
9032 | 0 | // URIs with these preferences set, and the importance of the correct functioning |
9033 | 0 | // of these URIs even with custom preferences. |
9034 | 0 | nsCOMPtr<nsIURI> uri = aURI; |
9035 | 0 | if (!uri) { |
9036 | 0 | Unused << aPrincipal->GetURI(getter_AddRefs(uri)); |
9037 | 0 | } |
9038 | 0 | if (uri) { |
9039 | 0 | bool isAbout = false; |
9040 | 0 | MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout)); |
9041 | 0 | if (isAbout) { |
9042 | 0 | return access; |
9043 | 0 | } |
9044 | 0 | } |
9045 | 0 | |
9046 | 0 | if (StorageDisabledByAntiTracking(aWindow, aChannel, aPrincipal, aURI)) { |
9047 | 0 | return StorageAccess::eDeny; |
9048 | 0 | } |
9049 | 0 | |
9050 | 0 | return access; |
9051 | 0 | } |
9052 | | |
9053 | | namespace { |
9054 | | |
9055 | | // We put StringBuilder in the anonymous namespace to prevent anything outside |
9056 | | // this file from accidentally being linked against it. |
9057 | | class BulkAppender |
9058 | | { |
9059 | | typedef typename nsAString::size_type size_type; |
9060 | | |
9061 | | public: |
9062 | | explicit BulkAppender(BulkWriteHandle<char16_t>&& aHandle) |
9063 | | : mHandle(std::move(aHandle)) |
9064 | | , mPosition(0) |
9065 | 0 | { |
9066 | 0 | } |
9067 | 0 | ~BulkAppender() = default; |
9068 | | |
9069 | | template<int N> |
9070 | | void AppendLiteral(const char16_t (&aStr)[N]) |
9071 | 0 | { |
9072 | 0 | size_t len = N - 1; |
9073 | 0 | MOZ_ASSERT(mPosition + len <= mHandle.Length()); |
9074 | 0 | memcpy(mHandle.Elements() + mPosition, aStr, len * sizeof(char16_t)); |
9075 | 0 | mPosition += len; |
9076 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::BulkAppender::AppendLiteral<7>(char16_t const (&) [7]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::BulkAppender::AppendLiteral<6>(char16_t const (&) [6]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::BulkAppender::AppendLiteral<5>(char16_t const (&) [5]) |
9077 | | |
9078 | | void Append(Span<const char16_t> aStr) |
9079 | 0 | { |
9080 | 0 | size_t len = aStr.Length(); |
9081 | 0 | MOZ_ASSERT(mPosition + len <= mHandle.Length()); |
9082 | 0 | // Both mHandle.Elements() and aStr.Elements() are guaranteed |
9083 | 0 | // to be non-null (by the string implementation and by Span, |
9084 | 0 | // respectively), so not checking the pointers for null before |
9085 | 0 | // memcpy does not lead to UB even if len was zero. |
9086 | 0 | memcpy( |
9087 | 0 | mHandle.Elements() + mPosition, aStr.Elements(), len * sizeof(char16_t)); |
9088 | 0 | mPosition += len; |
9089 | 0 | } |
9090 | | |
9091 | | void Append(Span<const char> aStr) |
9092 | 0 | { |
9093 | 0 | size_t len = aStr.Length(); |
9094 | 0 | MOZ_ASSERT(mPosition + len <= mHandle.Length()); |
9095 | 0 | ConvertLatin1toUTF16(aStr, mHandle.AsSpan().From(mPosition)); |
9096 | 0 | mPosition += len; |
9097 | 0 | } |
9098 | | |
9099 | 0 | void Finish() { mHandle.Finish(mPosition, false); } |
9100 | | |
9101 | | private: |
9102 | | mozilla::BulkWriteHandle<char16_t> mHandle; |
9103 | | size_type mPosition; |
9104 | | }; |
9105 | | |
9106 | | class StringBuilder |
9107 | | { |
9108 | | private: |
9109 | | // Try to keep the size of StringBuilder close to a jemalloc bucket size. |
9110 | | static const uint32_t STRING_BUFFER_UNITS = 1020; |
9111 | | class Unit |
9112 | | { |
9113 | | public: |
9114 | | Unit() : mAtom(nullptr), mType(eUnknown), mLength(0) |
9115 | 0 | { |
9116 | 0 | MOZ_COUNT_CTOR(StringBuilder::Unit); |
9117 | 0 | } |
9118 | | ~Unit() |
9119 | 0 | { |
9120 | 0 | if (mType == eString || mType == eStringWithEncode) { |
9121 | 0 | delete mString; |
9122 | 0 | } |
9123 | 0 | MOZ_COUNT_DTOR(StringBuilder::Unit); |
9124 | 0 | } |
9125 | | |
9126 | | enum Type |
9127 | | { |
9128 | | eUnknown, |
9129 | | eAtom, |
9130 | | eString, |
9131 | | eStringWithEncode, |
9132 | | eLiteral, |
9133 | | eTextFragment, |
9134 | | eTextFragmentWithEncode, |
9135 | | }; |
9136 | | |
9137 | | union |
9138 | | { |
9139 | | nsAtom* mAtom; |
9140 | | const char16_t* mLiteral; |
9141 | | nsAutoString* mString; |
9142 | | const nsTextFragment* mTextFragment; |
9143 | | }; |
9144 | | Type mType; |
9145 | | uint32_t mLength; |
9146 | | }; |
9147 | | public: |
9148 | | StringBuilder() : mLast(this), mLength(0) |
9149 | 0 | { |
9150 | 0 | MOZ_COUNT_CTOR(StringBuilder); |
9151 | 0 | } |
9152 | | |
9153 | | ~StringBuilder() |
9154 | 0 | { |
9155 | 0 | MOZ_COUNT_DTOR(StringBuilder); |
9156 | 0 | } |
9157 | | |
9158 | | void Append(nsAtom* aAtom) |
9159 | 0 | { |
9160 | 0 | Unit* u = AddUnit(); |
9161 | 0 | u->mAtom = aAtom; |
9162 | 0 | u->mType = Unit::eAtom; |
9163 | 0 | uint32_t len = aAtom->GetLength(); |
9164 | 0 | u->mLength = len; |
9165 | 0 | mLength += len; |
9166 | 0 | } |
9167 | | |
9168 | | template<int N> |
9169 | | void Append(const char16_t (&aLiteral)[N]) |
9170 | 0 | { |
9171 | 0 | Unit* u = AddUnit(); |
9172 | 0 | u->mLiteral = aLiteral; |
9173 | 0 | u->mType = Unit::eLiteral; |
9174 | 0 | uint32_t len = N - 1; |
9175 | 0 | u->mLength = len; |
9176 | 0 | mLength += len; |
9177 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<6>(char16_t const (&) [6]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<7>(char16_t const (&) [7]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<2>(char16_t const (&) [2]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<5>(char16_t const (&) [5]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<3>(char16_t const (&) [3]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<4>(char16_t const (&) [4]) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::Append<11>(char16_t const (&) [11]) |
9178 | | |
9179 | | void Append(const nsAString& aString) |
9180 | 0 | { |
9181 | 0 | Unit* u = AddUnit(); |
9182 | 0 | u->mString = new nsAutoString(aString); |
9183 | 0 | u->mType = Unit::eString; |
9184 | 0 | uint32_t len = aString.Length(); |
9185 | 0 | u->mLength = len; |
9186 | 0 | mLength += len; |
9187 | 0 | } |
9188 | | |
9189 | | void Append(nsAutoString* aString) |
9190 | 0 | { |
9191 | 0 | Unit* u = AddUnit(); |
9192 | 0 | u->mString = aString; |
9193 | 0 | u->mType = Unit::eString; |
9194 | 0 | uint32_t len = aString->Length(); |
9195 | 0 | u->mLength = len; |
9196 | 0 | mLength += len; |
9197 | 0 | } |
9198 | | |
9199 | | void AppendWithAttrEncode(nsAutoString* aString, uint32_t aLen) |
9200 | 0 | { |
9201 | 0 | Unit* u = AddUnit(); |
9202 | 0 | u->mString = aString; |
9203 | 0 | u->mType = Unit::eStringWithEncode; |
9204 | 0 | u->mLength = aLen; |
9205 | 0 | mLength += aLen; |
9206 | 0 | } |
9207 | | |
9208 | | void Append(const nsTextFragment* aTextFragment) |
9209 | 0 | { |
9210 | 0 | Unit* u = AddUnit(); |
9211 | 0 | u->mTextFragment = aTextFragment; |
9212 | 0 | u->mType = Unit::eTextFragment; |
9213 | 0 | uint32_t len = aTextFragment->GetLength(); |
9214 | 0 | u->mLength = len; |
9215 | 0 | mLength += len; |
9216 | 0 | } |
9217 | | |
9218 | | void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t aLen) |
9219 | 0 | { |
9220 | 0 | Unit* u = AddUnit(); |
9221 | 0 | u->mTextFragment = aTextFragment; |
9222 | 0 | u->mType = Unit::eTextFragmentWithEncode; |
9223 | 0 | u->mLength = aLen; |
9224 | 0 | mLength += aLen; |
9225 | 0 | } |
9226 | | |
9227 | | bool ToString(nsAString& aOut) |
9228 | 0 | { |
9229 | 0 | nsresult rv; |
9230 | 0 | BulkAppender appender(aOut.BulkWrite(mLength, 0, true, rv)); |
9231 | 0 | if (NS_FAILED(rv)) { |
9232 | 0 | return false; |
9233 | 0 | } |
9234 | 0 | |
9235 | 0 | for (StringBuilder* current = this; current; current = current->mNext) { |
9236 | 0 | uint32_t len = current->mUnits.Length(); |
9237 | 0 | for (uint32_t i = 0; i < len; ++i) { |
9238 | 0 | Unit& u = current->mUnits[i]; |
9239 | 0 | switch (u.mType) { |
9240 | 0 | case Unit::eAtom: |
9241 | 0 | appender.Append(*(u.mAtom)); |
9242 | 0 | break; |
9243 | 0 | case Unit::eString: |
9244 | 0 | appender.Append(*(u.mString)); |
9245 | 0 | break; |
9246 | 0 | case Unit::eStringWithEncode: |
9247 | 0 | EncodeAttrString(*(u.mString), appender); |
9248 | 0 | break; |
9249 | 0 | case Unit::eLiteral: |
9250 | 0 | appender.Append(MakeSpan(u.mLiteral, u.mLength)); |
9251 | 0 | break; |
9252 | 0 | case Unit::eTextFragment: |
9253 | 0 | if (u.mTextFragment->Is2b()) { |
9254 | 0 | appender.Append(MakeSpan(u.mTextFragment->Get2b(), |
9255 | 0 | u.mTextFragment->GetLength())); |
9256 | 0 | } else { |
9257 | 0 | appender.Append(MakeSpan(u.mTextFragment->Get1b(), |
9258 | 0 | u.mTextFragment->GetLength())); |
9259 | 0 | } |
9260 | 0 | break; |
9261 | 0 | case Unit::eTextFragmentWithEncode: |
9262 | 0 | if (u.mTextFragment->Is2b()) { |
9263 | 0 | EncodeTextFragment(MakeSpan(u.mTextFragment->Get2b(), |
9264 | 0 | u.mTextFragment->GetLength()), |
9265 | 0 | appender); |
9266 | 0 | } else { |
9267 | 0 | EncodeTextFragment(MakeSpan(u.mTextFragment->Get1b(), |
9268 | 0 | u.mTextFragment->GetLength()), |
9269 | 0 | appender); |
9270 | 0 | } |
9271 | 0 | break; |
9272 | 0 | default: |
9273 | 0 | MOZ_CRASH("Unknown unit type?"); |
9274 | 0 | } |
9275 | 0 | } |
9276 | 0 | } |
9277 | 0 | appender.Finish(); |
9278 | 0 | return true; |
9279 | 0 | } |
9280 | | private: |
9281 | | Unit* AddUnit() |
9282 | 0 | { |
9283 | 0 | if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) { |
9284 | 0 | new StringBuilder(this); |
9285 | 0 | } |
9286 | 0 | return mLast->mUnits.AppendElement(); |
9287 | 0 | } |
9288 | | |
9289 | | explicit StringBuilder(StringBuilder* aFirst) |
9290 | | : mLast(nullptr), mLength(0) |
9291 | 0 | { |
9292 | 0 | MOZ_COUNT_CTOR(StringBuilder); |
9293 | 0 | aFirst->mLast->mNext = this; |
9294 | 0 | aFirst->mLast = this; |
9295 | 0 | } |
9296 | | |
9297 | | void EncodeAttrString(Span<const char16_t> aStr, BulkAppender& aAppender) |
9298 | 0 | { |
9299 | 0 | size_t flushedUntil = 0; |
9300 | 0 | size_t currentPosition = 0; |
9301 | 0 | for (char16_t c : aStr) { |
9302 | 0 | switch (c) { |
9303 | 0 | case '"': |
9304 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9305 | 0 | aAppender.AppendLiteral(u"""); |
9306 | 0 | flushedUntil = currentPosition + 1; |
9307 | 0 | break; |
9308 | 0 | case '&': |
9309 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9310 | 0 | aAppender.AppendLiteral(u"&"); |
9311 | 0 | flushedUntil = currentPosition + 1; |
9312 | 0 | break; |
9313 | 0 | case 0x00A0: |
9314 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9315 | 0 | aAppender.AppendLiteral(u" "); |
9316 | 0 | flushedUntil = currentPosition + 1; |
9317 | 0 | break; |
9318 | 0 | default: |
9319 | 0 | break; |
9320 | 0 | } |
9321 | 0 | currentPosition++; |
9322 | 0 | } |
9323 | 0 | if (currentPosition > flushedUntil) { |
9324 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9325 | 0 | } |
9326 | 0 | } |
9327 | | |
9328 | | template<class T> |
9329 | | void EncodeTextFragment(Span<const T> aStr, BulkAppender& aAppender) |
9330 | 0 | { |
9331 | 0 | size_t flushedUntil = 0; |
9332 | 0 | size_t currentPosition = 0; |
9333 | 0 | for (T c : aStr) { |
9334 | 0 | switch (c) { |
9335 | 0 | case '<': |
9336 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9337 | 0 | aAppender.AppendLiteral(u"<"); |
9338 | 0 | flushedUntil = currentPosition + 1; |
9339 | 0 | break; |
9340 | 0 | case '>': |
9341 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9342 | 0 | aAppender.AppendLiteral(u">"); |
9343 | 0 | flushedUntil = currentPosition + 1; |
9344 | 0 | break; |
9345 | 0 | case '&': |
9346 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9347 | 0 | aAppender.AppendLiteral(u"&"); |
9348 | 0 | flushedUntil = currentPosition + 1; |
9349 | 0 | break; |
9350 | 0 | case T(0xA0): |
9351 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9352 | 0 | aAppender.AppendLiteral(u" "); |
9353 | 0 | flushedUntil = currentPosition + 1; |
9354 | 0 | break; |
9355 | 0 | default: |
9356 | 0 | break; |
9357 | 0 | } |
9358 | 0 | currentPosition++; |
9359 | 0 | } |
9360 | 0 | if (currentPosition > flushedUntil) { |
9361 | 0 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); |
9362 | 0 | } |
9363 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::EncodeTextFragment<char16_t>(mozilla::Span<char16_t const, 18446744073709551615ul>, (anonymous namespace)::BulkAppender&) Unexecuted instantiation: nsContentUtils.cpp:void (anonymous namespace)::StringBuilder::EncodeTextFragment<char>(mozilla::Span<char const, 18446744073709551615ul>, (anonymous namespace)::BulkAppender&) |
9364 | | |
9365 | | AutoTArray<Unit, STRING_BUFFER_UNITS> mUnits; |
9366 | | nsAutoPtr<StringBuilder> mNext; |
9367 | | StringBuilder* mLast; |
9368 | | // mLength is used only in the first StringBuilder object in the linked list. |
9369 | | uint32_t mLength; |
9370 | | }; |
9371 | | |
9372 | | } // namespace |
9373 | | |
9374 | | static void |
9375 | | AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder) |
9376 | 0 | { |
9377 | 0 | uint32_t extraSpaceNeeded = 0; |
9378 | 0 | uint32_t len = aText->GetLength(); |
9379 | 0 | if (aText->Is2b()) { |
9380 | 0 | const char16_t* data = aText->Get2b(); |
9381 | 0 | for (uint32_t i = 0; i < len; ++i) { |
9382 | 0 | const char16_t c = data[i]; |
9383 | 0 | switch (c) { |
9384 | 0 | case '<': |
9385 | 0 | extraSpaceNeeded += ArrayLength("<") - 2; |
9386 | 0 | break; |
9387 | 0 | case '>': |
9388 | 0 | extraSpaceNeeded += ArrayLength(">") - 2; |
9389 | 0 | break; |
9390 | 0 | case '&': |
9391 | 0 | extraSpaceNeeded += ArrayLength("&") - 2; |
9392 | 0 | break; |
9393 | 0 | case 0x00A0: |
9394 | 0 | extraSpaceNeeded += ArrayLength(" ") - 2; |
9395 | 0 | break; |
9396 | 0 | default: |
9397 | 0 | break; |
9398 | 0 | } |
9399 | 0 | } |
9400 | 0 | } else { |
9401 | 0 | const char* data = aText->Get1b(); |
9402 | 0 | for (uint32_t i = 0; i < len; ++i) { |
9403 | 0 | const unsigned char c = data[i]; |
9404 | 0 | switch (c) { |
9405 | 0 | case '<': |
9406 | 0 | extraSpaceNeeded += ArrayLength("<") - 2; |
9407 | 0 | break; |
9408 | 0 | case '>': |
9409 | 0 | extraSpaceNeeded += ArrayLength(">") - 2; |
9410 | 0 | break; |
9411 | 0 | case '&': |
9412 | 0 | extraSpaceNeeded += ArrayLength("&") - 2; |
9413 | 0 | break; |
9414 | 0 | case 0x00A0: |
9415 | 0 | extraSpaceNeeded += ArrayLength(" ") - 2; |
9416 | 0 | break; |
9417 | 0 | default: |
9418 | 0 | break; |
9419 | 0 | } |
9420 | 0 | } |
9421 | 0 | } |
9422 | 0 |
|
9423 | 0 | if (extraSpaceNeeded) { |
9424 | 0 | aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded); |
9425 | 0 | } else { |
9426 | 0 | aBuilder.Append(aText); |
9427 | 0 | } |
9428 | 0 | } |
9429 | | |
9430 | | static void |
9431 | | AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder) |
9432 | 0 | { |
9433 | 0 | const char16_t* c = aValue->BeginReading(); |
9434 | 0 | const char16_t* end = aValue->EndReading(); |
9435 | 0 |
|
9436 | 0 | uint32_t extraSpaceNeeded = 0; |
9437 | 0 | while (c < end) { |
9438 | 0 | switch (*c) { |
9439 | 0 | case '"': |
9440 | 0 | extraSpaceNeeded += ArrayLength(""") - 2; |
9441 | 0 | break; |
9442 | 0 | case '&': |
9443 | 0 | extraSpaceNeeded += ArrayLength("&") - 2; |
9444 | 0 | break; |
9445 | 0 | case 0x00A0: |
9446 | 0 | extraSpaceNeeded += ArrayLength(" ") - 2; |
9447 | 0 | break; |
9448 | 0 | default: |
9449 | 0 | break; |
9450 | 0 | } |
9451 | 0 | ++c; |
9452 | 0 | } |
9453 | 0 |
|
9454 | 0 | if (extraSpaceNeeded) { |
9455 | 0 | aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded); |
9456 | 0 | } else { |
9457 | 0 | aBuilder.Append(aValue); |
9458 | 0 | } |
9459 | 0 | } |
9460 | | |
9461 | | static void |
9462 | | StartElement(Element* aContent, StringBuilder& aBuilder) |
9463 | 0 | { |
9464 | 0 | nsAtom* localName = aContent->NodeInfo()->NameAtom(); |
9465 | 0 | int32_t tagNS = aContent->GetNameSpaceID(); |
9466 | 0 |
|
9467 | 0 | aBuilder.Append(u"<"); |
9468 | 0 | if (aContent->IsHTMLElement() || aContent->IsSVGElement() || |
9469 | 0 | aContent->IsMathMLElement()) { |
9470 | 0 | aBuilder.Append(localName); |
9471 | 0 | } else { |
9472 | 0 | aBuilder.Append(aContent->NodeName()); |
9473 | 0 | } |
9474 | 0 |
|
9475 | 0 | CustomElementData* ceData = aContent->GetCustomElementData(); |
9476 | 0 | if (ceData) { |
9477 | 0 | nsAtom* isAttr = ceData->GetIs(aContent); |
9478 | 0 | if (isAttr && !aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) { |
9479 | 0 | aBuilder.Append(uR"( is=")"); |
9480 | 0 | aBuilder.Append(nsDependentAtomString(isAttr)); |
9481 | 0 | aBuilder.Append(uR"(")"); |
9482 | 0 | } |
9483 | 0 | } |
9484 | 0 |
|
9485 | 0 | int32_t count = aContent->GetAttrCount(); |
9486 | 0 | for (int32_t i = 0; i < count; i++) { |
9487 | 0 | const nsAttrName* name = aContent->GetAttrNameAt(i); |
9488 | 0 | int32_t attNs = name->NamespaceID(); |
9489 | 0 | nsAtom* attName = name->LocalName(); |
9490 | 0 |
|
9491 | 0 | // Filter out any attribute starting with [-|_]moz |
9492 | 0 | nsDependentAtomString attrNameStr(attName); |
9493 | 0 | if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) || |
9494 | 0 | StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) { |
9495 | 0 | continue; |
9496 | 0 | } |
9497 | 0 | |
9498 | 0 | auto* attValue = new nsAutoString(); |
9499 | 0 | aContent->GetAttr(attNs, attName, *attValue); |
9500 | 0 |
|
9501 | 0 | // Filter out special case of <br type="_moz*"> used by the editor. |
9502 | 0 | // Bug 16988. Yuck. |
9503 | 0 | if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML && |
9504 | 0 | attName == nsGkAtoms::type && attNs == kNameSpaceID_None && |
9505 | 0 | StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) { |
9506 | 0 | delete attValue; |
9507 | 0 | continue; |
9508 | 0 | } |
9509 | 0 | |
9510 | 0 | aBuilder.Append(u" "); |
9511 | 0 |
|
9512 | 0 | if (MOZ_LIKELY(attNs == kNameSpaceID_None) || |
9513 | 0 | (attNs == kNameSpaceID_XMLNS && |
9514 | 0 | attName == nsGkAtoms::xmlns)) { |
9515 | 0 | // Nothing else required |
9516 | 0 | } else if (attNs == kNameSpaceID_XML) { |
9517 | 0 | aBuilder.Append(u"xml:"); |
9518 | 0 | } else if (attNs == kNameSpaceID_XMLNS) { |
9519 | 0 | aBuilder.Append(u"xmlns:"); |
9520 | 0 | } else if (attNs == kNameSpaceID_XLink) { |
9521 | 0 | aBuilder.Append(u"xlink:"); |
9522 | 0 | } else { |
9523 | 0 | nsAtom* prefix = name->GetPrefix(); |
9524 | 0 | if (prefix) { |
9525 | 0 | aBuilder.Append(prefix); |
9526 | 0 | aBuilder.Append(u":"); |
9527 | 0 | } |
9528 | 0 | } |
9529 | 0 |
|
9530 | 0 | aBuilder.Append(attName); |
9531 | 0 | aBuilder.Append(uR"(=")"); |
9532 | 0 | AppendEncodedAttributeValue(attValue, aBuilder); |
9533 | 0 | aBuilder.Append(uR"(")"); |
9534 | 0 | } |
9535 | 0 |
|
9536 | 0 | aBuilder.Append(u">"); |
9537 | 0 |
|
9538 | 0 | /* |
9539 | 0 | // Per HTML spec we should append one \n if the first child of |
9540 | 0 | // pre/textarea/listing is a textnode and starts with a \n. |
9541 | 0 | // But because browsers haven't traditionally had that behavior, |
9542 | 0 | // we're not changing our behavior either - yet. |
9543 | 0 | if (aContent->IsHTMLElement()) { |
9544 | 0 | if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea || |
9545 | 0 | localName == nsGkAtoms::listing) { |
9546 | 0 | nsIContent* fc = aContent->GetFirstChild(); |
9547 | 0 | if (fc && |
9548 | 0 | (fc->NodeType() == nsINode::TEXT_NODE || |
9549 | 0 | fc->NodeType() == nsINode::CDATA_SECTION_NODE)) { |
9550 | 0 | const nsTextFragment* text = fc->GetText(); |
9551 | 0 | if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) { |
9552 | 0 | aBuilder.Append("\n"); |
9553 | 0 | } |
9554 | 0 | } |
9555 | 0 | } |
9556 | 0 | }*/ |
9557 | 0 | } |
9558 | | |
9559 | | static inline bool |
9560 | | ShouldEscape(nsIContent* aParent) |
9561 | 0 | { |
9562 | 0 | if (!aParent || !aParent->IsHTMLElement()) { |
9563 | 0 | return true; |
9564 | 0 | } |
9565 | 0 | |
9566 | 0 | static const nsAtom* nonEscapingElements[] = { |
9567 | 0 | nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp, |
9568 | 0 | nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes, |
9569 | 0 | nsGkAtoms::plaintext, |
9570 | 0 | // Per the current spec noscript should be escaped in case |
9571 | 0 | // scripts are disabled or if document doesn't have |
9572 | 0 | // browsing context. However the latter seems to be a spec bug |
9573 | 0 | // and Gecko hasn't traditionally done the former. |
9574 | 0 | nsGkAtoms::noscript |
9575 | 0 | }; |
9576 | 0 | static mozilla::BloomFilter<12, nsAtom> sFilter; |
9577 | 0 | static bool sInitialized = false; |
9578 | 0 | if (!sInitialized) { |
9579 | 0 | sInitialized = true; |
9580 | 0 | for (auto& nonEscapingElement : nonEscapingElements) { |
9581 | 0 | sFilter.add(nonEscapingElement); |
9582 | 0 | } |
9583 | 0 | } |
9584 | 0 |
|
9585 | 0 | nsAtom* tag = aParent->NodeInfo()->NameAtom(); |
9586 | 0 | if (sFilter.mightContain(tag)) { |
9587 | 0 | for (auto& nonEscapingElement : nonEscapingElements) { |
9588 | 0 | if (tag == nonEscapingElement) { |
9589 | 0 | return false; |
9590 | 0 | } |
9591 | 0 | } |
9592 | 0 | } |
9593 | 0 | return true; |
9594 | 0 | } |
9595 | | |
9596 | | static inline bool |
9597 | | IsVoidTag(Element* aElement) |
9598 | 0 | { |
9599 | 0 | if (!aElement->IsHTMLElement()) { |
9600 | 0 | return false; |
9601 | 0 | } |
9602 | 0 | return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom()); |
9603 | 0 | } |
9604 | | |
9605 | | bool |
9606 | | nsContentUtils::SerializeNodeToMarkup(nsINode* aRoot, |
9607 | | bool aDescendentsOnly, |
9608 | | nsAString& aOut) |
9609 | 0 | { |
9610 | 0 | // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true |
9611 | 0 | MOZ_ASSERT(aDescendentsOnly || |
9612 | 0 | aRoot->NodeType() != nsINode::DOCUMENT_NODE); |
9613 | 0 |
|
9614 | 0 | nsINode* current = aDescendentsOnly ? |
9615 | 0 | nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : aRoot; |
9616 | 0 |
|
9617 | 0 | if (!current) { |
9618 | 0 | return true; |
9619 | 0 | } |
9620 | 0 | |
9621 | 0 | StringBuilder builder; |
9622 | 0 | nsIContent* next; |
9623 | 0 | while (true) { |
9624 | 0 | bool isVoid = false; |
9625 | 0 | switch (current->NodeType()) { |
9626 | 0 | case nsINode::ELEMENT_NODE: { |
9627 | 0 | Element* elem = current->AsElement(); |
9628 | 0 | StartElement(elem, builder); |
9629 | 0 | isVoid = IsVoidTag(elem); |
9630 | 0 | if (!isVoid && |
9631 | 0 | (next = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) { |
9632 | 0 | current = next; |
9633 | 0 | continue; |
9634 | 0 | } |
9635 | 0 | break; |
9636 | 0 | } |
9637 | 0 |
|
9638 | 0 | case nsINode::TEXT_NODE: |
9639 | 0 | case nsINode::CDATA_SECTION_NODE: { |
9640 | 0 | const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText(); |
9641 | 0 | nsIContent* parent = current->GetParent(); |
9642 | 0 | if (ShouldEscape(parent)) { |
9643 | 0 | AppendEncodedCharacters(text, builder); |
9644 | 0 | } else { |
9645 | 0 | builder.Append(text); |
9646 | 0 | } |
9647 | 0 | break; |
9648 | 0 | } |
9649 | 0 |
|
9650 | 0 | case nsINode::COMMENT_NODE: { |
9651 | 0 | builder.Append(u"<!--"); |
9652 | 0 | builder.Append(static_cast<nsIContent*>(current)->GetText()); |
9653 | 0 | builder.Append(u"-->"); |
9654 | 0 | break; |
9655 | 0 | } |
9656 | 0 |
|
9657 | 0 | case nsINode::DOCUMENT_TYPE_NODE: { |
9658 | 0 | builder.Append(u"<!DOCTYPE "); |
9659 | 0 | builder.Append(current->NodeName()); |
9660 | 0 | builder.Append(u">"); |
9661 | 0 | break; |
9662 | 0 | } |
9663 | 0 |
|
9664 | 0 | case nsINode::PROCESSING_INSTRUCTION_NODE: { |
9665 | 0 | builder.Append(u"<?"); |
9666 | 0 | builder.Append(current->NodeName()); |
9667 | 0 | builder.Append(u" "); |
9668 | 0 | builder.Append(static_cast<nsIContent*>(current)->GetText()); |
9669 | 0 | builder.Append(u">"); |
9670 | 0 | break; |
9671 | 0 | } |
9672 | 0 | } |
9673 | 0 | |
9674 | 0 | while (true) { |
9675 | 0 | if (!isVoid && current->NodeType() == nsINode::ELEMENT_NODE) { |
9676 | 0 | builder.Append(u"</"); |
9677 | 0 | nsIContent* elem = static_cast<nsIContent*>(current); |
9678 | 0 | if (elem->IsHTMLElement() || elem->IsSVGElement() || |
9679 | 0 | elem->IsMathMLElement()) { |
9680 | 0 | builder.Append(elem->NodeInfo()->NameAtom()); |
9681 | 0 | } else { |
9682 | 0 | builder.Append(current->NodeName()); |
9683 | 0 | } |
9684 | 0 | builder.Append(u">"); |
9685 | 0 | } |
9686 | 0 | isVoid = false; |
9687 | 0 |
|
9688 | 0 | if (current == aRoot) { |
9689 | 0 | return builder.ToString(aOut); |
9690 | 0 | } |
9691 | 0 | |
9692 | 0 | if ((next = current->GetNextSibling())) { |
9693 | 0 | current = next; |
9694 | 0 | break; |
9695 | 0 | } |
9696 | 0 | |
9697 | 0 | current = current->GetParentNode(); |
9698 | 0 |
|
9699 | 0 | // Handle template element. If the parent is a template's content, |
9700 | 0 | // then adjust the parent to be the template element. |
9701 | 0 | if (current != aRoot && |
9702 | 0 | current->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) { |
9703 | 0 | DocumentFragment* frag = static_cast<DocumentFragment*>(current); |
9704 | 0 | nsIContent* fragHost = frag->GetHost(); |
9705 | 0 | if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) { |
9706 | 0 | current = fragHost; |
9707 | 0 | } |
9708 | 0 | } |
9709 | 0 |
|
9710 | 0 | if (aDescendentsOnly && current == aRoot) { |
9711 | 0 | return builder.ToString(aOut); |
9712 | 0 | } |
9713 | 0 | } |
9714 | 0 | } |
9715 | 0 | } |
9716 | | |
9717 | | bool |
9718 | | nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri) |
9719 | 0 | { |
9720 | 0 | // aUri must start with about: or this isn't the right function to be using. |
9721 | 0 | MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0); |
9722 | 0 |
|
9723 | 0 | // Make sure the global is a window |
9724 | 0 | MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal)); |
9725 | 0 | nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobal); |
9726 | 0 | if (!win) { |
9727 | 0 | return false; |
9728 | 0 | } |
9729 | 0 | |
9730 | 0 | nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal(); |
9731 | 0 | NS_ENSURE_TRUE(principal, false); |
9732 | 0 | nsCOMPtr<nsIURI> uri; |
9733 | 0 | principal->GetURI(getter_AddRefs(uri)); |
9734 | 0 | if (!uri) { |
9735 | 0 | return false; |
9736 | 0 | } |
9737 | 0 | |
9738 | 0 | // First check the scheme to avoid getting long specs in the common case. |
9739 | 0 | bool isAbout = false; |
9740 | 0 | uri->SchemeIs("about", &isAbout); |
9741 | 0 | if (!isAbout) { |
9742 | 0 | return false; |
9743 | 0 | } |
9744 | 0 | |
9745 | 0 | // Now check the spec itself |
9746 | 0 | nsAutoCString spec; |
9747 | 0 | uri->GetSpecIgnoringRef(spec); |
9748 | 0 | return spec.EqualsASCII(aUri); |
9749 | 0 | } |
9750 | | |
9751 | | /* static */ void |
9752 | | nsContentUtils::SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible) |
9753 | 0 | { |
9754 | 0 | nsCOMPtr<nsIScrollable> scroller = do_QueryInterface(aDocShell); |
9755 | 0 |
|
9756 | 0 | if (scroller) { |
9757 | 0 | int32_t prefValue; |
9758 | 0 |
|
9759 | 0 | if (aVisible) { |
9760 | 0 | prefValue = nsIScrollable::Scrollbar_Auto; |
9761 | 0 | } else { |
9762 | 0 | prefValue = nsIScrollable::Scrollbar_Never; |
9763 | 0 | } |
9764 | 0 |
|
9765 | 0 | scroller->SetDefaultScrollbarPreferences( |
9766 | 0 | nsIScrollable::ScrollOrientation_Y, prefValue); |
9767 | 0 | scroller->SetDefaultScrollbarPreferences( |
9768 | 0 | nsIScrollable::ScrollOrientation_X, prefValue); |
9769 | 0 | } |
9770 | 0 | } |
9771 | | |
9772 | | /* static */ void |
9773 | | nsContentUtils::GetPresentationURL(nsIDocShell* aDocShell, nsAString& aPresentationUrl) |
9774 | 0 | { |
9775 | 0 | MOZ_ASSERT(aDocShell); |
9776 | 0 |
|
9777 | 0 | // Simulate receiver context for web platform test |
9778 | 0 | if (Preferences::GetBool("dom.presentation.testing.simulate-receiver")) { |
9779 | 0 | nsCOMPtr<nsIDocument> doc; |
9780 | 0 |
|
9781 | 0 | nsCOMPtr<nsPIDOMWindowOuter> docShellWin = |
9782 | 0 | do_QueryInterface(aDocShell->GetScriptGlobalObject()); |
9783 | 0 | if (docShellWin) { |
9784 | 0 | doc = docShellWin->GetExtantDoc(); |
9785 | 0 | } |
9786 | 0 |
|
9787 | 0 | if (NS_WARN_IF(!doc)) { |
9788 | 0 | return; |
9789 | 0 | } |
9790 | 0 | |
9791 | 0 | nsCOMPtr<nsIURI> uri = doc->GetDocumentURI(); |
9792 | 0 | if (NS_WARN_IF(!uri)) { |
9793 | 0 | return; |
9794 | 0 | } |
9795 | 0 | |
9796 | 0 | nsAutoCString uriStr; |
9797 | 0 | uri->GetSpec(uriStr); |
9798 | 0 | aPresentationUrl = NS_ConvertUTF8toUTF16(uriStr); |
9799 | 0 | return; |
9800 | 0 | } |
9801 | 0 | |
9802 | 0 | if (XRE_IsContentProcess()) { |
9803 | 0 | nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; |
9804 | 0 | aDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); |
9805 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
9806 | 0 | aDocShell->GetRootTreeItem(getter_AddRefs(root)); |
9807 | 0 | if (sameTypeRoot.get() == root.get()) { |
9808 | 0 | // presentation URL is stored in TabChild for the top most |
9809 | 0 | // <iframe mozbrowser> in content process. |
9810 | 0 | TabChild* tabChild = TabChild::GetFrom(aDocShell); |
9811 | 0 | if (tabChild) { |
9812 | 0 | aPresentationUrl = tabChild->PresentationURL(); |
9813 | 0 | } |
9814 | 0 | return; |
9815 | 0 | } |
9816 | 0 | } |
9817 | 0 |
|
9818 | 0 | nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(aDocShell)); |
9819 | 0 | RefPtr<Element> topFrameElt; |
9820 | 0 | loadContext->GetTopFrameElement(getter_AddRefs(topFrameElt)); |
9821 | 0 | if (!topFrameElt) { |
9822 | 0 | return; |
9823 | 0 | } |
9824 | 0 | |
9825 | 0 | topFrameElt->GetAttribute(NS_LITERAL_STRING("mozpresentation"), aPresentationUrl); |
9826 | 0 | } |
9827 | | |
9828 | | /* static */ nsIDocShell* |
9829 | | nsContentUtils::GetDocShellForEventTarget(EventTarget* aTarget) |
9830 | 0 | { |
9831 | 0 | nsCOMPtr<nsPIDOMWindowInner> innerWindow; |
9832 | 0 |
|
9833 | 0 | if (nsCOMPtr<nsINode> node = do_QueryInterface(aTarget)) { |
9834 | 0 | bool ignore; |
9835 | 0 | innerWindow = |
9836 | 0 | do_QueryInterface(node->OwnerDoc()->GetScriptHandlingObject(ignore)); |
9837 | 0 | } else if ((innerWindow = do_QueryInterface(aTarget))) { |
9838 | 0 | // Nothing else to do |
9839 | 0 | } else { |
9840 | 0 | nsCOMPtr<DOMEventTargetHelper> helper = do_QueryInterface(aTarget); |
9841 | 0 | if (helper) { |
9842 | 0 | innerWindow = helper->GetOwner(); |
9843 | 0 | } |
9844 | 0 | } |
9845 | 0 |
|
9846 | 0 | if (innerWindow) { |
9847 | 0 | return innerWindow->GetDocShell(); |
9848 | 0 | } |
9849 | 0 | |
9850 | 0 | return nullptr; |
9851 | 0 | } |
9852 | | |
9853 | | /* |
9854 | | * Note: this function only relates to figuring out HTTPS state, which is an |
9855 | | * input to the Secure Context algorithm. We are not actually implementing any |
9856 | | * part of the Secure Context algorithm itself here. |
9857 | | * |
9858 | | * This is a bit of a hack. Ideally we'd propagate HTTPS state through |
9859 | | * nsIChannel as described in the Fetch and HTML specs, but making channels |
9860 | | * know about whether they should inherit HTTPS state, propagating information |
9861 | | * about who the channel's "client" is, exposing GetHttpsState API on channels |
9862 | | * and modifying the various cache implementations to store and retrieve HTTPS |
9863 | | * state involves a huge amount of code (see bug 1220687). We avoid that for |
9864 | | * now using this function. |
9865 | | * |
9866 | | * This function takes advantage of the observation that we can return true if |
9867 | | * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for |
9868 | | * the document's origin (e.g. the origin has a scheme of 'https' or host |
9869 | | * 'localhost' etc.). Since we generally propagate a creator document's origin |
9870 | | * onto data:, blob:, etc. documents, this works for them too. |
9871 | | * |
9872 | | * The scenario where this observation breaks down is sandboxing without the |
9873 | | * 'allow-same-origin' flag, since in this case a document is given a unique |
9874 | | * origin (IsOriginPotentiallyTrustworthy would return false). We handle that |
9875 | | * by using the origin that the document would have had had it not been |
9876 | | * sandboxed. |
9877 | | * |
9878 | | * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's |
9879 | | * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of |
9880 | | * sandboxing is limited to the immediate sandbox. In the case that aDocument |
9881 | | * should inherit its origin (e.g. data: URI) but its parent has ended up |
9882 | | * with a unique origin due to sandboxing further up the parent chain we may |
9883 | | * end up returning false when we would ideally return true (since we will |
9884 | | * examine the parent's origin for 'https' and not finding it.) This means |
9885 | | * that we may restrict the privileges of some pages unnecessarily in this |
9886 | | * edge case. |
9887 | | */ |
9888 | | /* static */ bool |
9889 | | nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument) |
9890 | 0 | { |
9891 | 0 | if (!aDocument) { |
9892 | 0 | return false; |
9893 | 0 | } |
9894 | 0 | |
9895 | 0 | nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal(); |
9896 | 0 |
|
9897 | 0 | if (principal->GetIsSystemPrincipal()) { |
9898 | 0 | return true; |
9899 | 0 | } |
9900 | 0 | |
9901 | 0 | // If aDocument is sandboxed, try and get the principal that it would have |
9902 | 0 | // been given had it not been sandboxed: |
9903 | 0 | if (principal->GetIsNullPrincipal() && |
9904 | 0 | (aDocument->GetSandboxFlags() & SANDBOXED_ORIGIN)) { |
9905 | 0 | nsIChannel* channel = aDocument->GetChannel(); |
9906 | 0 | if (channel) { |
9907 | 0 | nsCOMPtr<nsIScriptSecurityManager> ssm = |
9908 | 0 | nsContentUtils::GetSecurityManager(); |
9909 | 0 | nsresult rv = |
9910 | 0 | ssm->GetChannelResultPrincipalIfNotSandboxed(channel, |
9911 | 0 | getter_AddRefs(principal)); |
9912 | 0 | if (NS_FAILED(rv)) { |
9913 | 0 | return false; |
9914 | 0 | } |
9915 | 0 | if (principal->GetIsSystemPrincipal()) { |
9916 | 0 | // If a document with the system principal is sandboxing a subdocument |
9917 | 0 | // that would normally inherit the embedding element's principal (e.g. |
9918 | 0 | // a srcdoc document) then the embedding document does not trust the |
9919 | 0 | // content that is written to the embedded document. Unlike when the |
9920 | 0 | // embedding document is https, in this case we have no indication as |
9921 | 0 | // to whether the embedded document's contents are delivered securely |
9922 | 0 | // or not, and the sandboxing would possibly indicate that they were |
9923 | 0 | // not. To play it safe we return false here. (See bug 1162772 |
9924 | 0 | // comment 73-80.) |
9925 | 0 | return false; |
9926 | 0 | } |
9927 | 0 | } |
9928 | 0 | } |
9929 | 0 | |
9930 | 0 | if (principal->GetIsNullPrincipal()) { |
9931 | 0 | return false; |
9932 | 0 | } |
9933 | 0 | |
9934 | 0 | MOZ_ASSERT(principal->GetIsCodebasePrincipal()); |
9935 | 0 |
|
9936 | 0 | nsCOMPtr<nsIContentSecurityManager> csm = |
9937 | 0 | do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); |
9938 | 0 | NS_WARNING_ASSERTION(csm, "csm is null"); |
9939 | 0 | if (csm) { |
9940 | 0 | bool isTrustworthyOrigin = false; |
9941 | 0 | csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin); |
9942 | 0 | if (isTrustworthyOrigin) { |
9943 | 0 | return true; |
9944 | 0 | } |
9945 | 0 | } |
9946 | 0 | |
9947 | 0 | return false; |
9948 | 0 | } |
9949 | | |
9950 | | /* static */ void |
9951 | | nsContentUtils::TryToUpgradeElement(Element* aElement) |
9952 | 0 | { |
9953 | 0 | NodeInfo* nodeInfo = aElement->NodeInfo(); |
9954 | 0 | RefPtr<nsAtom> typeAtom = |
9955 | 0 | aElement->GetCustomElementData()->GetCustomElementType(); |
9956 | 0 |
|
9957 | 0 | MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); |
9958 | 0 | CustomElementDefinition* definition = |
9959 | 0 | nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), |
9960 | 0 | nodeInfo->NameAtom(), |
9961 | 0 | nodeInfo->NamespaceID(), |
9962 | 0 | typeAtom); |
9963 | 0 | if (definition) { |
9964 | 0 | nsContentUtils::EnqueueUpgradeReaction(aElement, definition); |
9965 | 0 | } else { |
9966 | 0 | // Add an unresolved custom element that is a candidate for upgrade when a |
9967 | 0 | // custom element is connected to the document. |
9968 | 0 | nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom); |
9969 | 0 | } |
9970 | 0 | } |
9971 | | |
9972 | | static void |
9973 | | DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, NodeInfo* aNodeInfo, |
9974 | | CustomElementConstructor* aConstructor, ErrorResult& aRv) |
9975 | 0 | { |
9976 | 0 | RefPtr<Element> element = |
9977 | 0 | aConstructor->Construct("Custom Element Create", aRv); |
9978 | 0 | if (aRv.Failed()) { |
9979 | 0 | return; |
9980 | 0 | } |
9981 | 0 | |
9982 | 0 | if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
9983 | 0 | if (!element || !element->IsHTMLElement()) { |
9984 | 0 | aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement")); |
9985 | 0 | return; |
9986 | 0 | } |
9987 | 0 | } else { |
9988 | 0 | if (!element || !element->IsXULElement()) { |
9989 | 0 | aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("XULElement")); |
9990 | 0 | return; |
9991 | 0 | } |
9992 | 0 | } |
9993 | 0 |
|
9994 | 0 | nsAtom* localName = aNodeInfo->NameAtom(); |
9995 | 0 |
|
9996 | 0 | if (aDoc != element->OwnerDoc() || element->GetParentNode() || |
9997 | 0 | element->HasChildren() || element->GetAttrCount() || |
9998 | 0 | element->NodeInfo()->NameAtom() != localName) { |
9999 | 0 | aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
10000 | 0 | return; |
10001 | 0 | } |
10002 | 0 | |
10003 | 0 | element.forget(aElement); |
10004 | 0 | } |
10005 | | |
10006 | | /* static */ nsresult |
10007 | | nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo, |
10008 | | FromParser aFromParser, nsAtom* aIsAtom, |
10009 | | mozilla::dom::CustomElementDefinition* aDefinition) |
10010 | 0 | { |
10011 | 0 | RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo; |
10012 | 0 | MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) || |
10013 | 0 | nodeInfo->NamespaceEquals(kNameSpaceID_XUL), |
10014 | 0 | "Can only create XUL or XHTML elements."); |
10015 | 0 |
|
10016 | 0 | nsAtom *name = nodeInfo->NameAtom(); |
10017 | 0 | int32_t tag = eHTMLTag_unknown; |
10018 | 0 | bool isCustomElementName = false; |
10019 | 0 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
10020 | 0 | tag = nsHTMLTags::CaseSensitiveAtomTagToId(name); |
10021 | 0 | isCustomElementName = (tag == eHTMLTag_userdefined && |
10022 | 0 | nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML)); |
10023 | 0 | } else { // kNameSpaceID_XUL |
10024 | 0 | if (aIsAtom) { |
10025 | 0 | // Make sure the customized built-in element to be constructed confirms |
10026 | 0 | // to our naming requirement, i.e. [is] must be a dashed name and |
10027 | 0 | // the tag name must not. |
10028 | 0 | // if so, set isCustomElementName to false to kick off all the logics |
10029 | 0 | // that pick up aIsAtom. |
10030 | 0 | if (nsContentUtils::IsNameWithDash(aIsAtom) && |
10031 | 0 | !nsContentUtils::IsNameWithDash(name)) { |
10032 | 0 | isCustomElementName = false; |
10033 | 0 | } else { |
10034 | 0 | isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL); |
10035 | 0 | } |
10036 | 0 | } else { |
10037 | 0 | isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL); |
10038 | 0 | } |
10039 | 0 | } |
10040 | 0 |
|
10041 | 0 | nsAtom* tagAtom = nodeInfo->NameAtom(); |
10042 | 0 | nsAtom* typeAtom = nullptr; |
10043 | 0 | bool isCustomElement = isCustomElementName || aIsAtom; |
10044 | 0 | if (isCustomElement) { |
10045 | 0 | typeAtom = isCustomElementName ? tagAtom : aIsAtom; |
10046 | 0 | } |
10047 | 0 |
|
10048 | 0 | MOZ_ASSERT_IF(aDefinition, isCustomElement); |
10049 | 0 |
|
10050 | 0 | bool customElementEnabled = CustomElementRegistry::IsCustomElementEnabled(nodeInfo->GetDocument()); |
10051 | 0 |
|
10052 | 0 | // https://dom.spec.whatwg.org/#concept-create-element |
10053 | 0 | // We only handle the "synchronous custom elements flag is set" now. |
10054 | 0 | // For the unset case (e.g. cloning a node), see bug 1319342 for that. |
10055 | 0 | // Step 4. |
10056 | 0 | CustomElementDefinition* definition = aDefinition; |
10057 | 0 | if (customElementEnabled && isCustomElement && !definition) { |
10058 | 0 | MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); |
10059 | 0 | definition = |
10060 | 0 | nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), |
10061 | 0 | nodeInfo->NameAtom(), |
10062 | 0 | nodeInfo->NamespaceID(), |
10063 | 0 | typeAtom); |
10064 | 0 | } |
10065 | 0 |
|
10066 | 0 | // It might be a problem that parser synchronously calls constructor, so filed |
10067 | 0 | // bug 1378079 to figure out what we should do for parser case. |
10068 | 0 | if (definition) { |
10069 | 0 | /* |
10070 | 0 | * Synchronous custom elements flag is determined by 3 places in spec, |
10071 | 0 | * 1) create an element for a token, the flag is determined by |
10072 | 0 | * "will execute script" which is not originally created |
10073 | 0 | * for the HTML fragment parsing algorithm. |
10074 | 0 | * 2) createElement and createElementNS, the flag is the same as |
10075 | 0 | * NOT_FROM_PARSER. |
10076 | 0 | * 3) clone a node, our implementation will not go into this function. |
10077 | 0 | * For the unset case which is non-synchronous only applied for |
10078 | 0 | * inner/outerHTML. |
10079 | 0 | */ |
10080 | 0 | bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT || |
10081 | 0 | aFromParser == dom::NOT_FROM_PARSER; |
10082 | 0 | // Per discussion in https://github.com/w3c/webcomponents/issues/635, |
10083 | 0 | // use entry global in those places that are called from JS APIs and use the |
10084 | 0 | // node document's global object if it is called from parser. |
10085 | 0 | nsIGlobalObject* global; |
10086 | 0 | if (aFromParser == dom::NOT_FROM_PARSER) { |
10087 | 0 | global = GetEntryGlobal(); |
10088 | 0 |
|
10089 | 0 | // XUL documents always use NOT_FROM_PARSER for non-XUL elements. We can |
10090 | 0 | // get the global from the document in that case. |
10091 | 0 | if (!global) { |
10092 | 0 | nsIDocument* doc = nodeInfo->GetDocument(); |
10093 | 0 | if (doc && doc->IsXULDocument()) { |
10094 | 0 | global = doc->GetScopeObject(); |
10095 | 0 | } |
10096 | 0 | } |
10097 | 0 | } else { |
10098 | 0 | global = nodeInfo->GetDocument()->GetScopeObject(); |
10099 | 0 | } |
10100 | 0 | if (!global) { |
10101 | 0 | // In browser chrome code, one may have access to a document which doesn't |
10102 | 0 | // have scope object anymore. |
10103 | 0 | return NS_ERROR_FAILURE; |
10104 | 0 | } |
10105 | 0 | |
10106 | 0 | AutoEntryScript aes(global, "create custom elements"); |
10107 | 0 | JSContext* cx = aes.cx(); |
10108 | 0 | ErrorResult rv; |
10109 | 0 |
|
10110 | 0 | // Step 5. |
10111 | 0 | if (definition->IsCustomBuiltIn()) { |
10112 | 0 | // SetupCustomElement() should be called with an element that don't have |
10113 | 0 | // CustomElementData setup, if not we will hit the assertion in |
10114 | 0 | // SetCustomElementData(). |
10115 | 0 | // Built-in element |
10116 | 0 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
10117 | 0 | *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); |
10118 | 0 | } else { |
10119 | 0 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget())); |
10120 | 0 | } |
10121 | 0 | (*aResult)->SetCustomElementData(new CustomElementData(typeAtom)); |
10122 | 0 | if (synchronousCustomElements) { |
10123 | 0 | CustomElementRegistry::Upgrade(*aResult, definition, rv); |
10124 | 0 | if (rv.MaybeSetPendingException(cx)) { |
10125 | 0 | aes.ReportException(); |
10126 | 0 | } |
10127 | 0 | } else { |
10128 | 0 | nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); |
10129 | 0 | } |
10130 | 0 |
|
10131 | 0 | return NS_OK; |
10132 | 0 | } |
10133 | 0 |
|
10134 | 0 | // Step 6.1. |
10135 | 0 | if (synchronousCustomElements) { |
10136 | 0 | definition->mPrefixStack.AppendElement(nodeInfo->GetPrefixAtom()); |
10137 | 0 | DoCustomElementCreate(aResult, nodeInfo->GetDocument(), nodeInfo, |
10138 | 0 | definition->mConstructor, rv); |
10139 | 0 | if (rv.MaybeSetPendingException(cx)) { |
10140 | 0 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
10141 | 0 | NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser)); |
10142 | 0 | } else { |
10143 | 0 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget())); |
10144 | 0 | } |
10145 | 0 | (*aResult)->SetDefined(false); |
10146 | 0 | } |
10147 | 0 | definition->mPrefixStack.RemoveLastElement(); |
10148 | 0 | return NS_OK; |
10149 | 0 | } |
10150 | 0 |
|
10151 | 0 | // Step 6.2. |
10152 | 0 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
10153 | 0 | NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); |
10154 | 0 | } else { |
10155 | 0 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget())); |
10156 | 0 | } |
10157 | 0 | (*aResult)->SetCustomElementData(new CustomElementData(definition->mType)); |
10158 | 0 | nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); |
10159 | 0 | return NS_OK; |
10160 | 0 | } |
10161 | 0 |
|
10162 | 0 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
10163 | 0 | // Per the Custom Element specification, unknown tags that are valid custom |
10164 | 0 | // element names should be HTMLElement instead of HTMLUnknownElement. |
10165 | 0 | if (isCustomElementName) { |
10166 | 0 | NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); |
10167 | 0 | } else { |
10168 | 0 | *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); |
10169 | 0 | } |
10170 | 0 | } else { |
10171 | 0 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget())); |
10172 | 0 | } |
10173 | 0 |
|
10174 | 0 | if (!*aResult) { |
10175 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
10176 | 0 | } |
10177 | 0 | |
10178 | 0 | if (customElementEnabled && isCustomElement) { |
10179 | 0 | (*aResult)->SetCustomElementData(new CustomElementData(typeAtom)); |
10180 | 0 | nsContentUtils::RegisterCallbackUpgradeElement(*aResult, typeAtom); |
10181 | 0 | } |
10182 | 0 |
|
10183 | 0 | return NS_OK; |
10184 | 0 | } |
10185 | | |
10186 | | CustomElementRegistry* |
10187 | | nsContentUtils::GetCustomElementRegistry(nsIDocument* aDoc) |
10188 | 0 | { |
10189 | 0 | MOZ_ASSERT(aDoc); |
10190 | 0 |
|
10191 | 0 | if (!aDoc->GetDocShell()) { |
10192 | 0 | return nullptr; |
10193 | 0 | } |
10194 | 0 | |
10195 | 0 | nsPIDOMWindowInner* window = aDoc->GetInnerWindow(); |
10196 | 0 | if (!window) { |
10197 | 0 | return nullptr; |
10198 | 0 | } |
10199 | 0 | |
10200 | 0 | return window->CustomElements(); |
10201 | 0 | } |
10202 | | |
10203 | | /* static */ CustomElementDefinition* |
10204 | | nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc, |
10205 | | nsAtom* aNameAtom, |
10206 | | uint32_t aNameSpaceID, |
10207 | | nsAtom* aTypeAtom) |
10208 | 0 | { |
10209 | 0 | if (aNameSpaceID != kNameSpaceID_XUL && |
10210 | 0 | aNameSpaceID != kNameSpaceID_XHTML) { |
10211 | 0 | return nullptr; |
10212 | 0 | } |
10213 | 0 | |
10214 | 0 | RefPtr<CustomElementRegistry> registry = GetCustomElementRegistry(aDoc); |
10215 | 0 | if (!registry) { |
10216 | 0 | return nullptr; |
10217 | 0 | } |
10218 | 0 | |
10219 | 0 | return registry->LookupCustomElementDefinition(aNameAtom, aNameSpaceID, aTypeAtom); |
10220 | 0 | } |
10221 | | |
10222 | | /* static */ void |
10223 | | nsContentUtils::RegisterCallbackUpgradeElement(Element* aElement, |
10224 | | nsAtom* aTypeName) |
10225 | 0 | { |
10226 | 0 | MOZ_ASSERT(aElement); |
10227 | 0 |
|
10228 | 0 | nsIDocument* doc = aElement->OwnerDoc(); |
10229 | 0 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); |
10230 | 0 | if (registry) { |
10231 | 0 | registry->RegisterCallbackUpgradeElement(aElement, aTypeName); |
10232 | 0 | } |
10233 | 0 | } |
10234 | | |
10235 | | /* static */ void |
10236 | | nsContentUtils::RegisterUnresolvedElement(Element* aElement, nsAtom* aTypeName) |
10237 | 0 | { |
10238 | 0 | MOZ_ASSERT(aElement); |
10239 | 0 |
|
10240 | 0 | nsIDocument* doc = aElement->OwnerDoc(); |
10241 | 0 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); |
10242 | 0 | if (registry) { |
10243 | 0 | registry->RegisterUnresolvedElement(aElement, aTypeName); |
10244 | 0 | } |
10245 | 0 | } |
10246 | | |
10247 | | /* static */ void |
10248 | | nsContentUtils::UnregisterUnresolvedElement(Element* aElement) |
10249 | 0 | { |
10250 | 0 | MOZ_ASSERT(aElement); |
10251 | 0 |
|
10252 | 0 | nsAtom* typeAtom = |
10253 | 0 | aElement->GetCustomElementData()->GetCustomElementType(); |
10254 | 0 | nsIDocument* doc = aElement->OwnerDoc(); |
10255 | 0 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); |
10256 | 0 | if (registry) { |
10257 | 0 | registry->UnregisterUnresolvedElement(aElement, typeAtom); |
10258 | 0 | } |
10259 | 0 | } |
10260 | | |
10261 | | /* static */ void |
10262 | | nsContentUtils::EnqueueUpgradeReaction(Element* aElement, |
10263 | | CustomElementDefinition* aDefinition) |
10264 | 0 | { |
10265 | 0 | MOZ_ASSERT(aElement); |
10266 | 0 |
|
10267 | 0 | nsIDocument* doc = aElement->OwnerDoc(); |
10268 | 0 |
|
10269 | 0 | // No DocGroup means no custom element reactions stack. |
10270 | 0 | if (!doc->GetDocGroup()) { |
10271 | 0 | return; |
10272 | 0 | } |
10273 | 0 | |
10274 | 0 | CustomElementReactionsStack* stack = |
10275 | 0 | doc->GetDocGroup()->CustomElementReactionsStack(); |
10276 | 0 | stack->EnqueueUpgradeReaction(aElement, aDefinition); |
10277 | 0 | } |
10278 | | |
10279 | | /* static */ void |
10280 | | nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, |
10281 | | Element* aCustomElement, |
10282 | | LifecycleCallbackArgs* aArgs, |
10283 | | LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, |
10284 | | CustomElementDefinition* aDefinition) |
10285 | 0 | { |
10286 | 0 | // No DocGroup means no custom element reactions stack. |
10287 | 0 | if (!aCustomElement->OwnerDoc()->GetDocGroup()) { |
10288 | 0 | return; |
10289 | 0 | } |
10290 | 0 | |
10291 | 0 | CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs, |
10292 | 0 | aAdoptedCallbackArgs, |
10293 | 0 | aDefinition); |
10294 | 0 | } |
10295 | | |
10296 | | /* static */ bool |
10297 | | nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) |
10298 | 0 | { |
10299 | 0 | MOZ_ASSERT(aChannel); |
10300 | 0 |
|
10301 | 0 | nsCOMPtr<nsILoadGroup> loadGroup; |
10302 | 0 | nsresult rv = aChannel->GetLoadGroup(getter_AddRefs(loadGroup)); |
10303 | 0 | if (NS_WARN_IF(NS_FAILED(rv) || !loadGroup)) { |
10304 | 0 | return false; |
10305 | 0 | } |
10306 | 0 | |
10307 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
10308 | 0 | rv = loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
10309 | 0 | if (NS_WARN_IF(NS_FAILED(rv) || !callbacks)) { |
10310 | 0 | return false; |
10311 | 0 | } |
10312 | 0 | |
10313 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); |
10314 | 0 | if (NS_WARN_IF(!loadContext)) { |
10315 | 0 | return false; |
10316 | 0 | } |
10317 | 0 | |
10318 | 0 | nsCOMPtr<mozIDOMWindowProxy> window; |
10319 | 0 | rv = loadContext->GetAssociatedWindow(getter_AddRefs(window)); |
10320 | 0 | if (NS_WARN_IF(NS_FAILED(rv) || !window)) { |
10321 | 0 | return false; |
10322 | 0 | } |
10323 | 0 | |
10324 | 0 | nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(window); |
10325 | 0 | if (NS_WARN_IF(!outer)) { |
10326 | 0 | return false; |
10327 | 0 | } |
10328 | 0 | |
10329 | 0 | if (!XRE_IsContentProcess()) { |
10330 | 0 | outer->SetLargeAllocStatus(LargeAllocStatus::NON_E10S); |
10331 | 0 | return false; |
10332 | 0 | } |
10333 | 0 | |
10334 | 0 | nsIDocShell* docShell = outer->GetDocShell(); |
10335 | 0 | if (!docShell->GetIsOnlyToplevelInTabGroup()) { |
10336 | 0 | outer->SetLargeAllocStatus(LargeAllocStatus::NOT_ONLY_TOPLEVEL_IN_TABGROUP); |
10337 | 0 | return false; |
10338 | 0 | } |
10339 | 0 | |
10340 | 0 | // Get the request method, and check if it is a GET request. If it is not GET, |
10341 | 0 | // then we cannot perform a large allocation load. |
10342 | 0 | nsAutoCString requestMethod; |
10343 | 0 | rv = aChannel->GetRequestMethod(requestMethod); |
10344 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10345 | 0 |
|
10346 | 0 | if (NS_WARN_IF(!requestMethod.LowerCaseEqualsLiteral("get"))) { |
10347 | 0 | outer->SetLargeAllocStatus(LargeAllocStatus::NON_GET); |
10348 | 0 | return false; |
10349 | 0 | } |
10350 | 0 | |
10351 | 0 | TabChild* tabChild = TabChild::GetFrom(outer->AsOuter()); |
10352 | 0 | NS_ENSURE_TRUE(tabChild, false); |
10353 | 0 |
|
10354 | 0 | if (tabChild->IsAwaitingLargeAlloc()) { |
10355 | 0 | NS_WARNING("In a Large-Allocation TabChild, ignoring Large-Allocation header!"); |
10356 | 0 | tabChild->StopAwaitingLargeAlloc(); |
10357 | 0 | outer->SetLargeAllocStatus(LargeAllocStatus::SUCCESS); |
10358 | 0 | return false; |
10359 | 0 | } |
10360 | 0 |
|
10361 | 0 | // On Win32 systems, we want to behave differently, so set the isWin32 bool to |
10362 | 0 | // be true iff we are on win32. |
10363 | | #if defined(XP_WIN) && defined(_X86_) |
10364 | | const bool isWin32 = true; |
10365 | | #else |
10366 | 0 | const bool isWin32 = false; |
10367 | 0 | #endif |
10368 | 0 |
|
10369 | 0 | static bool sLargeAllocForceEnable = false; |
10370 | 0 | static bool sCachedLargeAllocForceEnable = false; |
10371 | 0 | if (!sCachedLargeAllocForceEnable) { |
10372 | 0 | sCachedLargeAllocForceEnable = true; |
10373 | 0 | mozilla::Preferences::AddBoolVarCache(&sLargeAllocForceEnable, |
10374 | 0 | "dom.largeAllocation.forceEnable"); |
10375 | 0 | } |
10376 | 0 |
|
10377 | 0 | // We want to enable the large allocation header on 32-bit windows machines, |
10378 | 0 | // and disable it on other machines, while still printing diagnostic messages. |
10379 | 0 | // dom.largeAllocation.forceEnable can allow you to enable the process |
10380 | 0 | // switching behavior of the Large-Allocation header on non 32-bit windows |
10381 | 0 | // machines. |
10382 | 0 | bool largeAllocEnabled = isWin32 || sLargeAllocForceEnable; |
10383 | 0 | if (!largeAllocEnabled) { |
10384 | 0 | NS_WARNING("dom.largeAllocation.forceEnable not set - " |
10385 | 0 | "ignoring otherwise successful Large-Allocation header."); |
10386 | 0 | // On platforms which aren't WIN32, we don't activate the largeAllocation |
10387 | 0 | // header, instead we simply emit diagnostics into the console. |
10388 | 0 | outer->SetLargeAllocStatus(LargeAllocStatus::NON_WIN32); |
10389 | 0 | return false; |
10390 | 0 | } |
10391 | 0 |
|
10392 | 0 | // At this point the fress process load should succeed! We just need to get |
10393 | 0 | // ourselves a nsIWebBrowserChrome3 to ask to perform the reload. We should |
10394 | 0 | // have one, as we have already confirmed that we are running in a content |
10395 | 0 | // process. |
10396 | 0 | nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
10397 | 0 | docShell->GetTreeOwner(getter_AddRefs(treeOwner)); |
10398 | 0 | NS_ENSURE_TRUE(treeOwner, false); |
10399 | 0 |
|
10400 | 0 | nsCOMPtr<nsIWebBrowserChrome3> wbc3 = do_GetInterface(treeOwner); |
10401 | 0 | NS_ENSURE_TRUE(wbc3, false); |
10402 | 0 |
|
10403 | 0 | nsCOMPtr<nsIURI> uri; |
10404 | 0 | rv = aChannel->GetURI(getter_AddRefs(uri)); |
10405 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10406 | 0 | NS_ENSURE_TRUE(uri, false); |
10407 | 0 |
|
10408 | 0 | nsCOMPtr<nsIURI> referrer; |
10409 | 0 | rv = aChannel->GetReferrer(getter_AddRefs(referrer)); |
10410 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10411 | 0 |
|
10412 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); |
10413 | 0 | if (!loadInfo) { |
10414 | 0 | return false; |
10415 | 0 | } |
10416 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo->TriggeringPrincipal(); |
10417 | 0 |
|
10418 | 0 | // Get the channel's load flags, and use them to generate nsIWebNavigation |
10419 | 0 | // load flags. We want to make sure to propagate the refresh and cache busting |
10420 | 0 | // flags. |
10421 | 0 | nsLoadFlags channelLoadFlags; |
10422 | 0 | aChannel->GetLoadFlags(&channelLoadFlags); |
10423 | 0 |
|
10424 | 0 | uint32_t webnavLoadFlags = nsIWebNavigation::LOAD_FLAGS_NONE; |
10425 | 0 | if (channelLoadFlags & nsIRequest::LOAD_BYPASS_CACHE) { |
10426 | 0 | webnavLoadFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE; |
10427 | 0 | webnavLoadFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY; |
10428 | 0 | } else if (channelLoadFlags & nsIRequest::VALIDATE_ALWAYS) { |
10429 | 0 | webnavLoadFlags |= nsIWebNavigation::LOAD_FLAGS_IS_REFRESH; |
10430 | 0 | } |
10431 | 0 |
|
10432 | 0 | // Actually perform the cross process load |
10433 | 0 | bool reloadSucceeded = false; |
10434 | 0 | rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer, |
10435 | 0 | triggeringPrincipal, webnavLoadFlags, |
10436 | 0 | &reloadSucceeded); |
10437 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10438 | 0 |
|
10439 | 0 | return reloadSucceeded; |
10440 | 0 | } |
10441 | | |
10442 | | /* static */ void |
10443 | | nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo( |
10444 | | nsIDocument* aDocument, |
10445 | | nsTArray<nsIContent*>& aElements) |
10446 | 0 | { |
10447 | 0 | MOZ_ASSERT(aDocument); |
10448 | | #ifdef DEBUG |
10449 | | size_t oldLength = aElements.Length(); |
10450 | | #endif |
10451 | |
|
10452 | 0 | if (nsIPresShell* presShell = aDocument->GetShell()) { |
10453 | 0 | if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) { |
10454 | 0 | nsIAnonymousContentCreator* creator = do_QueryFrame(scrollFrame); |
10455 | 0 | MOZ_ASSERT(creator, |
10456 | 0 | "scroll frame should always implement nsIAnonymousContentCreator"); |
10457 | 0 | creator->AppendAnonymousContentTo(aElements, 0); |
10458 | 0 | } |
10459 | 0 |
|
10460 | 0 | if (nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame()) { |
10461 | 0 | if (Element* container = canvasFrame->GetCustomContentContainer()) { |
10462 | 0 | aElements.AppendElement(container); |
10463 | 0 | } |
10464 | 0 | } |
10465 | 0 | } |
10466 | 0 |
|
10467 | | #ifdef DEBUG |
10468 | | for (size_t i = oldLength; i < aElements.Length(); i++) { |
10469 | | MOZ_ASSERT( |
10470 | | aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent), |
10471 | | "Someone here has lied, or missed to flag the node"); |
10472 | | } |
10473 | | #endif |
10474 | | } |
10475 | | |
10476 | | static void |
10477 | | AppendNativeAnonymousChildrenFromFrame( |
10478 | | nsIFrame* aFrame, |
10479 | | nsTArray<nsIContent*>& aKids, |
10480 | | uint32_t aFlags) |
10481 | 0 | { |
10482 | 0 | if (nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame)) { |
10483 | 0 | ac->AppendAnonymousContentTo(aKids, aFlags); |
10484 | 0 | } |
10485 | 0 | } |
10486 | | |
10487 | | /* static */ void |
10488 | | nsContentUtils::AppendNativeAnonymousChildren( |
10489 | | const nsIContent* aContent, |
10490 | | nsTArray<nsIContent*>& aKids, |
10491 | | uint32_t aFlags) |
10492 | 0 | { |
10493 | 0 | if (aContent->MayHaveAnonymousChildren()) { |
10494 | 0 | if (nsIFrame* primaryFrame = aContent->GetPrimaryFrame()) { |
10495 | 0 | // NAC created by the element's primary frame. |
10496 | 0 | AppendNativeAnonymousChildrenFromFrame(primaryFrame, aKids, aFlags); |
10497 | 0 |
|
10498 | 0 | // NAC created by any other non-primary frames for the element. |
10499 | 0 | AutoTArray<nsIFrame::OwnedAnonBox, 8> ownedAnonBoxes; |
10500 | 0 | primaryFrame->AppendOwnedAnonBoxes(ownedAnonBoxes); |
10501 | 0 | for (nsIFrame::OwnedAnonBox& box : ownedAnonBoxes) { |
10502 | 0 | MOZ_ASSERT(box.mAnonBoxFrame->GetContent() == aContent); |
10503 | 0 | AppendNativeAnonymousChildrenFromFrame(box.mAnonBoxFrame, aKids, aFlags); |
10504 | 0 | } |
10505 | 0 | } |
10506 | 0 |
|
10507 | 0 | // Get manually created NAC (editor resize handles, etc.). |
10508 | 0 | if (auto nac = static_cast<ManualNACArray*>( |
10509 | 0 | aContent->GetProperty(nsGkAtoms::manualNACProperty))) { |
10510 | 0 | aKids.AppendElements(*nac); |
10511 | 0 | } |
10512 | 0 | } |
10513 | 0 |
|
10514 | 0 | // The root scroll frame is not the primary frame of the root element. |
10515 | 0 | // Detect and handle this case. |
10516 | 0 | if (!(aFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) && |
10517 | 0 | aContent == aContent->OwnerDoc()->GetRootElement()) { |
10518 | 0 | AppendDocumentLevelNativeAnonymousContentTo(aContent->OwnerDoc(), aKids); |
10519 | 0 | } |
10520 | 0 | } |
10521 | | |
10522 | | /* static */ bool |
10523 | | nsContentUtils::QueryTriggeringPrincipal(nsIContent* aLoadingNode, |
10524 | | nsIPrincipal* aDefaultPrincipal, |
10525 | | nsIPrincipal** aTriggeringPrincipal) |
10526 | 0 | { |
10527 | 0 | MOZ_ASSERT(aLoadingNode); |
10528 | 0 | MOZ_ASSERT(aTriggeringPrincipal); |
10529 | 0 |
|
10530 | 0 | bool result = false; |
10531 | 0 | nsCOMPtr<nsIPrincipal> loadingPrincipal = aDefaultPrincipal; |
10532 | 0 | if (!loadingPrincipal) { |
10533 | 0 | loadingPrincipal = aLoadingNode->NodePrincipal(); |
10534 | 0 | } |
10535 | 0 |
|
10536 | 0 | // If aLoadingNode is content, bail out early. |
10537 | 0 | if (!aLoadingNode->NodePrincipal()->GetIsSystemPrincipal()) { |
10538 | 0 | loadingPrincipal.forget(aTriggeringPrincipal); |
10539 | 0 | return result; |
10540 | 0 | } |
10541 | 0 | |
10542 | 0 | nsAutoString loadingStr; |
10543 | 0 | if (aLoadingNode->IsElement()) { |
10544 | 0 | aLoadingNode->AsElement()->GetAttr(kNameSpaceID_None, |
10545 | 0 | nsGkAtoms::triggeringprincipal, |
10546 | 0 | loadingStr); |
10547 | 0 | } |
10548 | 0 |
|
10549 | 0 | // Fall back if 'triggeringprincipal' isn't specified, |
10550 | 0 | if (loadingStr.IsEmpty()) { |
10551 | 0 | loadingPrincipal.forget(aTriggeringPrincipal); |
10552 | 0 | return result; |
10553 | 0 | } |
10554 | 0 | |
10555 | 0 | nsCOMPtr<nsISupports> serializedPrincipal; |
10556 | 0 | NS_DeserializeObject(NS_ConvertUTF16toUTF8(loadingStr), |
10557 | 0 | getter_AddRefs(serializedPrincipal)); |
10558 | 0 | nsCOMPtr<nsIPrincipal> serializedPrin = do_QueryInterface(serializedPrincipal); |
10559 | 0 | if (serializedPrin) { |
10560 | 0 | result = true; |
10561 | 0 | serializedPrin.forget(aTriggeringPrincipal); |
10562 | 0 | } else { |
10563 | 0 | // Fallback if the deserialization is failed. |
10564 | 0 | loadingPrincipal.forget(aTriggeringPrincipal); |
10565 | 0 | } |
10566 | 0 |
|
10567 | 0 | return result; |
10568 | 0 | } |
10569 | | |
10570 | | /* static */ void |
10571 | | nsContentUtils::GetContentPolicyTypeForUIImageLoading(nsIContent* aLoadingNode, |
10572 | | nsIPrincipal** aTriggeringPrincipal, |
10573 | | nsContentPolicyType& aContentPolicyType, |
10574 | | uint64_t* aRequestContextID) |
10575 | 0 | { |
10576 | 0 | MOZ_ASSERT(aRequestContextID); |
10577 | 0 |
|
10578 | 0 | bool result = QueryTriggeringPrincipal(aLoadingNode, aTriggeringPrincipal); |
10579 | 0 | if (result) { |
10580 | 0 | // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for |
10581 | 0 | // indicating it's a favicon loading. |
10582 | 0 | aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON; |
10583 | 0 |
|
10584 | 0 | nsAutoString requestContextID; |
10585 | 0 | if (aLoadingNode->IsElement()) { |
10586 | 0 | aLoadingNode->AsElement()->GetAttr(kNameSpaceID_None, |
10587 | 0 | nsGkAtoms::requestcontextid, |
10588 | 0 | requestContextID); |
10589 | 0 | } |
10590 | 0 | nsresult rv; |
10591 | 0 | int64_t val = requestContextID.ToInteger64(&rv); |
10592 | 0 | *aRequestContextID = NS_SUCCEEDED(rv) |
10593 | 0 | ? val |
10594 | 0 | : 0; |
10595 | 0 | } else { |
10596 | 0 | aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE; |
10597 | 0 | } |
10598 | 0 | } |
10599 | | |
10600 | | /* static */ nsresult |
10601 | | nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx, |
10602 | | const Sequence<JSObject*>& aTransfer, |
10603 | | JS::MutableHandle<JS::Value> aValue) |
10604 | 0 | { |
10605 | 0 | if (aTransfer.IsEmpty()) { |
10606 | 0 | return NS_OK; |
10607 | 0 | } |
10608 | 0 | |
10609 | 0 | JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aTransfer.Length())); |
10610 | 0 | if (!array) { |
10611 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
10612 | 0 | } |
10613 | 0 | |
10614 | 0 | for (uint32_t i = 0; i < aTransfer.Length(); ++i) { |
10615 | 0 | JS::Rooted<JSObject*> object(aCx, aTransfer[i]); |
10616 | 0 | if (!object) { |
10617 | 0 | continue; |
10618 | 0 | } |
10619 | 0 | |
10620 | 0 | if (NS_WARN_IF(!JS_DefineElement(aCx, array, i, object, |
10621 | 0 | JSPROP_ENUMERATE))) { |
10622 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
10623 | 0 | } |
10624 | 0 | } |
10625 | 0 |
|
10626 | 0 | aValue.setObject(*array); |
10627 | 0 | return NS_OK; |
10628 | 0 | } |
10629 | | |
10630 | | /* static */ |
10631 | | bool |
10632 | | nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent* aKeyEvent) |
10633 | 0 | { |
10634 | 0 | nsCOMPtr<nsIPrincipal> principal; |
10635 | 0 | nsCOMPtr<nsIBrowser> targetBrowser = do_QueryInterface(aKeyEvent->mOriginalTarget); |
10636 | 0 | bool isRemoteBrowser = false; |
10637 | 0 | if (targetBrowser) { |
10638 | 0 | targetBrowser->GetIsRemoteBrowser(&isRemoteBrowser); |
10639 | 0 | } |
10640 | 0 |
|
10641 | 0 | if (isRemoteBrowser) { |
10642 | 0 | targetBrowser->GetContentPrincipal(getter_AddRefs(principal)); |
10643 | 0 | } |
10644 | 0 | else { |
10645 | 0 | // Get the top-level document. |
10646 | 0 | nsCOMPtr<nsIContent> content = do_QueryInterface(aKeyEvent->mOriginalTarget); |
10647 | 0 | if (content) { |
10648 | 0 | nsIDocument* doc = content->GetUncomposedDoc(); |
10649 | 0 | if (doc) { |
10650 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShell = doc->GetDocShell(); |
10651 | 0 | if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeContent) { |
10652 | 0 | nsCOMPtr<nsIDocShellTreeItem> rootItem; |
10653 | 0 | docShell->GetSameTypeRootTreeItem(getter_AddRefs(rootItem)); |
10654 | 0 | if (rootItem && rootItem->GetDocument()) { |
10655 | 0 | principal = rootItem->GetDocument()->NodePrincipal(); |
10656 | 0 | } |
10657 | 0 | } |
10658 | 0 | } |
10659 | 0 | } |
10660 | 0 | } |
10661 | 0 |
|
10662 | 0 | if (principal) { |
10663 | 0 | return nsContentUtils::IsSitePermDeny(principal, "shortcuts"); |
10664 | 0 | } |
10665 | 0 | |
10666 | 0 | return false; |
10667 | 0 | } |
10668 | | |
10669 | | /** |
10670 | | * Checks whether the given type is a supported document type for |
10671 | | * loading within the nsObjectLoadingContent specified by aContent. |
10672 | | * |
10673 | | * NOTE Helper method for nsContentUtils::HtmlObjectContentTypeForMIMEType. |
10674 | | * NOTE Does not take content policy or capabilities into account |
10675 | | */ |
10676 | | static bool |
10677 | | HtmlObjectContentSupportsDocument(const nsCString& aMimeType, |
10678 | | nsIContent* aContent) |
10679 | 0 | { |
10680 | 0 | nsCOMPtr<nsIWebNavigationInfo> info( |
10681 | 0 | do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID)); |
10682 | 0 | if (!info) { |
10683 | 0 | return false; |
10684 | 0 | } |
10685 | 0 | |
10686 | 0 | nsCOMPtr<nsIWebNavigation> webNav; |
10687 | 0 | if (aContent) { |
10688 | 0 | nsIDocument* currentDoc = aContent->GetComposedDoc(); |
10689 | 0 | if (currentDoc) { |
10690 | 0 | webNav = do_GetInterface(currentDoc->GetWindow()); |
10691 | 0 | } |
10692 | 0 | } |
10693 | 0 |
|
10694 | 0 | uint32_t supported; |
10695 | 0 | nsresult rv = info->IsTypeSupported(aMimeType, webNav, &supported); |
10696 | 0 |
|
10697 | 0 | if (NS_FAILED(rv)) { |
10698 | 0 | return false; |
10699 | 0 | } |
10700 | 0 | |
10701 | 0 | if (supported != nsIWebNavigationInfo::UNSUPPORTED) { |
10702 | 0 | // Don't want to support plugins as documents |
10703 | 0 | return supported != nsIWebNavigationInfo::PLUGIN; |
10704 | 0 | } |
10705 | 0 | |
10706 | 0 | // Try a stream converter |
10707 | 0 | // NOTE: We treat any type we can convert from as a supported type. If a |
10708 | 0 | // type is not actually supported, the URI loader will detect that and |
10709 | 0 | // return an error, and we'll fallback. |
10710 | 0 | nsCOMPtr<nsIStreamConverterService> convServ = |
10711 | 0 | do_GetService("@mozilla.org/streamConverters;1"); |
10712 | 0 | bool canConvert = false; |
10713 | 0 | if (convServ) { |
10714 | 0 | rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert); |
10715 | 0 | } |
10716 | 0 | return NS_SUCCEEDED(rv) && canConvert; |
10717 | 0 | } |
10718 | | |
10719 | | /* static */ |
10720 | | already_AddRefed<nsIPluginTag> |
10721 | | nsContentUtils::PluginTagForType(const nsCString& aMIMEType, bool aNoFakePlugin) |
10722 | 0 | { |
10723 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
10724 | 0 | nsCOMPtr<nsIPluginTag> tag; |
10725 | 0 | NS_ENSURE_TRUE(pluginHost, nullptr); |
10726 | 0 |
|
10727 | 0 | // ShouldPlay will handle the case where the plugin is disabled |
10728 | 0 | pluginHost->GetPluginTagForType(aMIMEType, |
10729 | 0 | aNoFakePlugin ? nsPluginHost::eExcludeFake |
10730 | 0 | : nsPluginHost::eExcludeNone, |
10731 | 0 | getter_AddRefs(tag)); |
10732 | 0 |
|
10733 | 0 | return tag.forget(); |
10734 | 0 | } |
10735 | | |
10736 | | /* static */ uint32_t |
10737 | | nsContentUtils::HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType, |
10738 | | bool aNoFakePlugin, |
10739 | | nsIContent* aContent) |
10740 | 0 | { |
10741 | 0 | if (aMIMEType.IsEmpty()) { |
10742 | 0 | return nsIObjectLoadingContent::TYPE_NULL; |
10743 | 0 | } |
10744 | 0 | |
10745 | 0 | if (imgLoader::SupportImageWithMimeType(aMIMEType.get())) { |
10746 | 0 | return nsIObjectLoadingContent::TYPE_IMAGE; |
10747 | 0 | } |
10748 | 0 | |
10749 | 0 | // Faking support of the PDF content as a document for EMBED tags |
10750 | 0 | // when internal PDF viewer is enabled. |
10751 | 0 | if (aMIMEType.LowerCaseEqualsLiteral("application/pdf") && |
10752 | 0 | IsPDFJSEnabled()) { |
10753 | 0 | return nsIObjectLoadingContent::TYPE_DOCUMENT; |
10754 | 0 | } |
10755 | 0 | |
10756 | 0 | if (HtmlObjectContentSupportsDocument(aMIMEType, aContent)) { |
10757 | 0 | return nsIObjectLoadingContent::TYPE_DOCUMENT; |
10758 | 0 | } |
10759 | 0 | |
10760 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
10761 | 0 | if (pluginHost) { |
10762 | 0 | nsCOMPtr<nsIPluginTag> tag = PluginTagForType(aMIMEType, aNoFakePlugin); |
10763 | 0 | if (tag) { |
10764 | 0 | if (!aNoFakePlugin && |
10765 | 0 | nsCOMPtr<nsIFakePluginTag>(do_QueryInterface(tag))) { |
10766 | 0 | return nsIObjectLoadingContent::TYPE_FAKE_PLUGIN; |
10767 | 0 | } |
10768 | 0 | |
10769 | 0 | // ShouldPlay will handle checking for disabled plugins |
10770 | 0 | return nsIObjectLoadingContent::TYPE_PLUGIN; |
10771 | 0 | } |
10772 | 0 | } |
10773 | 0 |
|
10774 | 0 | return nsIObjectLoadingContent::TYPE_NULL; |
10775 | 0 | } |
10776 | | |
10777 | | /* static */ already_AddRefed<nsISerialEventTarget> |
10778 | | nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aCategory) |
10779 | 0 | { |
10780 | 0 | if (NS_WARN_IF(!aLoadInfo)) { |
10781 | 0 | return nullptr; |
10782 | 0 | } |
10783 | 0 | |
10784 | 0 | nsCOMPtr<nsIDocument> doc; |
10785 | 0 | aLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); |
10786 | 0 | nsCOMPtr<nsISerialEventTarget> target; |
10787 | 0 | if (doc) { |
10788 | 0 | if (DocGroup* group = doc->GetDocGroup()) { |
10789 | 0 | target = group->EventTargetFor(aCategory); |
10790 | 0 | } |
10791 | 0 | } else { |
10792 | 0 | // There's no document yet, but this might be a top-level load where we can |
10793 | 0 | // find a TabGroup. |
10794 | 0 | uint64_t outerWindowId; |
10795 | 0 | if (NS_FAILED(aLoadInfo->GetOuterWindowID(&outerWindowId))) { |
10796 | 0 | // No window. This might be an add-on XHR, a service worker request, or |
10797 | 0 | // something else. |
10798 | 0 | return nullptr; |
10799 | 0 | } |
10800 | 0 | RefPtr<nsGlobalWindowOuter> window = |
10801 | 0 | nsGlobalWindowOuter::GetOuterWindowWithId(outerWindowId); |
10802 | 0 | if (!window) { |
10803 | 0 | return nullptr; |
10804 | 0 | } |
10805 | 0 | |
10806 | 0 | target = window->TabGroup()->EventTargetFor(aCategory); |
10807 | 0 | } |
10808 | 0 |
|
10809 | 0 | return target.forget(); |
10810 | 0 | } |
10811 | | |
10812 | | namespace { |
10813 | | template<class T> |
10814 | 0 | bool IsLocalRefURL(const T& aString) { |
10815 | 0 | // Find the first non-"C0 controls + space" character. |
10816 | 0 | const typename T::char_type* current = aString.BeginReading(); |
10817 | 0 | for (; current != aString.EndReading(); current++) { |
10818 | 0 | if (*current > 0x20) { |
10819 | 0 | // if the first non-"C0 controls + space" character is '#', this is a |
10820 | 0 | // local-ref URL. |
10821 | 0 | return *current == '#'; |
10822 | 0 | } |
10823 | 0 | } |
10824 | 0 |
|
10825 | 0 | return false; |
10826 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:bool (anonymous namespace)::IsLocalRefURL<nsTString<char16_t> >(nsTString<char16_t> const&) Unexecuted instantiation: nsContentUtils.cpp:bool (anonymous namespace)::IsLocalRefURL<nsTSubstring<char> >(nsTSubstring<char> const&) |
10827 | | } |
10828 | | |
10829 | | /* static */ bool |
10830 | | nsContentUtils::IsLocalRefURL(const nsString& aString) |
10831 | 0 | { |
10832 | 0 | return ::IsLocalRefURL(aString); |
10833 | 0 | } |
10834 | | |
10835 | | /* static */ bool |
10836 | | nsContentUtils::IsLocalRefURL(const nsACString& aString) |
10837 | 0 | { |
10838 | 0 | return ::IsLocalRefURL(aString); |
10839 | 0 | } |
10840 | | |
10841 | | static const uint64_t kIdProcessBits = 32; |
10842 | | static const uint64_t kIdBits = 64 - kIdProcessBits; |
10843 | | |
10844 | | /* static */ uint64_t |
10845 | | GenerateProcessSpecificId(uint64_t aId) |
10846 | 0 | { |
10847 | 0 | uint64_t processId = 0; |
10848 | 0 | if (XRE_IsContentProcess()) { |
10849 | 0 | ContentChild* cc = ContentChild::GetSingleton(); |
10850 | 0 | processId = cc->GetID(); |
10851 | 0 | } |
10852 | 0 |
|
10853 | 0 | MOZ_RELEASE_ASSERT(processId < (uint64_t(1) << kIdProcessBits)); |
10854 | 0 | uint64_t processBits = processId & ((uint64_t(1) << kIdProcessBits) - 1); |
10855 | 0 |
|
10856 | 0 | uint64_t id = aId; |
10857 | 0 | MOZ_RELEASE_ASSERT(id < (uint64_t(1) << kIdBits)); |
10858 | 0 | uint64_t bits = id & ((uint64_t(1) << kIdBits) - 1); |
10859 | 0 |
|
10860 | 0 | return (processBits << kIdBits) | bits; |
10861 | 0 | } |
10862 | | |
10863 | | // Tab ID is composed in a similar manner of Window ID. |
10864 | | static uint64_t gNextTabId = 0; |
10865 | | |
10866 | | /* static */ uint64_t |
10867 | | nsContentUtils::GenerateTabId() |
10868 | 0 | { |
10869 | 0 | return GenerateProcessSpecificId(++gNextTabId); |
10870 | 0 | } |
10871 | | |
10872 | | // Browsing context ID is composed in a similar manner of Window ID. |
10873 | | static uint64_t gNextBrowsingContextId = 0; |
10874 | | |
10875 | | /* static */ uint64_t |
10876 | | nsContentUtils::GenerateBrowsingContextId() |
10877 | 0 | { |
10878 | 0 | return GenerateProcessSpecificId(++gNextBrowsingContextId); |
10879 | 0 | } |
10880 | | |
10881 | | /* static */ bool |
10882 | | nsContentUtils::GetUserIsInteracting() |
10883 | 0 | { |
10884 | 0 | return UserInteractionObserver::sUserActive; |
10885 | 0 | } |
10886 | | |
10887 | | /* static */ bool |
10888 | | nsContentUtils::GetSourceMapURL(nsIHttpChannel* aChannel, nsACString& aResult) |
10889 | 0 | { |
10890 | 0 | nsresult rv = aChannel->GetResponseHeader(NS_LITERAL_CSTRING("SourceMap"), aResult); |
10891 | 0 | if (NS_FAILED(rv)) { |
10892 | 0 | rv = aChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), aResult); |
10893 | 0 | } |
10894 | 0 | return NS_SUCCEEDED(rv); |
10895 | 0 | } |
10896 | | |
10897 | | /* static */ bool |
10898 | | nsContentUtils::IsMessageInputEvent(const IPC::Message& aMsg) |
10899 | 0 | { |
10900 | 0 | if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) |
10901 | 0 | == mozilla::dom::PBrowser::PBrowserStart) { |
10902 | 0 | switch (aMsg.type()) { |
10903 | 0 | case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID: |
10904 | 0 | case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID: |
10905 | 0 | case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID: |
10906 | 0 | case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID: |
10907 | 0 | case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID: |
10908 | 0 | case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID: |
10909 | 0 | case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: |
10910 | 0 | case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID: |
10911 | 0 | case mozilla::dom::PBrowser::Msg_MouseEvent__ID: |
10912 | 0 | case mozilla::dom::PBrowser::Msg_SetDocShellIsActive__ID: |
10913 | 0 | return true; |
10914 | 0 | } |
10915 | 0 | } |
10916 | 0 | return false; |
10917 | 0 | } |
10918 | | |
10919 | | static const char* kUserInteractionInactive = "user-interaction-inactive"; |
10920 | | static const char* kUserInteractionActive = "user-interaction-active"; |
10921 | | |
10922 | | void |
10923 | | nsContentUtils::UserInteractionObserver::Init() |
10924 | 3 | { |
10925 | 3 | // Listen for the observer messages from EventStateManager which are telling |
10926 | 3 | // us whether or not the user is interacting. |
10927 | 3 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
10928 | 3 | obs->AddObserver(this, kUserInteractionInactive, false); |
10929 | 3 | obs->AddObserver(this, kUserInteractionActive, false); |
10930 | 3 | |
10931 | 3 | // We can't register ourselves as an annotator yet, as the |
10932 | 3 | // BackgroundHangMonitor hasn't started yet. It will have started by the |
10933 | 3 | // time we have the chance to spin the event loop. |
10934 | 3 | RefPtr<UserInteractionObserver> self = this; |
10935 | 3 | NS_DispatchToMainThread( |
10936 | 3 | NS_NewRunnableFunction("nsContentUtils::UserInteractionObserver::Init", |
10937 | 3 | [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); })); |
10938 | 3 | } |
10939 | | |
10940 | | void |
10941 | | nsContentUtils::UserInteractionObserver::Shutdown() |
10942 | 0 | { |
10943 | 0 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
10944 | 0 | if (obs) { |
10945 | 0 | obs->RemoveObserver(this, kUserInteractionInactive); |
10946 | 0 | obs->RemoveObserver(this, kUserInteractionActive); |
10947 | 0 | } |
10948 | 0 |
|
10949 | 0 | BackgroundHangMonitor::UnregisterAnnotator(*this); |
10950 | 0 | } |
10951 | | |
10952 | | /** |
10953 | | * NB: This function is always called by the BackgroundHangMonitor thread. |
10954 | | * Plan accordingly |
10955 | | */ |
10956 | | void |
10957 | | nsContentUtils::UserInteractionObserver::AnnotateHang(BackgroundHangAnnotations& aAnnotations) |
10958 | 0 | { |
10959 | 0 | // NOTE: Only annotate the hang report if the user is known to be interacting. |
10960 | 0 | if (sUserActive) { |
10961 | 0 | aAnnotations.AddAnnotation(NS_LITERAL_STRING("UserInteracting"), true); |
10962 | 0 | } |
10963 | 0 | } |
10964 | | |
10965 | | NS_IMETHODIMP |
10966 | | nsContentUtils::UserInteractionObserver::Observe(nsISupports* aSubject, |
10967 | | const char* aTopic, |
10968 | | const char16_t* aData) |
10969 | 0 | { |
10970 | 0 | if (!strcmp(aTopic, kUserInteractionInactive)) { |
10971 | 0 | sUserActive = false; |
10972 | 0 | } else if (!strcmp(aTopic, kUserInteractionActive)) { |
10973 | 0 | sUserActive = true; |
10974 | 0 | } else { |
10975 | 0 | NS_WARNING("Unexpected observer notification"); |
10976 | 0 | } |
10977 | 0 | return NS_OK; |
10978 | 0 | } |
10979 | | |
10980 | | Atomic<bool> nsContentUtils::UserInteractionObserver::sUserActive(false); |
10981 | | NS_IMPL_ISUPPORTS(nsContentUtils::UserInteractionObserver, nsIObserver) |
10982 | | |
10983 | | /* static */ bool |
10984 | | nsContentUtils::IsOverridingWindowName(const nsAString& aName) |
10985 | 0 | { |
10986 | 0 | return !aName.IsEmpty() && |
10987 | 0 | !aName.LowerCaseEqualsLiteral("_blank") && |
10988 | 0 | !aName.LowerCaseEqualsLiteral("_top") && |
10989 | 0 | !aName.LowerCaseEqualsLiteral("_parent") && |
10990 | 0 | !aName.LowerCaseEqualsLiteral("_self"); |
10991 | 0 | } |
10992 | | |
10993 | | // Unfortunately, we can't unwrap an IDL object using only a concrete type. |
10994 | | // We need to calculate type data based on the IDL typename. Which means |
10995 | | // wrapping our templated function in a macro. |
10996 | | #define EXTRACT_EXN_VALUES(T, ...) \ |
10997 | 0 | ExtractExceptionValues<mozilla::dom::prototypes::id::T, \ |
10998 | 0 | T##_Binding::NativeType, T>(__VA_ARGS__).isOk() |
10999 | | |
11000 | | template <prototypes::ID PrototypeID, class NativeType, typename T> |
11001 | | static Result<Ok, nsresult> |
11002 | | ExtractExceptionValues(JSContext* aCx, |
11003 | | JS::HandleObject aObj, |
11004 | | nsAString& aSourceSpecOut, |
11005 | | uint32_t* aLineOut, |
11006 | | uint32_t* aColumnOut, |
11007 | | nsString& aMessageOut) |
11008 | 0 | { |
11009 | 0 | RefPtr<T> exn; |
11010 | 0 | MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn))); |
11011 | 0 |
|
11012 | 0 | exn->GetFilename(aCx, aSourceSpecOut); |
11013 | 0 | if (!aSourceSpecOut.IsEmpty()) { |
11014 | 0 | *aLineOut = exn->LineNumber(aCx); |
11015 | 0 | *aColumnOut = exn->ColumnNumber(); |
11016 | 0 | } |
11017 | 0 |
|
11018 | 0 | exn->GetName(aMessageOut); |
11019 | 0 | aMessageOut.AppendLiteral(": "); |
11020 | 0 |
|
11021 | 0 | nsAutoString message; |
11022 | 0 | exn->GetMessageMoz(message); |
11023 | 0 | aMessageOut.Append(message); |
11024 | 0 | return Ok(); |
11025 | 0 | } Unexecuted instantiation: nsContentUtils.cpp:mozilla::Result<mozilla::Ok, nsresult> ExtractExceptionValues<(mozilla::dom::prototypes::id::ID)111, mozilla::dom::DOMException, mozilla::dom::DOMException>(JSContext*, JS::Handle<JSObject*>, nsTSubstring<char16_t>&, unsigned int*, unsigned int*, nsTString<char16_t>&) Unexecuted instantiation: nsContentUtils.cpp:mozilla::Result<mozilla::Ok, nsresult> ExtractExceptionValues<(mozilla::dom::prototypes::id::ID)159, mozilla::dom::Exception, mozilla::dom::Exception>(JSContext*, JS::Handle<JSObject*>, nsTSubstring<char16_t>&, unsigned int*, unsigned int*, nsTString<char16_t>&) |
11026 | | |
11027 | | /* static */ void |
11028 | | nsContentUtils::ExtractErrorValues(JSContext* aCx, |
11029 | | JS::Handle<JS::Value> aValue, |
11030 | | nsACString& aSourceSpecOut, |
11031 | | uint32_t* aLineOut, |
11032 | | uint32_t* aColumnOut, |
11033 | | nsString& aMessageOut) |
11034 | 0 | { |
11035 | 0 | nsAutoString sourceSpec; |
11036 | 0 | ExtractErrorValues(aCx, aValue, sourceSpec, aLineOut, aColumnOut, aMessageOut); |
11037 | 0 | CopyUTF16toUTF8(sourceSpec, aSourceSpecOut); |
11038 | 0 | } |
11039 | | |
11040 | | /* static */ void |
11041 | | nsContentUtils::ExtractErrorValues(JSContext* aCx, |
11042 | | JS::Handle<JS::Value> aValue, |
11043 | | nsAString& aSourceSpecOut, |
11044 | | uint32_t* aLineOut, |
11045 | | uint32_t* aColumnOut, |
11046 | | nsString& aMessageOut) |
11047 | 0 | { |
11048 | 0 | MOZ_ASSERT(aLineOut); |
11049 | 0 | MOZ_ASSERT(aColumnOut); |
11050 | 0 |
|
11051 | 0 | if (aValue.isObject()) { |
11052 | 0 | JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); |
11053 | 0 |
|
11054 | 0 | // Try to process as an Error object. Use the file/line/column values |
11055 | 0 | // from the Error as they will be more specific to the root cause of |
11056 | 0 | // the problem. |
11057 | 0 | JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr; |
11058 | 0 | if (err) { |
11059 | 0 | // Use xpc to extract the error message only. We don't actually send |
11060 | 0 | // this report anywhere. |
11061 | 0 | RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport(); |
11062 | 0 | report->Init(err, |
11063 | 0 | "<unknown>", // toString result |
11064 | 0 | false, // chrome |
11065 | 0 | 0); // window ID |
11066 | 0 |
|
11067 | 0 | if (!report->mFileName.IsEmpty()) { |
11068 | 0 | aSourceSpecOut = report->mFileName; |
11069 | 0 | *aLineOut = report->mLineNumber; |
11070 | 0 | *aColumnOut = report->mColumn; |
11071 | 0 | } |
11072 | 0 | aMessageOut.Assign(report->mErrorMsg); |
11073 | 0 | } |
11074 | 0 |
|
11075 | 0 | // Next, try to unwrap the rejection value as a DOMException. |
11076 | 0 | else if (EXTRACT_EXN_VALUES(DOMException, aCx, obj, aSourceSpecOut, |
11077 | 0 | aLineOut, aColumnOut, aMessageOut)) { |
11078 | 0 | return; |
11079 | 0 | } |
11080 | 0 | |
11081 | 0 | // Next, try to unwrap the rejection value as an XPC Exception. |
11082 | 0 | else if (EXTRACT_EXN_VALUES(Exception, aCx, obj, aSourceSpecOut, |
11083 | 0 | aLineOut, aColumnOut, aMessageOut)) { |
11084 | 0 | return; |
11085 | 0 | } |
11086 | 0 | } |
11087 | 0 | |
11088 | 0 | // If we could not unwrap a specific error type, then perform default safe |
11089 | 0 | // string conversions on primitives. Objects will result in "[Object]" |
11090 | 0 | // unfortunately. |
11091 | 0 | if (aMessageOut.IsEmpty()) { |
11092 | 0 | nsAutoJSString jsString; |
11093 | 0 | if (jsString.init(aCx, aValue)) { |
11094 | 0 | aMessageOut = jsString; |
11095 | 0 | } else { |
11096 | 0 | JS_ClearPendingException(aCx); |
11097 | 0 | } |
11098 | 0 | } |
11099 | 0 | } |
11100 | | |
11101 | | #undef EXTRACT_EXN_VALUES |
11102 | | |
11103 | | /* static */ bool |
11104 | | nsContentUtils::ContentIsLink(nsIContent* aContent) |
11105 | 0 | { |
11106 | 0 | if (!aContent || !aContent->IsElement()) { |
11107 | 0 | return false; |
11108 | 0 | } |
11109 | 0 | |
11110 | 0 | if (aContent->IsHTMLElement(nsGkAtoms::a)) { |
11111 | 0 | return true; |
11112 | 0 | } |
11113 | 0 | |
11114 | 0 | return aContent->AsElement()->AttrValueIs( |
11115 | 0 | kNameSpaceID_XLink, nsGkAtoms::type, nsGkAtoms::simple, eCaseMatters); |
11116 | 0 | } |
11117 | | |
11118 | | /* static */ already_AddRefed<ContentFrameMessageManager> |
11119 | | nsContentUtils::TryGetTabChildGlobal(nsISupports* aFrom) |
11120 | 0 | { |
11121 | 0 | nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom); |
11122 | 0 | if (!frameLoaderOwner) { |
11123 | 0 | return nullptr; |
11124 | 0 | } |
11125 | 0 | |
11126 | 0 | RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader(); |
11127 | 0 | if (!frameLoader) { |
11128 | 0 | return nullptr; |
11129 | 0 | } |
11130 | 0 | |
11131 | 0 | RefPtr<ContentFrameMessageManager> manager = frameLoader->GetTabChildMessageManager(); |
11132 | 0 | return manager.forget(); |
11133 | 0 | } |
11134 | | |
11135 | | /* static */ uint32_t |
11136 | | nsContentUtils::InnerOrOuterWindowCreated() |
11137 | 0 | { |
11138 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
11139 | 0 | ++sInnerOrOuterWindowCount; |
11140 | 0 | return ++sInnerOrOuterWindowSerialCounter; |
11141 | 0 | } |
11142 | | |
11143 | | /* static */ void |
11144 | | nsContentUtils::InnerOrOuterWindowDestroyed() |
11145 | 0 | { |
11146 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
11147 | 0 | MOZ_ASSERT(sInnerOrOuterWindowCount > 0); |
11148 | 0 | --sInnerOrOuterWindowCount; |
11149 | 0 | } |
11150 | | |
11151 | | /* static */ bool |
11152 | | nsContentUtils::CanShowPopup(nsIPrincipal* aPrincipal) |
11153 | 0 | { |
11154 | 0 | MOZ_ASSERT(aPrincipal); |
11155 | 0 | uint32_t permit; |
11156 | 0 | nsCOMPtr<nsIPermissionManager> permissionManager = |
11157 | 0 | services::GetPermissionManager(); |
11158 | 0 |
|
11159 | 0 | if (permissionManager && |
11160 | 0 | NS_SUCCEEDED(permissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) { |
11161 | 0 | if (permit == nsIPermissionManager::ALLOW_ACTION) { |
11162 | 0 | return true; |
11163 | 0 | } |
11164 | 0 | if (permit == nsIPermissionManager::DENY_ACTION) { |
11165 | 0 | return false; |
11166 | 0 | } |
11167 | 0 | } |
11168 | 0 | |
11169 | 0 | return !sDisablePopups; |
11170 | 0 | } |
11171 | | |
11172 | | static bool |
11173 | | JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) |
11174 | 0 | { |
11175 | 0 | nsAString* result = static_cast<nsAString*>(aData); |
11176 | 0 | result->Append(static_cast<const char16_t*>(aBuf), |
11177 | 0 | static_cast<uint32_t>(aLen)); |
11178 | 0 | return true; |
11179 | 0 | } |
11180 | | |
11181 | | /* static */ bool |
11182 | | nsContentUtils::StringifyJSON(JSContext* aCx, JS::MutableHandle<JS::Value> aValue, nsAString& aOutStr) |
11183 | 0 | { |
11184 | 0 | MOZ_ASSERT(aCx); |
11185 | 0 | aOutStr.Truncate(); |
11186 | 0 | JS::RootedValue value(aCx, aValue.get()); |
11187 | 0 | nsAutoString serializedValue; |
11188 | 0 | NS_ENSURE_TRUE(JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue, |
11189 | 0 | JSONCreator, &serializedValue), false); |
11190 | 0 | aOutStr = serializedValue; |
11191 | 0 | return true; |
11192 | 0 | } |