diff options
Diffstat (limited to '')
40 files changed, 576 insertions, 398 deletions
diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index f350e5210a..ddc6240216 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -439,7 +439,6 @@ void FontFaceSet::MaybeResolve() { break; case FontFaceLoadStatus::Loading: // We should've returned above at MightHavePendingFontLoads()! - case FontFaceLoadStatus::EndGuard_: MOZ_ASSERT_UNREACHABLE("unexpected FontFaceLoadStatus"); break; } diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp index 5c7992f8db..dc43e9cf6a 100644 --- a/layout/style/GeckoBindings.cpp +++ b/layout/style/GeckoBindings.cpp @@ -27,7 +27,6 @@ #include "mozilla/dom/DocumentInlines.h" #include "nsILoadContext.h" #include "nsIFrame.h" -#include "nsIMozBrowserFrame.h" #include "nsINode.h" #include "nsIURI.h" #include "nsFontMetrics.h" @@ -44,6 +43,7 @@ #include "mozilla/css/ImageLoader.h" #include "mozilla/DeclarationBlock.h" #include "mozilla/AttributeStyles.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/EffectCompositor.h" #include "mozilla/EffectSet.h" #include "mozilla/FontPropertyTypes.h" diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index ebbc934466..1ea37b094f 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -8,7 +8,9 @@ #include "mozilla/css/Loader.h" +#include "MainThreadUtils.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/css/ErrorReporter.h" #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/FetchPriority.h" #include "mozilla/dom/SRILogHelper.h" @@ -22,6 +24,7 @@ #include "mozilla/SchedulerGroup.h" #include "mozilla/URLPreloader.h" #include "nsIChildChannel.h" +#include "nsIPrincipal.h" #include "nsISupportsPriority.h" #include "nsITimedChannel.h" #include "nsICachingChannel.h" @@ -34,7 +37,6 @@ #include "nsICookieJarSettings.h" #include "mozilla/dom/Document.h" #include "nsIURI.h" -#include "nsNetUtil.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" #include "nsContentPolicyUtils.h" @@ -64,6 +66,7 @@ #include "mozilla/css/StreamLoader.h" #include "mozilla/SharedStyleSheetCache.h" #include "mozilla/StaticPrefs_layout.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_network.h" #include "mozilla/Try.h" @@ -308,7 +311,10 @@ SheetLoadData::SheetLoadData( mNonce(aNonce), mFetchPriority{aFetchPriority}, mGuessedEncoding(GetFallbackEncoding(*aLoader, aOwningNode, nullptr)), - mCompatMode(aLoader->CompatMode(aPreloadKind)) { + mCompatMode(aLoader->CompatMode(aPreloadKind)), + mRecordErrors( + aLoader && aLoader->GetDocument() && + css::ErrorReporter::ShouldReportErrors(*aLoader->GetDocument())) { MOZ_ASSERT(!aOwningNode || dom::LinkStyle::FromNode(*aOwningNode), "Must implement LinkStyle"); MOZ_ASSERT(mTriggeringPrincipal); @@ -349,7 +355,10 @@ SheetLoadData::SheetLoadData(css::Loader* aLoader, nsIURI* aURI, mFetchPriority(FetchPriority::Auto), mGuessedEncoding(GetFallbackEncoding( *aLoader, nullptr, aParentData ? aParentData->mEncoding : nullptr)), - mCompatMode(aLoader->CompatMode(mPreloadKind)) { + mCompatMode(aLoader->CompatMode(mPreloadKind)), + mRecordErrors( + aLoader && aLoader->GetDocument() && + css::ErrorReporter::ShouldReportErrors(*aLoader->GetDocument())) { MOZ_ASSERT(mLoader, "Must have a loader!"); MOZ_ASSERT(mTriggeringPrincipal); MOZ_ASSERT(!mUseSystemPrincipal || mSyncLoad, @@ -391,7 +400,10 @@ SheetLoadData::SheetLoadData( mFetchPriority(aFetchPriority), mGuessedEncoding( GetFallbackEncoding(*aLoader, nullptr, aPreloadEncoding)), - mCompatMode(aLoader->CompatMode(aPreloadKind)) { + mCompatMode(aLoader->CompatMode(aPreloadKind)), + mRecordErrors( + aLoader && aLoader->GetDocument() && + css::ErrorReporter::ShouldReportErrors(*aLoader->GetDocument())) { MOZ_ASSERT(mTriggeringPrincipal); MOZ_ASSERT(mLoader, "Must have a loader!"); MOZ_ASSERT(!mUseSystemPrincipal || mSyncLoad, @@ -639,43 +651,54 @@ static bool AllLoadsCanceled(const SheetLoadData& aData) { * page and check the mimetype on the channel to make sure we're not * loading non-text/css data in standards mode. */ -nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, - const nsACString& aBytes1, - const nsACString& aBytes2, - nsIChannel* aChannel) { +nsresult SheetLoadData::VerifySheetReadyToParse( + nsresult aStatus, const nsACString& aBytes1, const nsACString& aBytes2, + nsIChannel* aChannel, nsIURI* aFinalChannelURI, + nsIPrincipal* aChannelResultPrincipal) { LOG(("SheetLoadData::VerifySheetReadyToParse")); - NS_ASSERTION(!mLoader->mSyncCallback, "Synchronous callback from necko"); + NS_ASSERTION((!NS_IsMainThread() || !mLoader->mSyncCallback), + "Synchronous callback from necko"); if (AllLoadsCanceled(*this)) { - LOG_WARN((" All loads are canceled, dropping")); - mLoader->SheetComplete(*this, NS_BINDING_ABORTED); + if (NS_IsMainThread()) { + LOG_WARN((" All loads are canceled, dropping")); + mLoader->SheetComplete(*this, NS_BINDING_ABORTED); + } + return NS_OK; + } + + if (!NS_IsMainThread() && mRecordErrors) { + // we cannot parse sheet OMT if we need to record errors return NS_OK; } if (NS_FAILED(aStatus)) { - LOG_WARN( - (" Load failed: status 0x%" PRIx32, static_cast<uint32_t>(aStatus))); - // Handle sheet not loading error because source was a tracking URL (or - // fingerprinting, cryptomining, etc). - // We make a note of this sheet node by including it in a dedicated - // array of blocked tracking nodes under its parent document. - // - // Multiple sheet load instances might be tied to this request, - // we annotate each one linked to a valid owning element (node). - if (net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode( - aStatus)) { - if (Document* doc = mLoader->GetDocument()) { - for (SheetLoadData* data = this; data; data = data->mNext) { - // owner node may be null but AddBlockTrackingNode can cope - doc->AddBlockedNodeByClassifier(data->mSheet->GetOwnerNode()); + if (NS_IsMainThread()) { + LOG_WARN( + (" Load failed: status 0x%" PRIx32, static_cast<uint32_t>(aStatus))); + // Handle sheet not loading error because source was a tracking URL (or + // fingerprinting, cryptomining, etc). + // We make a note of this sheet node by including it in a dedicated + // array of blocked tracking nodes under its parent document. + // + // Multiple sheet load instances might be tied to this request, + // we annotate each one linked to a valid owning element (node). + if (net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode( + aStatus)) { + if (Document* doc = mLoader->GetDocument()) { + for (SheetLoadData* data = this; data; data = data->mNext) { + // owner node may be null but AddBlockTrackingNode can cope + doc->AddBlockedNodeByClassifier(data->mSheet->GetOwnerNode()); + } } } + mLoader->SheetComplete(*this, aStatus); } - mLoader->SheetComplete(*this, aStatus); return NS_OK; } if (!aChannel) { + MOZ_ASSERT(NS_IsMainThread()); mLoader->SheetComplete(*this, NS_OK); return NS_OK; } @@ -688,10 +711,8 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, // having a chrome URI. (Whether or not chrome stylesheets come through // this codepath seems nondeterministic.) // Otherwise we want the potentially-HTTP-redirected URI. - nsCOMPtr<nsIURI> channelURI; - NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); - - if (!channelURI || !originalURI) { + if (!aFinalChannelURI || !originalURI) { + MOZ_ASSERT(NS_IsMainThread()); NS_ERROR("Someone just violated the nsIRequest contract"); LOG_WARN((" Channel without a URI. Bad!")); mLoader->SheetComplete(*this, NS_ERROR_UNEXPECTED); @@ -705,32 +726,33 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, if (mUseSystemPrincipal) { result = secMan->GetSystemPrincipal(getter_AddRefs(principal)); } else { - result = secMan->GetChannelResultPrincipal(aChannel, - getter_AddRefs(principal)); + if (aChannelResultPrincipal) { + principal = aChannelResultPrincipal; + result = NS_OK; + } } } if (NS_FAILED(result)) { - LOG_WARN((" Couldn't get principal")); - mLoader->SheetComplete(*this, result); + if (NS_IsMainThread()) { + LOG_WARN((" Couldn't get principal")); + mLoader->SheetComplete(*this, result); + } return NS_OK; } mSheet->SetPrincipal(principal); - if (mSheet->GetCORSMode() == CORS_NONE && - !mTriggeringPrincipal->Subsumes(principal)) { - mIsCrossOriginNoCORS = true; - } - // If it's an HTTP channel, we want to make sure this is not an // error document we got. if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) { bool requestSucceeded; result = httpChannel->GetRequestSucceeded(&requestSucceeded); if (NS_SUCCEEDED(result) && !requestSucceeded) { - LOG((" Load returned an error page")); - mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE); + if (NS_IsMainThread()) { + LOG((" Load returned an error page")); + mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE); + } return NS_OK; } @@ -753,6 +775,9 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, contentType.IsEmpty(); if (!validType) { + if (!NS_IsMainThread()) { + return NS_OK; + } const char* errorMessage; uint32_t errorFlag; bool sameOrigin = true; @@ -772,7 +797,8 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, } AutoTArray<nsString, 2> strings; - CopyUTF8toUTF16(channelURI->GetSpecOrDefault(), *strings.AppendElement()); + CopyUTF8toUTF16(aFinalChannelURI->GetSpecOrDefault(), + *strings.AppendElement()); CopyASCIItoUTF16(contentType, *strings.AppendElement()); nsCOMPtr<nsIURI> referrer = ReferrerInfo()->GetOriginalReferrer(); @@ -791,6 +817,13 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, SRIMetadata sriMetadata; mSheet->GetIntegrity(sriMetadata); if (!sriMetadata.IsEmpty()) { + if (!NS_IsMainThread()) { + // We dont process any further in OMT. + // This is because we have some main-thread only accesses below. + // We need to find a way to optimize this handling. + // See Bug 1882046. + return NS_OK; + } nsAutoCString sourceUri; if (mLoader->mDocument && mLoader->mDocument->GetDocumentURI()) { mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri); @@ -815,9 +848,13 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus, } } + if (mSheet->GetCORSMode() == CORS_NONE && + !mTriggeringPrincipal->Subsumes(principal)) { + mIsCrossOriginNoCORS = true; + } // Enough to set the URIs on mSheet, since any sibling datas we have share // the same mInner as mSheet and will thus get the same URI. - mSheet->SetURIs(channelURI, originalURI, channelURI); + mSheet->SetURIs(aFinalChannelURI, originalURI, aFinalChannelURI); ReferrerPolicy policy = nsContentUtils::GetReferrerPolicyFromChannel(aChannel); @@ -1353,11 +1390,11 @@ nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState, void Loader::AdjustPriority(const SheetLoadData& aLoadData, nsIChannel* aChannel) { - if (!StaticPrefs::network_fetchpriority_enabled()) { - if (!aLoadData.ShouldDefer() && aLoadData.IsLinkRelPreload()) { - SheetLoadData::PrioritizeAsPreload(aChannel); - } + if (!aLoadData.ShouldDefer() && aLoadData.IsLinkRelPreload()) { + SheetLoadData::PrioritizeAsPreload(aChannel); + } + if (!StaticPrefs::network_fetchpriority_enabled()) { return; } @@ -1367,32 +1404,27 @@ void Loader::AdjustPriority(const SheetLoadData& aLoadData, return; } - // Adjusting priorites is specified as implementation-defined. To align with - // other browsers for potentially important cases, some adjustments are made - // according to - // <https://web.dev/articles/fetch-priority#browser_priority_and_fetchpriority>. - const int32_t supportsPriority = [&]() { + // Adjusting priorites is specified as implementation-defined. + // See corresponding preferences in StaticPrefList.yaml for more context. + const int32_t supportsPriorityDelta = [&]() { if (aLoadData.ShouldDefer()) { - return nsISupportsPriority::PRIORITY_LOW; + return FETCH_PRIORITY_ADJUSTMENT_FOR(deferred_style, + aLoadData.mFetchPriority); } - switch (aLoadData.mFetchPriority) { - case FetchPriority::Auto: { - return nsISupportsPriority::PRIORITY_HIGHEST; - } - case FetchPriority::High: { - return nsISupportsPriority::PRIORITY_HIGHEST; - } - case FetchPriority::Low: { - return nsISupportsPriority::PRIORITY_HIGH; - } + if (aLoadData.IsLinkRelPreload()) { + return FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_style, + aLoadData.mFetchPriority); } - - MOZ_ASSERT_UNREACHABLE(); - return nsISupportsPriority::PRIORITY_HIGHEST; + return FETCH_PRIORITY_ADJUSTMENT_FOR(non_deferred_style, + aLoadData.mFetchPriority); }(); - LogPriorityMapping(sCssLoaderLog, aLoadData.mFetchPriority, supportsPriority); - sp->SetPriority(supportsPriority); + sp->AdjustPriority(supportsPriorityDelta); +#ifdef DEBUG + int32_t adjustedPriority; + sp->GetPriority(&adjustedPriority); + LogPriorityMapping(sCssLoaderLog, aLoadData.mFetchPriority, adjustedPriority); +#endif } nsresult Loader::LoadSheetAsyncInternal(SheetLoadData& aLoadData, @@ -1582,32 +1614,35 @@ nsresult Loader::LoadSheetAsyncInternal(SheetLoadData& aLoadData, /** * ParseSheet handles parsing the data stream. */ -Loader::Completed Loader::ParseSheet(const nsACString& aBytes, - SheetLoadData& aLoadData, - AllowAsyncParse aAllowAsync) { +Loader::Completed Loader::ParseSheet( + const nsACString& aBytes, const RefPtr<SheetLoadDataHolder>& aLoadData, + AllowAsyncParse aAllowAsync) { LOG(("css::Loader::ParseSheet")); - if (aLoadData.mURI) { - LOG_URI(" Load succeeded for URI: '%s', parsing", aLoadData.mURI); + SheetLoadData* loadData = aLoadData->get(); + MOZ_ASSERT(loadData); + + if (loadData->mURI) { + LOG_URI(" Load succeeded for URI: '%s', parsing", loadData->mURI); } AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(LAYOUT_CSSParsing); ++mParsedSheetCount; - aLoadData.mIsBeingParsed = true; + loadData->mIsBeingParsed = true; - StyleSheet* sheet = aLoadData.mSheet; + StyleSheet* sheet = loadData->mSheet; MOZ_ASSERT(sheet); // Some cases, like inline style and UA stylesheets, need to be parsed // synchronously. The former may trigger child loads, the latter must not. - if (aLoadData.mSyncLoad || aAllowAsync == AllowAsyncParse::No) { - sheet->ParseSheetSync(this, aBytes, &aLoadData); - aLoadData.mIsBeingParsed = false; + if (loadData->mSyncLoad || aAllowAsync == AllowAsyncParse::No) { + sheet->ParseSheetSync(this, aBytes, loadData); + loadData->mIsBeingParsed = false; - bool noPendingChildren = aLoadData.mPendingChildren == 0; - MOZ_ASSERT_IF(aLoadData.mSyncLoad, noPendingChildren); + bool noPendingChildren = loadData->mPendingChildren == 0; + MOZ_ASSERT_IF(loadData->mSyncLoad, noPendingChildren); if (noPendingChildren) { - SheetComplete(aLoadData, NS_OK); + SheetComplete(*loadData, NS_OK); return Completed::Yes; } return Completed::No; @@ -1621,9 +1656,9 @@ Loader::Completed Loader::ParseSheet(const nsACString& aBytes, sheet->ParseSheet(*this, aBytes, aLoadData) ->Then( GetMainThreadSerialEventTarget(), __func__, - [loadData = RefPtr<SheetLoadData>(&aLoadData)](bool aDummy) { + [loadData = aLoadData](bool aDummy) { MOZ_ASSERT(NS_IsMainThread()); - loadData->SheetFinishedParsingAsync(); + loadData->get()->SheetFinishedParsingAsync(); }, [] { MOZ_CRASH("rejected parse promise"); }); return Completed::No; @@ -1847,7 +1882,10 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle( // effects of inline stylesheets are visible immediately (aside from // @imports). NS_ConvertUTF16toUTF8 utf8(aBuffer); - completed = ParseSheet(utf8, *data, AllowAsyncParse::No); + RefPtr<SheetLoadDataHolder> holder( + new nsMainThreadPtrHolder<css::SheetLoadData>(__func__, data.get(), + true)); + completed = ParseSheet(utf8, holder, AllowAsyncParse::No); if (completed == Completed::Yes) { if (isWorthCaching) { mInlineSheets.InsertOrUpdate(aBuffer, std::move(sheet)); diff --git a/layout/style/Loader.h b/layout/style/Loader.h index ba60218e94..70eefffb4a 100644 --- a/layout/style/Loader.h +++ b/layout/style/Loader.h @@ -590,7 +590,8 @@ class Loader final { // // If this function returns Completed::Yes, then ParseSheet also called // SheetComplete on aLoadData. - Completed ParseSheet(const nsACString&, SheetLoadData&, AllowAsyncParse); + Completed ParseSheet(const nsACString&, const RefPtr<SheetLoadDataHolder>&, + AllowAsyncParse); // The load of the sheet in the load data is done, one way or another. // Do final cleanup. @@ -646,7 +647,7 @@ class Loader final { uint32_t mPendingLoadCount = 0; // The number of stylesheets that we have parsed, for testing purposes. - uint32_t mParsedSheetCount = 0; + Atomic<uint32_t, MemoryOrdering::Relaxed> mParsedSheetCount{0}; bool mEnabled = true; diff --git a/layout/style/PseudoStyleType.h b/layout/style/PseudoStyleType.h index 6804b500c3..88eb4e4cf8 100644 --- a/layout/style/PseudoStyleType.h +++ b/layout/style/PseudoStyleType.h @@ -7,6 +7,7 @@ #ifndef mozilla_PseudoStyleType_h #define mozilla_PseudoStyleType_h +#include <cstddef> #include <cstdint> #include <iosfwd> diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index cc6d13fb5e..20e1ca4116 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -186,16 +186,9 @@ allowlist-vars = [ "NODE_.*", "ELEMENT_.*", "NS_FONT_.*", - "NS_STYLE_.*", - "NS_MATHML_.*", - "NS_RADIUS_.*", - "BORDER_COLOR_.*", - "BORDER_STYLE_.*", "CSS_PSEUDO_ELEMENT_.*", "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*", "kNameSpaceID_.*", - "kGenericFont_.*", - "kPresContext_.*", "nsNameSpaceManager_.*", "GECKO_IS_NIGHTLY", "NS_SAME_AS_FOREGROUND_COLOR", @@ -205,9 +198,7 @@ allowlist-vars = [ # TODO(emilio): A bunch of types here can go away once we generate bindings and # structs together. allowlist-types = [ - "ServoCssRules", "nsFontFaceRuleContainer", - "Matrix4x4Components", "mozilla::ComputedKeyframeValues", "mozilla::Keyframe", "mozilla::PropertyValuePair", @@ -223,7 +214,6 @@ allowlist-types = [ "mozilla::ServoElementSnapshot.*", "mozilla::ComputedStyle", "mozilla::StyleSheet", - "mozilla::ServoStyleSheetInner", "mozilla::ServoStyleSetSizes", "mozilla::ServoTraversalStatistics", "mozilla::css::LoaderReusableStyleSheets", @@ -247,27 +237,14 @@ allowlist-types = [ "mozilla::gfx::Float", "mozilla::gfx::FontVariation", "mozilla::gfx::FontPaletteValueSet", - "mozilla::gfx::FontPaletteValueSet::PaletteValeus", "mozilla::StyleImageLayerAttachment", "gfxFontFeature", "gfxFontVariation", - ".*ThreadSafe.*Holder", - "AnonymousContent", - "AudioContext", - "DefaultDelete", - "DOMIntersectionObserverEntry", "Element", - "mozilla::FontSizePrefs", - "FragmentOrURL", - "FrameRequestCallback", - "GeckoParserExtraData", "GeckoFontMetrics", "gfxFontFeatureValueSet", - "GridNamedArea", "mozilla::HalfCorner", "Image", - "ImageURL", - "Keyframe", "mozilla::MediumFeaturesChangedResult", "nsAttrName", "nsAttrValue", @@ -280,15 +257,7 @@ allowlist-types = [ "nsCSSPropertyID", "nsCSSPropertyIDSet", "nsCSSProps", - "nsCSSShadowArray", "nsCSSValue", - "nsCSSValueList", - "nsCSSValueList_heap", - "nsCSSValuePair_heap", - "nsCSSValuePairList", - "nsCSSValuePairList_heap", - "nsCSSValueTriplet_heap", - "nsCursorImage", "nsFont", "nsAtom", "nsDynamicAtom", @@ -299,19 +268,11 @@ allowlist-types = [ "nsSize", "nsStyleBackground", "nsStyleBorder", - "nsStyleColor", "nsStyleColumn", "nsStyleContent", - "nsStyleContentData", - "ComputedStyle", - "nsStyleCounterData", "nsStyleDisplay", "nsStyleEffects", - "nsStyleFilter", "nsStyleFont", - "nsStyleGradient", - "nsStyleGridTemplate", - "nsStyleImage", "nsStyleImageLayers", "nsStyleList", "nsStyleMargin", @@ -319,37 +280,17 @@ allowlist-types = [ "nsStylePadding", "nsStylePage", "nsStylePosition", - "nsStyleSides", "nsStyleSVG", - "nsStyleSVGOpacitySource", "nsStyleSVGReset", "nsStyleTable", "nsStyleTableBorder", "nsStyleText", "nsStyleTextReset", "nsStyleUIReset", - "nsStyleUnion", "nsStyleUI", "nsStyleVisibility", "nsStyleXUL", "nsTArrayHeader", - "Position", - "PropertyValuePair", - "Runnable", - "ServoAttrSnapshot", - "ServoComputedData", - "ServoComputedDataBorrowed", - "ServoElementSnapshot", - "ComputedStyleStrong", - "ComputedStyleBorrowed", - "ComputedStyleBorrowedOrNull", - "SheetParsingMode", - "StaticRefPtr", - "StyleAnimation", - "StyleGeometryBox", - "StyleShapeSource", - "StyleTransition", - "ThemeWidgetType", "mozilla::UniquePtr", "mozilla::DeclarationBlock", "mozilla::DefaultDelete", @@ -430,6 +371,7 @@ opaque-types = [ cbindgen-types = [ { gecko = "StyleAnimationIterationCount", servo = "crate::values::computed::AnimationIterationCount" }, { gecko = "StyleAnimationTimeline", servo = "crate::values::computed::AnimationTimeline" }, + { gecko = "StyleTransitionBehavior", servo = "crate::values::computed::TransitionBehavior" }, { gecko = "StyleAppearance", servo = "crate::values::specified::Appearance" }, { gecko = "StyleAspectRatio", servo = "crate::values::computed::position::AspectRatio" }, { gecko = "StyleAtom", servo = "crate::Atom" }, diff --git a/layout/style/ServoCSSParser.cpp b/layout/style/ServoCSSParser.cpp index 92e1271f2c..89f17f1733 100644 --- a/layout/style/ServoCSSParser.cpp +++ b/layout/style/ServoCSSParser.cpp @@ -33,6 +33,16 @@ bool ServoCSSParser::ComputeColor(ServoStyleSet* aStyleSet, } /* static */ +bool ServoCSSParser::ColorTo(const nsACString& aFromColor, + const nsACString& aToColorSpace, + nsACString* aResultColor, + nsTArray<float>* aResultComponents, + bool* aResultAdjusted, css::Loader* aLoader) { + return Servo_ColorTo(&aFromColor, &aToColorSpace, aResultColor, + aResultComponents, aResultAdjusted, aLoader); +} + +/* static */ already_AddRefed<StyleLockedDeclarationBlock> ServoCSSParser::ParseProperty( nsCSSPropertyID aProperty, const nsACString& aValue, const ParsingEnvironment& aParsingEnvironment, diff --git a/layout/style/ServoCSSParser.h b/layout/style/ServoCSSParser.h index 4bbde6a0e8..583a2eebd9 100644 --- a/layout/style/ServoCSSParser.h +++ b/layout/style/ServoCSSParser.h @@ -80,6 +80,27 @@ class ServoCSSParser { css::Loader* aLoader = nullptr); /** + * Takes a CSS <color> and convert it to another color space. + * + * @param aStyleSet The style set whose nsPresContext will be used to + * compute system colors and other special color values. + * @param aFromColor The CSS <color> we use to convert from. + * @param aToColorSpace The CSS <color-space> to convert the color into. + * @param aResultColor The resulting converted color value. + * @param aResultAdjusted Whether the color was adjusted to fit into the SRGB + color space. + * @param aLoader The CSS loader for document we're parsing a color for, + * so that parse errors can be reported to the console. If nullptr, errors + * won't be reported to the console. + * @return Whether aFromColor and aToColorSpace was successfully parsed and + * aResultColor and aResultAdjusted was set. + */ + static bool ColorTo(const nsACString& aFromColor, + const nsACString& aToColorSpace, nsACString* aResultColor, + nsTArray<float>* aResultComponents, bool* aResultAdjusted, + css::Loader* aLoader = nullptr); + + /** * Parse a string representing a CSS property value into a * StyleLockedDeclarationBlock. * diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h index b6a574037a..1985e8fbeb 100644 --- a/layout/style/ServoStyleConstsInlines.h +++ b/layout/style/ServoStyleConstsInlines.h @@ -507,20 +507,15 @@ StyleCSSPixelLength StyleCSSPixelLength::ScaledBy(float aScale) const { return FromPixels(ToCSSPixels() * aScale); } -nscoord StyleCSSPixelLength::ToAppUnits() const { - // We want to resolve the length part of the calc() expression rounding 0.5 - // away from zero, instead of the default behavior of - // NSToCoordRound{,WithClamp} which do floor(x + 0.5). - // - // This is what the rust code in the app_units crate does, and not doing this - // would regress bug 1323735, for example. - // - // FIXME(emilio, bug 1528114): Probably we should do something smarter. - if (IsZero()) { - // Avoid the expensive FP math below. - return 0; - } - float length = _0 * float(mozilla::AppUnitsPerCSSPixel()); +namespace detail { +static inline nscoord DefaultPercentLengthToAppUnits(float aPixelLength) { + return NSToCoordTruncClamped(aPixelLength); +} + +static inline nscoord DefaultLengthToAppUnits(float aPixelLength) { + // We want to round lengths rounding 0.5 away from zero, instead of the + // default behavior of NSToCoordRound{,WithClamp} which do floor(x + 0.5). + float length = aPixelLength * float(mozilla::AppUnitsPerCSSPixel()); if (length >= float(nscoord_MAX)) { return nscoord_MAX; } @@ -529,6 +524,15 @@ nscoord StyleCSSPixelLength::ToAppUnits() const { } return NSToIntRound(length); } +} // namespace detail + +nscoord StyleCSSPixelLength::ToAppUnits() const { + if (IsZero()) { + // Avoid the expensive FP math below. + return 0; + } + return detail::DefaultLengthToAppUnits(_0); +} bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH; } @@ -693,6 +697,11 @@ CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const { return Servo_ResolveCalcLengthPercentage(this, aBasis); } +nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis) const { + return detail::DefaultLengthToAppUnits( + ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis))); +} + template <> void StyleCalcNode::ScaleLengthsBy(float); @@ -708,20 +717,18 @@ CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { template <typename T> CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const { - static_assert(std::is_same<decltype(aPercentageGetter()), CSSCoord>::value, - "Should return CSS pixels"); + static_assert(std::is_same_v<decltype(aPercentageGetter()), CSSCoord>); if (ConvertsToLength()) { return ToLengthInCSSPixels(); } return ResolveToCSSPixels(aPercentageGetter()); } -template <typename T, typename U> -nscoord LengthPercentage::Resolve(T aPercentageGetter, U aRounder) const { - static_assert(std::is_same<decltype(aPercentageGetter()), nscoord>::value, - "Should return app units"); - static_assert(std::is_same<decltype(aRounder(1.0f)), nscoord>::value, - "Should return app units"); +template <typename T, typename PercentRounder> +nscoord LengthPercentage::Resolve(T aPercentageGetter, + PercentRounder aPercentRounder) const { + static_assert(std::is_same_v<decltype(aPercentageGetter()), nscoord>); + static_assert(std::is_same_v<decltype(aPercentRounder(1.0f)), nscoord>); if (ConvertsToLength()) { return ToLength(); } @@ -730,29 +737,26 @@ nscoord LengthPercentage::Resolve(T aPercentageGetter, U aRounder) const { } nscoord basis = aPercentageGetter(); if (IsPercentage()) { - return aRounder(basis * AsPercentage()._0); + return aPercentRounder(basis * AsPercentage()._0); } - return AsCalc().Resolve(basis, aRounder); + return AsCalc().Resolve(basis); } -// Note: the static_cast<> wrappers below are needed to disambiguate between -// the versions of NSToCoordTruncClamped that take float vs. double as the arg. nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { return Resolve([=] { return aPercentageBasis; }, - static_cast<nscoord (*)(float)>(NSToCoordTruncClamped)); + detail::DefaultPercentLengthToAppUnits); } template <typename T> nscoord LengthPercentage::Resolve(T aPercentageGetter) const { - return Resolve(aPercentageGetter, - static_cast<nscoord (*)(float)>(NSToCoordTruncClamped)); + return Resolve(aPercentageGetter, detail::DefaultPercentLengthToAppUnits); } -template <typename T> +template <typename PercentRounder> nscoord LengthPercentage::Resolve(nscoord aPercentageBasis, - T aPercentageRounder) const { + PercentRounder aPercentRounder) const { return Resolve([aPercentageBasis] { return aPercentageBasis; }, - aPercentageRounder); + aPercentRounder); } void LengthPercentage::ScaleLengthsBy(float aScale) { diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index d7225349cc..eee6cba0f7 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -686,8 +686,8 @@ class ServoStyleSet { // Stores pointers to our cached ComputedStyles for non-inheriting anonymous // boxes. - EnumeratedArray<nsCSSAnonBoxes::NonInheriting, - nsCSSAnonBoxes::NonInheriting::_Count, RefPtr<ComputedStyle>> + EnumeratedArray<nsCSSAnonBoxes::NonInheriting, RefPtr<ComputedStyle>, + size_t(nsCSSAnonBoxes::NonInheriting::_Count)> mNonInheritingComputedStyles; public: diff --git a/layout/style/SheetLoadData.h b/layout/style/SheetLoadData.h index c817e4c1f3..6621af35bd 100644 --- a/layout/style/SheetLoadData.h +++ b/layout/style/SheetLoadData.h @@ -90,7 +90,9 @@ class SheetLoadData final // so aBytes1 and aBytes2 refer to those pieces. nsresult VerifySheetReadyToParse(nsresult aStatus, const nsACString& aBytes1, const nsACString& aBytes2, - nsIChannel* aChannel); + nsIChannel* aChannel, + nsIURI* aFinalChannelURI, + nsIPrincipal* aPrincipal); NS_DECL_ISUPPORTS @@ -237,6 +239,8 @@ class SheetLoadData final // listening for the load. bool mIntentionallyDropped = false; + const bool mRecordErrors; + bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; } RefPtr<StyleSheet> ValueForCache() const; diff --git a/layout/style/StreamLoader.cpp b/layout/style/StreamLoader.cpp index 3e8bd37d76..3c614d7d0c 100644 --- a/layout/style/StreamLoader.cpp +++ b/layout/style/StreamLoader.cpp @@ -5,8 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/css/StreamLoader.h" - +#include "mozilla/StaticPrefs_network.h" #include "mozilla/Encoding.h" +#include "mozilla/glean/GleanMetrics.h" #include "mozilla/TaskQueue.h" #include "nsContentUtils.h" #include "nsIChannel.h" @@ -14,16 +15,21 @@ #include "nsIThreadRetargetableRequest.h" #include "nsIStreamTransportService.h" #include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsProxyRelease.h" #include "nsServiceManagerUtils.h" namespace mozilla::css { StreamLoader::StreamLoader(SheetLoadData& aSheetLoadData) - : mSheetLoadData(&aSheetLoadData), mStatus(NS_OK) {} + : mSheetLoadData(&aSheetLoadData), + mStatus(NS_OK), + mMainThreadSheetLoadData(new nsMainThreadPtrHolder<SheetLoadData>( + "StreamLoader::SheetLoadData", mSheetLoadData, false)) {} StreamLoader::~StreamLoader() { #ifdef NIGHTLY_BUILD - MOZ_RELEASE_ASSERT(mOnStopRequestCalled || mChannelOpenFailed); + MOZ_RELEASE_ASSERT(mOnStopProcessingDone || mChannelOpenFailed); #endif } @@ -34,6 +40,7 @@ NS_IMPL_ISUPPORTS(StreamLoader, nsIStreamListener, NS_IMETHODIMP StreamLoader::OnStartRequest(nsIRequest* aRequest) { MOZ_ASSERT(aRequest); + mRequest = aRequest; mSheetLoadData->NotifyStart(aRequest); // It's kinda bad to let Web content send a number that results @@ -52,6 +59,12 @@ StreamLoader::OnStartRequest(nsIRequest* aRequest) { return (mStatus = NS_ERROR_OUT_OF_MEMORY); } } + NS_GetFinalChannelURI(channel, getter_AddRefs(mFinalChannelURI)); + nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); + // we dont return on error here as the error is handled in + // SheetLoadData::VerifySheetReadyToParse + Unused << secMan->GetChannelResultPrincipal( + channel, getter_AddRefs(mChannelResultPrincipal)); } if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) { nsCOMPtr<nsIEventTarget> sts = @@ -73,6 +86,13 @@ StreamLoader::OnStartRequest(nsIRequest* aRequest) { return *info.mExpirationTime; }(); + // We need to block block resolution of parse promise until we receive + // OnStopRequest on Main thread. This is necessary because parse promise + // resolution fires OnLoad event OnLoad event must not be dispatched until + // OnStopRequest in main thread is processed, for stuff like performance + // resource entries. + mSheetLoadData->mSheet->BlockParsePromise(); + return NS_OK; } @@ -81,39 +101,80 @@ StreamLoader::CheckListenerChain() { return NS_OK; } NS_IMETHODIMP StreamLoader::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { -#ifdef NIGHTLY_BUILD - MOZ_RELEASE_ASSERT(!mOnStopRequestCalled); - mOnStopRequestCalled = true; -#endif + MOZ_ASSERT_IF(!StaticPrefs::network_send_OnDataFinished_cssLoader(), + !mOnStopProcessingDone); + + // StreamLoader::OnStopRequest can get triggered twice for a request. + // Once from the path + // nsIThreadRetargetableStreamListener::OnDataFinished->StreamLoader::OnDataFinished + // (non-main thread) and + // once from nsIRequestObserver::OnStopRequest path (main thread). It is + // guaranteed that we will always get + // nsIThreadRetargetableStreamListener::OnDataFinished trigger first and this + // is always followed by nsIRequestObserver::OnStopRequest + + // If we are executing OnStopRequest OMT, we need to block resolution of parse + // promise and unblock again if we are executing this in main thread. + // Resolution of parse promise fires onLoadEvent and this should not happen + // before main thread OnStopRequest is dispatched. + if (NS_IsMainThread()) { + if (mOnDataFinishedTime) { + // collect telemetry for the delta between OnDataFinished and + // OnStopRequest + TimeDuration delta = (TimeStamp::Now() - mOnDataFinishedTime); + glean::networking::http_content_cssloader_ondatafinished_to_onstop_delay + .AccumulateRawDuration(delta); + } + mSheetLoadData->mSheet->UnblockParsePromise(); + } + + if (mOnStopProcessingDone) { + return NS_OK; + } + mOnStopProcessingDone = true; nsresult rv = mStatus; // Decoded data nsCString utf8String; { - // Hold the nsStringBuffer for the bytes from the stack to ensure release - // no matter which return branch is taken. - nsCString bytes = std::move(mBytes); - nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); if (NS_FAILED(mStatus)) { - mSheetLoadData->VerifySheetReadyToParse(mStatus, ""_ns, ""_ns, channel); + mSheetLoadData->VerifySheetReadyToParse(mStatus, ""_ns, ""_ns, channel, + mFinalChannelURI, + mChannelResultPrincipal); + + if (!NS_IsMainThread()) { + // When processing OMT, we have code paths in VerifySheetReadyToParse + // that are main-thread only. We bail on such scenarios and continue + // processing them on main thread OnStopRequest. + mOnStopProcessingDone = false; + } return mStatus; } - rv = mSheetLoadData->VerifySheetReadyToParse(aStatus, mBOMBytes, bytes, - channel); + rv = mSheetLoadData->VerifySheetReadyToParse(aStatus, mBOMBytes, mBytes, + channel, mFinalChannelURI, + mChannelResultPrincipal); if (rv != NS_OK_PARSE_SHEET) { + if (!NS_IsMainThread()) { + mOnStopProcessingDone = false; + } return rv; } - // BOM detection generally happens during the write callback, but that won't - // have happened if fewer than three bytes were received. + // At this point all the conditions that requires us to run on main + // are checked in VerifySheetReadyToParse + + // BOM detection generally happens during the write callback, but that + // won't have happened if fewer than three bytes were received. if (mEncodingFromBOM.isNothing()) { HandleBOM(); MOZ_ASSERT(mEncodingFromBOM.isSome()); } - + // Hold the nsStringBuffer for the bytes from the stack to ensure release + // after its scope ends + nsCString bytes = std::move(mBytes); // The BOM handling has happened, but we still may not have an encoding if // there was no BOM. Ensure we have one. const Encoding* encoding = mEncodingFromBOM.value(); @@ -142,9 +203,11 @@ StreamLoader::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { // For reasons I don't understand, factoring the below lines into // a method on SheetLoadData resulted in a linker error. Hence, // accessing fields of mSheetLoadData from here. - mSheetLoadData->mLoader->ParseSheet(utf8String, *mSheetLoadData, + mSheetLoadData->mLoader->ParseSheet(utf8String, mMainThreadSheetLoadData, Loader::AllowAsyncParse::Yes); + mRequest = nullptr; + return NS_OK; } @@ -159,9 +222,6 @@ StreamLoader::OnDataAvailable(nsIRequest*, nsIInputStream* aInputStream, return aInputStream->ReadSegments(WriteSegmentFun, this, aCount, &dummy); } -NS_IMETHODIMP -StreamLoader::OnDataFinished(nsresult aStatus) { return NS_OK; } - void StreamLoader::HandleBOM() { MOZ_ASSERT(mEncodingFromBOM.isNothing()); MOZ_ASSERT(mBytes.IsEmpty()); @@ -176,6 +236,18 @@ void StreamLoader::HandleBOM() { mBOMBytes.Truncate(bomLength); } +NS_IMETHODIMP +StreamLoader::OnDataFinished(nsresult aResult) { + if (StaticPrefs::network_send_OnDataFinished_cssLoader()) { + MOZ_ASSERT(mOnDataFinishedTime.IsNull(), + "OnDataFinished should only be called once"); + mOnDataFinishedTime = TimeStamp::Now(); + return OnStopRequest(mRequest, aResult); + } + + return NS_OK; +} + nsresult StreamLoader::WriteSegmentFun(nsIInputStream*, void* aClosure, const char* aSegment, uint32_t, uint32_t aCount, uint32_t* aWriteCount) { diff --git a/layout/style/StreamLoader.h b/layout/style/StreamLoader.h index a34117625a..e940fc7936 100644 --- a/layout/style/StreamLoader.h +++ b/layout/style/StreamLoader.h @@ -9,6 +9,7 @@ #include "nsIStreamListener.h" #include "nsIThreadRetargetableStreamListener.h" +#include "nsIURI.h" #include "nsString.h" #include "mozilla/css/SheetLoadData.h" #include "mozilla/Assertions.h" @@ -52,10 +53,17 @@ class StreamLoader : public nsIThreadRetargetableStreamListener { // mBytes, and store all subsequent data in that buffer. nsCString mBytes; nsAutoCStringN<3> mBOMBytes; + nsCOMPtr<nsIRequest> mRequest; + nsCOMPtr<nsIURI> mFinalChannelURI; + nsCOMPtr<nsIPrincipal> mChannelResultPrincipal; + // flag to indicate that we can skip processing of data in OnStopRequest + bool mOnStopProcessingDone{false}; + RefPtr<SheetLoadDataHolder> mMainThreadSheetLoadData; + + mozilla::TimeStamp mOnDataFinishedTime; #ifdef NIGHTLY_BUILD bool mChannelOpenFailed = false; - bool mOnStopRequestCalled = false; #endif }; diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp index 494618d879..b1ce1d66e2 100644 --- a/layout/style/StyleSheet.cpp +++ b/layout/style/StyleSheet.cpp @@ -28,7 +28,6 @@ #include "mozilla/css/SheetLoadData.h" #include "mozAutoDocUpdate.h" -#include "SheetLoadData.h" namespace mozilla { @@ -136,8 +135,12 @@ already_AddRefed<StyleSheet> StyleSheet::Constructor( // 3. Set the sheet's disabled flag according to aOptions. sheet->SetDisabled(aOptions.mDisabled); + sheet->SetURLExtraData(); sheet->SetComplete(); + sheet->ReplaceSync(""_ns, aRv); + MOZ_ASSERT(!aRv.Failed()); + // 4. Return sheet. return sheet.forget(); } @@ -740,7 +743,9 @@ already_AddRefed<dom::Promise> StyleSheet::Replace(const nsACString& aText, loadData->mIsBeingParsed = true; MOZ_ASSERT(!mReplacePromise); mReplacePromise = promise; - ParseSheet(*loader, aText, *loadData) + RefPtr<css::SheetLoadDataHolder> holder( + new css::SheetLoadDataHolder(__func__, loadData, false)); + ParseSheet(*loader, aText, holder) ->Then( target, __func__, [loadData] { loadData->SheetFinishedParsingAsync(); }, @@ -769,7 +774,6 @@ void StyleSheet::ReplaceSync(const nsACString& aText, ErrorResult& aRv) { // 3. Parse aText into rules. // 4. If rules contain @imports, skip them and continue parsing. auto* loader = mConstructorDocument->CSSLoader(); - SetURLExtraData(); RefPtr<const StyleStylesheetContents> rawContent = Servo_StyleSheet_FromUTF8Bytes( loader, this, @@ -1159,28 +1163,19 @@ already_AddRefed<StyleSheet> StyleSheet::CreateEmptyChildSheet( return child.forget(); } -// We disable parallel stylesheet parsing if the browser is recording CSS errors -// (which parallel parsing can't handle). -static bool AllowParallelParse(css::Loader& aLoader, URLExtraData* aUrlData) { - Document* doc = aLoader.GetDocument(); - if (doc && css::ErrorReporter::ShouldReportErrors(*doc)) { - return false; - } - // Otherwise we can parse in parallel. - return true; -} - RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet( css::Loader& aLoader, const nsACString& aBytes, - css::SheetLoadData& aLoadData) { + const RefPtr<css::SheetLoadDataHolder>& aLoadData) { MOZ_ASSERT(mParsePromise.IsEmpty()); + MOZ_ASSERT_IF(NS_IsMainThread(), mAsyncParseBlockers == 0); + RefPtr<StyleSheetParsePromise> p = mParsePromise.Ensure(__func__); - if (!aLoadData.ShouldDefer()) { + if (!aLoadData->get()->ShouldDefer()) { mParsePromise.SetTaskPriority(nsIRunnablePriority::PRIORITY_RENDER_BLOCKING, __func__); } + BlockParsePromise(); SetURLExtraData(); - // @import rules are disallowed due to this decision: // https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418 // We may allow @import rules again in the future. @@ -1191,26 +1186,26 @@ RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet( const bool shouldRecordCounters = aLoader.GetDocument() && aLoader.GetDocument()->GetStyleUseCounters() && !urlData->ChromeRulesEnabled(); - if (!AllowParallelParse(aLoader, urlData)) { + + if (aLoadData->get()->mRecordErrors) { + MOZ_ASSERT(NS_IsMainThread()); UniquePtr<StyleUseCounters> counters; if (shouldRecordCounters) { counters.reset(Servo_UseCounters_Create()); } - RefPtr<StyleStylesheetContents> contents = Servo_StyleSheet_FromUTF8Bytes( - &aLoader, this, &aLoadData, &aBytes, mParsingMode, urlData, - aLoadData.mCompatMode, + &aLoader, this, aLoadData->get(), &aBytes, mParsingMode, urlData, + aLoadData->get()->mCompatMode, /* reusable_sheets = */ nullptr, counters.get(), allowImportRules, StyleSanitizationKind::None, /* sanitized_output = */ nullptr) .Consume(); FinishAsyncParse(contents.forget(), std::move(counters)); } else { - auto holder = MakeRefPtr<css::SheetLoadDataHolder>(__func__, &aLoadData); - Servo_StyleSheet_FromUTF8BytesAsync(holder, urlData, &aBytes, mParsingMode, - aLoadData.mCompatMode, - shouldRecordCounters, allowImportRules); + Servo_StyleSheet_FromUTF8BytesAsync( + aLoadData, urlData, &aBytes, mParsingMode, + aLoadData->get()->mCompatMode, shouldRecordCounters, allowImportRules); } return p; @@ -1224,7 +1219,7 @@ void StyleSheet::FinishAsyncParse( Inner().mContents = aSheetContents; Inner().mUseCounters = std::move(aUseCounters); FixUpRuleListAfterContentsChangeIfNeeded(); - mParsePromise.Resolve(true, __func__); + UnblockParsePromise(); } void StyleSheet::ParseSheetSync( diff --git a/layout/style/StyleSheet.h b/layout/style/StyleSheet.h index 1dbcad1e01..873ff2f4fc 100644 --- a/layout/style/StyleSheet.h +++ b/layout/style/StyleSheet.h @@ -7,6 +7,7 @@ #ifndef mozilla_StyleSheet_h #define mozilla_StyleSheet_h +#include "mozilla/Assertions.h" #include "mozilla/css/SheetParsingMode.h" #include "mozilla/dom/CSSStyleSheetBinding.h" #include "mozilla/dom/SRIMetadata.h" @@ -15,11 +16,13 @@ #include "mozilla/RefPtr.h" #include "mozilla/ServoBindingTypes.h" #include "mozilla/ServoTypes.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/StyleSheetInfo.h" #include "nsICSSLoaderObserver.h" #include "nsIPrincipal.h" #include "nsWrapperCache.h" #include "nsStringFwd.h" +#include "nsProxyRelease.h" class nsIGlobalObject; class nsINode; @@ -44,6 +47,7 @@ class Loader; class LoaderReusableStyleSheets; class Rule; class SheetLoadData; +using SheetLoadDataHolder = nsMainThreadPtrHolder<SheetLoadData>; } // namespace css namespace dom { @@ -112,9 +116,9 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache { // SheetLoadData for this stylesheet. // NOTE: ParseSheet can run synchronously or asynchronously // based on the result of `AllowParallelParse` - RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader&, - const nsACString& aBytes, - css::SheetLoadData&); + RefPtr<StyleSheetParsePromise> ParseSheet( + css::Loader&, const nsACString& aBytes, + const RefPtr<css::SheetLoadDataHolder>& aLoadData); // Common code that needs to be called after servo finishes parsing. This is // shared between the parallel and sequential paths. @@ -301,7 +305,7 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache { */ void SetPrincipal(nsIPrincipal* aPrincipal) { StyleSheetInfo& info = Inner(); - MOZ_ASSERT(!info.mPrincipalSet, "Should only set principal once"); + MOZ_ASSERT_IF(info.mPrincipalSet, info.mPrincipal == aPrincipal); if (aPrincipal) { info.mPrincipal = aPrincipal; #ifdef DEBUG @@ -468,6 +472,23 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache { // Gets the relevant global if exists. nsISupports* GetRelevantGlobal() const; + // Blocks/Unblocks resolution of parse promise + void BlockParsePromise() { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + uint32_t count = +#endif + ++mAsyncParseBlockers; + MOZ_DIAGNOSTIC_ASSERT(count); + } + + void UnblockParsePromise() { + uint32_t count = --mAsyncParseBlockers; + MOZ_DIAGNOSTIC_ASSERT(count != UINT32_MAX); + if (!count && !mParsePromise.IsEmpty()) { + mParsePromise.Resolve(true, __func__); + } + } + private: void SetModifiedRules() { mState |= State::ModifiedRules | State::ModifiedRulesForDevtools; @@ -591,6 +612,8 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache { State mState; + Atomic<uint32_t, ReleaseAcquire> mAsyncParseBlockers{0}; + // Core information we get from parsed sheets, which are shared amongst // StyleSheet clones. // diff --git a/layout/style/contenteditable.css b/layout/style/contenteditable.css index a2e2ca8712..7e9a197740 100644 --- a/layout/style/contenteditable.css +++ b/layout/style/contenteditable.css @@ -77,10 +77,6 @@ input[contenteditable="true"][type="hidden"] { visibility: visible !important; } -*|*::-moz-display-comboboxcontrol-frame { - user-select: text; -} - option:read-write { user-select: text; } diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list index 3e7d1e2669..d54f053f1b 100644 --- a/layout/style/crashtests/crashtests.list +++ b/layout/style/crashtests/crashtests.list @@ -16,11 +16,8 @@ load 391034-1.xhtml load 397022-1.html load 399289-1.svg load 404470-1.html -load 411603-1.html load 412588-1.html -load 413274-1.xhtml skip-if(Android) load chrome://reftest/content/crashtests/layout/style/crashtests/416461-1.xhtml -load 418007-1.xhtml load chrome://reftest/content/crashtests/layout/style/crashtests/431705-1.xhtml load 432561-1.html load 437170-1.html @@ -229,7 +226,6 @@ load 1384232.html load 1395725.html load 1396041.html pref(dom.animations-api.compositing.enabled,true) load 1397363-1.html -load 1397439-1.html load 1395719.html load 1397091.html load 1398479.html @@ -251,7 +247,6 @@ load 1402419.html load 1402472.html load 1403028.html load 1403433.html -load 1403465.html load 1403592.html load 1403615.html load 1403712.html diff --git a/layout/style/nsCSSAnonBoxList.h b/layout/style/nsCSSAnonBoxList.h index 891b34814b..4d62f5bd79 100644 --- a/layout/style/nsCSSAnonBoxList.h +++ b/layout/style/nsCSSAnonBoxList.h @@ -99,7 +99,6 @@ CSS_ANON_BOX(buttonContent, ":-moz-button-content") CSS_ANON_BOX(cellContent, ":-moz-cell-content") CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list") CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content") -CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame") CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content") CSS_WRAPPER_ANON_BOX(inlineTable, ":-moz-inline-table") diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 3b25ff9726..d40d4bc801 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -733,6 +733,16 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp, } } +float nsComputedDOMStyle::UsedFontSize() { + UpdateCurrentStyleSources(eCSSProperty_font_size); + + if (!mComputedStyle) { + return -1.0; + } + + return mComputedStyle->StyleFont()->mFont.size.ToCSSPixels(); +} + void nsComputedDOMStyle::GetCSSImageURLs(const nsACString& aPropertyName, nsTArray<nsCString>& aImageURLs, mozilla::ErrorResult& aRv) { @@ -990,6 +1000,19 @@ bool nsComputedDOMStyle::NeedsToFlushLayout(nsCSSPropertyID aPropID) const { } } +bool nsComputedDOMStyle::NeedsToFlushLayoutForContainerQuery() const { + const auto* outerFrame = GetOuterFrame(); + if (!outerFrame) { + return false; + } + const auto* innerFrame = nsLayoutUtils::GetStyleFrame(outerFrame); + MOZ_ASSERT(innerFrame, "No valid inner frame?"); + // It's possible that potential containers are styled but not yet reflowed, + // i.e. They don't have a correct size, which makes any container query + // evaluation against them invalid. + return innerFrame->HasUnreflowedContainerQueryAncestor(); +} + void nsComputedDOMStyle::Flush(Document& aDocument, FlushType aFlushType) { MOZ_ASSERT(mElement->IsInComposedDoc()); MOZ_ASSERT(mDocumentWeak == &aDocument); @@ -1051,8 +1074,9 @@ void nsComputedDOMStyle::UpdateCurrentStyleSources(nsCSSPropertyID aPropID) { Flush(*document, FlushType::Frames); } - if (NeedsToFlushLayout(aPropID)) { - MOZ_ASSERT(MayNeedToFlushLayout(aPropID)); + const bool needsToFlushLayoutForProp = NeedsToFlushLayout(aPropID); + if (needsToFlushLayoutForProp || NeedsToFlushLayoutForContainerQuery()) { + MOZ_ASSERT_IF(needsToFlushLayoutForProp, MayNeedToFlushLayout(aPropID)); didFlush = true; Flush(*document, FlushType::Layout); #ifdef DEBUG diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 4a6fec785d..4f135a3aca 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -120,6 +120,8 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, mExposeVisitedStyle = aExpose; } + float UsedFontSize() final; + void GetCSSImageURLs(const nsACString& aPropertyName, nsTArray<nsCString>& aImageURLs, mozilla::ErrorResult& aRv) final; @@ -312,6 +314,10 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, // Find out if we need to flush layout of the document, depending on the // property that was requested. bool NeedsToFlushLayout(nsCSSPropertyID) const; + // Find out if we need to flush layout of the document due to container + // query being made before relevant query containers are reflowed at least + // once. + bool NeedsToFlushLayoutForContainerQuery() const; // Flushes the given document, which must be our document, and potentially the // mElement's document. void Flush(Document&, mozilla::FlushType); diff --git a/layout/style/nsICSSDeclaration.h b/layout/style/nsICSSDeclaration.h index 1750fd75c3..53dcbed4ec 100644 --- a/layout/style/nsICSSDeclaration.h +++ b/layout/style/nsICSSDeclaration.h @@ -86,6 +86,11 @@ class nsICSSDeclaration : public nsISupports, public nsWrapperCache { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); } + // [Chrome only] + // Used font-size (taking account of the min-font-size prefs), if available; + // returns -1.0 on failure to retrieve a value. + virtual float UsedFontSize() { return -1.0; } + // WebIDL interface for CSSStyleDeclaration virtual void SetCssText(const nsACString& aString, nsIPrincipal* aSubjectPrincipal, diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index c99eecb486..f888c127d4 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -248,6 +248,9 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { #elif defined(XP_MACOSX) case StylePlatform::Macos: return true; +#elif defined(XP_IOS) + case StylePlatform::Ios: + return true; #else # error "Unknown platform?" #endif diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 123a1b3304..39f5b1a760 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2020,7 +2020,7 @@ StyleTransition::StyleTransition(const StyleTransition& aCopy) = default; bool StyleTransition::operator==(const StyleTransition& aOther) const { return mTimingFunction == aOther.mTimingFunction && mDuration == aOther.mDuration && mDelay == aOther.mDelay && - mProperty == aOther.mProperty; + mProperty == aOther.mProperty && mBehavior == aOther.mBehavior; } StyleAnimation::StyleAnimation(const StyleAnimation& aCopy) = default; @@ -3079,6 +3079,7 @@ nsStyleUIReset::nsStyleUIReset() mTransitionDurationCount(1), mTransitionDelayCount(1), mTransitionPropertyCount(1), + mTransitionBehaviorCount(1), mAnimations( nsStyleAutoArray<StyleAnimation>::WITH_SINGLE_INITIAL_ELEMENT), mAnimationTimingFunctionCount(1), @@ -3120,6 +3121,7 @@ nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource) mTransitionDurationCount(aSource.mTransitionDurationCount), mTransitionDelayCount(aSource.mTransitionDelayCount), mTransitionPropertyCount(aSource.mTransitionPropertyCount), + mTransitionBehaviorCount(aSource.mTransitionBehaviorCount), mAnimations(aSource.mAnimations.Clone()), mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount), mAnimationDurationCount(aSource.mAnimationDurationCount), @@ -3178,6 +3180,7 @@ nsChangeHint nsStyleUIReset::CalcDifference( mTransitionDurationCount != aNewData.mTransitionDurationCount || mTransitionDelayCount != aNewData.mTransitionDelayCount || mTransitionPropertyCount != aNewData.mTransitionPropertyCount || + mTransitionBehaviorCount != aNewData.mTransitionBehaviorCount || mAnimations != aNewData.mAnimations || mAnimationTimingFunctionCount != aNewData.mAnimationTimingFunctionCount || @@ -3461,12 +3464,6 @@ void StyleCalcNode::ScaleLengthsBy(float aScale) { } } -nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis, - CoordRounder aRounder) const { - CSSCoord result = ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis)); - return aRounder(result * AppUnitsPerCSSPixel()); -} - bool nsStyleDisplay::PrecludesSizeContainmentOrContentVisibilityWithFrame( const nsIFrame& aFrame) const { // The spec says that in the case of SVG, the contain property only applies diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index b2d68a5976..8835934eaf 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1120,6 +1120,7 @@ struct StyleTransition { const StyleTime& GetDelay() const { return mDelay; } const StyleTime& GetDuration() const { return mDuration; } const StyleTransitionProperty& GetProperty() const { return mProperty; } + StyleTransitionBehavior GetBehavior() const { return mBehavior; } bool operator==(const StyleTransition& aOther) const; bool operator!=(const StyleTransition& aOther) const { @@ -1133,6 +1134,7 @@ struct StyleTransition { StyleTime mDelay{0.0}; StyleTransitionProperty mProperty{StyleTransitionProperty::NonCustom( StyleNonCustomPropertyId{uint16_t(eCSSProperty_all)})}; + StyleTransitionBehavior mBehavior = StyleTransitionBehavior::Normal; }; struct StyleAnimation { @@ -1647,6 +1649,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset { return mTransitions[aIndex % mTransitionTimingFunctionCount] .GetTimingFunction(); } + mozilla::StyleTransitionBehavior GetTransitionBehavior( + uint32_t aIndex) const { + return mTransitions[aIndex % mTransitionBehaviorCount].GetBehavior(); + } mozilla::StyleTime GetTransitionCombinedDuration(uint32_t aIndex) const { // https://drafts.csswg.org/css-transitions/#transition-combined-duration return {std::max(GetTransitionDuration(aIndex).seconds, 0.0f) + @@ -1708,6 +1714,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset { uint32_t mTransitionDurationCount; uint32_t mTransitionDelayCount; uint32_t mTransitionPropertyCount; + uint32_t mTransitionBehaviorCount; nsStyleAutoArray<mozilla::StyleAnimation> mAnimations; // The number of elements in mAnimations that are not from repeating // a list due to another property being longer. diff --git a/layout/style/nsStyleTransformMatrix.cpp b/layout/style/nsStyleTransformMatrix.cpp index 593bcbb39d..71f8f826c2 100644 --- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -101,7 +101,8 @@ static nsRect GetSVGBox(const nsIFrame* aFrame) { // FIXME: Bug 1849054. We may have to update // SVGGeometryFrame::GetBBoxContribution() to get tighter stroke bounds. nsRect strokeBox = nsLayoutUtils::ComputeSVGReferenceRect( - const_cast<nsIFrame*>(aFrame), StyleGeometryBox::StrokeBox); + const_cast<nsIFrame*>(aFrame), StyleGeometryBox::StrokeBox, + nsLayoutUtils::MayHaveNonScalingStrokeCyclicDependency::Yes); // The |nsIFrame::mRect| includes markers, so we have to compute the // offsets without markers. return nsRect{strokeBox.x - aFrame->GetPosition().x, diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index ad3809c37f..66f1004354 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -116,6 +116,7 @@ bool nsTransitionManager::DoUpdateTransitions( continue; } + const auto behavior = aStyle.GetTransitionBehavior(i); ExpandTransitionProperty(aStyle.GetTransitionProperty(i), [&](const AnimatedPropertyID& aProperty) { // We might have something to transition. See if @@ -123,8 +124,9 @@ bool nsTransitionManager::DoUpdateTransitions( // are animatable. startedAny |= ConsiderInitiatingTransition( aProperty, aStyle, i, delay, duration, - aElement, aPseudoType, aElementTransitions, - aOldStyle, aNewStyle, propertiesChecked); + behavior, aElement, aPseudoType, + aElementTransitions, aOldStyle, aNewStyle, + propertiesChecked); }); } @@ -248,8 +250,8 @@ GetReplacedTransitionProperties(const CSSTransition* aTransition, bool nsTransitionManager::ConsiderInitiatingTransition( const AnimatedPropertyID& aProperty, const nsStyleUIReset& aStyle, uint32_t aTransitionIndex, float aDelay, float aDuration, - dom::Element* aElement, PseudoStyleType aPseudoType, - CSSTransitionCollection*& aElementTransitions, + mozilla::StyleTransitionBehavior aBehavior, dom::Element* aElement, + PseudoStyleType aPseudoType, CSSTransitionCollection*& aElementTransitions, const ComputedStyle& aOldStyle, const ComputedStyle& aNewStyle, AnimatedPropertyIDSet& aPropertiesChecked) { // IsShorthand itself will assert if aProperty is not a property. @@ -294,7 +296,7 @@ bool nsTransitionManager::ConsiderInitiatingTransition( AnimationValue startValue, endValue; const StyleShouldTransitionResult result = Servo_ComputedValues_ShouldTransition( - &aOldStyle, &aNewStyle, &property, + &aOldStyle, &aNewStyle, &property, aBehavior, oldTransition ? oldTransition->ToValue().mServo.get() : nullptr, &startValue.mServo, &endValue.mServo); diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index e87a0109a2..02a577690d 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -63,6 +63,7 @@ class nsTransitionManager final bool ConsiderInitiatingTransition( const mozilla::AnimatedPropertyID&, const nsStyleUIReset& aStyle, uint32_t aTransitionIndex, float aDelay, float aDuration, + mozilla::StyleTransitionBehavior aBehavior, mozilla::dom::Element* aElement, mozilla::PseudoStyleType aPseudoType, CSSTransitionCollection*& aElementTransitions, const mozilla::ComputedStyle& aOldStyle, diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index 9fb833aa74..a2d026639b 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -259,40 +259,27 @@ select:-moz-select-list-box { } select > button { - inline-size: 12px; - white-space: nowrap; - position: static; + padding: 0; + border: 0; appearance: auto; -moz-default-appearance: -moz-menulist-arrow-button; - /* Make sure to size correctly if the combobox has a non-auto height. */ - block-size: 100%; - box-sizing: border-box; - /* Draw the arrow in the select's color */ color: inherit; - /* - Make sure to align properly with the display frame. Note that we - want the baseline of the combobox to match the baseline of the - display frame, so the dropmarker is what gets the vertical-align. - */ + /* We don't want the button to grow the line-height */ + font: inherit; + max-block-size: 100%; + + /* Make sure to align properly with the display frame. Note that we want the + * baseline of the combobox to match the baseline of the label, so the + * dropmarker is what gets the vertical-align. */ vertical-align: top; } -*|*::-moz-display-comboboxcontrol-frame { - content: inherit; +select > label { + display: inline-block; overflow: clip; - color: unset; - white-space: nowrap; - text-align: unset; - user-select: none; - /* Make sure to size correctly if the combobox has a non-auto block-size. */ - block-size: 100%; - /* Try to always display our own text */ - min-inline-size: max-content; - box-sizing: border-box; - line-height: -moz-block-height; } option[label]::before { @@ -668,16 +655,15 @@ input[type=file] > label { * inherit into the ':-moz-button-content' pseudo-element. * * <select>: - * inherit into the ':-moz-display-comboboxcontrol-frame' pseudo-element and - * the <optgroup>'s ':before' pseudo-element, which is where the label of - * the <optgroup> gets displayed. The <option>s don't use anonymous boxes, - * so they need no special rules. + * inherit into the label and the <optgroup>'s ':before' pseudo-element, + * which is where the label of the <optgroup> gets displayed. The <option>s + * don't use anonymous boxes, so they need no special rules. */ ::placeholder, ::-moz-text-control-editing-root, *|*::-moz-button-content, -*|*::-moz-display-comboboxcontrol-frame, -optgroup:before { +select > label, +optgroup::before { unicode-bidi: inherit; text-overflow: inherit; } @@ -868,6 +854,13 @@ input[type=number]::-moz-number-spin-box { overflow: clip; } +/* stylelint-disable-next-line media-query-no-invalid */ +@media (-moz-bool-pref: "dom.forms.number.hide_spin_buttons_when_no_hover_or_focus") { + input[type=number]:not(:hover, :focus)::-moz-number-spin-box { + opacity: 0; + } +} + input[type=number]::-moz-number-spin-up, input[type=number]::-moz-number-spin-down { writing-mode: horizontal-tb; @@ -922,11 +915,7 @@ input:is([type=date], [type=time], [type=datetime-local]):is(:disabled, :read-on } input:autofill, select:autofill { - /* The idea behind using background-image instead of plain background-color - * is that it's less likely to be overridden by the page. */ - background-image: linear-gradient(-moz-autofill-background, -moz-autofill-background); -} - -input:-moz-autofill-preview, select:-moz-autofill-preview { - color: GrayText; + background-color: -moz-autofill-background !important; + background-image: none !important; + color: FieldText !important; } diff --git a/layout/style/res/html.css b/layout/style/res/html.css index 383aa35f7b..ff58ecd4d1 100644 --- a/layout/style/res/html.css +++ b/layout/style/res/html.css @@ -149,10 +149,8 @@ dd { blockquote, figure { display: block; - margin-block-start: 1em; - margin-block-end: 1em; - margin-inline-start: 40px; - margin-inline-end: 40px; + margin-block: 1em; + margin-inline: 40px; } address { @@ -169,68 +167,85 @@ h1 { display: block; font-size: 2em; font-weight: bold; - margin-block-start: .67em; - margin-block-end: .67em; + margin-block: .67em; } -h2, -:is(article, aside, nav, section) -h1 { +h2 { display: block; font-size: 1.5em; font-weight: bold; - margin-block-start: .83em; - margin-block-end: .83em; + margin-block: .83em; } -h3, -:is(article, aside, nav, section) -:is(article, aside, nav, section) -h1 { +h3 { display: block; font-size: 1.17em; font-weight: bold; - margin-block-start: 1em; - margin-block-end: 1em; + margin-block: 1em; } -h4, -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -h1 { +h4 { display: block; font-size: 1.00em; font-weight: bold; - margin-block-start: 1.33em; - margin-block-end: 1.33em; + margin-block: 1.33em; } -h5, -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -h1 { +h5 { display: block; font-size: 0.83em; font-weight: bold; - margin-block-start: 1.67em; - margin-block-end: 1.67em; + margin-block: 1.67em; } -h6, -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -:is(article, aside, nav, section) -h1 { +h6 { display: block; font-size: 0.67em; font-weight: bold; - margin-block-start: 2.33em; - margin-block-end: 2.33em; + margin-block: 2.33em; +} + +/* stylelint-disable-next-line media-query-no-invalid */ +@media (-moz-bool-pref: "layout.css.h1-in-section-ua-styles.enabled") { + :is(article, aside, nav, section) + h1 { + margin-block: 0.83em; + font-size: 1.50em; + } + + :is(article, aside, nav, section) + :is(article, aside, nav, section) + h1 { + margin-block: 1.00em; + font-size: 1.17em; + } + + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + h1 { + margin-block: 1.33em; + font-size: 1.00em; + } + + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + h1 { + margin-block: 1.67em; + font-size: 0.83em; + } + + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + :is(article, aside, nav, section) + h1 { + margin-block: 2.33em; + font-size: 0.67em; + } } listing { @@ -238,16 +253,14 @@ listing { font-family: -moz-fixed; font-size: medium; white-space: pre; - margin-block-start: 1em; - margin-block-end: 1em; + margin-block: 1em; } xmp, pre, plaintext { display: block; font-family: -moz-fixed; white-space: pre; - margin-block-start: 1em; - margin-block-end: 1em; + margin-block: 1em; } /* tables */ @@ -380,25 +393,19 @@ table[rules][rules="cols"] > tr > td, table[rules][rules="cols"] > * > tr > td, table[rules][rules="cols"] > tr > th, table[rules][rules="cols"] > * > tr > th { - border-inline-start-width: thin; - border-inline-end-width: thin; - border-inline-start-style: solid; - border-inline-end-style: solid; + border-inline-width: thin; + border-inline-style: solid; } table[rules][rules="groups"] > colgroup { - border-inline-start-width: thin; - border-inline-end-width: thin; - border-inline-start-style: solid; - border-inline-end-style: solid; + border-inline-width: thin; + border-inline-style: solid; } table[rules][rules="groups"] > tfoot, table[rules][rules="groups"] > thead, table[rules][rules="groups"] > tbody { - border-block-start-width: thin; - border-block-end-width: thin; - border-block-start-style: solid; - border-block-end-style: solid; + border-block-width: thin; + border-block-style: solid; } @@ -409,8 +416,7 @@ caption { } table[align="center"] > caption { - margin-inline-start: auto; - margin-inline-end: auto; + margin-inline: auto; } table[align="center"] > caption[align="left"]:dir(ltr) { @@ -589,8 +595,7 @@ li { :is(ul, ol, dir, menu, dl) dir, :is(ul, ol, dir, menu, dl) menu, :is(ul, ol, dir, menu, dl) dl { - margin-block-start: 0; - margin-block-end: 0; + margin-block: 0; } /* 2 deep unordered lists use a circle */ @@ -618,10 +623,8 @@ hr { color: gray; border-width: 1px; border-style: inset; - margin-block-start: 0.5em; - margin-block-end: 0.5em; - margin-inline-start: auto; - margin-inline-end: auto; + margin-block: 0.5em; + margin-inline: auto; overflow: hidden; /* FIXME: This is not really per spec */ diff --git a/layout/style/test/ParseCSS.cpp b/layout/style/test/ParseCSS.cpp index 04e37d48e2..e201d191a9 100644 --- a/layout/style/test/ParseCSS.cpp +++ b/layout/style/test/ParseCSS.cpp @@ -18,7 +18,6 @@ #include "nsIFile.h" #include "nsNetUtil.h" -#include "nsContentCID.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/css/Loader.h" diff --git a/layout/style/test/animation_utils.js b/layout/style/test/animation_utils.js index 6f7ededcd4..7239885e7c 100644 --- a/layout/style/test/animation_utils.js +++ b/layout/style/test/animation_utils.js @@ -4,6 +4,8 @@ // //---------------------------------------------------------------------- +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function advance_clock(milliseconds) { SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(milliseconds); } diff --git a/layout/style/test/chrome/bug418986-2.js b/layout/style/test/chrome/bug418986-2.js index 6d2af235c3..c945eecca0 100644 --- a/layout/style/test/chrome/bug418986-2.js +++ b/layout/style/test/chrome/bug418986-2.js @@ -1,5 +1,7 @@ // # Bug 418986, part 2. +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + const is_chrome_window = window.location.protocol === "chrome:"; const HTML_NS = "http://www.w3.org/1999/xhtml"; diff --git a/layout/style/test/mochitest.toml b/layout/style/test/mochitest.toml index 9df86ea539..54ad9736f2 100644 --- a/layout/style/test/mochitest.toml +++ b/layout/style/test/mochitest.toml @@ -18,6 +18,7 @@ prefs = [ "layout.css.basic-shape-rect.enabled=true", "layout.css.basic-shape-xywh.enabled=true", "layout.css.transform-box-content-stroke.enabled=true", + "layout.css.transition-behavior.enabled=true", ] support-files = [ "animation_utils.js", diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 422f2ffe5c..2e8b4c71a3 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -13604,36 +13604,32 @@ if (IsCSSPropertyPrefEnabled("layout.css.backdrop-filter.enabled")) { }; } -if (IsCSSPropertyPrefEnabled("layout.css.math-depth.enabled")) { - gCSSProperties["math-depth"] = { - domProp: "mathDepth", - inherited: true, - type: CSS_TYPE_LONGHAND, - initial_values: ["0"], - other_values: [ - // auto-add cannot be tested here because it has no effect when the - // inherited math-style is equal to the default (normal). - "123", - "-123", - "add(123)", - "add(-123)", - "calc(1 + 2*3)", - "add(calc(4 - 2/3))", - ], - invalid_values: ["auto", "1,23", "1.23", "add(1,23)", "add(1.23)"], - }; -} +gCSSProperties["math-depth"] = { + domProp: "mathDepth", + inherited: true, + type: CSS_TYPE_LONGHAND, + initial_values: ["0"], + other_values: [ + // auto-add cannot be tested here because it has no effect when the + // inherited math-style is equal to the default (normal). + "123", + "-123", + "add(123)", + "add(-123)", + "calc(1 + 2*3)", + "add(calc(4 - 2/3))", + ], + invalid_values: ["auto", "1,23", "1.23", "add(1,23)", "add(1.23)"], +}; -if (IsCSSPropertyPrefEnabled("layout.css.math-style.enabled")) { - gCSSProperties["math-style"] = { - domProp: "mathStyle", - inherited: true, - type: CSS_TYPE_LONGHAND, - initial_values: ["normal"], - other_values: ["compact"], - invalid_values: [], - }; -} +gCSSProperties["math-style"] = { + domProp: "mathStyle", + inherited: true, + type: CSS_TYPE_LONGHAND, + initial_values: ["normal"], + other_values: ["compact"], + invalid_values: [], +}; if (IsCSSPropertyPrefEnabled("layout.css.forced-color-adjust.enabled")) { gCSSProperties["forced-color-adjust"] = { @@ -14088,6 +14084,36 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.transitions")) { }); } +if (IsCSSPropertyPrefEnabled("layout.css.transition-behavior.enabled")) { + Object.assign(gCSSProperties, { + "transition-behavior": { + domProp: "transitionBehavior", + inherited: false, + type: CSS_TYPE_LONGHAND, + applies_to_marker: true, + initial_values: ["normal"], + other_values: ["allow-discrete"], + invalid_values: ["none", "auto", "discrete"], + }, + }); + + gCSSProperties["transition"].subproperties.push("transition-behavior"); + gCSSProperties["transition"].initial_values.push("normal"); + gCSSProperties["transition"].other_values.push( + "allow-discrete", + "width allow-discrete", + "1s allow-discrete", + "linear allow-discrete" + ); + gCSSProperties["-webkit-transition"].subproperties.push( + "transition-behavior" + ); + + if (IsCSSPropertyPrefEnabled("layout.css.prefixes.transitions")) { + gCSSProperties["-moz-transition"].subproperties.push("transition-behavior"); + } +} + // Copy aliased properties' fields from their alias targets. Keep this logic // at the bottom of this file to ensure all the aliased properties are // processed. diff --git a/layout/style/test/test_shorthand_property_getters.html b/layout/style/test/test_shorthand_property_getters.html index cade526183..b5db9519a6 100644 --- a/layout/style/test/test_shorthand_property_getters.html +++ b/layout/style/test/test_shorthand_property_getters.html @@ -183,17 +183,19 @@ e.setAttribute("style", "background-position-x: 0px; background-position-y: top is(e.style.backgroundPosition, "left 0px top 0px", "should serialize to 4-value form if 3-value form would only have one edge"); // Check that we only serialize transition when the lists are the same length. -e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s"); +e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete;"); isnot(e.style.transition, "", "should have transition shorthand (lists same length)"); -e.setAttribute("style", "transition-property: color, width, left; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s"); +e.setAttribute("style", "transition-property: color, width, left; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete;"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); -e.setAttribute("style", "transition-property: all; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s"); +e.setAttribute("style", "transition-property: all; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete;"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); -e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms, 300ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s"); +e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms, 300ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete;"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); -e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear, ease-out; transition-delay: 0s, 1s"); +e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear, ease-out; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete;"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); -e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s, 0s"); +e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s, 0s; transition-behavior: normal, allow-discrete;"); +is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); +e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s; transition-behavior: normal, allow-discrete, normal;"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); e.setAttribute("style", "transition: color, width; transition-delay: 0s"); is(e.style.transition, "", "should not have transition shorthand (lists different lengths)"); diff --git a/layout/style/crashtests/1397439-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1397439-1.html index b617f8e0ed..b617f8e0ed 100644 --- a/layout/style/crashtests/1397439-1.html +++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1397439-1.html diff --git a/layout/style/crashtests/1403465.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1403465.html index 924392757b..924392757b 100644 --- a/layout/style/crashtests/1403465.html +++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1403465.html diff --git a/layout/style/crashtests/411603-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/411603-1.html index 596565fbc3..596565fbc3 100644 --- a/layout/style/crashtests/411603-1.html +++ b/testing/web-platform/tests/mathml/crashtests/mozilla/411603-1.html diff --git a/layout/style/crashtests/413274-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/413274-1.xhtml index 19d8fab0fd..19d8fab0fd 100644 --- a/layout/style/crashtests/413274-1.xhtml +++ b/testing/web-platform/tests/mathml/crashtests/mozilla/413274-1.xhtml diff --git a/layout/style/crashtests/418007-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/418007-1.xhtml index f07a693444..f07a693444 100644 --- a/layout/style/crashtests/418007-1.xhtml +++ b/testing/web-platform/tests/mathml/crashtests/mozilla/418007-1.xhtml |