layout/forms/nsButtonFrameRenderer.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/forms/nsButtonFrameRenderer.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,408 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +#include "nsButtonFrameRenderer.h"
     1.9 +#include "nsCSSRendering.h"
    1.10 +#include "nsPresContext.h"
    1.11 +#include "nsGkAtoms.h"
    1.12 +#include "nsCSSPseudoElements.h"
    1.13 +#include "nsNameSpaceManager.h"
    1.14 +#include "nsStyleSet.h"
    1.15 +#include "nsDisplayList.h"
    1.16 +#include "nsITheme.h"
    1.17 +#include "nsFrame.h"
    1.18 +#include "mozilla/EventStates.h"
    1.19 +#include "mozilla/dom/Element.h"
    1.20 +
    1.21 +#define ACTIVE   "active"
    1.22 +#define HOVER    "hover"
    1.23 +#define FOCUS    "focus"
    1.24 +
    1.25 +nsButtonFrameRenderer::nsButtonFrameRenderer()
    1.26 +{
    1.27 +  MOZ_COUNT_CTOR(nsButtonFrameRenderer);
    1.28 +}
    1.29 +
    1.30 +nsButtonFrameRenderer::~nsButtonFrameRenderer()
    1.31 +{
    1.32 +  MOZ_COUNT_DTOR(nsButtonFrameRenderer);
    1.33 +}
    1.34 +
    1.35 +void
    1.36 +nsButtonFrameRenderer::SetFrame(nsFrame* aFrame, nsPresContext* aPresContext)
    1.37 +{
    1.38 +  mFrame = aFrame;
    1.39 +  ReResolveStyles(aPresContext);
    1.40 +}
    1.41 +
    1.42 +nsIFrame*
    1.43 +nsButtonFrameRenderer::GetFrame()
    1.44 +{
    1.45 +  return mFrame;
    1.46 +}
    1.47 +
    1.48 +void
    1.49 +nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool notify)
    1.50 +{
    1.51 +  if (aDisabled)
    1.52 +    mFrame->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
    1.53 +                                  notify);
    1.54 +  else
    1.55 +    mFrame->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, notify);
    1.56 +}
    1.57 +
    1.58 +bool
    1.59 +nsButtonFrameRenderer::isDisabled() 
    1.60 +{
    1.61 +  return mFrame->GetContent()->AsElement()->
    1.62 +    State().HasState(NS_EVENT_STATE_DISABLED);
    1.63 +}
    1.64 +
    1.65 +class nsDisplayButtonBoxShadowOuter : public nsDisplayItem {
    1.66 +public:
    1.67 +  nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
    1.68 +                                nsButtonFrameRenderer* aRenderer)
    1.69 +    : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
    1.70 +    MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
    1.71 +  }
    1.72 +#ifdef NS_BUILD_REFCNT_LOGGING
    1.73 +  virtual ~nsDisplayButtonBoxShadowOuter() {
    1.74 +    MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
    1.75 +  }
    1.76 +#endif  
    1.77 +  
    1.78 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
    1.79 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
    1.80 +  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
    1.81 +                           bool* aSnap) MOZ_OVERRIDE;
    1.82 +  NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
    1.83 +private:
    1.84 +  nsButtonFrameRenderer* mBFR;
    1.85 +};
    1.86 +
    1.87 +nsRect
    1.88 +nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
    1.89 +  *aSnap = false;
    1.90 +  return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
    1.91 +}
    1.92 +
    1.93 +void
    1.94 +nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
    1.95 +                                     nsRenderingContext* aCtx) {
    1.96 +  nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
    1.97 +
    1.98 +  nsRect buttonRect;
    1.99 +  mBFR->GetButtonRect(frameRect, buttonRect);
   1.100 +
   1.101 +  nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
   1.102 +                                      buttonRect, mVisibleRect);
   1.103 +}
   1.104 +
   1.105 +class nsDisplayButtonBorderBackground : public nsDisplayItem {
   1.106 +public:
   1.107 +  nsDisplayButtonBorderBackground(nsDisplayListBuilder* aBuilder,
   1.108 +                                  nsButtonFrameRenderer* aRenderer)
   1.109 +    : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
   1.110 +    MOZ_COUNT_CTOR(nsDisplayButtonBorderBackground);
   1.111 +  }
   1.112 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.113 +  virtual ~nsDisplayButtonBorderBackground() {
   1.114 +    MOZ_COUNT_DTOR(nsDisplayButtonBorderBackground);
   1.115 +  }
   1.116 +#endif  
   1.117 +  
   1.118 +  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   1.119 +                       HitTestState* aState,
   1.120 +                       nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
   1.121 +    aOutFrames->AppendElement(mFrame);
   1.122 +  }
   1.123 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.124 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.125 +  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
   1.126 +                           bool* aSnap) MOZ_OVERRIDE;
   1.127 +  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.128 +                                         const nsDisplayItemGeometry* aGeometry,
   1.129 +                                         nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   1.130 +  NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
   1.131 +private:
   1.132 +  nsButtonFrameRenderer* mBFR;
   1.133 +};
   1.134 +
   1.135 +nsRect
   1.136 +nsDisplayButtonBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   1.137 +  *aSnap = false;
   1.138 +  return aBuilder->IsForEventDelivery() ? nsRect(ToReferenceFrame(), mFrame->GetSize())
   1.139 +          : mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
   1.140 +}
   1.141 +
   1.142 +class nsDisplayButtonForeground : public nsDisplayItem {
   1.143 +public:
   1.144 +  nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,
   1.145 +                            nsButtonFrameRenderer* aRenderer)
   1.146 +    : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
   1.147 +    MOZ_COUNT_CTOR(nsDisplayButtonForeground);
   1.148 +  }
   1.149 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.150 +  virtual ~nsDisplayButtonForeground() {
   1.151 +    MOZ_COUNT_DTOR(nsDisplayButtonForeground);
   1.152 +  }
   1.153 +#endif  
   1.154 +
   1.155 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.156 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.157 +  NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
   1.158 +private:
   1.159 +  nsButtonFrameRenderer* mBFR;
   1.160 +};
   1.161 +
   1.162 +void
   1.163 +nsDisplayButtonBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.164 +                                                           const nsDisplayItemGeometry* aGeometry,
   1.165 +                                                           nsRegion *aInvalidRegion)
   1.166 +{
   1.167 +  AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
   1.168 +
   1.169 +  nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   1.170 +}
   1.171 +
   1.172 +void nsDisplayButtonBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
   1.173 +                                            nsRenderingContext* aCtx)
   1.174 +{
   1.175 +  NS_ASSERTION(mFrame, "No frame?");
   1.176 +  nsPresContext* pc = mFrame->PresContext();
   1.177 +  nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
   1.178 +  
   1.179 +  // draw the border and background inside the focus and outline borders
   1.180 +  mBFR->PaintBorderAndBackground(pc, *aCtx, mVisibleRect, r,
   1.181 +                                 aBuilder->GetBackgroundPaintFlags());
   1.182 +}
   1.183 +
   1.184 +void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
   1.185 +                                      nsRenderingContext* aCtx)
   1.186 +{
   1.187 +  nsPresContext *presContext = mFrame->PresContext();
   1.188 +  const nsStyleDisplay *disp = mFrame->StyleDisplay();
   1.189 +  if (!mFrame->IsThemed(disp) ||
   1.190 +      !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
   1.191 +    // draw the focus and outline borders
   1.192 +    nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
   1.193 +    mBFR->PaintOutlineAndFocusBorders(presContext, *aCtx, mVisibleRect, r);
   1.194 +  }
   1.195 +}
   1.196 +
   1.197 +nsresult
   1.198 +nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
   1.199 +                                     nsDisplayList* aBackground,
   1.200 +                                     nsDisplayList* aForeground)
   1.201 +{
   1.202 +  if (mFrame->StyleBorder()->mBoxShadow) {
   1.203 +    aBackground->AppendNewToTop(new (aBuilder)
   1.204 +      nsDisplayButtonBoxShadowOuter(aBuilder, this));
   1.205 +  }
   1.206 +
   1.207 +  // Almost all buttons draw some kind of background so there's not much
   1.208 +  // point in checking whether we should create this item.
   1.209 +  aBackground->AppendNewToTop(new (aBuilder)
   1.210 +    nsDisplayButtonBorderBackground(aBuilder, this));
   1.211 +
   1.212 +  // Only display focus rings if we actually have them. Since at most one
   1.213 +  // button would normally display a focus ring, most buttons won't have them.
   1.214 +  if ((mOuterFocusStyle && mOuterFocusStyle->StyleBorder()->HasBorder()) ||
   1.215 +      (mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder())) {
   1.216 +    aForeground->AppendNewToTop(new (aBuilder)
   1.217 +      nsDisplayButtonForeground(aBuilder, this));
   1.218 +  }
   1.219 +  return NS_OK;
   1.220 +}
   1.221 +
   1.222 +void
   1.223 +nsButtonFrameRenderer::PaintOutlineAndFocusBorders(nsPresContext* aPresContext,
   1.224 +          nsRenderingContext& aRenderingContext,
   1.225 +          const nsRect& aDirtyRect,
   1.226 +          const nsRect& aRect)
   1.227 +{
   1.228 +  // once we have all that we'll draw the focus if we have it. We will
   1.229 +  // need to draw 2 focuses, the inner and the outer. This is so we
   1.230 +  // can do any kind of look and feel. Some buttons have focus on the
   1.231 +  // outside like mac and motif. While others like windows have it
   1.232 +  // inside (dotted line).  Usually only one will be specifed. But I
   1.233 +  // guess you could have both if you wanted to.
   1.234 +
   1.235 +  nsRect rect;
   1.236 +
   1.237 +  if (mOuterFocusStyle) {
   1.238 +    // ---------- paint the outer focus border -------------
   1.239 +
   1.240 +    GetButtonOuterFocusRect(aRect, rect);
   1.241 +
   1.242 +    nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   1.243 +                                aDirtyRect, rect, mOuterFocusStyle);
   1.244 +  }
   1.245 +
   1.246 +  if (mInnerFocusStyle) { 
   1.247 +    // ---------- paint the inner focus border -------------
   1.248 +
   1.249 +    GetButtonInnerFocusRect(aRect, rect);
   1.250 +
   1.251 +    nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   1.252 +                                aDirtyRect, rect, mInnerFocusStyle);
   1.253 +  }
   1.254 +}
   1.255 +
   1.256 +
   1.257 +void
   1.258 +nsButtonFrameRenderer::PaintBorderAndBackground(nsPresContext* aPresContext,
   1.259 +          nsRenderingContext& aRenderingContext,
   1.260 +          const nsRect& aDirtyRect,
   1.261 +          const nsRect& aRect,
   1.262 +          uint32_t aBGFlags)
   1.263 +
   1.264 +{
   1.265 +  // get the button rect this is inside the focus and outline rects
   1.266 +  nsRect buttonRect;
   1.267 +  GetButtonRect(aRect, buttonRect);
   1.268 +
   1.269 +  nsStyleContext* context = mFrame->StyleContext();
   1.270 +
   1.271 +  nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, mFrame,
   1.272 +                                  aDirtyRect, buttonRect, aBGFlags);
   1.273 +  nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext,
   1.274 +                                      mFrame, buttonRect, aDirtyRect);
   1.275 +  nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   1.276 +                              aDirtyRect, buttonRect, context);
   1.277 +}
   1.278 +
   1.279 +
   1.280 +void
   1.281 +nsButtonFrameRenderer::GetButtonOuterFocusRect(const nsRect& aRect, nsRect& focusRect)
   1.282 +{
   1.283 +  focusRect = aRect;
   1.284 +}
   1.285 +
   1.286 +void
   1.287 +nsButtonFrameRenderer::GetButtonRect(const nsRect& aRect, nsRect& r)
   1.288 +{
   1.289 +  r = aRect;
   1.290 +  r.Deflate(GetButtonOuterFocusBorderAndPadding());
   1.291 +}
   1.292 +
   1.293 +
   1.294 +void
   1.295 +nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect, nsRect& focusRect)
   1.296 +{
   1.297 +  GetButtonRect(aRect, focusRect);
   1.298 +  focusRect.Deflate(GetButtonBorderAndPadding());
   1.299 +  focusRect.Deflate(GetButtonInnerFocusMargin());
   1.300 +}
   1.301 +
   1.302 +
   1.303 +nsMargin
   1.304 +nsButtonFrameRenderer::GetButtonOuterFocusBorderAndPadding()
   1.305 +{
   1.306 +  nsMargin result(0,0,0,0);
   1.307 +
   1.308 +  if (mOuterFocusStyle) {
   1.309 +    if (!mOuterFocusStyle->StylePadding()->GetPadding(result)) {
   1.310 +      NS_NOTYETIMPLEMENTED("percentage padding");
   1.311 +    }
   1.312 +    result += mOuterFocusStyle->StyleBorder()->GetComputedBorder();
   1.313 +  }
   1.314 +
   1.315 +  return result;
   1.316 +}
   1.317 +
   1.318 +nsMargin
   1.319 +nsButtonFrameRenderer::GetButtonBorderAndPadding()
   1.320 +{
   1.321 +  return mFrame->GetUsedBorderAndPadding();
   1.322 +}
   1.323 +
   1.324 +/**
   1.325 + * Gets the size of the buttons border this is the union of the normal and disabled borders.
   1.326 + */
   1.327 +nsMargin
   1.328 +nsButtonFrameRenderer::GetButtonInnerFocusMargin()
   1.329 +{
   1.330 +  nsMargin innerFocusMargin(0,0,0,0);
   1.331 +
   1.332 +  if (mInnerFocusStyle) {
   1.333 +    const nsStyleMargin* margin = mInnerFocusStyle->StyleMargin();
   1.334 +    if (!margin->GetMargin(innerFocusMargin)) {
   1.335 +      NS_NOTYETIMPLEMENTED("percentage margin");
   1.336 +    }
   1.337 +  }
   1.338 +
   1.339 +  return innerFocusMargin;
   1.340 +}
   1.341 +
   1.342 +nsMargin
   1.343 +nsButtonFrameRenderer::GetButtonInnerFocusBorderAndPadding()
   1.344 +{
   1.345 +  nsMargin result(0,0,0,0);
   1.346 +
   1.347 +  if (mInnerFocusStyle) {
   1.348 +    if (!mInnerFocusStyle->StylePadding()->GetPadding(result)) {
   1.349 +      NS_NOTYETIMPLEMENTED("percentage padding");
   1.350 +    }
   1.351 +    result += mInnerFocusStyle->StyleBorder()->GetComputedBorder();
   1.352 +  }
   1.353 +
   1.354 +  return result;
   1.355 +}
   1.356 +
   1.357 +// gets all the focus borders and padding that will be added to the regular border
   1.358 +nsMargin
   1.359 +nsButtonFrameRenderer::GetAddedButtonBorderAndPadding()
   1.360 +{
   1.361 +  return GetButtonOuterFocusBorderAndPadding() + GetButtonInnerFocusMargin() + GetButtonInnerFocusBorderAndPadding();
   1.362 +}
   1.363 +
   1.364 +/**
   1.365 + * Call this when styles change
   1.366 + */
   1.367 +void
   1.368 +nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext)
   1.369 +{
   1.370 +  // get all the styles
   1.371 +  nsStyleContext* context = mFrame->StyleContext();
   1.372 +  nsStyleSet *styleSet = aPresContext->StyleSet();
   1.373 +
   1.374 +  // style for the inner such as a dotted line (Windows)
   1.375 +  mInnerFocusStyle =
   1.376 +    styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
   1.377 +                                      nsCSSPseudoElements::ePseudo_mozFocusInner,
   1.378 +                                      context);
   1.379 +
   1.380 +  // style for outer focus like a ridged border (MAC).
   1.381 +  mOuterFocusStyle =
   1.382 +    styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
   1.383 +                                      nsCSSPseudoElements::ePseudo_mozFocusOuter,
   1.384 +                                      context);
   1.385 +}
   1.386 +
   1.387 +nsStyleContext*
   1.388 +nsButtonFrameRenderer::GetStyleContext(int32_t aIndex) const
   1.389 +{
   1.390 +  switch (aIndex) {
   1.391 +  case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
   1.392 +    return mInnerFocusStyle;
   1.393 +  case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
   1.394 +    return mOuterFocusStyle;
   1.395 +  default:
   1.396 +    return nullptr;
   1.397 +  }
   1.398 +}
   1.399 +
   1.400 +void 
   1.401 +nsButtonFrameRenderer::SetStyleContext(int32_t aIndex, nsStyleContext* aStyleContext)
   1.402 +{
   1.403 +  switch (aIndex) {
   1.404 +  case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
   1.405 +    mInnerFocusStyle = aStyleContext;
   1.406 +    break;
   1.407 +  case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
   1.408 +    mOuterFocusStyle = aStyleContext;
   1.409 +    break;
   1.410 +  }
   1.411 +}

mercurial