Coverage Report

Created: 2018-09-25 14:53

/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"&quot;");
9306
0
          flushedUntil = currentPosition + 1;
9307
0
          break;
9308
0
        case '&':
9309
0
          aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9310
0
          aAppender.AppendLiteral(u"&amp;");
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"&nbsp;");
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"&lt;");
9338
0
          flushedUntil = currentPosition + 1;
9339
0
          break;
9340
0
        case '>':
9341
0
          aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9342
0
          aAppender.AppendLiteral(u"&gt;");
9343
0
          flushedUntil = currentPosition + 1;
9344
0
          break;
9345
0
        case '&':
9346
0
          aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9347
0
          aAppender.AppendLiteral(u"&amp;");
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"&nbsp;");
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("&lt;") - 2;
9386
0
          break;
9387
0
        case '>':
9388
0
          extraSpaceNeeded += ArrayLength("&gt;") - 2;
9389
0
          break;
9390
0
        case '&':
9391
0
          extraSpaceNeeded += ArrayLength("&amp;") - 2;
9392
0
          break;
9393
0
        case 0x00A0:
9394
0
          extraSpaceNeeded += ArrayLength("&nbsp;") - 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("&lt;") - 2;
9407
0
          break;
9408
0
        case '>':
9409
0
          extraSpaceNeeded += ArrayLength("&gt;") - 2;
9410
0
          break;
9411
0
        case '&':
9412
0
          extraSpaceNeeded += ArrayLength("&amp;") - 2;
9413
0
          break;
9414
0
        case 0x00A0:
9415
0
          extraSpaceNeeded += ArrayLength("&nbsp;") - 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("&quot;") - 2;
9441
0
        break;
9442
0
      case '&':
9443
0
        extraSpaceNeeded += ArrayLength("&amp;") - 2;
9444
0
        break;
9445
0
      case 0x00A0:
9446
0
        extraSpaceNeeded += ArrayLength("&nbsp;") - 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
}