Commit e7d8e6bf authored by Emilio Cobos Álvarez's avatar Emilio Cobos Álvarez
Browse files

Bug 1702216 - Paint auto-style outline with webrender if possible. r=mstange

I noticed we weren't doing this when looking at bug 1701910.

We remove support for auto style outlines in trees, which is unused
(checked that thunderbird and FF trees don't use outline: auto) and for
some mathml debugging code, which seems ok.

Differential Revision: https://phabricator.services.mozilla.com/D110399
parent e1a031b7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -9462,7 +9462,7 @@ static void ComputeAndIncludeOutlineArea(nsIFrame* aFrame,
    }
  }

  // Keep this code in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
  // Keep this code in sync with nsDisplayOutline::GetInnerRect.
  SetOrUpdateRectValuedProperty(aFrame, nsIFrame::OutlineInnerRectProperty(),
                                innerRect);
  const nscoord offset = outline->mOutlineOffset.ToAppUnits();
+2 −2
Original line number Diff line number Diff line
@@ -1798,8 +1798,8 @@ void nsDisplayMathMLCharDebug::Paint(nsDisplayListBuilder* aBuilder,
                                        GetPaintRect(), rect, computedStyle,
                                        flags, skipSides);

  nsCSSRendering::PaintOutline(presContext, *aCtx, mFrame, GetPaintRect(), rect,
                               computedStyle);
  nsCSSRendering::PaintNonThemedOutline(presContext, *aCtx, mFrame,
                                        GetPaintRect(), rect, computedStyle);
}
#endif

+24 −55
Original line number Diff line number Diff line
@@ -940,65 +940,34 @@ nsCSSRendering::CreateNullBorderRendererWithStyleBorder(
  return Some(br);
}

static nsRect GetOutlineInnerRect(nsIFrame* aFrame) {
  nsRect* savedOutlineInnerRect =
      aFrame->GetProperty(nsIFrame::OutlineInnerRectProperty());
  if (savedOutlineInnerRect) {
    return *savedOutlineInnerRect;
  }

  // FIXME bug 1221888
  NS_ERROR("we should have saved a frame property");
  return nsRect(nsPoint(0, 0), aFrame->GetSize());
}

Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRendererForOutline(
    nsPresContext* aPresContext, gfxContext* aRenderingContext,
    nsIFrame* aForFrame, const nsRect& aDirtyRect, const nsRect& aBorderArea,
    ComputedStyle* aStyle) {
Maybe<nsCSSBorderRenderer>
nsCSSRendering::CreateBorderRendererForNonThemedOutline(
    nsPresContext* aPresContext, DrawTarget* aDrawTarget, nsIFrame* aForFrame,
    const nsRect& aDirtyRect, const nsRect& aInnerRect, ComputedStyle* aStyle) {
  // Get our ComputedStyle's color struct.
  const nsStyleOutline* ourOutline = aStyle->StyleOutline();

  if (!ourOutline->ShouldPaintOutline()) {
    // Empty outline
    return Nothing();
  }

  nsRect innerRect;
  if (
#ifdef MOZ_XUL
      aStyle->GetPseudoType() == PseudoStyleType::XULTree
#else
      false
#endif
  ) {
    innerRect = aBorderArea;
  } else {
    innerRect = GetOutlineInnerRect(aForFrame) + aBorderArea.TopLeft();
  }
  nscoord offset = ourOutline->mOutlineOffset.ToAppUnits();
  innerRect.Inflate(offset);
  // If the dirty rect is completely inside the border area (e.g., only the
  // content is being painted), then we can skip out now
  // XXX this isn't exactly true for rounded borders, where the inside curves
  // may encroach into the content area.  A safer calculation would be to
  // shorten insideRect by the radius one each side before performing this test.
  if (innerRect.Contains(aDirtyRect)) return Nothing();
  if (aInnerRect.Contains(aDirtyRect)) {
    return Nothing();
  }

  const nscoord offset = ourOutline->mOutlineOffset.ToAppUnits();
  nsRect innerRect = aInnerRect;
  innerRect.Inflate(offset);
  nscoord width = ourOutline->GetOutlineWidth();

  StyleBorderStyle outlineStyle;
  // Themed outlines are handled by our callers, if supported.
  if (ourOutline->mOutlineStyle.IsAuto()) {
    if (StaticPrefs::layout_css_outline_style_auto_enabled()) {
      nsITheme* theme = aPresContext->Theme();
      if (theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                     StyleAppearance::FocusOutline)) {
        theme->DrawWidgetBackground(aRenderingContext, aForFrame,
                                    StyleAppearance::FocusOutline, innerRect,
                                    aDirtyRect);
        return Nothing();
      }
    }
    if (width == 0) {
      return Nothing();  // empty outline
    }
@@ -1036,8 +1005,9 @@ Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRendererForOutline(
      nsCSSBorderRenderer::ComputeOuterRadii(innerRadii, widths, &outlineRadii);
    }
  } else {
    nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(),
                                 outerRect.Size(), Sides(), twipsRadii);
    nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius,
                                 aForFrame->GetSize(), outerRect.Size(),
                                 Sides(), twipsRadii);
    ComputePixelRadii(twipsRadii, oneDevPixel, &outlineRadii);
  }

@@ -1053,21 +1023,20 @@ Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRendererForOutline(

  Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);

  DrawTarget* dt =
      aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
  return Some(nsCSSBorderRenderer(
      aPresContext, dt, dirtyRect, oRect, outlineStyles, outlineWidths,
      aPresContext, aDrawTarget, dirtyRect, oRect, outlineStyles, outlineWidths,
      outlineRadii, outlineColors, !aForFrame->BackfaceIsHidden(), Nothing()));
}

void nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
void nsCSSRendering::PaintNonThemedOutline(nsPresContext* aPresContext,
                                           gfxContext& aRenderingContext,
                                  nsIFrame* aForFrame, const nsRect& aDirtyRect,
                                  const nsRect& aBorderArea,
                                           nsIFrame* aForFrame,
                                           const nsRect& aDirtyRect,
                                           const nsRect& aInnerRect,
                                           ComputedStyle* aStyle) {
  Maybe<nsCSSBorderRenderer> br = CreateBorderRendererForOutline(
      aPresContext, &aRenderingContext, aForFrame, aDirtyRect, aBorderArea,
      aStyle);
  Maybe<nsCSSBorderRenderer> br = CreateBorderRendererForNonThemedOutline(
      aPresContext, aRenderingContext.GetDrawTarget(), aForFrame, aDirtyRect,
      aInnerRect, aStyle);
  if (!br) {
    return;
  }
+14 −10
Original line number Diff line number Diff line
@@ -199,9 +199,12 @@ struct nsCSSRendering {
      const nsStyleBorder& aBorderStyle, mozilla::ComputedStyle* aStyle,
      bool* aOutBorderIsEmpty, Sides aSkipSides = Sides());

  static mozilla::Maybe<nsCSSBorderRenderer> CreateBorderRendererForOutline(
      nsPresContext* aPresContext, gfxContext* aRenderingContext,
      nsIFrame* aForFrame, const nsRect& aDirtyRect, const nsRect& aBorderArea,
  static mozilla::Maybe<nsCSSBorderRenderer>
  CreateBorderRendererForNonThemedOutline(nsPresContext* aPresContext,
                                          DrawTarget* aDrawTarget,
                                          nsIFrame* aForFrame,
                                          const nsRect& aDirtyRect,
                                          const nsRect& aInnerRect,
                                          mozilla::ComputedStyle* aStyle);

  static ImgDrawResult CreateWebRenderCommandsForBorder(
@@ -229,12 +232,13 @@ struct nsCSSRendering {
      const nsStyleBorder& aStyleBorder);

  /**
   * Render the outline for an element using css rendering rules
   * for borders.
   * Render the outline for an element using css rendering rules for borders.
   */
  static void PaintOutline(nsPresContext* aPresContext,
                           gfxContext& aRenderingContext, nsIFrame* aForFrame,
                           const nsRect& aDirtyRect, const nsRect& aBorderArea,
  static void PaintNonThemedOutline(nsPresContext* aPresContext,
                                    gfxContext& aRenderingContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aDirtyRect,
                                    const nsRect& aInnerRect,
                                    mozilla::ComputedStyle* aStyle);

  /**
+33 −11
Original line number Diff line number Diff line
@@ -4768,15 +4768,34 @@ nsRect nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder,
  return mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
}

nsRect nsDisplayOutline::GetInnerRect() const {
  nsRect* savedOutlineInnerRect =
      mFrame->GetProperty(nsIFrame::OutlineInnerRectProperty());
  if (savedOutlineInnerRect) {
    return *savedOutlineInnerRect;
  }

  // FIXME bug 1221888
  NS_ERROR("we should have saved a frame property");
  return nsRect(nsPoint(), mFrame->GetSize());
}

void nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
  // TODO join outlines together
  MOZ_ASSERT(mFrame->StyleOutline()->ShouldPaintOutline(),
             "Should have not created a nsDisplayOutline!");

  nsPoint offset = ToReferenceFrame();
  nsCSSRendering::PaintOutline(
      mFrame->PresContext(), *aCtx, mFrame, GetPaintRect(),
      nsRect(offset, mFrame->GetSize()), mFrame->Style());
  nsRect rect = GetInnerRect() + ToReferenceFrame();
  nsPresContext* pc = mFrame->PresContext();
  if (IsThemedOutline()) {
    rect.Inflate(mFrame->StyleOutline()->mOutlineOffset.ToAppUnits());
    pc->Theme()->DrawWidgetBackground(
        aCtx, mFrame, StyleAppearance::FocusOutline, rect, GetPaintRect());
    return;
  }

  nsCSSRendering::PaintNonThemedOutline(pc, *aCtx, mFrame, GetPaintRect(), rect,
                                        mFrame->Style());
}

bool nsDisplayOutline::IsThemedOutline() const {
@@ -4797,16 +4816,19 @@ bool nsDisplayOutline::CreateWebRenderCommands(
    const StackingContextHelper& aSc,
    mozilla::layers::RenderRootStateManager* aManager,
    nsDisplayListBuilder* aDisplayListBuilder) {
  nsPresContext* pc = mFrame->PresContext();
  nsRect rect = GetInnerRect() + ToReferenceFrame();
  if (IsThemedOutline()) {
    return false;
    rect.Inflate(mFrame->StyleOutline()->mOutlineOffset.ToAppUnits());
    return pc->Theme()->CreateWebRenderCommandsForWidget(
        aBuilder, aResources, aSc, aManager, mFrame,
        StyleAppearance::FocusOutline, rect);
  }

  nsPoint offset = ToReferenceFrame();

  mozilla::Maybe<nsCSSBorderRenderer> borderRenderer =
      nsCSSRendering::CreateBorderRendererForOutline(
          mFrame->PresContext(), nullptr, mFrame, GetPaintRect(),
          nsRect(offset, mFrame->GetSize()), mFrame->Style());
  Maybe<nsCSSBorderRenderer> borderRenderer =
      nsCSSRendering::CreateBorderRendererForNonThemedOutline(
          pc, /* aDrawTarget = */ nullptr, mFrame, GetPaintRect(), rect,
          mFrame->Style());

  if (!borderRenderer) {
    // No border renderer means "there is no outline".
Loading