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 "nsGkAtoms.h"
10 #include "nsCSSPseudoElements.h"
11 #include "nsNameSpaceManager.h"
12 #include "mozilla/StyleSetHandle.h"
13 #include "mozilla/StyleSetHandleInlines.h"
14 #include "mozilla/Unused.h"
15 #include "nsDisplayList.h"
16 #include "nsITheme.h"
17 #include "nsFrame.h"
18 #include "mozilla/EventStates.h"
19 #include "mozilla/dom/Element.h"
20 #include "Layers.h"
21 #include "gfxPrefs.h"
22 #include "gfxUtils.h"
23 #include "mozilla/layers/WebRenderLayerManager.h"
24
25 #define ACTIVE "active"
26 #define HOVER "hover"
27 #define FOCUS "focus"
28
29 using namespace mozilla;
30 using namespace mozilla::image;
31 using namespace mozilla::layers;
32
nsButtonFrameRenderer()33 nsButtonFrameRenderer::nsButtonFrameRenderer() {
34 MOZ_COUNT_CTOR(nsButtonFrameRenderer);
35 }
36
~nsButtonFrameRenderer()37 nsButtonFrameRenderer::~nsButtonFrameRenderer() {
38 MOZ_COUNT_DTOR(nsButtonFrameRenderer);
39
40 #ifdef DEBUG
41 if (mInnerFocusStyle) {
42 mInnerFocusStyle->FrameRelease();
43 }
44 #endif
45 }
46
SetFrame(nsFrame * aFrame,nsPresContext * aPresContext)47 void nsButtonFrameRenderer::SetFrame(nsFrame* aFrame,
48 nsPresContext* aPresContext) {
49 mFrame = aFrame;
50 ReResolveStyles(aPresContext);
51 }
52
GetFrame()53 nsIFrame* nsButtonFrameRenderer::GetFrame() { return mFrame; }
54
SetDisabled(bool aDisabled,bool aNotify)55 void nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool aNotify) {
56 Element* element = mFrame->GetContent()->AsElement();
57 if (aDisabled)
58 element->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
59 aNotify);
60 else
61 element->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, aNotify);
62 }
63
isDisabled()64 bool nsButtonFrameRenderer::isDisabled() {
65 return mFrame->GetContent()->AsElement()->State().HasState(
66 NS_EVENT_STATE_DISABLED);
67 }
68
69 class nsDisplayButtonBoxShadowOuter : public nsDisplayItem {
70 public:
nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder * aBuilder,nsButtonFrameRenderer * aRenderer)71 nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
72 nsButtonFrameRenderer* aRenderer)
73 : nsDisplayItem(aBuilder, aRenderer->GetFrame()) {
74 MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
75 }
76 #ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayButtonBoxShadowOuter()77 virtual ~nsDisplayButtonBoxShadowOuter() {
78 MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
79 }
80 #endif
81
82 virtual bool CreateWebRenderCommands(
83 mozilla::wr::DisplayListBuilder& aBuilder,
84 mozilla::wr::IpcResourceUpdateQueue& aResources,
85 const StackingContextHelper& aSc,
86 mozilla::layers::WebRenderLayerManager* aManager,
87 nsDisplayListBuilder* aDisplayListBuilder) override;
88
89 virtual already_AddRefed<Layer> BuildLayer(
90 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
91 const ContainerLayerParameters& aContainerParameters) override;
92
93 bool CanBuildWebRenderDisplayItems();
94
95 virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
96 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
97 bool* aSnap) const override;
98 NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
99 };
100
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap) const101 nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
102 bool* aSnap) const {
103 *aSnap = false;
104 return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
105 }
106
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)107 void nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
108 gfxContext* aCtx) {
109 nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
110
111 nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
112 frameRect, mVisibleRect);
113 }
114
CanBuildWebRenderDisplayItems()115 bool nsDisplayButtonBoxShadowOuter::CanBuildWebRenderDisplayItems() {
116 nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
117 if (!shadows) {
118 return false;
119 }
120
121 bool hasBorderRadius;
122 bool nativeTheme =
123 nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
124
125 // We don't support native themed things yet like box shadows around
126 // input buttons.
127 if (nativeTheme) {
128 return false;
129 }
130
131 return true;
132 }
133
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aContainerParameters)134 already_AddRefed<Layer> nsDisplayButtonBoxShadowOuter::BuildLayer(
135 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
136 const ContainerLayerParameters& aContainerParameters) {
137 return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
138 }
139
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::WebRenderLayerManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)140 bool nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
141 mozilla::wr::DisplayListBuilder& aBuilder,
142 mozilla::wr::IpcResourceUpdateQueue& aResources,
143 const StackingContextHelper& aSc,
144 mozilla::layers::WebRenderLayerManager* aManager,
145 nsDisplayListBuilder* aDisplayListBuilder) {
146 if (!CanBuildWebRenderDisplayItems()) {
147 return false;
148 }
149 int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
150 nsRect shadowRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
151 LayoutDeviceRect deviceBox =
152 LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
153 wr::LayoutRect deviceBoxRect = aSc.ToRelativeLayoutRect(deviceBox);
154
155 LayoutDeviceRect clipRect =
156 LayoutDeviceRect::FromAppUnits(mVisibleRect, appUnitsPerDevPixel);
157 wr::LayoutRect deviceClipRect = aSc.ToRelativeLayoutRect(clipRect);
158
159 bool hasBorderRadius;
160 Unused << nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
161
162 LayoutDeviceSize zeroSize;
163 wr::BorderRadius borderRadius =
164 wr::ToBorderRadius(zeroSize, zeroSize, zeroSize, zeroSize);
165 if (hasBorderRadius) {
166 mozilla::gfx::RectCornerRadii borderRadii;
167 hasBorderRadius = nsCSSRendering::GetBorderRadii(shadowRect, shadowRect,
168 mFrame, borderRadii);
169 if (hasBorderRadius) {
170 borderRadius = wr::ToBorderRadius(
171 LayoutDeviceSize::FromUnknownSize(borderRadii.TopLeft()),
172 LayoutDeviceSize::FromUnknownSize(borderRadii.TopRight()),
173 LayoutDeviceSize::FromUnknownSize(borderRadii.BottomLeft()),
174 LayoutDeviceSize::FromUnknownSize(borderRadii.BottomRight()));
175 }
176 }
177
178 nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
179 MOZ_ASSERT(shadows);
180
181 for (uint32_t i = shadows->Length(); i > 0; i--) {
182 nsCSSShadowItem* shadow = shadows->ShadowAt(i - 1);
183 if (shadow->mInset) {
184 continue;
185 }
186 float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
187 gfx::Color shadowColor =
188 nsCSSRendering::GetShadowColor(shadow, mFrame, 1.0);
189
190 LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
191 nsPoint(shadow->mXOffset, shadow->mYOffset), appUnitsPerDevPixel);
192
193 float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
194
195 aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
196 deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
197 wr::ToColorF(shadowColor), blurRadius, spreadRadius,
198 borderRadius, wr::BoxShadowClipMode::Outset);
199 }
200 return true;
201 }
202
203 class nsDisplayButtonBorder : public nsDisplayItem {
204 public:
nsDisplayButtonBorder(nsDisplayListBuilder * aBuilder,nsButtonFrameRenderer * aRenderer)205 nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder,
206 nsButtonFrameRenderer* aRenderer)
207 : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
208 MOZ_COUNT_CTOR(nsDisplayButtonBorder);
209 }
210 #ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayButtonBorder()211 virtual ~nsDisplayButtonBorder() { MOZ_COUNT_DTOR(nsDisplayButtonBorder); }
212 #endif
MustPaintOnContentSide() const213 virtual bool MustPaintOnContentSide() const override { return true; }
214
HitTest(nsDisplayListBuilder * aBuilder,const nsRect & aRect,HitTestState * aState,nsTArray<nsIFrame * > * aOutFrames)215 virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
216 HitTestState* aState,
217 nsTArray<nsIFrame*>* aOutFrames) override {
218 aOutFrames->AppendElement(mFrame);
219 }
220 virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
221 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
222 bool* aSnap) const override;
223 virtual nsDisplayItemGeometry* AllocateGeometry(
224 nsDisplayListBuilder* aBuilder) override;
225 virtual void ComputeInvalidationRegion(
226 nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
227 nsRegion* aInvalidRegion) const override;
228 virtual already_AddRefed<Layer> BuildLayer(
229 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
230 const ContainerLayerParameters& aContainerParameters) override;
231 virtual bool CreateWebRenderCommands(
232 mozilla::wr::DisplayListBuilder& aBuilder,
233 mozilla::wr::IpcResourceUpdateQueue& aResources,
234 const StackingContextHelper& aSc,
235 mozilla::layers::WebRenderLayerManager* aManager,
236 nsDisplayListBuilder* aDisplayListBuilder) override;
237 NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
238 private:
239 nsButtonFrameRenderer* mBFR;
240 };
241
AllocateGeometry(nsDisplayListBuilder * aBuilder)242 nsDisplayItemGeometry* nsDisplayButtonBorder::AllocateGeometry(
243 nsDisplayListBuilder* aBuilder) {
244 return new nsDisplayItemGenericImageGeometry(this, aBuilder);
245 }
246
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aContainerParameters)247 already_AddRefed<Layer> nsDisplayButtonBorder::BuildLayer(
248 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
249 const ContainerLayerParameters& aContainerParameters) {
250 return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
251 }
252
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::WebRenderLayerManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)253 bool nsDisplayButtonBorder::CreateWebRenderCommands(
254 mozilla::wr::DisplayListBuilder& aBuilder,
255 mozilla::wr::IpcResourceUpdateQueue& aResources,
256 const StackingContextHelper& aSc,
257 mozilla::layers::WebRenderLayerManager* aManager,
258 nsDisplayListBuilder* aDisplayListBuilder) {
259 // This is really a combination of paint box shadow inner +
260 // paint border.
261 nsRect buttonRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
262 bool snap;
263 nsRegion visible = GetBounds(aDisplayListBuilder, &snap);
264 nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
265 aBuilder, aSc, visible, mFrame, buttonRect);
266
267 bool borderIsEmpty = false;
268 Maybe<nsCSSBorderRenderer> br = nsCSSRendering::CreateBorderRenderer(
269 mFrame->PresContext(), nullptr, mFrame, nsRect(),
270 nsRect(ToReferenceFrame(), mFrame->GetSize()), mFrame->StyleContext(),
271 &borderIsEmpty, mFrame->GetSkipSides());
272 if (!br) {
273 return borderIsEmpty;
274 }
275
276 br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
277
278 return true;
279 }
280
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion) const281 void nsDisplayButtonBorder::ComputeInvalidationRegion(
282 nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
283 nsRegion* aInvalidRegion) const {
284 auto geometry =
285 static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
286
287 if (aBuilder->ShouldSyncDecodeImages() &&
288 geometry->ShouldInvalidateToSyncDecodeImages()) {
289 bool snap;
290 aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
291 }
292
293 nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
294 }
295
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)296 void nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
297 gfxContext* aCtx) {
298 NS_ASSERTION(mFrame, "No frame?");
299 nsPresContext* pc = mFrame->PresContext();
300 nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
301
302 // draw the border and background inside the focus and outline borders
303 ImgDrawResult result =
304 mBFR->PaintBorder(aBuilder, pc, *aCtx, mVisibleRect, r);
305
306 nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
307 }
308
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap) const309 nsRect nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder,
310 bool* aSnap) const {
311 *aSnap = false;
312 return aBuilder->IsForEventDelivery()
313 ? nsRect(ToReferenceFrame(), mFrame->GetSize())
314 : mFrame->GetVisualOverflowRectRelativeToSelf() +
315 ToReferenceFrame();
316 }
317
318 class nsDisplayButtonForeground : public nsDisplayItem {
319 public:
nsDisplayButtonForeground(nsDisplayListBuilder * aBuilder,nsButtonFrameRenderer * aRenderer)320 nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,
321 nsButtonFrameRenderer* aRenderer)
322 : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
323 MOZ_COUNT_CTOR(nsDisplayButtonForeground);
324 }
325 #ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayButtonForeground()326 virtual ~nsDisplayButtonForeground() {
327 MOZ_COUNT_DTOR(nsDisplayButtonForeground);
328 }
329 #endif
330
331 nsDisplayItemGeometry* AllocateGeometry(
332 nsDisplayListBuilder* aBuilder) override;
333 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
334 const nsDisplayItemGeometry* aGeometry,
335 nsRegion* aInvalidRegion) const override;
336 virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
337 virtual already_AddRefed<Layer> BuildLayer(
338 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
339 const ContainerLayerParameters& aContainerParameters) override;
340 virtual bool CreateWebRenderCommands(
341 mozilla::wr::DisplayListBuilder& aBuilder,
342 mozilla::wr::IpcResourceUpdateQueue& aResources,
343 const StackingContextHelper& aSc,
344 mozilla::layers::WebRenderLayerManager* aManager,
345 nsDisplayListBuilder* aDisplayListBuilder) override;
346 NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
347 private:
348 nsButtonFrameRenderer* mBFR;
349 };
350
AllocateGeometry(nsDisplayListBuilder * aBuilder)351 nsDisplayItemGeometry* nsDisplayButtonForeground::AllocateGeometry(
352 nsDisplayListBuilder* aBuilder) {
353 return new nsDisplayItemGenericImageGeometry(this, aBuilder);
354 }
355
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion) const356 void nsDisplayButtonForeground::ComputeInvalidationRegion(
357 nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
358 nsRegion* aInvalidRegion) const {
359 auto geometry =
360 static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
361
362 if (aBuilder->ShouldSyncDecodeImages() &&
363 geometry->ShouldInvalidateToSyncDecodeImages()) {
364 bool snap;
365 aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
366 }
367
368 nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
369 }
370
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)371 void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
372 gfxContext* aCtx) {
373 nsPresContext* presContext = mFrame->PresContext();
374 const nsStyleDisplay* disp = mFrame->StyleDisplay();
375 if (!mFrame->IsThemed(disp) ||
376 !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
377 nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
378
379 // Draw the -moz-focus-inner border
380 ImgDrawResult result = mBFR->PaintInnerFocusBorder(aBuilder, presContext,
381 *aCtx, mVisibleRect, r);
382
383 nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
384 }
385 }
386
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aContainerParameters)387 already_AddRefed<mozilla::layers::Layer> nsDisplayButtonForeground::BuildLayer(
388 nsDisplayListBuilder* aBuilder, LayerManager* aManager,
389 const ContainerLayerParameters& aContainerParameters) {
390 return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
391 }
392
CreateWebRenderCommands(mozilla::wr::DisplayListBuilder & aBuilder,mozilla::wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,mozilla::layers::WebRenderLayerManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)393 bool nsDisplayButtonForeground::CreateWebRenderCommands(
394 mozilla::wr::DisplayListBuilder& aBuilder,
395 mozilla::wr::IpcResourceUpdateQueue& aResources,
396 const StackingContextHelper& aSc,
397 mozilla::layers::WebRenderLayerManager* aManager,
398 nsDisplayListBuilder* aDisplayListBuilder) {
399 Maybe<nsCSSBorderRenderer> br;
400 bool borderIsEmpty = false;
401 nsPresContext* presContext = mFrame->PresContext();
402 const nsStyleDisplay* disp = mFrame->StyleDisplay();
403 if (!mFrame->IsThemed(disp) ||
404 !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
405 nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
406 br = mBFR->CreateInnerFocusBorderRenderer(aDisplayListBuilder, presContext,
407 nullptr, mVisibleRect, r,
408 &borderIsEmpty);
409 }
410
411 if (!br) {
412 return borderIsEmpty;
413 }
414
415 br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
416 return true;
417 }
418
DisplayButton(nsDisplayListBuilder * aBuilder,nsDisplayList * aBackground,nsDisplayList * aForeground)419 nsresult nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
420 nsDisplayList* aBackground,
421 nsDisplayList* aForeground) {
422 if (mFrame->StyleEffects()->mBoxShadow) {
423 aBackground->AppendToTop(
424 MakeDisplayItem<nsDisplayButtonBoxShadowOuter>(aBuilder, this));
425 }
426
427 nsRect buttonRect = mFrame->GetRectRelativeToSelf();
428
429 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, mFrame,
430 buttonRect, aBackground);
431
432 aBackground->AppendToTop(
433 MakeDisplayItem<nsDisplayButtonBorder>(aBuilder, this));
434
435 // Only display focus rings if we actually have them. Since at most one
436 // button would normally display a focus ring, most buttons won't have them.
437 if (mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder()) {
438 aForeground->AppendToTop(
439 MakeDisplayItem<nsDisplayButtonForeground>(aBuilder, this));
440 }
441 return NS_OK;
442 }
443
GetButtonInnerFocusRect(const nsRect & aRect,nsRect & aResult)444 void nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect,
445 nsRect& aResult) {
446 aResult = aRect;
447 aResult.Deflate(mFrame->GetUsedBorderAndPadding());
448
449 nsMargin innerFocusPadding(0, 0, 0, 0);
450 if (mInnerFocusStyle) {
451 mInnerFocusStyle->StylePadding()->GetPadding(innerFocusPadding);
452 }
453 aResult.Inflate(innerFocusPadding);
454 }
455
PaintInnerFocusBorder(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext & aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect)456 ImgDrawResult nsButtonFrameRenderer::PaintInnerFocusBorder(
457 nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
458 gfxContext& aRenderingContext, const nsRect& aDirtyRect,
459 const nsRect& aRect) {
460 // we draw the -moz-focus-inner border just inside the button's
461 // normal border and padding, to match Windows themes.
462
463 nsRect rect;
464
465 PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
466 ? PaintBorderFlags::SYNC_DECODE_IMAGES
467 : PaintBorderFlags();
468
469 ImgDrawResult result = ImgDrawResult::SUCCESS;
470
471 if (mInnerFocusStyle) {
472 GetButtonInnerFocusRect(aRect, rect);
473
474 result &=
475 nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
476 aDirtyRect, rect, mInnerFocusStyle, flags);
477 }
478
479 return result;
480 }
481
482 Maybe<nsCSSBorderRenderer>
CreateInnerFocusBorderRenderer(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext * aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect,bool * aBorderIsEmpty)483 nsButtonFrameRenderer::CreateInnerFocusBorderRenderer(
484 nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
485 gfxContext* aRenderingContext, const nsRect& aDirtyRect,
486 const nsRect& aRect, bool* aBorderIsEmpty) {
487 if (mInnerFocusStyle) {
488 nsRect rect;
489 GetButtonInnerFocusRect(aRect, rect);
490
491 gfx::DrawTarget* dt =
492 aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
493 return nsCSSRendering::CreateBorderRenderer(
494 aPresContext, dt, mFrame, aDirtyRect, rect, mInnerFocusStyle,
495 aBorderIsEmpty);
496 }
497
498 return Nothing();
499 }
500
PaintBorder(nsDisplayListBuilder * aBuilder,nsPresContext * aPresContext,gfxContext & aRenderingContext,const nsRect & aDirtyRect,const nsRect & aRect)501 ImgDrawResult nsButtonFrameRenderer::PaintBorder(nsDisplayListBuilder* aBuilder,
502 nsPresContext* aPresContext,
503 gfxContext& aRenderingContext,
504 const nsRect& aDirtyRect,
505 const nsRect& aRect) {
506 // get the button rect this is inside the focus and outline rects
507 nsRect buttonRect = aRect;
508 nsStyleContext* context = mFrame->StyleContext();
509
510 PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
511 ? PaintBorderFlags::SYNC_DECODE_IMAGES
512 : PaintBorderFlags();
513
514 nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext, mFrame,
515 buttonRect);
516
517 ImgDrawResult result =
518 nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
519 aDirtyRect, buttonRect, context, borderFlags);
520
521 return result;
522 }
523
524 /**
525 * Call this when styles change
526 */
ReResolveStyles(nsPresContext * aPresContext)527 void nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) {
528 // get all the styles
529 nsStyleContext* context = mFrame->StyleContext();
530 StyleSetHandle styleSet = aPresContext->StyleSet();
531
532 #ifdef DEBUG
533 if (mInnerFocusStyle) {
534 mInnerFocusStyle->FrameRelease();
535 }
536 #endif
537
538 // get styles assigned to -moz-inner-focus (ie dotted border on Windows)
539 mInnerFocusStyle = styleSet->ProbePseudoElementStyle(
540 mFrame->GetContent()->AsElement(), CSSPseudoElementType::mozFocusInner,
541 context);
542
543 #ifdef DEBUG
544 if (mInnerFocusStyle) {
545 mInnerFocusStyle->FrameAddRef();
546 }
547 #endif
548 }
549
GetStyleContext(int32_t aIndex) const550 nsStyleContext* nsButtonFrameRenderer::GetStyleContext(int32_t aIndex) const {
551 switch (aIndex) {
552 case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
553 return mInnerFocusStyle;
554 default:
555 return nullptr;
556 }
557 }
558
SetStyleContext(int32_t aIndex,nsStyleContext * aStyleContext)559 void nsButtonFrameRenderer::SetStyleContext(int32_t aIndex,
560 nsStyleContext* aStyleContext) {
561 switch (aIndex) {
562 case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
563 #ifdef DEBUG
564 if (mInnerFocusStyle) {
565 mInnerFocusStyle->FrameRelease();
566 }
567 #endif
568 mInnerFocusStyle = aStyleContext;
569 break;
570 }
571 #ifdef DEBUG
572 aStyleContext->FrameAddRef();
573 #endif
574 }
575