layout/forms/nsSelectsAreaFrame.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/. */
     5 #include "nsSelectsAreaFrame.h"
     6 #include "nsIContent.h"
     7 #include "nsListControlFrame.h"
     8 #include "nsDisplayList.h"
    10 nsIFrame*
    11 NS_NewSelectsAreaFrame(nsIPresShell* aShell, nsStyleContext* aContext, nsFrameState aFlags)
    12 {
    13   nsSelectsAreaFrame* it = new (aShell) nsSelectsAreaFrame(aContext);
    15   // We need NS_BLOCK_FLOAT_MGR to ensure that the options inside the select
    16   // aren't expanded by right floats outside the select.
    17   it->SetFlags(aFlags | NS_BLOCK_FLOAT_MGR);
    19   return it;
    20 }
    22 NS_IMPL_FRAMEARENA_HELPERS(nsSelectsAreaFrame)
    24 //---------------------------------------------------------
    25 /**
    26  * This wrapper class lets us redirect mouse hits from the child frame of
    27  * an option element to the element's own frame.
    28  * REVIEW: This is what nsSelectsAreaFrame::GetFrameForPoint used to do
    29  */
    30 class nsDisplayOptionEventGrabber : public nsDisplayWrapList {
    31 public:
    32   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
    33                               nsIFrame* aFrame, nsDisplayItem* aItem)
    34     : nsDisplayWrapList(aBuilder, aFrame, aItem) {}
    35   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
    36                               nsIFrame* aFrame, nsDisplayList* aList)
    37     : nsDisplayWrapList(aBuilder, aFrame, aList) {}
    38   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
    39                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
    40   NS_DISPLAY_DECL_NAME("OptionEventGrabber", TYPE_OPTION_EVENT_GRABBER)
    41 };
    43 void nsDisplayOptionEventGrabber::HitTest(nsDisplayListBuilder* aBuilder,
    44     const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
    45 {
    46   nsTArray<nsIFrame*> outFrames;
    47   mList.HitTest(aBuilder, aRect, aState, &outFrames);
    49   for (uint32_t i = 0; i < outFrames.Length(); i++) {
    50     nsIFrame* selectedFrame = outFrames.ElementAt(i);
    51     while (selectedFrame &&
    52            !(selectedFrame->GetContent() &&
    53              selectedFrame->GetContent()->IsHTML(nsGkAtoms::option))) {
    54       selectedFrame = selectedFrame->GetParent();
    55     }
    56     if (selectedFrame) {
    57       aOutFrames->AppendElement(selectedFrame);
    58     } else {
    59       // keep the original result, which could be this frame
    60       aOutFrames->AppendElement(outFrames.ElementAt(i));
    61     }
    62   }
    63 }
    65 class nsOptionEventGrabberWrapper : public nsDisplayWrapper
    66 {
    67 public:
    68   nsOptionEventGrabberWrapper() {}
    69   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
    70                                   nsIFrame* aFrame, nsDisplayList* aList) {
    71     return new (aBuilder) nsDisplayOptionEventGrabber(aBuilder, aFrame, aList);
    72   }
    73   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
    74                                   nsDisplayItem* aItem) {
    75     return new (aBuilder) nsDisplayOptionEventGrabber(aBuilder, aItem->Frame(), aItem);
    76   }
    77 };
    79 static nsListControlFrame* GetEnclosingListFrame(nsIFrame* aSelectsAreaFrame)
    80 {
    81   nsIFrame* frame = aSelectsAreaFrame->GetParent();
    82   while (frame) {
    83     if (frame->GetType() == nsGkAtoms::listControlFrame)
    84       return static_cast<nsListControlFrame*>(frame);
    85     frame = frame->GetParent();
    86   }
    87   return nullptr;
    88 }
    90 class nsDisplayListFocus : public nsDisplayItem {
    91 public:
    92   nsDisplayListFocus(nsDisplayListBuilder* aBuilder,
    93                      nsSelectsAreaFrame* aFrame) :
    94     nsDisplayItem(aBuilder, aFrame) {
    95     MOZ_COUNT_CTOR(nsDisplayListFocus);
    96   }
    97 #ifdef NS_BUILD_REFCNT_LOGGING
    98   virtual ~nsDisplayListFocus() {
    99     MOZ_COUNT_DTOR(nsDisplayListFocus);
   100   }
   101 #endif
   103   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   104     *aSnap = false;
   105     // override bounds because the list item focus ring may extend outside
   106     // the nsSelectsAreaFrame
   107     nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
   108     return listFrame->GetVisualOverflowRectRelativeToSelf() +
   109            listFrame->GetOffsetToCrossDoc(ReferenceFrame());
   110   }
   111   virtual void Paint(nsDisplayListBuilder* aBuilder,
   112                      nsRenderingContext* aCtx) {
   113     nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
   114     // listFrame must be non-null or we wouldn't get called.
   115     listFrame->PaintFocus(*aCtx, aBuilder->ToReferenceFrame(listFrame));
   116   }
   117   NS_DISPLAY_DECL_NAME("ListFocus", TYPE_LIST_FOCUS)
   118 };
   120 void
   121 nsSelectsAreaFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   122                                      const nsRect&           aDirtyRect,
   123                                      const nsDisplayListSet& aLists)
   124 {
   125   if (!aBuilder->IsForEventDelivery()) {
   126     BuildDisplayListInternal(aBuilder, aDirtyRect, aLists);
   127     return;
   128   }
   130   nsDisplayListCollection set;
   131   BuildDisplayListInternal(aBuilder, aDirtyRect, set);
   133   nsOptionEventGrabberWrapper wrapper;
   134   wrapper.WrapLists(aBuilder, this, set, aLists);
   135 }
   137 void
   138 nsSelectsAreaFrame::BuildDisplayListInternal(nsDisplayListBuilder*   aBuilder,
   139                                              const nsRect&           aDirtyRect,
   140                                              const nsDisplayListSet& aLists)
   141 {
   142   nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
   144   nsListControlFrame* listFrame = GetEnclosingListFrame(this);
   145   if (listFrame && listFrame->IsFocused()) {
   146     // we can't just associate the display item with the list frame,
   147     // because then the list's scrollframe won't clip it (the scrollframe
   148     // only clips contained descendants).
   149     aLists.Outlines()->AppendNewToTop(new (aBuilder)
   150       nsDisplayListFocus(aBuilder, this));
   151   }
   152 }
   154 nsresult 
   155 nsSelectsAreaFrame::Reflow(nsPresContext*           aPresContext, 
   156                            nsHTMLReflowMetrics&     aDesiredSize,
   157                            const nsHTMLReflowState& aReflowState, 
   158                            nsReflowStatus&          aStatus)
   159 {
   160   nsListControlFrame* list = GetEnclosingListFrame(this);
   161   NS_ASSERTION(list,
   162                "Must have an nsListControlFrame!  Frame constructor is "
   163                "broken");
   165   bool isInDropdownMode = list->IsInDropDownMode();
   167   // See similar logic in nsListControlFrame::Reflow and
   168   // nsListControlFrame::ReflowAsDropdown.  We need to match it here.
   169   nscoord oldHeight;
   170   if (isInDropdownMode) {
   171     // Store the height now in case it changes during
   172     // nsBlockFrame::Reflow for some odd reason.
   173     if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
   174       oldHeight = GetSize().height;
   175     } else {
   176       oldHeight = NS_UNCONSTRAINEDSIZE;
   177     }
   178   }
   180   nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize,
   181                                     aReflowState, aStatus);
   182   NS_ENSURE_SUCCESS(rv, rv);
   184   // Check whether we need to suppress scrollbar updates.  We want to do that if
   185   // we're in a possible first pass and our height of a row has changed.
   186   if (list->MightNeedSecondPass()) {
   187     nscoord newHeightOfARow = list->CalcHeightOfARow();
   188     // We'll need a second pass if our height of a row changed.  For
   189     // comboboxes, we'll also need it if our height changed.  If we're going
   190     // to do a second pass, suppress scrollbar updates for this pass.
   191     if (newHeightOfARow != mHeightOfARow ||
   192         (isInDropdownMode && (oldHeight != aDesiredSize.Height() ||
   193                               oldHeight != GetSize().height))) {
   194       mHeightOfARow = newHeightOfARow;
   195       list->SetSuppressScrollbarUpdate(true);
   196     }
   197   }
   199   return rv;
   200 }

mercurial