/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A namespace class for static layout utilities. */
// A global hashtable to for keeping the arena alive for cross docGroup node // adoption. static nsRefPtrHashtable<nsPtrHashKey<const nsINode>, mozilla::dom::DOMArena>*
sDOMArenaHashtable;
class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter {
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) override { // We don't measure the |EventListenerManager| objects pointed to by the // entries because those references are non-owning.
int64_t amount =
sEventListenerManagersHash
? sEventListenerManagersHash->ShallowSizeOfIncludingThis(
MallocSizeOf)
: 0;
MOZ_COLLECT_REPORT( "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES,
amount, "Memory used by the event listener manager's hash table.");
staticvoid EventListenerManagerHashInitEntry(PLDHashEntryHdr* entry, constvoid* key) { // Initialize the entry with placement new new (entry) EventListenerManagerMapEntry(key);
}
void AutoSuppressEventHandling::SuppressDocument(Document* aDoc) { // Note: Document::SuppressEventHandling will also automatically suppress // event handling for any in-process sub-documents. However, since we need // to deal with cases where remote BrowsingContexts may be interleaved // with in-process ones, we still need to walk the entire tree ourselves. // This may be slightly redundant in some cases, but since event handling // suppressions maintain a count of current blockers, it does not cause // any problems.
aDoc->SuppressEventHandling();
}
/** * This class is used to determine whether or not the user is currently * interacting with the browser. It listens to observer events to toggle the * value of the sUserActive static. * * This class is an internal implementation detail. * nsContentUtils::GetUserIsInteracting() should be used to access current * user interaction status.
*/ class nsContentUtils::UserInteractionObserver final
: public nsIObserver, public BackgroundHangAnnotator { public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
staticvoid RecomputeResistFingerprintingAllDocs(constchar*, void*) {
AutoTArray<RefPtr<BrowsingContextGroup>, 5> bcGroups;
BrowsingContextGroup::GetAllGroups(bcGroups); for (auto& bcGroup : bcGroups) {
AutoTArray<DocGroup*, 5> docGroups;
bcGroup->GetDocGroups(docGroups); for (auto* docGroup : docGroups) { for (Document* doc : *docGroup) { if (doc->RecomputeResistFingerprinting()) { if (auto* pc = doc->GetPresContext()) {
pc->MediaFeatureValuesChanged(
{MediaFeatureChangeReason::PreferenceChange},
MediaFeatureChangePropagation::JustThisDocument);
}
}
}
}
}
}
// static
nsresult nsContentUtils::Init() { if (sInitialized) {
NS_WARNING("Init() called twice");
return NS_OK;
}
nsHTMLTags::AddRefTable();
sXPConnect = nsXPConnect::XPConnect(); // We hold a strong ref to sXPConnect to ensure that it does not go away until // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be // triggered by xpcModuleDtor late in shutdown and cause crashes due to // various stuff already being torn down by then. Note that this means that // we are effectively making sure that if we leak nsLayoutStatics then we also // leak nsXPConnect.
NS_ADDREF(sXPConnect);
sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); if (!sSecurityManager) return NS_ERROR_FAILURE;
NS_ADDREF(sSecurityManager);
if (XRE_IsParentProcess()) {
AsyncPrecreateStringBundles();
#ifdefined(MOZ_WIDGET_ANDROID) // On Android, at-shutdown ping submission isn't reliable // (( because, on Android, we usually get killed, not shut down )). // To have a chance at submitting the ping, aim for idle after startup.
nsresult rv = NS_DispatchToCurrentThreadQueue(
NS_NewRunnableFunction( "AndroidUseCounterPingSubmitter",
[]() { glean_pings::UseCounters.Submit("idle_startup"_ns); }),
EventQueuePriority::Idle); // This is mostly best-effort, so if it goes awry, just log.
Unused << NS_WARN_IF(NS_FAILED(rv)); #endif// defined(MOZ_WIDGET_ANDROID)
void nsContentUtils::GetAltText(nsAString& text) { if (!sAltText) InitializeModifierStrings();
text.Assign(*sAltText);
}
void nsContentUtils::GetModifierSeparatorText(nsAString& text) { if (!sModifierSeparator) InitializeModifierStrings();
text.Assign(*sModifierSeparator);
}
void nsContentUtils::InitializeModifierStrings() { // load the display strings for the keyboard accelerators
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::components::StringBundle::Service();
nsCOMPtr<nsIStringBundle> bundle;
DebugOnly<nsresult> rv = NS_OK; if (bundleService) {
rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
getter_AddRefs(bundle));
}
NS_ASSERTION(
NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
nsAutoString shiftModifier;
nsAutoString commandOrWinModifier;
nsAutoString altModifier;
nsAutoString controlModifier;
nsAutoString modifierSeparator; if (bundle) { // macs use symbols for each modifier key, so fetch each from the bundle, // which also covers i18n
bundle->GetStringFromName("VK_SHIFT", shiftModifier);
bundle->GetStringFromName("VK_COMMAND_OR_WIN", commandOrWinModifier);
bundle->GetStringFromName("VK_ALT", altModifier);
bundle->GetStringFromName("VK_CONTROL", controlModifier);
bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator);
} // if any of these don't exist, we get an empty string
sShiftText = new nsString(shiftModifier);
sCommandOrWinText = new nsString(commandOrWinModifier);
sAltText = new nsString(altModifier);
sControlText = new nsString(controlModifier);
sModifierSeparator = new nsString(modifierSeparator);
}
sAtomEventTable = new nsTHashMap<RefPtr<nsAtom>, EventNameMapping>(std::size(eventArray));
sStringEventTable = new nsTHashMap<nsStringHashKey, EventNameMapping>(std::size(eventArray));
sUserDefinedEvents = new nsTArray<RefPtr<nsAtom>>(64);
// Subtract one from the length because of the trailing null for (uint32_t i = 0; i < std::size(eventArray) - 1; ++i) {
MOZ_ASSERT(!sAtomEventTable->Contains(eventArray[i].mAtom), "Double-defining event name; fix your EventNameList.h");
sAtomEventTable->InsertOrUpdate(eventArray[i].mAtom, eventArray[i]);
sStringEventTable->InsertOrUpdate(
Substring(nsDependentAtomString(eventArray[i].mAtom), 2),
eventArray[i]);
}
returntrue;
}
void nsContentUtils::InitializeTouchEventTable() { staticbool sEventTableInitialized = false; if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) {
sEventTableInitialized = true; staticconst EventNameMapping touchEventArray[] = { #define EVENT(name_, _message, _type, _class) #define TOUCH_EVENT(name_, _message, _type, _class) \
{nsGkAtoms::on##name_, _type, _message, _class}, #include"mozilla/EventNameList.h" #undef TOUCH_EVENT #undef EVENT
{nullptr}}; // Subtract one from the length because of the trailing null for (uint32_t i = 0; i < std::size(touchEventArray) - 1; ++i) {
sAtomEventTable->InsertOrUpdate(touchEventArray[i].mAtom,
touchEventArray[i]);
sStringEventTable->InsertOrUpdate(
Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2),
touchEventArray[i]);
}
}
}
if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
uint32_t atomCount = aAttr->GetAtomCount(); for (uint32_t i = 0; i < atomCount; i++) { if (i != 0) {
aResult.Append(' ');
}
aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
}
nsContentUtils::ASCIIToLower(aResult); return aCachedState;
}
aResult.Truncate();
mozilla::dom::AutocompleteInfo info;
AutocompleteAttrState state =
InternalSerializeAutocompleteAttribute(aAttr, info); if (state == eAutocompleteAttrState_Valid) { // Concatenate the info fields.
aResult = info.mSection;
if (!info.mAddressType.IsEmpty()) { if (!aResult.IsEmpty()) {
aResult += ' ';
}
aResult += info.mAddressType;
}
if (!info.mContactType.IsEmpty()) { if (!aResult.IsEmpty()) {
aResult += ' ';
}
aResult += info.mContactType;
}
if (!info.mFieldName.IsEmpty()) { if (!aResult.IsEmpty()) {
aResult += ' ';
}
aResult += info.mFieldName;
}
// The autocomplete attribute value "webauthn" is interpreted as both a // field name and a credential type. The corresponding IDL-exposed autofill // value is "webauthn", not "webauthn webauthn". if (!info.mCredentialType.IsEmpty() &&
!(info.mCredentialType.Equals(u"webauthn"_ns) &&
info.mCredentialType.Equals(aResult))) { if (!aResult.IsEmpty()) {
aResult += ' ';
}
aResult += info.mCredentialType;
}
}
/** * Helper to validate the @autocomplete tokens. * * @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
*/
nsContentUtils::AutocompleteAttrState
nsContentUtils::InternalSerializeAutocompleteAttribute( const nsAttrValue* aAttrVal, mozilla::dom::AutocompleteInfo& aInfo, bool aGrantAllValidValue) { // No autocomplete attribute so we are done if (!aAttrVal) { return eAutocompleteAttrState_Invalid;
}
// Only the Normal and Contact categories are allowed with webauthn // - disallow Credential if (enumValue.ParseEnumValue(tokenString, kAutocompleteCredentialTypeTable, false)) { return eAutocompleteAttrState_Invalid;
} // - disallow Off and Automatic if (enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false)) { if (enumValue.Equals(u"off"_ns, eIgnoreCase) ||
enumValue.Equals(u"on"_ns, eIgnoreCase)) { return eAutocompleteAttrState_Invalid;
}
}
// Proceed to process the remaining tokens as if "webauthn" was not present. // We need to decrement numTokens to enforce the correct per-category limits // on the maximum number of tokens.
--numTokens;
}
bool unsupported = false; if (!aGrantAllValidValue) {
unsupported = enumValue.ParseEnumValue(
tokenString, kAutocompleteUnsupportedFieldNameTable, false); if (unsupported) { return eAutocompleteAttrState_Invalid;
}
}
nsAutoString fieldNameStr;
result =
enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false);
// Only allow on/off if form autofill @autocomplete values aren't enabled // and it doesn't grant all valid values. if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
!aGrantAllValidValue) { return eAutocompleteAttrState_Invalid;
}
// Normal category if (numTokens > 3) { return eAutocompleteAttrState_Invalid;
}
category = eAutocompleteCategory_NORMAL;
} else { // Check if the last token is of the contact category instead. // Only allow on/off if form autofill @autocomplete values aren't enabled // and it doesn't grant all valid values. if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
!aGrantAllValidValue) { return eAutocompleteAttrState_Invalid;
}
result = enumValue.ParseEnumValue(
tokenString, kAutocompleteContactFieldNameTable, false); if (!result || numTokens > 4) { return eAutocompleteAttrState_Invalid;
}
if (category == eAutocompleteCategory_CONTACT) { if (!aGrantAllValidValue) {
unsupported = enumValue.ParseEnumValue(
tokenString, kAutocompleteUnsupportedContactFieldHintTable, false); if (unsupported) { return eAutocompleteAttrState_Invalid;
}
}
nsAttrValue contactFieldHint;
result = contactFieldHint.ParseEnumValue(
tokenString, kAutocompleteContactFieldHintTable, false); if (result) {
nsAutoString contactFieldHintString;
contactFieldHint.ToString(contactFieldHintString);
ASCIIToLower(contactFieldHintString);
aInfo.mContactType.Assign(contactFieldHintString); if (index == 0) { return eAutocompleteAttrState_Valid;
}
--index;
tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
}
}
// Check for billing/shipping tokens
nsAttrValue fieldHint; if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable, false)) {
nsString fieldHintString;
fieldHint.ToString(fieldHintString);
ASCIIToLower(fieldHintString);
aInfo.mAddressType.Assign(fieldHintString); if (index == 0) { return eAutocompleteAttrState_Valid;
}
--index;
tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
}
// Check for section-* token const nsDependentSubstring& section = Substring(tokenString, 0, 8); if (section.LowerCaseEqualsASCII("section-")) {
ASCIIToLower(tokenString);
aInfo.mSection.Assign(tokenString); if (index == 0) { return eAutocompleteAttrState_Valid;
}
}
// Clear the fields as the autocomplete attribute is invalid.
aInfo.mSection.Truncate();
aInfo.mAddressType.Truncate();
aInfo.mContactType.Truncate();
aInfo.mFieldName.Truncate();
aInfo.mCredentialType.Truncate();
return eAutocompleteAttrState_Invalid;
}
// Parse an integer according to HTML spec template <class CharT>
int32_t nsContentUtils::ParseHTMLIntegerImpl( const CharT* aStart, const CharT* aEnd,
ParseHTMLIntegerResultFlags* aResult) { int result = eParseHTMLInteger_NoFlags;
const CharT* iter = aStart;
while (iter != aEnd && nsContentUtils::IsHTMLWhitespace(*iter)) {
result |= eParseHTMLInteger_NonStandard;
++iter;
}
if (iter == aEnd) {
result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue;
*aResult = (ParseHTMLIntegerResultFlags)result; return 0;
}
int sign = 1; if (*iter == CharT('-')) {
sign = -1;
result |= eParseHTMLInteger_Negative;
++iter;
} elseif (*iter == CharT('+')) {
result |= eParseHTMLInteger_NonStandard;
++iter;
}
bool foundValue = false;
CheckedInt32 value = 0;
// Check for leading zeros first.
uint64_t leadingZeros = 0; while (iter != aEnd) { if (*iter != CharT('0')) { break;
}
++leadingZeros;
foundValue = true;
++iter;
}
while (iter != aEnd) { if (*iter >= CharT('0') && *iter <= CharT('9')) {
value = (value * 10) + (*iter - CharT('0')) * sign;
++iter; if (!value.isValid()) {
result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow; break;
}
foundValue = true;
} else { break;
}
}
if (!foundValue) {
result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue;
}
if (value.isValid() &&
((leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) ||
(sign == -1 && value == 0))) {
result |= eParseHTMLInteger_NonStandard;
}
if (iter != aEnd) {
result |= eParseHTMLInteger_DidNotConsumeAllInput;
}
// Now check whether this is a valid name="value" pair.
start = iter;
SKIP_WHITESPACE(start, end, false) if (*start != '=') { // No '=', so this is not a name="value" pair. We don't know // what it is, and we have no way to handle it. returnfalse;
}
// Have to skip the value.
++start;
SKIP_WHITESPACE(start, end, false)
char16_t q = *start; if (q != kQuote && q != kApostrophe) { // Not a valid quoted value, so bail. returnfalse;
}
++start; // Point to the first char of the value.
iter = start;
// At this point attrName holds the name of the "attribute" and // the value is between start and iter.
if (aName->Equals(attrName)) { // We'll accumulate as many characters as possible (until we hit either // the end of the string or the beginning of an entity). Chunks will be // delimited by start and chunkEnd. const char16_t* chunkEnd = start; while (chunkEnd != iter) { if (*chunkEnd == kLessThan) {
aValue.Truncate();
returnfalse;
}
if (*chunkEnd == kAmpersand) {
aValue.Append(start, chunkEnd - start);
/** * A helper function that parses a sandbox attribute (of an <iframe> or a CSP * directive) and converts it to the set of flags used internally. * * @param aSandboxAttr the sandbox attribute * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is * null)
*/
uint32_t nsContentUtils::ParseSandboxAttributeToFlags( const nsAttrValue* aSandboxAttr) { if (!aSandboxAttr) { return SANDBOXED_NONE;
}
uint32_t out = SANDBOX_ALL_FLAGS;
#define SANDBOX_KEYWORD(string, atom, flags) \ if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \
out &= ~(flags); \
} #include"IframeSandboxKeywordList.h" #undef SANDBOX_KEYWORD
return out;
}
/** * A helper function that checks if a string matches a valid sandbox flag. * * @param aFlag the potential sandbox flag. * @return true if the flag is a sandbox flag.
*/ bool nsContentUtils::IsValidSandboxFlag(const nsAString& aFlag) { #define SANDBOX_KEYWORD(string, atom, flags) \ if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \ returntrue; \
} #include"IframeSandboxKeywordList.h" #undef SANDBOX_KEYWORD returnfalse;
}
/** * A helper function that returns a string attribute corresponding to the * sandbox flags. * * @param aFlags the sandbox flags * @param aString the attribute corresponding to the flags (null if aFlags * is zero)
*/ void nsContentUtils::SandboxFlagsToString(uint32_t aFlags, nsAString& aString) { if (!aFlags) {
SetDOMStringToNull(aString); return;
}
/** * This is used to determine whether a character is in one of the classes * which CSS says should be part of the first-letter. Currently, that is * all punctuation classes (P*). Note that this is a change from CSS2 * which excluded Pc and Pd. * * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode * general category [UAX44]) [...]"
*/
// static bool nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar) { switch (mozilla::unicode::GetGeneralCategory(aChar)) { case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: /* Pc */ case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: /* Pd */ case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: /* Pe */ case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: /* Pf */ case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: /* Pi */ case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: /* Po */ case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: /* Ps */ returntrue; default: returnfalse;
}
}
if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) { return 0;
}
// We don't have to worry about overflow, since we can bail out as soon as // we're bigger than 7.
int32_t value = 0; while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) {
value = 10 * value + (*iter - char16_t('0')); if (value >= 7) { break;
}
++iter;
}
if (relative) { if (negate) {
value = 3 - value;
} else {
value = 3 + value;
}
}
if (sEventListenerManagersHash) {
NS_ASSERTION(sEventListenerManagersHash->EntryCount() == 0, "Event listener manager hash not empty at shutdown!");
// See comment above.
// However, we have to handle this table differently. If it still // has entries, we want to leak it too, so that we can keep it alive // in case any elements are destroyed. Because if they are, we need // their event listener managers to be destroyed too, or otherwise // it could leave dangling references in DOMClassInfo's preserved // wrapper table.
if (sUserInteractionObserver) {
sUserInteractionObserver->Shutdown();
NS_RELEASE(sUserInteractionObserver);
}
for (constauto& pref : kRfpPrefs) {
Preferences::UnregisterCallback(RecomputeResistFingerprintingAllDocs, pref);
}
TextControlState::Shutdown();
}
/** * Checks whether two nodes come from the same origin. aTrustedNode is * considered 'safe' in that a user can operate on it.
*/ // static
nsresult nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode, const nsINode* unTrustedNode) {
MOZ_ASSERT(aTrustedNode);
MOZ_ASSERT(unTrustedNode);
if (trustedPrincipal == unTrustedPrincipal) { return NS_OK;
}
bool equal; // XXXbz should we actually have a Subsumes() check here instead? Or perhaps // a separate method for that, with callers using one or the other? if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) ||
!equal) { return NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
return NS_OK;
}
// static
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.47 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.