1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsButtonFrameRenderer.h"
7 #include "nsCSSRendering.h"
8 #include "nsPresContext.h"
9 #include "nsPresContextInlines.h"
10 #include "nsGkAtoms.h"
11 #include "nsCSSPseudoElements.h"
12 #include "nsNameSpaceManager.h"
13 #include "mozilla/ServoStyleSet.h"
14 #include "mozilla/Unused.h"
15 #include "nsDisplayList.h"
16 #include "nsITheme.h"
17 #include "nsIFrame.h"
18 #include "mozilla/EventStates.h"
19 #include "mozilla/dom/Element.h"
20 #include "Layers.h"
21 
22 #include "gfxUtils.h"
23 #include "mozilla/layers/RenderRootStateManager.h"
24 
25 using namespace mozilla;
26 using namespace mozilla::image;
27 using namespace mozilla::layers;
28 
29 namespace mozilla {
30 class nsDisplayButtonBoxShadowOuter;
31 class nsDisplayButtonBorder;
32 class nsDisplayButtonForeground;
33 }  // namespace mozilla
34 
nsButtonFrameRenderer()35 nsButtonFrameRenderer::nsButtonFrameRenderer() : mFrame(nullptr) {
36   MOZ_COUNT_CTOR(nsButtonFrameRenderer);
37 }
38 
~nsButtonFrameRenderer()39 nsButtonFrameRenderer::~nsButtonFrameRenderer() {
40   MOZ_COUNT_DTOR(nsButtonFrameRenderer);
41 }
42 
SetFrame(nsIFrame * aFrame,nsPresContext * aPresContext)43 void nsButtonFrameRenderer::SetFrame(nsIFrame* aFrame,
44                                      nsPresContext* aPresContext) {
45   mFrame = aFrame;
46   ReResolveStyles(aPresContext);
47 }
48 
GetFrame()49 nsIFrame* nsButtonFrameRenderer::GetFrame() { return mFrame; }
50 
SetDisabled(bool aDisabled,bool aNotify)51 void nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool aNotify) {
52   dom::Element* element = mFrame->GetContent()->AsElement();
53   if (aDisabled)
54     element->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, u""_ns, aNotify);
55   else
56     element->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, aNotify);
57 }
58 
isDisabled()59 bool nsButtonFrameRenderer::isDisabled() {
60   return mFrame->GetContent()->AsElement()->IsDisabled();
61 }
62 
DisplayButton(nsDisplayListBuilder * aBuilder,nsDisplayList * aBackground,nsDisplayList * aForeground)63 nsresult nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
64                                               nsDisplayList* aBackground,
65                                               nsDisplayList* aForeground) {
66   if (!mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
67     aBackground->AppendNewToTop<nsDisplayButtonBoxShadowOuter>(aBuilder,
68                                                                GetFrame());
69   }
70 
71   nsRect buttonRect =
72       mFrame->GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(mFrame);
73 
74   const AppendedBackgroundType result =
75       nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
76           aBuilder, mFrame, buttonRect, aBackground);
77   if (result == AppendedBackgroundType::None) {
78     aBuilder->BuildCompositorHitTestInfoIfNeeded(GetFrame(), aBackground);
79   }
80 
81   aBackground->AppendNewToTop<nsDisplayButtonBorder>(aBuilder, GetFrame(),
82                                                      this);
83 
84   // Only display focus rings if we actually have them. Since at most one
85   // button would normally display a focus ring, most buttons won't have them.
86   const auto* disp = mFrame->StyleDisplay();
87   nsPresContext* pc = mFrame->PresContext();
88   if (mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder() &&
89       mFrame->IsThemed(disp) &&
90       pc->Theme()->ThemeWantsButtonInnerFocusRing(
91           mFrame, disp->EffectiveAppearance())) {
92     aForeground->AppendNewToTop<nsDisplayButtonForeground>(aBuilder, GetFrame(),
93                                                            this);
94   }
95   return NS_OK;
96 }
97 
GetButtonInnerFocusRect(const nsRect & aRect,nsRect & aResult)98 void nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect,
99                                                     nsRect& aResult) {
100   aResult = aRect;
101   aResult.Deflate(mFrame->GetUsedBorderAndPadding());
102 
103   if (mInnerFocusStyle) {
104     nsMargin innerFocusPadding(0, 0, 0, 0);
105     mInnerFocusStyle->StylePadding()->GetPadding(innerFocusPadding);
106 
107     nsMargin framePadding = mFrame->GetUsedPadding();
108 
109     innerFocusPadding.top = std::min(innerFocusPadding.top, framePadding.top);
110     innerFocusPadding.right =
111         std::min(innerFocusPadding.right, framePadding.right);
112     innerFocusPadding.bottom =
113         std::min(innerFocusPadding.bottom, framePadding.bottom);
114     innerFocusPadding.left =
115         std::min(innerFocusPadding.left, framePadding.left);
116 
117     aResult.Inflate(innerFocusPadding);
118   }
119 }
120 
PaintInnerFocusBorder(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext & aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect)121 ImgDrawResult nsButtonFrameRenderer::PaintInnerFocusBorder(
122     nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
123     gfxContext& aRenderingContext, const nsRect& aDirtyRect,
124     const nsRect& aRect) {
125   // we draw the -moz-focus-inner border just inside the button's
126   // normal border and padding, to match Windows themes.
127 
128   nsRect rect;
129 
130   PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
131                                ? PaintBorderFlags::SyncDecodeImages
132                                : PaintBorderFlags();
133 
134   ImgDrawResult result = ImgDrawResult::SUCCESS;
135 
136   if (mInnerFocusStyle) {
137     GetButtonInnerFocusRect(aRect, rect);
138 
139     result &=
140         nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
141                                     aDirtyRect, rect, mInnerFocusStyle, flags);
142   }
143 
144   return result;
145 }
146 
147 Maybe<nsCSSBorderRenderer>
CreateInnerFocusBorderRenderer(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext * aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect,bool * aBorderIsEmpty)148 nsButtonFrameRenderer::CreateInnerFocusBorderRenderer(
149     nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
150     gfxContext* aRenderingContext, const nsRect& aDirtyRect,
151     const nsRect& aRect, bool* aBorderIsEmpty) {
152   if (mInnerFocusStyle) {
153     nsRect rect;
154     GetButtonInnerFocusRect(aRect, rect);
155 
156     gfx::DrawTarget* dt =
157         aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
158     return nsCSSRendering::CreateBorderRenderer(
159         aPresContext, dt, mFrame, aDirtyRect, rect, mInnerFocusStyle,
160         aBorderIsEmpty);
161   }
162 
163   return Nothing();
164 }
165 
PaintBorder(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext & aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect)166 ImgDrawResult nsButtonFrameRenderer::PaintBorder(nsDisplayListBuilder* aBuilder,
167                                                  nsPresContext* aPresContext,
168                                                  gfxContext& aRenderingContext,
169                                                  const nsRect& aDirtyRect,
170                                                  const nsRect& aRect) {
171   // get the button rect this is inside the focus and outline rects
172   nsRect buttonRect = aRect;
173   ComputedStyle* context = mFrame->Style();
174 
175   PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
176                                      ? PaintBorderFlags::SyncDecodeImages
177                                      : PaintBorderFlags();
178 
179   nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext, mFrame,
180                                       buttonRect);
181 
182   ImgDrawResult result =
183       nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
184                                   aDirtyRect, buttonRect, context, borderFlags);
185 
186   return result;
187 }
188 
189 /**
190  * Call this when styles change
191  */
ReResolveStyles(nsPresContext * aPresContext)192 void nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) {
193   // get all the styles
194   ServoStyleSet* styleSet = aPresContext->StyleSet();
195 
196   // get styles assigned to -moz-focus-inner (ie dotted border on Windows)
197   mInnerFocusStyle = styleSet->ProbePseudoElementStyle(
198       *mFrame->GetContent()->AsElement(), PseudoStyleType::mozFocusInner,
199       mFrame->Style());
200 }
201 
GetComputedStyle(int32_t aIndex) const202 ComputedStyle* nsButtonFrameRenderer::GetComputedStyle(int32_t aIndex) const {
203   switch (aIndex) {
204     case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
205       return mInnerFocusStyle;
206     default:
207       return nullptr;
208   }
209 }
210 
SetComputedStyle(int32_t aIndex,ComputedStyle * aComputedStyle)211 void nsButtonFrameRenderer::SetComputedStyle(int32_t aIndex,
212                                              ComputedStyle* aComputedStyle) {
213   switch (aIndex) {
214     case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
215       mInnerFocusStyle = aComputedStyle;
216       break;
217   }
218 }
219 
220 namespace mozilla {
221 
222 class nsDisplayButtonBoxShadowOuter : public nsPaintedDisplayItem {
223  public:
nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)224   nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
225                                 nsIFrame* aFrame)
226       : nsPaintedDisplayItem(aBuilder, aFrame) {
227     MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
228   }
229   MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonBoxShadowOuter)
230 
231   virtual bool CreateWebRenderCommands(
232       mozilla::wr::DisplayListBuilder& aBuilder,
233       mozilla::wr::IpcResourceUpdateQueue& aResources,
234       const StackingContextHelper& aSc,
235       mozilla::layers::RenderRootStateManager* aManager,
236       nsDisplayListBuilder* aDisplayListBuilder) override;
237 
238   bool CanBuildWebRenderDisplayItems();
239 
240   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
241   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
242                            bool* aSnap) const override;
243   NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
244 };
245 
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap) const246 nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
247                                                 bool* aSnap) const {
248   *aSnap = false;
249   return mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
250 }
251 
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)252 void nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
253                                           gfxContext* aCtx) {
254   nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
255 
256   nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
257                                       frameRect, GetPaintRect(aBuilder, aCtx));
258 }
259 
CanBuildWebRenderDisplayItems()260 bool nsDisplayButtonBoxShadowOuter::CanBuildWebRenderDisplayItems() {
261   // FIXME(emilio): Is this right? That doesn't make much sense.
262   if (mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
263     return false;
264   }
265 
266   bool hasBorderRadius;
267   bool nativeTheme =
268       nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
269 
270   // We don't support native themed things yet like box shadows around
271   // input buttons.
272   return !nativeTheme;
273 }
274 
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::RenderRootStateManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)275 bool nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
276     mozilla::wr::DisplayListBuilder& aBuilder,
277     mozilla::wr::IpcResourceUpdateQueue& aResources,
278     const StackingContextHelper& aSc,
279     mozilla::layers::RenderRootStateManager* aManager,
280     nsDisplayListBuilder* aDisplayListBuilder) {
281   if (!CanBuildWebRenderDisplayItems()) {
282     return false;
283   }
284   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
285   nsRect shadowRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
286   LayoutDeviceRect deviceBox =
287       LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
288   wr::LayoutRect deviceBoxRect = wr::ToLayoutRect(deviceBox);
289 
290   bool dummy;
291   LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
292       GetBounds(aDisplayListBuilder, &dummy), appUnitsPerDevPixel);
293   wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
294 
295   bool hasBorderRadius;
296   Unused << nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
297 
298   LayoutDeviceSize zeroSize;
299   wr::BorderRadius borderRadius =
300       wr::ToBorderRadius(zeroSize, zeroSize, zeroSize, zeroSize);
301   if (hasBorderRadius) {
302     gfx::RectCornerRadii borderRadii;
303     hasBorderRadius = nsCSSRendering::GetBorderRadii(shadowRect, shadowRect,
304                                                      mFrame, borderRadii);
305     if (hasBorderRadius) {
306       borderRadius = wr::ToBorderRadius(borderRadii);
307     }
308   }
309 
310   const Span<const StyleBoxShadow> shadows =
311       mFrame->StyleEffects()->mBoxShadow.AsSpan();
312   MOZ_ASSERT(!shadows.IsEmpty());
313 
314   for (const StyleBoxShadow& shadow : Reversed(shadows)) {
315     if (shadow.inset) {
316       continue;
317     }
318     float blurRadius =
319         float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
320     gfx::DeviceColor shadowColor =
321         ToDeviceColor(nsCSSRendering::GetShadowColor(shadow.base, mFrame, 1.0));
322 
323     LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
324         nsPoint(shadow.base.horizontal.ToAppUnits(),
325                 shadow.base.vertical.ToAppUnits()),
326         appUnitsPerDevPixel);
327 
328     float spreadRadius =
329         float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
330 
331     aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
332                            deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
333                            wr::ToColorF(shadowColor), blurRadius, spreadRadius,
334                            borderRadius, wr::BoxShadowClipMode::Outset);
335   }
336   return true;
337 }
338 
339 class nsDisplayButtonBorder final : public nsPaintedDisplayItem {
340  public:
nsDisplayButtonBorder(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsButtonFrameRenderer * aRenderer)341   nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
342                         nsButtonFrameRenderer* aRenderer)
343       : nsPaintedDisplayItem(aBuilder, aFrame), mBFR(aRenderer) {
344     MOZ_COUNT_CTOR(nsDisplayButtonBorder);
345   }
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonBorder)346   MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonBorder)
347 
348   virtual bool MustPaintOnContentSide() const override { return true; }
349 
HitTest(nsDisplayListBuilder * aBuilder,const nsRect & aRect,HitTestState * aState,nsTArray<nsIFrame * > * aOutFrames)350   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
351                        HitTestState* aState,
352                        nsTArray<nsIFrame*>* aOutFrames) override {
353     aOutFrames->AppendElement(mFrame);
354   }
355   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
356   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
357                            bool* aSnap) const override;
358   virtual nsDisplayItemGeometry* AllocateGeometry(
359       nsDisplayListBuilder* aBuilder) override;
360   virtual void ComputeInvalidationRegion(
361       nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
362       nsRegion* aInvalidRegion) const override;
363   virtual bool CreateWebRenderCommands(
364       mozilla::wr::DisplayListBuilder& aBuilder,
365       mozilla::wr::IpcResourceUpdateQueue& aResources,
366       const StackingContextHelper& aSc,
367       mozilla::layers::RenderRootStateManager* aManager,
368       nsDisplayListBuilder* aDisplayListBuilder) override;
369   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
370  private:
371   nsButtonFrameRenderer* mBFR;
372 };
373 
AllocateGeometry(nsDisplayListBuilder * aBuilder)374 nsDisplayItemGeometry* nsDisplayButtonBorder::AllocateGeometry(
375     nsDisplayListBuilder* aBuilder) {
376   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
377 }
378 
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::RenderRootStateManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)379 bool nsDisplayButtonBorder::CreateWebRenderCommands(
380     mozilla::wr::DisplayListBuilder& aBuilder,
381     mozilla::wr::IpcResourceUpdateQueue& aResources,
382     const StackingContextHelper& aSc,
383     mozilla::layers::RenderRootStateManager* aManager,
384     nsDisplayListBuilder* aDisplayListBuilder) {
385   // This is really a combination of paint box shadow inner +
386   // paint border.
387   aBuilder.StartGroup(this);
388   const nsRect buttonRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
389   bool snap;
390   nsRect visible = GetBounds(aDisplayListBuilder, &snap);
391   nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
392       aBuilder, aSc, visible, mFrame, buttonRect);
393 
394   bool borderIsEmpty = false;
395   Maybe<nsCSSBorderRenderer> br = nsCSSRendering::CreateBorderRenderer(
396       mFrame->PresContext(), nullptr, mFrame, nsRect(),
397       nsRect(ToReferenceFrame(), mFrame->GetSize()), mFrame->Style(),
398       &borderIsEmpty, mFrame->GetSkipSides());
399   if (!br) {
400     if (borderIsEmpty) {
401       aBuilder.FinishGroup();
402     } else {
403       aBuilder.CancelGroup(true);
404     }
405 
406     return borderIsEmpty;
407   }
408 
409   br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
410   aBuilder.FinishGroup();
411   return true;
412 }
413 
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion) const414 void nsDisplayButtonBorder::ComputeInvalidationRegion(
415     nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
416     nsRegion* aInvalidRegion) const {
417   auto geometry =
418       static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
419 
420   if (aBuilder->ShouldSyncDecodeImages() &&
421       geometry->ShouldInvalidateToSyncDecodeImages()) {
422     bool snap;
423     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
424   }
425 
426   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
427 }
428 
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)429 void nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
430                                   gfxContext* aCtx) {
431   NS_ASSERTION(mFrame, "No frame?");
432   nsPresContext* pc = mFrame->PresContext();
433   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
434 
435   // draw the border and background inside the focus and outline borders
436   ImgDrawResult result =
437       mBFR->PaintBorder(aBuilder, pc, *aCtx, GetPaintRect(aBuilder, aCtx), r);
438 
439   nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
440 }
441 
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap) const442 nsRect nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder,
443                                         bool* aSnap) const {
444   *aSnap = false;
445   return aBuilder->IsForEventDelivery()
446              ? nsRect(ToReferenceFrame(), mFrame->GetSize())
447              : mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
448 }
449 
450 class nsDisplayButtonForeground final : public nsPaintedDisplayItem {
451  public:
nsDisplayButtonForeground(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsButtonFrameRenderer * aRenderer)452   nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
453                             nsButtonFrameRenderer* aRenderer)
454       : nsPaintedDisplayItem(aBuilder, aFrame), mBFR(aRenderer) {
455     MOZ_COUNT_CTOR(nsDisplayButtonForeground);
456   }
457   MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonForeground)
458 
459   nsDisplayItemGeometry* AllocateGeometry(
460       nsDisplayListBuilder* aBuilder) override;
461   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
462                                  const nsDisplayItemGeometry* aGeometry,
463                                  nsRegion* aInvalidRegion) const override;
464   void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
465   bool CreateWebRenderCommands(
466       mozilla::wr::DisplayListBuilder& aBuilder,
467       mozilla::wr::IpcResourceUpdateQueue& aResources,
468       const StackingContextHelper& aSc,
469       mozilla::layers::RenderRootStateManager* aManager,
470       nsDisplayListBuilder* aDisplayListBuilder) override;
471   NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
472  private:
473   nsButtonFrameRenderer* mBFR;
474 };
475 
AllocateGeometry(nsDisplayListBuilder * aBuilder)476 nsDisplayItemGeometry* nsDisplayButtonForeground::AllocateGeometry(
477     nsDisplayListBuilder* aBuilder) {
478   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
479 }
480 
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion) const481 void nsDisplayButtonForeground::ComputeInvalidationRegion(
482     nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
483     nsRegion* aInvalidRegion) const {
484   auto geometry =
485       static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
486 
487   if (aBuilder->ShouldSyncDecodeImages() &&
488       geometry->ShouldInvalidateToSyncDecodeImages()) {
489     bool snap;
490     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
491   }
492 
493   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
494 }
495 
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)496 void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
497                                       gfxContext* aCtx) {
498   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
499 
500   // Draw the -moz-focus-inner border
501   ImgDrawResult result = mBFR->PaintInnerFocusBorder(
502       aBuilder, mFrame->PresContext(), *aCtx, GetPaintRect(aBuilder, aCtx), r);
503 
504   nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
505 }
506 
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::RenderRootStateManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)507 bool nsDisplayButtonForeground::CreateWebRenderCommands(
508     mozilla::wr::DisplayListBuilder& aBuilder,
509     mozilla::wr::IpcResourceUpdateQueue& aResources,
510     const StackingContextHelper& aSc,
511     mozilla::layers::RenderRootStateManager* aManager,
512     nsDisplayListBuilder* aDisplayListBuilder) {
513   Maybe<nsCSSBorderRenderer> br;
514   bool borderIsEmpty = false;
515   bool dummy;
516   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
517   br = mBFR->CreateInnerFocusBorderRenderer(
518       aDisplayListBuilder, mFrame->PresContext(), nullptr,
519       GetBounds(aDisplayListBuilder, &dummy), r, &borderIsEmpty);
520 
521   if (!br) {
522     return borderIsEmpty;
523   }
524 
525   aBuilder.StartGroup(this);
526   br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
527   aBuilder.FinishGroup();
528 
529   return true;
530 }
531 
532 }  // namespace mozilla
533