diff options
Diffstat (limited to 'layout/base')
-rw-r--r-- | layout/base/nsCSSFrameConstructor.cpp | 16 | ||||
-rw-r--r-- | layout/base/nsCSSRendering.cpp | 215 | ||||
-rw-r--r-- | layout/base/nsDisplayList.cpp | 121 | ||||
-rw-r--r-- | layout/base/nsDisplayList.h | 47 | ||||
-rw-r--r-- | layout/base/nsLayoutUtils.cpp | 130 | ||||
-rw-r--r-- | layout/base/nsLayoutUtils.h | 5 | ||||
-rw-r--r-- | layout/base/nsPresShell.cpp | 4 | ||||
-rw-r--r-- | layout/base/nsRefreshDriver.cpp | 38 |
8 files changed, 329 insertions, 247 deletions
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index c63374541..07a5b80e7 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -7021,8 +7021,11 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, nsIContent* aContainer, nsIContent* aChild) { + // XXXmats no lazy frames for display:contents direct descendants yet + // (Mozilla bug 979782). if (mPresShell->GetPresContext()->IsChrome() || !aContainer || - aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement()) { + aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement() || + GetDisplayContentsStyleFor(aContainer)) { return false; } @@ -7056,6 +7059,10 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, // ignore anonymous children (eg framesets) make this complicated. So we set // these two booleans if we encounter these situations and unset them if we // hit a node with a leaf frame. + // + // Also, it's fine if one of the nodes without primary frame is a display: + // contents node except if it's the direct ancestor of the children we're + // recreating frames for. bool noPrimaryFrame = false; bool needsFrameBitSet = false; #endif @@ -7065,17 +7072,14 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) { noPrimaryFrame = needsFrameBitSet = false; } - if (!noPrimaryFrame && !content->GetPrimaryFrame()) { + if (!noPrimaryFrame && !content->GetPrimaryFrame() && + !GetDisplayContentsStyleFor(content)) { noPrimaryFrame = true; } if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) { needsFrameBitSet = true; } #endif - // XXXmats no lazy frames for display:contents descendants yet (bug 979782). - if (GetDisplayContentsStyleFor(content)) { - return false; - } content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES); content = content->GetFlattenedTreeParent(); } diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 71ebfad22..ff9edf742 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -1803,6 +1803,44 @@ SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect, "second should be empty if first is"); } +static bool +IsSVGStyleGeometryBox(StyleGeometryBox aBox) +{ + return (aBox == StyleGeometryBox::Fill || aBox == StyleGeometryBox::Stroke || + aBox == StyleGeometryBox::View); +} + +static bool +IsHTMLStyleGeometryBox(StyleGeometryBox aBox) +{ + return (aBox == StyleGeometryBox::Content || + aBox == StyleGeometryBox::Padding || + aBox == StyleGeometryBox::Border || + aBox == StyleGeometryBox::Margin); +} + +static StyleGeometryBox +ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox) +{ + // Except <svg>, all svg elements are not associate with CSS layout box. + if (aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)) { + // For SVG elements without associated CSS layout box, the values + // content-box, padding-box, border-box and margin-box compute to fill-box. + if (IsHTMLStyleGeometryBox(aBox)) { + return StyleGeometryBox::Fill; + } + } else { + // For elements with associated CSS layout box, the values fill-box, + // stroke-box and view-box compute to the initial value of mask-clip. + if (IsSVGStyleGeometryBox(aBox)) { + return StyleGeometryBox::Border; + } + } + + return aBox; +} + /* static */ void nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, nsIFrame* aForFrame, const nsStyleBorder& aBorder, @@ -1810,6 +1848,55 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, bool aWillPaintBorder, nscoord aAppUnitsPerPixel, /* out */ ImageLayerClipState* aClipState) { + StyleGeometryBox layerClip = ComputeBoxValue(aForFrame, aLayer.mClip); + + if (IsSVGStyleGeometryBox(layerClip)) { + MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)); + + aClipState->mHasAdditionalBGClipArea = false; + aClipState->mCustomClip = false; + + // The coordinate space of clipArea is svg user space. + nsRect clipArea = + nsLayoutUtils::ComputeGeometryBox(aForFrame, layerClip); + + nsRect strokeBox = (layerClip == StyleGeometryBox::Stroke) + ? clipArea + : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::Stroke); + nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft(); + + // aBorderArea is the stroke-box area in a coordinate space defined by + // the caller. This coordinate space can be svg user space of aForFrame, + // the space of aForFrame's reference-frame, or anything else. + // + // Which coordinate space chosen for aBorderArea is not matter. What + // matter is to ensure returning aClipState->mBGClipArea in the consistent + // coordiante space with aBorderArea. So we evaluate the position of clip + // area base on the position of aBorderArea here. + aClipState->mBGClipArea = + clipAreaRelativeToStrokeBox + aBorderArea.TopLeft(); + + SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, + aAppUnitsPerPixel, &aClipState->mDirtyRect, + &aClipState->mDirtyRectGfx); + return; + } + + if (layerClip == StyleGeometryBox::NoClip) { + aClipState->mBGClipArea = aCallerDirtyRect; + aClipState->mHasAdditionalBGClipArea = false; + aClipState->mCustomClip = false; + + SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, + aAppUnitsPerPixel, &aClipState->mDirtyRect, + &aClipState->mDirtyRectGfx); + return; + } + + MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) || + aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame); + // Compute the outermost boundary of the area that might be painted. // Same coordinate space as aBorderArea. Sides skipSides = aForFrame->GetSkipSides(); @@ -1819,16 +1906,15 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, aClipState->mRadii); - uint8_t backgroundClip = aLayer.mClip; - bool isSolidBorder = aWillPaintBorder && IsOpaqueBorder(aBorder); - if (isSolidBorder && backgroundClip == NS_STYLE_IMAGELAYER_CLIP_BORDER) { + if (isSolidBorder && layerClip == StyleGeometryBox::Border) { // If we have rounded corners, we need to inflate the background // drawing area a bit to avoid seams between the border and // background. - backgroundClip = haveRoundedCorners ? - NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_IMAGELAYER_CLIP_PADDING; + layerClip = haveRoundedCorners + ? StyleGeometryBox::MozAlmostPadding + : StyleGeometryBox::Padding; } aClipState->mBGClipArea = clipBorderArea; @@ -1844,7 +1930,7 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, // but the background is also clipped at a non-scrolling 'padding-box' // like the content. (See below.) // Therefore, only 'content-box' makes a difference here. - if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) { + if (layerClip == StyleGeometryBox::Content) { nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame); // Clip at a rectangle attached to the scrolled content. aClipState->mHasAdditionalBGClipArea = true; @@ -1864,22 +1950,30 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, // Also clip at a non-scrolling, rounded-corner 'padding-box', // same as the scrolled content because of the 'overflow' property. - backgroundClip = NS_STYLE_IMAGELAYER_CLIP_PADDING; + layerClip = StyleGeometryBox::Padding; } - if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_BORDER && - backgroundClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) { + // See the comment of StyleGeometryBox::Margin. + // Hitting this assertion means we decide to turn on margin-box support for + // positioned mask from CSS parser and style system. In this case, you + // should *inflate* mBGClipArea by the margin returning from + // aForFrame->GetUsedMargin() in the code chunk bellow. + MOZ_ASSERT(layerClip != StyleGeometryBox::Margin, + "StyleGeometryBox::Margin rendering is not supported yet.\n"); + + if (layerClip != StyleGeometryBox::Border && + layerClip != StyleGeometryBox::Text) { nsMargin border = aForFrame->GetUsedBorder(); - if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING) { + if (layerClip == StyleGeometryBox::MozAlmostPadding) { // Reduce |border| by 1px (device pixels) on all sides, if // possible, so that we don't get antialiasing seams between the - // background and border. + // {background|mask} and border. border.top = std::max(0, border.top - aAppUnitsPerPixel); border.right = std::max(0, border.right - aAppUnitsPerPixel); border.bottom = std::max(0, border.bottom - aAppUnitsPerPixel); border.left = std::max(0, border.left - aAppUnitsPerPixel); - } else if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_PADDING) { - NS_ASSERTION(backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT, + } else if (layerClip != StyleGeometryBox::Padding) { + NS_ASSERTION(layerClip == StyleGeometryBox::Content, "unexpected background-clip"); border += aForFrame->GetUsedPadding(); } @@ -3163,7 +3257,7 @@ nsCSSRendering::PaintBackgroundWithSC(const PaintBGParams& aParams, if (drawBackgroundImage) { bool clipSet = false; - uint8_t currentBackgroundClip = NS_STYLE_IMAGELAYER_CLIP_BORDER; + StyleGeometryBox currentBackgroundClip = StyleGeometryBox::Border; NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers, layers.mImageCount - 1, nLayers + (layers.mImageCount - startLayer - 1)) { @@ -3239,16 +3333,43 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, nsIFrame** aAttachedToFrame, bool* aOutIsTransformedFixed) { - // Compute background origin area relative to aBorderArea now as we may need - // it to compute the effective image size for a CSS gradient. - nsRect bgPositioningArea; + // Compute {background|mask} origin area relative to aBorderArea now as we + // may need it to compute the effective image size for a CSS gradient. + nsRect positionArea; + + StyleGeometryBox layerOrigin = + ComputeBoxValue(aForFrame, aLayer.mOrigin); + + if (IsSVGStyleGeometryBox(layerOrigin)) { + MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)); + *aAttachedToFrame = aForFrame; + + positionArea = + nsLayoutUtils::ComputeGeometryBox(aForFrame, layerOrigin); + + nsPoint toStrokeBoxOffset = nsPoint(0, 0); + if (layerOrigin != StyleGeometryBox::Stroke) { + nsRect strokeBox = + nsLayoutUtils::ComputeGeometryBox(aForFrame, + StyleGeometryBox::Stroke); + toStrokeBoxOffset = positionArea.TopLeft() - strokeBox.TopLeft(); + } + + // For SVG frames, the return value is relative to the stroke box + return nsRect(toStrokeBoxOffset, positionArea.Size()); + } + + MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) || + aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame); + nsIAtom* frameType = aForFrame->GetType(); nsIFrame* geometryFrame = aForFrame; if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame && NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) { nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame); - bgPositioningArea = nsRect( + positionArea = nsRect( scrollableFrame->GetScrolledFrame()->GetPosition() // For the dir=rtl case: + scrollableFrame->GetScrollRange().TopLeft(), @@ -3256,20 +3377,20 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, // The ScrolledRect’s size does not include the borders or scrollbars, // reverse the handling of background-origin // compared to the common case below. - if (aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_BORDER) { + if (layerOrigin == StyleGeometryBox::Border) { nsMargin border = geometryFrame->GetUsedBorder(); border.ApplySkipSides(geometryFrame->GetSkipSides()); - bgPositioningArea.Inflate(border); - bgPositioningArea.Inflate(scrollableFrame->GetActualScrollbarSizes()); - } else if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) { + positionArea.Inflate(border); + positionArea.Inflate(scrollableFrame->GetActualScrollbarSizes()); + } else if (layerOrigin != StyleGeometryBox::Padding) { nsMargin padding = geometryFrame->GetUsedPadding(); padding.ApplySkipSides(geometryFrame->GetSkipSides()); - bgPositioningArea.Deflate(padding); - NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT, + positionArea.Deflate(padding); + NS_ASSERTION(layerOrigin == StyleGeometryBox::Content, "unknown background-origin value"); } *aAttachedToFrame = aForFrame; - return bgPositioningArea; + return positionArea; } if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) { @@ -3279,25 +3400,31 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, // finished and this page only displays the continuations of // absolutely positioned content). if (geometryFrame) { - bgPositioningArea = geometryFrame->GetRect(); + positionArea = geometryFrame->GetRect(); } } else { - bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size()); + positionArea = nsRect(nsPoint(0,0), aBorderArea.Size()); } - // Background images are tiled over the 'background-clip' area - // but the origin of the tiling is based on the 'background-origin' area - // XXX: Bug 1303623 will bring in new origin value, we should iterate from - // NS_STYLE_IMAGELAYER_ORIGIN_MARGIN instead of - // NS_STYLE_IMAGELAYER_ORIGIN_BORDER. - if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_BORDER && geometryFrame) { + // See the comment of StyleGeometryBox::Margin. + // Hitting this assertion means we decide to turn on margin-box support for + // positioned mask from CSS parser and style system. In this case, you + // should *inflate* positionArea by the margin returning from + // geometryFrame->GetUsedMargin() in the code chunk bellow. + MOZ_ASSERT(aLayer.mOrigin != StyleGeometryBox::Margin, + "StyleGeometryBox::Margin rendering is not supported yet.\n"); + + // {background|mask} images are tiled over the '{background|mask}-clip' area + // but the origin of the tiling is based on the '{background|mask}-origin' + // area. + if (layerOrigin != StyleGeometryBox::Border && geometryFrame) { nsMargin border = geometryFrame->GetUsedBorder(); - if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) { + if (layerOrigin != StyleGeometryBox::Padding) { border += geometryFrame->GetUsedPadding(); - NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT, + NS_ASSERTION(layerOrigin == StyleGeometryBox::Content, "unknown background-origin value"); } - bgPositioningArea.Deflate(border); + positionArea.Deflate(border); } nsIFrame* attachedToFrame = aForFrame; @@ -3325,7 +3452,7 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, } else { // Set the background positioning area to the viewport's area // (relative to aForFrame) - bgPositioningArea = + positionArea = nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize()); if (!pageContentFrame) { @@ -3334,14 +3461,14 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, aPresContext->PresShell()->GetRootScrollFrameAsScrollable(); if (scrollableFrame) { nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes(); - bgPositioningArea.Deflate(scrollbars); + positionArea.Deflate(scrollbars); } } } } *aAttachedToFrame = attachedToFrame; - return bgPositioningArea; + return positionArea; } // Implementation of the formula for computation of background-repeat round @@ -3569,7 +3696,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, bool transformedFixed = false; // Compute background origin area relative to aBorderArea now as we may need // it to compute the effective image size for a CSS gradient. - nsRect bgPositioningArea = + nsRect positionArea = ComputeImageLayerPositioningArea(aPresContext, aForFrame, aBorderArea, aLayer, &attachedToFrame, &transformedFixed); if (aOutIsTransformedFixed) { @@ -3594,7 +3721,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, // not a pure optimization since it can affect the values of pixels at the // edge of the viewport --- whether they're sampled from a putative "next // tile" or not.) - bgClipRect.IntersectRect(bgClipRect, bgPositioningArea + aBorderArea.TopLeft()); + bgClipRect.IntersectRect(bgClipRect, positionArea + aBorderArea.TopLeft()); } } @@ -3605,7 +3732,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, // Also as required for proper background positioning when background-position // is defined with percentages. CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize(); - nsSize bgPositionSize = bgPositioningArea.Size(); + nsSize bgPositionSize = positionArea.Size(); nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize, bgPositionSize, aLayer.mSize, @@ -3650,8 +3777,8 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, } } - imageTopLeft += bgPositioningArea.TopLeft(); - state.mAnchor += bgPositioningArea.TopLeft(); + imageTopLeft += positionArea.TopLeft(); + state.mAnchor += positionArea.TopLeft(); state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize); state.mFillArea = state.mDestArea; diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 2bf20144a..d619576ba 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -61,7 +61,6 @@ #include "mozilla/OperatorNewExtensions.h" #include "mozilla/PendingAnimationTracker.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" #include "mozilla/gfx/gfxVars.h" @@ -1857,7 +1856,6 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB RefPtr<ContainerLayer> root; { - PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization); root = layerBuilder-> BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this, containerParameters, nullptr); @@ -3016,7 +3014,7 @@ nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder, /* static */ nsRegion nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem, - uint8_t aClip, + StyleGeometryBox aClip, const nsRect& aRect, const nsRect& aBackgroundRect) { @@ -3030,10 +3028,10 @@ nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem, if (frame->GetType() == nsGkAtoms::canvasFrame) { nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame); clipRect = canvasFrame->CanvasArea() + aItem->ToReferenceFrame(); - } else if (aClip == NS_STYLE_IMAGELAYER_CLIP_PADDING || - aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) { + } else if (aClip == StyleGeometryBox::Padding || + aClip == StyleGeometryBox::Content) { nsMargin border = frame->GetUsedBorder(); - if (aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) { + if (aClip == StyleGeometryBox::Content) { border += frame->GetUsedPadding(); } border.ApplySkipSides(frame->GetSkipSides()); @@ -3066,7 +3064,7 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL && layer.mRepeat.mXRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE && layer.mRepeat.mYRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE && - layer.mClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) { + layer.mClip != StyleGeometryBox::Text) { result = GetInsideClipRegion(this, layer.mClip, mBounds, mBackgroundRect); } } @@ -3145,9 +3143,9 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder, CheckForBorderItem(this, flags); gfxContext* ctx = aCtx->ThebesContext(); - uint8_t clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip; + StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip; - if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) { + if (clip == StyleGeometryBox::Text) { if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) { return; } @@ -3163,7 +3161,7 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder, image::DrawResult result = nsCSSRendering::PaintBackground(params); - if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) { + if (clip == StyleGeometryBox::Text) { ctx->PopGroupAndBlend(); } @@ -3585,8 +3583,8 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, nsLayoutUtils::RectToGfxRect(mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel()); - uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip; - if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) { + StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[0].mClip; + if (clip == StyleGeometryBox::Text) { if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) { return; } @@ -3620,7 +3618,7 @@ nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, const nsStyleImageLayers::Layer& bottomLayer = mBackgroundStyle->BottomLayer(); - if (bottomLayer.mClip == NS_STYLE_IMAGELAYER_CLIP_TEXT) { + if (bottomLayer.mClip == StyleGeometryBox::Text) { return nsRegion(); } @@ -7453,100 +7451,3 @@ nsDisplayFilter::PrintEffects(nsACString& aTo) aTo += ")"; } #endif - -namespace mozilla { - -uint32_t PaintTelemetry::sPaintLevel = 0; -uint32_t PaintTelemetry::sMetricLevel = 0; -EnumeratedArray<PaintTelemetry::Metric, - PaintTelemetry::Metric::COUNT, - double> PaintTelemetry::sMetrics; - -PaintTelemetry::AutoRecordPaint::AutoRecordPaint() -{ - // Don't record nested paints. - if (sPaintLevel++ > 0) { - return; - } - - // Reset metrics for a new paint. - for (auto& metric : sMetrics) { - metric = 0.0; - } - mStart = TimeStamp::Now(); -} - -PaintTelemetry::AutoRecordPaint::~AutoRecordPaint() -{ - MOZ_ASSERT(sPaintLevel != 0); - if (--sPaintLevel > 0) { - return; - } - - // If we're in multi-process mode, don't include paint times for the parent - // process. - if (gfxVars::BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) { - return; - } - - double totalMs = (TimeStamp::Now() - mStart).ToMilliseconds(); - - // If the total time was >= 16ms, then it's likely we missed a frame due to - // painting. In this case we'll gather some detailed metrics below. - if (totalMs <= 16.0) { - return; - } - - auto record = [=](const char* aKey, double aDurationMs) -> void { - MOZ_ASSERT(aDurationMs <= totalMs); - - uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0); - }; - - double dlMs = sMetrics[Metric::DisplayList]; - double flbMs = sMetrics[Metric::Layerization]; - double rMs = sMetrics[Metric::Rasterization]; - - // Record all permutations since aggregation makes it difficult to - // correlate. For example we can't derive "flb+r" from "dl" because we - // don't know the total time associated with a bucket entry. So we just - // play it safe and include everything. We can however derive "other" time - // from the final permutation. - record("dl", dlMs); - record("flb", flbMs); - record("r", rMs); - record("dl,flb", dlMs + flbMs); - record("dl,r", dlMs + rMs); - record("flb,r", flbMs + rMs); - record("dl,flb,r", dlMs + flbMs + rMs); -} - -PaintTelemetry::AutoRecord::AutoRecord(Metric aMetric) - : mMetric(aMetric) -{ - // Don't double-record anything nested. - if (sMetricLevel++ > 0) { - return; - } - - // Don't record inside nested paints, or outside of paints. - if (sPaintLevel != 1) { - return; - } - - mStart = TimeStamp::Now(); -} - -PaintTelemetry::AutoRecord::~AutoRecord() -{ - MOZ_ASSERT(sMetricLevel != 0); - - sMetricLevel--; - if (mStart.IsNull()) { - return; - } - - sMetrics[mMetric] += (TimeStamp::Now() - mStart).ToMilliseconds(); -} - -} // namespace mozilla diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index df584b489..c9f773f5b 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2713,6 +2713,8 @@ private: */ class nsDisplayBackgroundImage : public nsDisplayImageContainer { public: + typedef mozilla::StyleGeometryBox StyleGeometryBox; + /** * aLayer signifies which background layer this item represents. * aIsThemed should be the value of aFrame->IsThemed. @@ -2790,8 +2792,10 @@ public: virtual already_AddRefed<imgIContainer> GetImage() override; virtual nsRect GetDestRect() override; - static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, uint8_t aClip, - const nsRect& aRect, const nsRect& aBackgroundRect); + static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, + StyleGeometryBox aClip, + const nsRect& aRect, + const nsRect& aBackgroundRect); virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) override; @@ -4508,43 +4512,4 @@ public: mutable mozilla::Maybe<bool> mIsFrameSelected; }; -namespace mozilla { - -class PaintTelemetry -{ - public: - enum class Metric { - DisplayList, - Layerization, - Rasterization, - COUNT, - }; - - class AutoRecord - { - public: - explicit AutoRecord(Metric aMetric); - ~AutoRecord(); - private: - Metric mMetric; - mozilla::TimeStamp mStart; - }; - - class AutoRecordPaint - { - public: - AutoRecordPaint(); - ~AutoRecordPaint(); - private: - mozilla::TimeStamp mStart; - }; - - private: - static uint32_t sPaintLevel; - static uint32_t sMetricLevel; - static mozilla::EnumeratedArray<Metric, Metric::COUNT, double> sMetrics; -}; - -} // namespace mozilla - #endif /*NSDISPLAYLIST_H_*/ diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index c1f4ad372..f0341f9ef 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -111,13 +111,13 @@ #include "FrameLayerBuilder.h" #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/CompositorBridgeChild.h" -#include "mozilla/Telemetry.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventStateManager.h" #include "mozilla/RuleNodeCacheConditions.h" #include "mozilla/StyleSetHandle.h" #include "mozilla/StyleSetHandleInlines.h" #include "RegionBuilder.h" +#include "SVGSVGElement.h" #ifdef MOZ_XUL #include "nsXULPopupManager.h" @@ -3534,8 +3534,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList", js::ProfileEntry::Category::GRAPHICS); - - PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList); aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list); } @@ -6938,7 +6936,7 @@ nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame, const nsStyleBackground* bg = bgSC->StyleBackground(); if (NS_GET_A(bg->mBackgroundColor) < 255 || // bottom layer's clip is used for the color - bg->BottomLayer().mClip != NS_STYLE_IMAGELAYER_CLIP_BORDER) + bg->BottomLayer().mClip != StyleGeometryBox::Border) return eTransparencyTransparent; return eTransparencyOpaque; } @@ -9296,3 +9294,127 @@ nsLayoutUtils::IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame) return lineNonEmpty; } + +static nsRect +ComputeSVGReferenceRect(nsIFrame* aFrame, + StyleGeometryBox aGeometryBox) +{ + MOZ_ASSERT(aFrame->GetContent()->IsSVGElement()); + nsRect r; + + // For SVG elements without associated CSS layout box, the used value for + // content-box, padding-box, border-box and margin-box is fill-box. + switch (aGeometryBox) { + case StyleGeometryBox::Stroke: { + // XXX Bug 1299876 + // The size of srtoke-box is not correct if this graphic element has + // specific stroke-linejoin or stroke-linecap. + gfxRect bbox = nsSVGUtils::GetBBox(aFrame, + nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke); + r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, + nsPresContext::AppUnitsPerCSSPixel()); + break; + } + case StyleGeometryBox::View: { + nsIContent* content = aFrame->GetContent(); + nsSVGElement* element = static_cast<nsSVGElement*>(content); + SVGSVGElement* svgElement = element->GetCtx(); + MOZ_ASSERT(svgElement); + + if (svgElement && svgElement->HasViewBoxRect()) { + // If a ‘viewBox‘ attribute is specified for the SVG viewport creating + // element: + // 1. The reference box is positioned at the origin of the coordinate + // system established by the ‘viewBox‘ attribute. + // 2. The dimension of the reference box is set to the width and height + // values of the ‘viewBox‘ attribute. + nsSVGViewBox* viewBox = svgElement->GetViewBox(); + const nsSVGViewBoxRect& value = viewBox->GetAnimValue(); + r = nsRect(nsPresContext::CSSPixelsToAppUnits(value.x), + nsPresContext::CSSPixelsToAppUnits(value.y), + nsPresContext::CSSPixelsToAppUnits(value.width), + nsPresContext::CSSPixelsToAppUnits(value.height)); + } else { + // No viewBox is specified, uses the nearest SVG viewport as reference + // box. + svgFloatSize viewportSize = svgElement->GetViewportSize(); + r = nsRect(0, 0, + nsPresContext::CSSPixelsToAppUnits(viewportSize.width), + nsPresContext::CSSPixelsToAppUnits(viewportSize.height)); + } + + break; + } + case StyleGeometryBox::NoBox: + case StyleGeometryBox::Border: + case StyleGeometryBox::Content: + case StyleGeometryBox::Padding: + case StyleGeometryBox::Margin: + case StyleGeometryBox::Fill: { + gfxRect bbox = nsSVGUtils::GetBBox(aFrame, + nsSVGUtils::eBBoxIncludeFill); + r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, + nsPresContext::AppUnitsPerCSSPixel()); + break; + } + default:{ + MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type"); + gfxRect bbox = nsSVGUtils::GetBBox(aFrame, + nsSVGUtils::eBBoxIncludeFill); + r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, + nsPresContext::AppUnitsPerCSSPixel()); + break; + } + } + + return r; +} + +static nsRect +ComputeHTMLReferenceRect(nsIFrame* aFrame, + StyleGeometryBox aGeometryBox) +{ + nsRect r; + + // For elements with associated CSS layout box, the used value for fill-box, + // stroke-box and view-box is border-box. + switch (aGeometryBox) { + case StyleGeometryBox::Content: + r = aFrame->GetContentRectRelativeToSelf(); + break; + case StyleGeometryBox::Padding: + r = aFrame->GetPaddingRectRelativeToSelf(); + break; + case StyleGeometryBox::Margin: + r = aFrame->GetMarginRectRelativeToSelf(); + break; + case StyleGeometryBox::NoBox: + case StyleGeometryBox::Border: + case StyleGeometryBox::Fill: + case StyleGeometryBox::Stroke: + case StyleGeometryBox::View: + r = aFrame->GetRectRelativeToSelf(); + break; + default: + MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type"); + r = aFrame->GetRectRelativeToSelf(); + break; + } + + return r; +} + +/* static */ nsRect +nsLayoutUtils::ComputeGeometryBox(nsIFrame* aFrame, + StyleGeometryBox aGeometryBox) +{ + // We use ComputeSVGReferenceRect for all SVG elements, except <svg> + // element, which does have an associated CSS layout box. In this case we + // should still use ComputeHTMLReferenceRect for region computing. + nsRect r = aFrame->IsFrameOfType(nsIFrame::eSVG) && + (aFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) + ? ComputeSVGReferenceRect(aFrame, aGeometryBox) + : ComputeHTMLReferenceRect(aFrame, aGeometryBox); + + return r; +} diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 97fc410b0..63253fd10 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -30,6 +30,7 @@ #include "mozilla/ReflowOutput.h" #include "ImageContainer.h" #include "gfx2DGlue.h" +#include "nsStyleConsts.h" #include <limits> #include <algorithm> @@ -152,6 +153,7 @@ public: typedef mozilla::CSSRect CSSRect; typedef mozilla::ScreenMargin ScreenMargin; typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; + typedef mozilla::StyleGeometryBox StyleGeometryBox; /** * Finds previously assigned ViewID for the given content element, if any. @@ -2870,6 +2872,9 @@ public: */ static bool IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame = nullptr); + static nsRect ComputeGeometryBox(nsIFrame* aFrame, + StyleGeometryBox aGeometryBox); + private: static uint32_t sFontSizeInflationEmPerLine; static uint32_t sFontSizeInflationMinTwips; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 340042b46..969ebc962 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -170,7 +170,6 @@ #include "mozilla/css/ImageLoader.h" #include "mozilla/dom/DocumentTimeline.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "nsCanvasFrame.h" #include "nsIImageLoadingContent.h" #include "nsImageFrame.h" @@ -9394,9 +9393,6 @@ PresShell::DoVerifyReflow() } #endif -// used with Telemetry metrics -#define NS_LONG_REFLOW_TIME_MS 5000 - bool PresShell::ProcessReflowCommands(bool aInterruptible) { diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index b975a69dd..5ea7a0188 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -55,7 +55,6 @@ #include "nsDocShell.h" #include "nsISimpleEnumerator.h" #include "nsJSEnvironment.h" -#include "mozilla/Telemetry.h" #include "gfxPrefs.h" #include "BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" @@ -524,46 +523,10 @@ private: private: ~RefreshDriverVsyncObserver() = default; - void RecordTelemetryProbes(TimeStamp aVsyncTimestamp) - { - MOZ_ASSERT(NS_IsMainThread()); - #ifndef ANDROID /* bug 1142079 */ - if (XRE_IsParentProcess()) { - TimeDuration vsyncLatency = TimeStamp::Now() - aVsyncTimestamp; - uint32_t sample = (uint32_t)vsyncLatency.ToMilliseconds(); - RecordJank(sample); - } else if (mVsyncRate != TimeDuration::Forever()) { - TimeDuration contentDelay = (TimeStamp::Now() - mLastChildTick) - mVsyncRate; - if (contentDelay.ToMilliseconds() < 0 ){ - // Vsyncs are noisy and some can come at a rate quicker than - // the reported hardware rate. In those cases, consider that we have 0 delay. - contentDelay = TimeDuration::FromMilliseconds(0); - } - uint32_t sample = (uint32_t)contentDelay.ToMilliseconds(); - RecordJank(sample); - } else { - // Request the vsync rate from the parent process. Might be a few vsyncs - // until the parent responds. - mVsyncRate = mVsyncRefreshDriverTimer->mVsyncChild->GetVsyncRate(); - } - #endif - } - - void RecordJank(uint32_t aJankMS) - { - uint32_t duration = 1 /* ms */; - for (size_t i = 0; - i < mozilla::ArrayLength(sJankLevels) && duration < aJankMS; - ++i, duration *= 2) { - sJankLevels[i]++; - } - } - void TickRefreshDriver(TimeStamp aVsyncTimestamp) { MOZ_ASSERT(NS_IsMainThread()); - RecordTelemetryProbes(aVsyncTimestamp); if (XRE_IsParentProcess()) { MonitorAutoLock lock(mRefreshTickLock); aVsyncTimestamp = mRecentVsync; @@ -2006,7 +1969,6 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime) mViewManagerFlushIsPending = false; RefPtr<nsViewManager> vm = mPresContext->GetPresShell()->GetViewManager(); { - PaintTelemetry::AutoRecordPaint record; vm->ProcessPendingUpdates(); } |