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