layout/forms/nsHTMLButtonControlFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #include "nsHTMLButtonControlFrame.h"
     8 #include "nsContainerFrame.h"
     9 #include "nsIFormControlFrame.h"
    10 #include "nsPresContext.h"
    11 #include "nsGkAtoms.h"
    12 #include "nsButtonFrameRenderer.h"
    13 #include "nsCSSAnonBoxes.h"
    14 #include "nsFormControlFrame.h"
    15 #include "nsNameSpaceManager.h"
    16 #include "nsStyleSet.h"
    17 #include "nsDisplayList.h"
    18 #include <algorithm>
    20 using namespace mozilla;
    22 nsIFrame*
    23 NS_NewHTMLButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    24 {
    25   return new (aPresShell) nsHTMLButtonControlFrame(aContext);
    26 }
    28 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLButtonControlFrame)
    30 nsHTMLButtonControlFrame::nsHTMLButtonControlFrame(nsStyleContext* aContext)
    31   : nsContainerFrame(aContext)
    32 {
    33 }
    35 nsHTMLButtonControlFrame::~nsHTMLButtonControlFrame()
    36 {
    37 }
    39 void
    40 nsHTMLButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
    41 {
    42   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
    43   nsContainerFrame::DestroyFrom(aDestructRoot);
    44 }
    46 void
    47 nsHTMLButtonControlFrame::Init(
    48               nsIContent*      aContent,
    49               nsIFrame*        aParent,
    50               nsIFrame*        aPrevInFlow)
    51 {
    52   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    53   mRenderer.SetFrame(this, PresContext());
    54 }
    56 NS_QUERYFRAME_HEAD(nsHTMLButtonControlFrame)
    57   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
    58 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    60 #ifdef ACCESSIBILITY
    61 a11y::AccType
    62 nsHTMLButtonControlFrame::AccessibleType()
    63 {
    64   return a11y::eHTMLButtonType;
    65 }
    66 #endif
    68 nsIAtom*
    69 nsHTMLButtonControlFrame::GetType() const
    70 {
    71   return nsGkAtoms::HTMLButtonControlFrame;
    72 }
    74 void 
    75 nsHTMLButtonControlFrame::SetFocus(bool aOn, bool aRepaint)
    76 {
    77 }
    79 nsresult
    80 nsHTMLButtonControlFrame::HandleEvent(nsPresContext* aPresContext, 
    81                                       WidgetGUIEvent* aEvent,
    82                                       nsEventStatus* aEventStatus)
    83 {
    84   // if disabled do nothing
    85   if (mRenderer.isDisabled()) {
    86     return NS_OK;
    87   }
    89   // mouse clicks are handled by content
    90   // we don't want our children to get any events. So just pass it to frame.
    91   return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    92 }
    95 void
    96 nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    97                                            const nsRect&           aDirtyRect,
    98                                            const nsDisplayListSet& aLists)
    99 {
   100   nsDisplayList onTop;
   101   if (IsVisibleForPainting(aBuilder)) {
   102     mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop);
   103   }
   105   nsDisplayListCollection set;
   107   // Do not allow the child subtree to receive events.
   108   if (!aBuilder->IsForEventDelivery()) {
   109     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
   111     if (IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE) {
   112       nsMargin border = StyleBorder()->GetComputedBorder();
   113       nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
   114       rect.Deflate(border);
   115       nscoord radii[8];
   116       bool hasRadii = GetPaddingBoxBorderRadii(radii);
   117       clipState.ClipContainingBlockDescendants(rect, hasRadii ? radii : nullptr);
   118     }
   120     BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), aDirtyRect, set,
   121                              DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
   122     // That should put the display items in set.Content()
   123   }
   125   // Put the foreground outline and focus rects on top of the children
   126   set.Content()->AppendToTop(&onTop);
   127   set.MoveTo(aLists);
   129   DisplayOutline(aBuilder, aLists);
   131   // to draw border when selected in editor
   132   DisplaySelectionOverlay(aBuilder, aLists.Content());
   133 }
   135 nscoord
   136 nsHTMLButtonControlFrame::GetMinWidth(nsRenderingContext* aRenderingContext)
   137 {
   138   nscoord result;
   139   DISPLAY_MIN_WIDTH(this, result);
   141   nsIFrame* kid = mFrames.FirstChild();
   142   result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
   143                                                 kid,
   144                                                 nsLayoutUtils::MIN_WIDTH);
   146   result += mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
   148   return result;
   149 }
   151 nscoord
   152 nsHTMLButtonControlFrame::GetPrefWidth(nsRenderingContext* aRenderingContext)
   153 {
   154   nscoord result;
   155   DISPLAY_PREF_WIDTH(this, result);
   157   nsIFrame* kid = mFrames.FirstChild();
   158   result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
   159                                                 kid,
   160                                                 nsLayoutUtils::PREF_WIDTH);
   161   result += mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
   162   return result;
   163 }
   165 nsresult 
   166 nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
   167                                nsHTMLReflowMetrics& aDesiredSize,
   168                                const nsHTMLReflowState& aReflowState,
   169                                nsReflowStatus& aStatus)
   170 {
   171   DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame");
   172   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   174   NS_PRECONDITION(aReflowState.ComputedWidth() != NS_INTRINSICSIZE,
   175                   "Should have real computed width by now");
   177   if (mState & NS_FRAME_FIRST_REFLOW) {
   178     nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
   179   }
   181   // Reflow the child
   182   nsIFrame* firstKid = mFrames.FirstChild();
   184   MOZ_ASSERT(firstKid, "Button should have a child frame for its contents");
   185   MOZ_ASSERT(!firstKid->GetNextSibling(),
   186              "Button should have exactly one child frame");
   187   MOZ_ASSERT(firstKid->StyleContext()->GetPseudo() ==
   188              nsCSSAnonBoxes::buttonContent,
   189              "Button's child frame has unexpected pseudo type!");
   191   // XXXbz Eventually we may want to check-and-bail if
   192   // !aReflowState.ShouldReflowAllKids() &&
   193   // !NS_SUBTREE_DIRTY(firstKid).
   194   // We'd need to cache our ascent for that, of course.
   196   // Reflow the contents of the button.
   197   // (This populates our aDesiredSize, too.)
   198   ReflowButtonContents(aPresContext, aDesiredSize,
   199                        aReflowState, firstKid);
   201   ConsiderChildOverflow(aDesiredSize.mOverflowAreas, firstKid);
   203   aStatus = NS_FRAME_COMPLETE;
   204   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
   205                                  aReflowState, aStatus);
   207   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   208   return NS_OK;
   209 }
   211 // Helper-function that lets us clone the button's reflow state, but with its
   212 // ComputedWidth and ComputedHeight reduced by the amount of renderer-specific
   213 // focus border and padding that we're using. (This lets us provide a more
   214 // appropriate content-box size for descendents' percent sizes to resolve
   215 // against.)
   216 static nsHTMLReflowState
   217 CloneReflowStateWithReducedContentBox(
   218   const nsHTMLReflowState& aButtonReflowState,
   219   const nsMargin& aFocusPadding)
   220 {
   221   nscoord adjustedWidth =
   222     aButtonReflowState.ComputedWidth() - aFocusPadding.LeftRight();
   223   adjustedWidth = std::max(0, adjustedWidth);
   225   // (Only adjust height if it's an actual length.)
   226   nscoord adjustedHeight = aButtonReflowState.ComputedHeight();
   227   if (adjustedHeight != NS_INTRINSICSIZE) {
   228     adjustedHeight -= aFocusPadding.TopBottom();
   229     adjustedHeight = std::max(0, adjustedHeight);
   230   }
   232   nsHTMLReflowState clone(aButtonReflowState);
   233   clone.SetComputedWidth(adjustedWidth);
   234   clone.SetComputedHeight(adjustedHeight);
   236   return clone;
   237 }
   239 void
   240 nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
   241                                                nsHTMLReflowMetrics& aButtonDesiredSize,
   242                                                const nsHTMLReflowState& aButtonReflowState,
   243                                                nsIFrame* aFirstKid)
   244 {
   245   // Buttons have some bonus renderer-determined border/padding,
   246   // which occupies part of the button's content-box area:
   247   const nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding();
   249   nsSize availSize(aButtonReflowState.ComputedWidth(), NS_INTRINSICSIZE);
   251   // Indent the child inside us by the focus border. We must do this separate
   252   // from the regular border.
   253   availSize.width -= focusPadding.LeftRight();
   255   // See whether out availSize's width is big enough.  If it's smaller than our
   256   // intrinsic min width, that means that the kid wouldn't really fit; for a
   257   // better look in such cases we adjust the available width and our left
   258   // offset to allow the kid to spill left into our padding.
   259   nscoord xoffset = focusPadding.left +
   260     aButtonReflowState.ComputedPhysicalBorderPadding().left;
   261   nscoord extrawidth = GetMinWidth(aButtonReflowState.rendContext) -
   262     aButtonReflowState.ComputedWidth();
   263   if (extrawidth > 0) {
   264     nscoord extraleft = extrawidth / 2;
   265     nscoord extraright = extrawidth - extraleft;
   266     NS_ASSERTION(extraright >=0, "How'd that happen?");
   268     // Do not allow the extras to be bigger than the relevant padding
   269     extraleft = std::min(extraleft, aButtonReflowState.ComputedPhysicalPadding().left);
   270     extraright = std::min(extraright, aButtonReflowState.ComputedPhysicalPadding().right);
   271     xoffset -= extraleft;
   272     availSize.width += extraleft + extraright;
   273   }
   274   availSize.width = std::max(availSize.width,0);
   276   // Give child a clone of the button's reflow state, with height/width reduced
   277   // by focusPadding, so that descendants with height:100% don't protrude.
   278   nsHTMLReflowState adjustedButtonReflowState =
   279     CloneReflowStateWithReducedContentBox(aButtonReflowState, focusPadding);
   281   nsHTMLReflowState contentsReflowState(aPresContext,
   282                                         adjustedButtonReflowState,
   283                                         aFirstKid, availSize);
   285   nsReflowStatus contentsReflowStatus;
   286   nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState);
   287   ReflowChild(aFirstKid, aPresContext,
   288               contentsDesiredSize, contentsReflowState,
   289               xoffset,
   290               focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top,
   291               0, contentsReflowStatus);
   292   MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
   293              "We gave button-contents frame unconstrained available height, "
   294              "so it should be complete");
   296   // Compute the button's content-box height:
   297   nscoord buttonContentBoxHeight = 0;
   298   if (aButtonReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
   299     // Button has a fixed height -- that's its content-box height.
   300     buttonContentBoxHeight = aButtonReflowState.ComputedHeight();
   301   } else {
   302     // Button is intrinsically sized -- it should shrinkwrap the
   303     // button-contents' height, plus any focus-padding space:
   304     buttonContentBoxHeight =
   305       contentsDesiredSize.Height() + focusPadding.TopBottom();
   307     // Make sure we obey min/max-height in the case when we're doing intrinsic
   308     // sizing (we get it for free when we have a non-intrinsic
   309     // aButtonReflowState.ComputedHeight()).  Note that we do this before
   310     // adjusting for borderpadding, since mComputedMaxHeight and
   311     // mComputedMinHeight are content heights.
   312     buttonContentBoxHeight =
   313       NS_CSS_MINMAX(buttonContentBoxHeight,
   314                     aButtonReflowState.ComputedMinHeight(),
   315                     aButtonReflowState.ComputedMaxHeight());
   316   }
   318   // Center child vertically in the button
   319   // (technically, inside of the button's focus-padding area)
   320   nscoord extraSpace =
   321     buttonContentBoxHeight - focusPadding.TopBottom() -
   322     contentsDesiredSize.Height();
   324   nscoord yoffset = std::max(0, extraSpace / 2);
   326   // Adjust yoffset to be in terms of the button's frame-rect, instead of
   327   // its focus-padding rect:
   328   yoffset += focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top;
   330   // Place the child
   331   FinishReflowChild(aFirstKid, aPresContext,
   332                     contentsDesiredSize, &contentsReflowState,
   333                     xoffset, yoffset, 0);
   335   // Make sure we have a useful 'ascent' value for the child
   336   if (contentsDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
   337     contentsDesiredSize.SetTopAscent(aFirstKid->GetBaseline());
   338   }
   340   // OK, we're done with the child frame.
   341   // Use what we learned to populate the button frame's reflow metrics.
   342   //  * Button's height & width are content-box size + border-box contribution:
   343   aButtonDesiredSize.Width() = aButtonReflowState.ComputedWidth() +
   344     aButtonReflowState.ComputedPhysicalBorderPadding().LeftRight();
   346   aButtonDesiredSize.Height() = buttonContentBoxHeight +
   347     aButtonReflowState.ComputedPhysicalBorderPadding().TopBottom();
   349   //  * Button's ascent is its child's ascent, plus the child's y-offset
   350   // within our frame:
   351   aButtonDesiredSize.SetTopAscent(contentsDesiredSize.TopAscent() + yoffset);
   353   aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
   354 }
   356 nsresult nsHTMLButtonControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
   357 {
   358   if (nsGkAtoms::value == aName) {
   359     return mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
   360                              aValue, true);
   361   }
   362   return NS_OK;
   363 }
   365 nsStyleContext*
   366 nsHTMLButtonControlFrame::GetAdditionalStyleContext(int32_t aIndex) const
   367 {
   368   return mRenderer.GetStyleContext(aIndex);
   369 }
   371 void
   372 nsHTMLButtonControlFrame::SetAdditionalStyleContext(int32_t aIndex, 
   373                                                     nsStyleContext* aStyleContext)
   374 {
   375   mRenderer.SetStyleContext(aIndex, aStyleContext);
   376 }
   378 nsresult 
   379 nsHTMLButtonControlFrame::AppendFrames(ChildListID     aListID,
   380                                        nsFrameList&    aFrameList)
   381 {
   382   NS_NOTREACHED("unsupported operation");
   383   return NS_ERROR_UNEXPECTED;
   384 }
   386 nsresult
   387 nsHTMLButtonControlFrame::InsertFrames(ChildListID     aListID,
   388                                        nsIFrame*       aPrevFrame,
   389                                        nsFrameList&    aFrameList)
   390 {
   391   NS_NOTREACHED("unsupported operation");
   392   return NS_ERROR_UNEXPECTED;
   393 }
   395 nsresult
   396 nsHTMLButtonControlFrame::RemoveFrame(ChildListID     aListID,
   397                                       nsIFrame*       aOldFrame)
   398 {
   399   NS_NOTREACHED("unsupported operation");
   400   return NS_ERROR_UNEXPECTED;
   401 }

mercurial