/* -*- 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/. */
// Definitions of the global traversal stats. bool ServoTraversalStatistics::sActive = false;
ServoTraversalStatistics ServoTraversalStatistics::sSingleton;
/* * Does this child count as significant for selector matching? * * See nsStyleUtil::IsSignificantChild for details.
*/ bool Gecko_IsSignificantChild(const nsINode* aNode, bool aWhitespaceIsSignificant) { return nsStyleUtil::ThreadSafeIsSignificantChild(aNode->AsContent(),
aWhitespaceIsSignificant);
}
void ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const { // Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a // servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need // to measure it with a function that can handle an interior pointer. We use // ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's // output the memory measured here. #define STYLE_STRUCT(name_) \
static_assert(alignof(nsStyle##name_) <= sizeof(size_t), \ "alignment will break AddSizeOfExcludingThis()"); \ constvoid* p##name_ = Style##name_(); \ if (!aSizes.mState.HaveSeenPtr(p##name_)) { \
aSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_) += \
ServoStyleStructsMallocEnclosingSizeOf(p##name_); \
} #include"nsStyleStructList.h" #undef STYLE_STRUCT
if (visited_style && !aSizes.mState.HaveSeenPtr(visited_style)) {
visited_style->AddSizeOfIncludingThis(aSizes,
&aSizes.mLayoutComputedValuesVisited);
}
// Measurement of the following members may be added later if DMD finds it is // worthwhile: // - custom_properties // - writing_mode // - rules // - font_computation_data
}
bool Gecko_HaveSeenPtr(SeenPtrs* aTable, constvoid* aPtr) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aTable); // Empty Rust allocations are indicated by small values up to the alignment // of the relevant type. We shouldn't see anything like that here.
MOZ_ASSERT(uintptr_t(aPtr) > 16);
StyleSheet* Gecko_StyleSheet_Clone(const StyleSheet* aSheet) {
MOZ_ASSERT(aSheet);
MOZ_ASSERT(aSheet->GetParentSheet(), "Should only be used for @import"); // NOTE(emilio): We don't pass either the parent pointer of the stylesheet, // nor fix up the child list (yet). This is fixed up in the StylesheetInner // constructor.
RefPtr<StyleSheet> newSheet = aSheet->Clone(nullptr, nullptr); returnstatic_cast<StyleSheet*>(newSheet.forget().take());
}
GeckoImplicitScopeRoot Gecko_StyleSheet_ImplicitScopeRoot( const mozilla::StyleSheet* aSheet) { if (aSheet->IsConstructed()) { return GeckoImplicitScopeRoot{
.mHost = nullptr, .mRoot = nullptr, .mConstructed = true};
} // https://drafts.csswg.org/css-cascade-6/#scope-limits // "If no <scope-start> is specified, the scoping root is the parent element // of the owner node of the stylesheet where the @scope rule is defined." constauto* node = aSheet->GetOwnerNodeOfOutermostSheet(); if (!node) { return GeckoImplicitScopeRoot{
.mHost = nullptr, .mRoot = nullptr, .mConstructed = false};
} constauto* host = node->GetContainingShadowHost();
if (auto* aElement = node->GetParentElement()) { return GeckoImplicitScopeRoot{
.mHost = host, .mRoot = aElement, .mConstructed = false};
} // "[...] If no such element exists, then the scoping root is the root of the // containing node tree." This really should only happen for stylesheets // defined at the edge of the shadow root. return GeckoImplicitScopeRoot{
.mHost = host, .mRoot = host, .mConstructed = false};
}
// Handle scroll/view timelines first because CSS animations may refer to the // timeline defined by itself. if (aTasks & UpdateAnimationsTasks::ScrollTimelines) {
presContext->TimelineManager()->UpdateTimelines( const_cast<Element*>(element), pseudoRequest, aComputedData,
TimelineManager::ProgressTimelineType::Scroll);
}
if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
presContext->AnimationManager()->UpdateAnimations( const_cast<Element*>(element), pseudoRequest, aComputedData);
}
// aComputedData might be nullptr if the target element is now in a // display:none subtree. We still call Gecko_UpdateAnimations in this case // because we need to stop CSS animations in the display:none subtree. // However, we don't need to update transitions since they are stopped by // RestyleManager::AnimationsWithDestroyedFrame so we just return early // here. if (!aComputedData) { return;
}
if (aTasks & UpdateAnimationsTasks::EffectProperties) {
presContext->EffectCompositor()->UpdateEffectProperties(
aComputedData, const_cast<Element*>(element), pseudoRequest);
}
if (aTasks & UpdateAnimationsTasks::CascadeResults) {
EffectSet* effectSet = EffectSet::Get(element, pseudoRequest); // CSS animations/transitions might have been destroyed as part of the above // steps so before updating cascade results, we check if there are still any // animations to update. if (effectSet) { // We call UpdateCascadeResults directly (intead of // MaybeUpdateCascadeResults) since we know for sure that the cascade has // changed, but we were unable to call MarkCascadeUpdated when we noticed // it since we avoid mutating state as part of the Servo parallel // traversal.
presContext->EffectCompositor()->UpdateCascadeResults(
*effectSet, const_cast<Element*>(element), pseudoRequest);
}
}
double Gecko_GetPositionInSegment(const AnimationPropertySegment* aSegment, double aProgress, bool aBeforeFlag) {
MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey, "The segment from key should be less than to key");
double positionInSegment = (aProgress - aSegment->mFromKey) / // To avoid floating precision inaccuracies, make // sure we calculate both the numerator and // denominator using double precision.
(double(aSegment->mToKey) - aSegment->mFromKey);
float Gecko_GetLookAndFeelFloat(int32_t aId) { auto id = static_cast<LookAndFeel::FloatID>(aId);
AutoWriteLock guard(*sServoFFILock); return LookAndFeel::GetFloat(id);
}
bool Gecko_MatchLang(const Element* aElement, nsAtom* aOverrideLang, bool aHasOverrideLang, const char16_t* aValue) {
MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang), "aHasOverrideLang should only be set when aOverrideLang is null");
MOZ_ASSERT(aValue, "null lang parameter"); if (!aValue || !*aValue) { returnfalse;
}
// We have to determine the language of the current element. Since // this is currently no property and since the language is inherited // from the parent we have to be prepared to look at all parent // nodes. The language itself is encoded in the LANG attribute. if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) { return nsStyleUtil::LangTagCompare(nsAtomCString(language),
NS_ConvertUTF16toUTF8(aValue));
}
// Try to get the language from the HTTP header or if this // is missing as well from the preferences. // The content language can be a comma-separated list of // language codes. // FIXME: We're not really consistent in our treatment of comma-separated // content-language values. if (nsAtom* language = aElement->OwnerDoc()->GetContentLanguage()) { const NS_ConvertUTF16toUTF8 langString(aValue);
nsAtomCString docLang(language);
docLang.StripWhitespace(); for (autoconst& lang : docLang.Split(',')) { if (nsStyleUtil::LangTagCompare(lang, langString)) { returntrue;
}
}
} returnfalse;
}
// We have passed uninitialized memory to this function, // initialize it. We can't simply return an nsFont because then // we need to know its size beforehand. Servo cannot initialize nsFont // itself, so this will do. new (aDest) nsFont(defaultVariableFont);
static Keyframe* GetOrCreateKeyframe(
nsTArray<Keyframe>* aKeyframes, float aOffset, const StyleComputedTimingFunction* aTimingFunction, const CompositeOperationOrAuto aComposition,
KeyframeSearchDirection aSearchDirection,
KeyframeInsertPosition aInsertPosition) {
MOZ_ASSERT(aKeyframes, "The keyframe array should be valid");
MOZ_ASSERT(aTimingFunction, "The timing function should be valid");
MOZ_ASSERT(aOffset >= 0. && aOffset <= 1., "The offset should be in the range of [0.0, 1.0]");
Keyframe* Gecko_GetOrCreateKeyframeAtStart(
nsTArray<Keyframe>* aKeyframes, float aOffset, const StyleComputedTimingFunction* aTimingFunction, const CompositeOperationOrAuto aComposition) {
MOZ_ASSERT(aKeyframes->IsEmpty() ||
aKeyframes->ElementAt(0).mOffset.value() >= aOffset, "The offset should be less than or equal to the first keyframe's " "offset if there are exisiting keyframes");
void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) { // TODO(emilio): Do we have more useful stuff to put here, maybe? if (aURI) {
*aOut = aURI->GetSpecOrDefault();
}
}
// XXX Implemented by hand because even though it's thread-safe, only the // subclasses have the HasThreadSafeRefCnt bits. void Gecko_AddRefnsIURIArbitraryThread(nsIURI* aPtr) { NS_ADDREF(aPtr); } void Gecko_ReleasensIURIArbitraryThread(nsIURI* aPtr) { NS_RELEASE(aPtr); }
Length Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont* aFont, const Document* aDocument) { // Don't change font-size:0, since that would un-hide hidden text. if (aFont->mSize.IsZero()) { return {0};
} // Don't change it for docs where we don't enable the min-font-size. if (!aFont->MinFontSizeEnabled()) { return {0};
}
Length minFontSize; bool needsCache = false;
// Getting font metrics can require some main thread only work to be // done, such as work that needs to touch non-threadsafe refcounted // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc. // // To handle this work, font code checks whether we are in a Servo traversal // and if so, appends PostTraversalTasks to the current ServoStyleSet // to be performed immediately after the traversal is finished. This // works well for starting downloadable font loads, since we don't have // those fonts available to get metrics for anyway. Platform fonts and // ArrayBuffer-backed FontFace objects are handled synchronously.
static already_AddRefed<StyleSheet> LoadImportSheet(
Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
LoaderReusableStyleSheets* aReusableSheets, const StyleCssUrl& aURL,
already_AddRefed<StyleLockedMediaList> aMediaList) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aLoader, "Should've catched this before");
MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
auto media = MakeRefPtr<MediaList>(std::move(aMediaList));
nsCOMPtr<nsIURI> uri = aURL.GetURI();
nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
size_t previousSheetCount = aParent->ChildSheets().Length(); if (NS_SUCCEEDED(rv)) { // TODO(emilio): We should probably make LoadChildSheet return the // stylesheet rather than the return code.
rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
aReusableSheets);
}
if (NS_FAILED(rv) || previousSheetCount == aParent->ChildSheets().Length()) { // Servo and Gecko have different ideas of what a valid URL is, so we might // get in here with a URL string that NS_NewURI can't handle. We may also // reach here via an import cycle. For the import cycle case, we need some // sheet object per spec, even if its empty. DevTools uses the URI to // realize it has hit an import cycle, so we mark it complete to make the // sheet readable from JS.
RefPtr<StyleSheet> emptySheet =
aParent->CreateEmptyChildSheet(media.forget()); // Make a dummy URI if we don't have one because some methods assume // non-null URIs. if (!uri) {
NS_NewURI(getter_AddRefs(uri), "about:invalid"_ns);
}
emptySheet->SetURIs(uri, uri, uri);
emptySheet->SetPrincipal(aURL.ExtraData().Principal());
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForExternalCSSResources(emptySheet);
emptySheet->SetReferrerInfo(referrerInfo);
emptySheet->SetComplete();
aParent->AppendStyleSheet(*emptySheet); return emptySheet.forget();
}
bool Gecko_ComputeBoolPrefMediaQuery(nsAtom* aPref) {
MOZ_ASSERT(NS_IsMainThread()); // This map leaks until shutdown, but that's fine, all the values are // controlled by us so it's not expected to be big. static StaticAutoPtr<nsTHashMap<RefPtr<nsAtom>, bool>> sRegisteredPrefs; if (!sRegisteredPrefs) { if (PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal)) { // Styling doesn't really matter much at this point, don't bother. returnfalse;
}
sRegisteredPrefs = new nsTHashMap<RefPtr<nsAtom>, bool>();
ClearOnShutdown(&sRegisteredPrefs);
} return sRegisteredPrefs->LookupOrInsertWith(aPref, [&] {
nsAutoAtomCString prefName(aPref);
Preferences::RegisterCallback(
[](constchar* aPrefName, void*) { if (sRegisteredPrefs) {
RefPtr<nsAtom> name = NS_Atomize(nsDependentCString(aPrefName));
sRegisteredPrefs->InsertOrUpdate(name,
Preferences::GetBool(aPrefName));
}
LookAndFeel::NotifyChangedAllWindows(
widget::ThemeChangeKind::MediaQueriesOnly);
},
prefName); return Preferences::GetBool(prefName.get());
});
}
int32_t Gecko_GetNumStyleThreads() { if (constauto& cpuInfo = hal::GetHeterogeneousCpuInfo()) {
size_t numBigCpus = cpuInfo->mBigCpus.Count(); // If CPUs are homogeneous we do not need to override stylo's // default number of threads. if (numBigCpus != cpuInfo->mTotalNumCpus) { // From testing on a variety of devices it appears using only // the number of big cores gives best performance when there are // 2 or more big cores. If there are fewer than 2 big cores then // additionally using the medium cores performs better. if (numBigCpus >= 2) { returnstatic_cast<int32_t>(numBigCpus);
} returnstatic_cast<int32_t>(numBigCpus + cpuInfo->mMediumCpus.Count());
}
}
StyleSingleFontFamily StyleSingleFontFamily::Parse( const nsACString& aFamilyOrGenericName) { // should only be passed a single font - not entirely correct, a family // *could* have a comma in it but in practice never does so // for debug purposes this is fine
NS_ASSERTION(aFamilyOrGenericName.FindChar(',') == -1, "Convert method should only be passed a single family name");
auto genericType = Servo_GenericFontFamily_Parse(&aFamilyOrGenericName); if (genericType != StyleGenericFontFamily::None) { return Generic(genericType);
} return FamilyName({StyleAtom(NS_Atomize(aFamilyOrGenericName)),
StyleFontFamilyNameSyntax::Identifiers});
}
void StyleSingleFontFamily::AppendToString(nsACString& aName, bool aQuote) const { if (IsFamilyName()) { constauto& name = AsFamilyName(); if (!aQuote) {
aName.Append(nsAutoAtomCString(name.name.AsAtom())); return;
}
Servo_FamilyName_Serialize(&name, &aName); return;
}
switch (AsGeneric()) { case StyleGenericFontFamily::None: case StyleGenericFontFamily::MozEmoji:
MOZ_FALLTHROUGH_ASSERT("Should never appear in a font-family name!"); case StyleGenericFontFamily::Serif: return aName.AppendLiteral("serif"); case StyleGenericFontFamily::SansSerif: return aName.AppendLiteral("sans-serif"); case StyleGenericFontFamily::Monospace: return aName.AppendLiteral("monospace"); case StyleGenericFontFamily::Cursive: return aName.AppendLiteral("cursive"); case StyleGenericFontFamily::Fantasy: return aName.AppendLiteral("fantasy"); case StyleGenericFontFamily::SystemUi: return aName.AppendLiteral("system-ui");
}
MOZ_ASSERT_UNREACHABLE("Unknown generic font-family!"); return aName.AppendLiteral("serif");
}
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 und die Messung sind noch experimentell.