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.

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

mercurial