layout/forms/nsButtonFrameRenderer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsButtonFrameRenderer.h"
     6 #include "nsCSSRendering.h"
     7 #include "nsPresContext.h"
     8 #include "nsGkAtoms.h"
     9 #include "nsCSSPseudoElements.h"
    10 #include "nsNameSpaceManager.h"
    11 #include "nsStyleSet.h"
    12 #include "nsDisplayList.h"
    13 #include "nsITheme.h"
    14 #include "nsFrame.h"
    15 #include "mozilla/EventStates.h"
    16 #include "mozilla/dom/Element.h"
    18 #define ACTIVE   "active"
    19 #define HOVER    "hover"
    20 #define FOCUS    "focus"
    22 nsButtonFrameRenderer::nsButtonFrameRenderer()
    23 {
    24   MOZ_COUNT_CTOR(nsButtonFrameRenderer);
    25 }
    27 nsButtonFrameRenderer::~nsButtonFrameRenderer()
    28 {
    29   MOZ_COUNT_DTOR(nsButtonFrameRenderer);
    30 }
    32 void
    33 nsButtonFrameRenderer::SetFrame(nsFrame* aFrame, nsPresContext* aPresContext)
    34 {
    35   mFrame = aFrame;
    36   ReResolveStyles(aPresContext);
    37 }
    39 nsIFrame*
    40 nsButtonFrameRenderer::GetFrame()
    41 {
    42   return mFrame;
    43 }
    45 void
    46 nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool notify)
    47 {
    48   if (aDisabled)
    49     mFrame->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
    50                                   notify);
    51   else
    52     mFrame->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, notify);
    53 }
    55 bool
    56 nsButtonFrameRenderer::isDisabled() 
    57 {
    58   return mFrame->GetContent()->AsElement()->
    59     State().HasState(NS_EVENT_STATE_DISABLED);
    60 }
    62 class nsDisplayButtonBoxShadowOuter : public nsDisplayItem {
    63 public:
    64   nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
    65                                 nsButtonFrameRenderer* aRenderer)
    66     : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
    67     MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
    68   }
    69 #ifdef NS_BUILD_REFCNT_LOGGING
    70   virtual ~nsDisplayButtonBoxShadowOuter() {
    71     MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
    72   }
    73 #endif  
    75   virtual void Paint(nsDisplayListBuilder* aBuilder,
    76                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
    77   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
    78                            bool* aSnap) MOZ_OVERRIDE;
    79   NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
    80 private:
    81   nsButtonFrameRenderer* mBFR;
    82 };
    84 nsRect
    85 nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
    86   *aSnap = false;
    87   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
    88 }
    90 void
    91 nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
    92                                      nsRenderingContext* aCtx) {
    93   nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
    95   nsRect buttonRect;
    96   mBFR->GetButtonRect(frameRect, buttonRect);
    98   nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
    99                                       buttonRect, mVisibleRect);
   100 }
   102 class nsDisplayButtonBorderBackground : public nsDisplayItem {
   103 public:
   104   nsDisplayButtonBorderBackground(nsDisplayListBuilder* aBuilder,
   105                                   nsButtonFrameRenderer* aRenderer)
   106     : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
   107     MOZ_COUNT_CTOR(nsDisplayButtonBorderBackground);
   108   }
   109 #ifdef NS_BUILD_REFCNT_LOGGING
   110   virtual ~nsDisplayButtonBorderBackground() {
   111     MOZ_COUNT_DTOR(nsDisplayButtonBorderBackground);
   112   }
   113 #endif  
   115   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   116                        HitTestState* aState,
   117                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
   118     aOutFrames->AppendElement(mFrame);
   119   }
   120   virtual void Paint(nsDisplayListBuilder* aBuilder,
   121                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   122   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
   123                            bool* aSnap) MOZ_OVERRIDE;
   124   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   125                                          const nsDisplayItemGeometry* aGeometry,
   126                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   127   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
   128 private:
   129   nsButtonFrameRenderer* mBFR;
   130 };
   132 nsRect
   133 nsDisplayButtonBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   134   *aSnap = false;
   135   return aBuilder->IsForEventDelivery() ? nsRect(ToReferenceFrame(), mFrame->GetSize())
   136           : mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
   137 }
   139 class nsDisplayButtonForeground : public nsDisplayItem {
   140 public:
   141   nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,
   142                             nsButtonFrameRenderer* aRenderer)
   143     : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
   144     MOZ_COUNT_CTOR(nsDisplayButtonForeground);
   145   }
   146 #ifdef NS_BUILD_REFCNT_LOGGING
   147   virtual ~nsDisplayButtonForeground() {
   148     MOZ_COUNT_DTOR(nsDisplayButtonForeground);
   149   }
   150 #endif  
   152   virtual void Paint(nsDisplayListBuilder* aBuilder,
   153                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   154   NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
   155 private:
   156   nsButtonFrameRenderer* mBFR;
   157 };
   159 void
   160 nsDisplayButtonBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   161                                                            const nsDisplayItemGeometry* aGeometry,
   162                                                            nsRegion *aInvalidRegion)
   163 {
   164   AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
   166   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   167 }
   169 void nsDisplayButtonBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
   170                                             nsRenderingContext* aCtx)
   171 {
   172   NS_ASSERTION(mFrame, "No frame?");
   173   nsPresContext* pc = mFrame->PresContext();
   174   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
   176   // draw the border and background inside the focus and outline borders
   177   mBFR->PaintBorderAndBackground(pc, *aCtx, mVisibleRect, r,
   178                                  aBuilder->GetBackgroundPaintFlags());
   179 }
   181 void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
   182                                       nsRenderingContext* aCtx)
   183 {
   184   nsPresContext *presContext = mFrame->PresContext();
   185   const nsStyleDisplay *disp = mFrame->StyleDisplay();
   186   if (!mFrame->IsThemed(disp) ||
   187       !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
   188     // draw the focus and outline borders
   189     nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
   190     mBFR->PaintOutlineAndFocusBorders(presContext, *aCtx, mVisibleRect, r);
   191   }
   192 }
   194 nsresult
   195 nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
   196                                      nsDisplayList* aBackground,
   197                                      nsDisplayList* aForeground)
   198 {
   199   if (mFrame->StyleBorder()->mBoxShadow) {
   200     aBackground->AppendNewToTop(new (aBuilder)
   201       nsDisplayButtonBoxShadowOuter(aBuilder, this));
   202   }
   204   // Almost all buttons draw some kind of background so there's not much
   205   // point in checking whether we should create this item.
   206   aBackground->AppendNewToTop(new (aBuilder)
   207     nsDisplayButtonBorderBackground(aBuilder, this));
   209   // Only display focus rings if we actually have them. Since at most one
   210   // button would normally display a focus ring, most buttons won't have them.
   211   if ((mOuterFocusStyle && mOuterFocusStyle->StyleBorder()->HasBorder()) ||
   212       (mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder())) {
   213     aForeground->AppendNewToTop(new (aBuilder)
   214       nsDisplayButtonForeground(aBuilder, this));
   215   }
   216   return NS_OK;
   217 }
   219 void
   220 nsButtonFrameRenderer::PaintOutlineAndFocusBorders(nsPresContext* aPresContext,
   221           nsRenderingContext& aRenderingContext,
   222           const nsRect& aDirtyRect,
   223           const nsRect& aRect)
   224 {
   225   // once we have all that we'll draw the focus if we have it. We will
   226   // need to draw 2 focuses, the inner and the outer. This is so we
   227   // can do any kind of look and feel. Some buttons have focus on the
   228   // outside like mac and motif. While others like windows have it
   229   // inside (dotted line).  Usually only one will be specifed. But I
   230   // guess you could have both if you wanted to.
   232   nsRect rect;
   234   if (mOuterFocusStyle) {
   235     // ---------- paint the outer focus border -------------
   237     GetButtonOuterFocusRect(aRect, rect);
   239     nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   240                                 aDirtyRect, rect, mOuterFocusStyle);
   241   }
   243   if (mInnerFocusStyle) { 
   244     // ---------- paint the inner focus border -------------
   246     GetButtonInnerFocusRect(aRect, rect);
   248     nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   249                                 aDirtyRect, rect, mInnerFocusStyle);
   250   }
   251 }
   254 void
   255 nsButtonFrameRenderer::PaintBorderAndBackground(nsPresContext* aPresContext,
   256           nsRenderingContext& aRenderingContext,
   257           const nsRect& aDirtyRect,
   258           const nsRect& aRect,
   259           uint32_t aBGFlags)
   261 {
   262   // get the button rect this is inside the focus and outline rects
   263   nsRect buttonRect;
   264   GetButtonRect(aRect, buttonRect);
   266   nsStyleContext* context = mFrame->StyleContext();
   268   nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, mFrame,
   269                                   aDirtyRect, buttonRect, aBGFlags);
   270   nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext,
   271                                       mFrame, buttonRect, aDirtyRect);
   272   nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
   273                               aDirtyRect, buttonRect, context);
   274 }
   277 void
   278 nsButtonFrameRenderer::GetButtonOuterFocusRect(const nsRect& aRect, nsRect& focusRect)
   279 {
   280   focusRect = aRect;
   281 }
   283 void
   284 nsButtonFrameRenderer::GetButtonRect(const nsRect& aRect, nsRect& r)
   285 {
   286   r = aRect;
   287   r.Deflate(GetButtonOuterFocusBorderAndPadding());
   288 }
   291 void
   292 nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect, nsRect& focusRect)
   293 {
   294   GetButtonRect(aRect, focusRect);
   295   focusRect.Deflate(GetButtonBorderAndPadding());
   296   focusRect.Deflate(GetButtonInnerFocusMargin());
   297 }
   300 nsMargin
   301 nsButtonFrameRenderer::GetButtonOuterFocusBorderAndPadding()
   302 {
   303   nsMargin result(0,0,0,0);
   305   if (mOuterFocusStyle) {
   306     if (!mOuterFocusStyle->StylePadding()->GetPadding(result)) {
   307       NS_NOTYETIMPLEMENTED("percentage padding");
   308     }
   309     result += mOuterFocusStyle->StyleBorder()->GetComputedBorder();
   310   }
   312   return result;
   313 }
   315 nsMargin
   316 nsButtonFrameRenderer::GetButtonBorderAndPadding()
   317 {
   318   return mFrame->GetUsedBorderAndPadding();
   319 }
   321 /**
   322  * Gets the size of the buttons border this is the union of the normal and disabled borders.
   323  */
   324 nsMargin
   325 nsButtonFrameRenderer::GetButtonInnerFocusMargin()
   326 {
   327   nsMargin innerFocusMargin(0,0,0,0);
   329   if (mInnerFocusStyle) {
   330     const nsStyleMargin* margin = mInnerFocusStyle->StyleMargin();
   331     if (!margin->GetMargin(innerFocusMargin)) {
   332       NS_NOTYETIMPLEMENTED("percentage margin");
   333     }
   334   }
   336   return innerFocusMargin;
   337 }
   339 nsMargin
   340 nsButtonFrameRenderer::GetButtonInnerFocusBorderAndPadding()
   341 {
   342   nsMargin result(0,0,0,0);
   344   if (mInnerFocusStyle) {
   345     if (!mInnerFocusStyle->StylePadding()->GetPadding(result)) {
   346       NS_NOTYETIMPLEMENTED("percentage padding");
   347     }
   348     result += mInnerFocusStyle->StyleBorder()->GetComputedBorder();
   349   }
   351   return result;
   352 }
   354 // gets all the focus borders and padding that will be added to the regular border
   355 nsMargin
   356 nsButtonFrameRenderer::GetAddedButtonBorderAndPadding()
   357 {
   358   return GetButtonOuterFocusBorderAndPadding() + GetButtonInnerFocusMargin() + GetButtonInnerFocusBorderAndPadding();
   359 }
   361 /**
   362  * Call this when styles change
   363  */
   364 void
   365 nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext)
   366 {
   367   // get all the styles
   368   nsStyleContext* context = mFrame->StyleContext();
   369   nsStyleSet *styleSet = aPresContext->StyleSet();
   371   // style for the inner such as a dotted line (Windows)
   372   mInnerFocusStyle =
   373     styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
   374                                       nsCSSPseudoElements::ePseudo_mozFocusInner,
   375                                       context);
   377   // style for outer focus like a ridged border (MAC).
   378   mOuterFocusStyle =
   379     styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
   380                                       nsCSSPseudoElements::ePseudo_mozFocusOuter,
   381                                       context);
   382 }
   384 nsStyleContext*
   385 nsButtonFrameRenderer::GetStyleContext(int32_t aIndex) const
   386 {
   387   switch (aIndex) {
   388   case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
   389     return mInnerFocusStyle;
   390   case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
   391     return mOuterFocusStyle;
   392   default:
   393     return nullptr;
   394   }
   395 }
   397 void 
   398 nsButtonFrameRenderer::SetStyleContext(int32_t aIndex, nsStyleContext* aStyleContext)
   399 {
   400   switch (aIndex) {
   401   case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
   402     mInnerFocusStyle = aStyleContext;
   403     break;
   404   case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
   405     mOuterFocusStyle = aStyleContext;
   406     break;
   407   }
   408 }

mercurial