forked from mirrors/gecko-dev
		
	 fdc00547f6
			
		
	
	
		fdc00547f6
		
	
	
	
	
		
			
			This patch is generated by: ``` # Rename the nsOverflowType enum. rg -l "eVisualOverflow" layout/ gfx/ | xargs sed -i "s/eVisualOverflow/eInkOverflow/g" # Rename and drop the "Get" prefix from various functions. rg -l "GetVisualOverflowRect" layout/ gfx/ | xargs sed -i "s/GetVisualOverflowRect/InkOverflowRect/g" rg -l "GetPreEffectsVisualOverflowRect" layout/ gfx/ | xargs sed -i "s/GetPreEffectsVisualOverflowRect/PreEffectsInkOverflowRect/g" rg -l "GetVisualOverflowFromDeltas" layout/ gfx/ | xargs sed -i "s/GetVisualOverflowFromDeltas/InkOverflowFromDeltas/g" rg -l "GetScrollableOverflowRect" layout/ gfx/ | xargs sed -i "s/GetScrollableOverflowRect/ScrollableOverflowRect/g" # Rename, drop the "Get" prefix, and change the suffix "Area" to "Rect" # (because they return nsRect) for the two methods in nsLineBox. rg -l "GetVisualOverflowArea" layout/ gfx/ | xargs sed -i "s/GetVisualOverflowArea/InkOverflowRect/g" rg -l "GetScrollableOverflowArea" layout/ gfx/ | xargs sed -i "s/GetScrollableOverflowArea/ScrollableOverflowRect/g" # Rename rest of the functions and variables. rg -l "VisualOverflow" layout/ gfx/ | xargs sed -i "s/VisualOverflow/InkOverflow/g" rg -l "visual overflow" layout/ gfx/ | xargs sed -i "s/visual overflow/ink overflow/g" rg -l "visualOverflow" layout/ gfx/ | xargs sed -i "s/visualOverflow/inkOverflow/g" rg -l "visOverflow" layout/ gfx/ | xargs sed -i "s/visOverflow/inkOverflow/g" rg -l "vis-overflow" layout/ gfx/ python/ | xargs sed -i "s/vis-overflow/ink-overflow/g" ./mach clang-format ``` Differential Revision: https://phabricator.services.mozilla.com/D84231
		
			
				
	
	
		
			202 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| #include "nsSelectsAreaFrame.h"
 | |
| 
 | |
| #include "mozilla/PresShell.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsListControlFrame.h"
 | |
| #include "nsDisplayList.h"
 | |
| #include "WritingModes.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| 
 | |
| nsContainerFrame* NS_NewSelectsAreaFrame(PresShell* aShell,
 | |
|                                          ComputedStyle* aStyle,
 | |
|                                          nsFrameState aFlags) {
 | |
|   nsSelectsAreaFrame* it =
 | |
|       new (aShell) nsSelectsAreaFrame(aStyle, aShell->GetPresContext());
 | |
| 
 | |
|   // We need NS_BLOCK_FLOAT_MGR to ensure that the options inside the select
 | |
|   // aren't expanded by right floats outside the select.
 | |
|   it->AddStateBits(aFlags | NS_BLOCK_FLOAT_MGR);
 | |
| 
 | |
|   return it;
 | |
| }
 | |
| 
 | |
| NS_IMPL_FRAMEARENA_HELPERS(nsSelectsAreaFrame)
 | |
| 
 | |
| //---------------------------------------------------------
 | |
| /**
 | |
|  * This wrapper class lets us redirect mouse hits from the child frame of
 | |
|  * an option element to the element's own frame.
 | |
|  * REVIEW: This is what nsSelectsAreaFrame::GetFrameForPoint used to do
 | |
|  */
 | |
| class nsDisplayOptionEventGrabber : public nsDisplayWrapList {
 | |
|  public:
 | |
|   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
 | |
|                               nsDisplayItem* aItem)
 | |
|       : nsDisplayWrapList(aBuilder, aFrame, aItem) {}
 | |
|   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
 | |
|                               nsDisplayList* aList)
 | |
|       : nsDisplayWrapList(aBuilder, aFrame, aList) {}
 | |
|   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
 | |
|                        HitTestState* aState,
 | |
|                        nsTArray<nsIFrame*>* aOutFrames) override;
 | |
|   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
 | |
|     return false;
 | |
|   }
 | |
|   NS_DISPLAY_DECL_NAME("OptionEventGrabber", TYPE_OPTION_EVENT_GRABBER)
 | |
| };
 | |
| 
 | |
| void nsDisplayOptionEventGrabber::HitTest(nsDisplayListBuilder* aBuilder,
 | |
|                                           const nsRect& aRect,
 | |
|                                           HitTestState* aState,
 | |
|                                           nsTArray<nsIFrame*>* aOutFrames) {
 | |
|   nsTArray<nsIFrame*> outFrames;
 | |
|   mList.HitTest(aBuilder, aRect, aState, &outFrames);
 | |
| 
 | |
|   for (uint32_t i = 0; i < outFrames.Length(); i++) {
 | |
|     nsIFrame* selectedFrame = outFrames.ElementAt(i);
 | |
|     while (selectedFrame &&
 | |
|            !(selectedFrame->GetContent() &&
 | |
|              selectedFrame->GetContent()->IsHTMLElement(nsGkAtoms::option))) {
 | |
|       selectedFrame = selectedFrame->GetParent();
 | |
|     }
 | |
|     if (selectedFrame) {
 | |
|       aOutFrames->AppendElement(selectedFrame);
 | |
|     } else {
 | |
|       // keep the original result, which could be this frame
 | |
|       aOutFrames->AppendElement(outFrames.ElementAt(i));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| class nsOptionEventGrabberWrapper : public nsDisplayWrapper {
 | |
|  public:
 | |
|   nsOptionEventGrabberWrapper() = default;
 | |
|   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
 | |
|                                   nsIFrame* aFrame,
 | |
|                                   nsDisplayList* aList) override {
 | |
|     return MakeDisplayItem<nsDisplayOptionEventGrabber>(aBuilder, aFrame,
 | |
|                                                         aList);
 | |
|   }
 | |
|   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
 | |
|                                   nsDisplayItem* aItem) override {
 | |
|     return MakeDisplayItem<nsDisplayOptionEventGrabber>(aBuilder,
 | |
|                                                         aItem->Frame(), aItem);
 | |
|   }
 | |
| };
 | |
| 
 | |
| static nsListControlFrame* GetEnclosingListFrame(nsIFrame* aSelectsAreaFrame) {
 | |
|   nsIFrame* frame = aSelectsAreaFrame->GetParent();
 | |
|   while (frame) {
 | |
|     if (frame->IsListControlFrame())
 | |
|       return static_cast<nsListControlFrame*>(frame);
 | |
|     frame = frame->GetParent();
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| class nsDisplayListFocus : public nsPaintedDisplayItem {
 | |
|  public:
 | |
|   nsDisplayListFocus(nsDisplayListBuilder* aBuilder, nsSelectsAreaFrame* aFrame)
 | |
|       : nsPaintedDisplayItem(aBuilder, aFrame) {
 | |
|     MOZ_COUNT_CTOR(nsDisplayListFocus);
 | |
|   }
 | |
|   MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayListFocus)
 | |
| 
 | |
|   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
 | |
|                            bool* aSnap) const override {
 | |
|     *aSnap = false;
 | |
|     // override bounds because the list item focus ring may extend outside
 | |
|     // the nsSelectsAreaFrame
 | |
|     nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
 | |
|     return listFrame->InkOverflowRectRelativeToSelf() +
 | |
|            listFrame->GetOffsetToCrossDoc(ReferenceFrame());
 | |
|   }
 | |
|   virtual void Paint(nsDisplayListBuilder* aBuilder,
 | |
|                      gfxContext* aCtx) override {
 | |
|     nsListControlFrame* listFrame = GetEnclosingListFrame(Frame());
 | |
|     // listFrame must be non-null or we wouldn't get called.
 | |
|     listFrame->PaintFocus(aCtx->GetDrawTarget(),
 | |
|                           aBuilder->ToReferenceFrame(listFrame));
 | |
|   }
 | |
|   NS_DISPLAY_DECL_NAME("ListFocus", TYPE_LIST_FOCUS)
 | |
| };
 | |
| 
 | |
| void nsSelectsAreaFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
 | |
|                                           const nsDisplayListSet& aLists) {
 | |
|   if (!aBuilder->IsForEventDelivery()) {
 | |
|     BuildDisplayListInternal(aBuilder, aLists);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsDisplayListCollection set(aBuilder);
 | |
|   BuildDisplayListInternal(aBuilder, set);
 | |
| 
 | |
|   nsOptionEventGrabberWrapper wrapper;
 | |
|   wrapper.WrapLists(aBuilder, this, set, aLists);
 | |
| }
 | |
| 
 | |
| void nsSelectsAreaFrame::BuildDisplayListInternal(
 | |
|     nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) {
 | |
|   nsBlockFrame::BuildDisplayList(aBuilder, aLists);
 | |
| 
 | |
|   nsListControlFrame* listFrame = GetEnclosingListFrame(this);
 | |
|   if (listFrame && listFrame->IsFocused()) {
 | |
|     // we can't just associate the display item with the list frame,
 | |
|     // because then the list's scrollframe won't clip it (the scrollframe
 | |
|     // only clips contained descendants).
 | |
|     aLists.Outlines()->AppendNewToTop<nsDisplayListFocus>(aBuilder, this);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSelectsAreaFrame::Reflow(nsPresContext* aPresContext,
 | |
|                                 ReflowOutput& aDesiredSize,
 | |
|                                 const ReflowInput& aReflowInput,
 | |
|                                 nsReflowStatus& aStatus) {
 | |
|   MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
 | |
| 
 | |
|   nsListControlFrame* list = GetEnclosingListFrame(this);
 | |
|   NS_ASSERTION(list,
 | |
|                "Must have an nsListControlFrame!  Frame constructor is "
 | |
|                "broken");
 | |
| 
 | |
|   bool isInDropdownMode = list->IsInDropDownMode();
 | |
| 
 | |
|   // See similar logic in nsListControlFrame::Reflow and
 | |
|   // nsListControlFrame::ReflowAsDropdown.  We need to match it here.
 | |
|   WritingMode wm = aReflowInput.GetWritingMode();
 | |
|   nscoord oldBSize;
 | |
|   if (isInDropdownMode) {
 | |
|     // Store the block size now in case it changes during
 | |
|     // nsBlockFrame::Reflow for some odd reason.
 | |
|     if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
 | |
|       oldBSize = BSize(wm);
 | |
|     } else {
 | |
|       oldBSize = NS_UNCONSTRAINEDSIZE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
 | |
| 
 | |
|   // Check whether we need to suppress scrollbar updates.  We want to do
 | |
|   // that if we're in a possible first pass and our block size of a row
 | |
|   // has changed.
 | |
|   if (list->MightNeedSecondPass()) {
 | |
|     nscoord newBSizeOfARow = list->CalcBSizeOfARow();
 | |
|     // We'll need a second pass if our block size of a row changed.  For
 | |
|     // comboboxes, we'll also need it if our block size changed.  If
 | |
|     // we're going to do a second pass, suppress scrollbar updates for
 | |
|     // this pass.
 | |
|     if (newBSizeOfARow != mBSizeOfARow ||
 | |
|         (isInDropdownMode &&
 | |
|          (oldBSize != aDesiredSize.BSize(wm) || oldBSize != BSize(wm)))) {
 | |
|       mBSizeOfARow = newBSizeOfARow;
 | |
|       list->SetSuppressScrollbarUpdate(true);
 | |
|     }
 | |
|   }
 | |
| }
 |