Skip to content

Commit

Permalink
Bug 1362907 - Make select use nsHTMLButtonControlFrame for layout. r=…
Browse files Browse the repository at this point in the history
…jfkthame,dholbert

This simplifies our combobox code a bit more:

 * Reflow() is only needed to compute the label isize.
 * Frame construction uses a setup more similar to <input type=file> to
   get the right frame tree, removing a bunch of special code.
 * Lots of special code removed all over the place.

Differential Revision: https://phabricator.services.mozilla.com/D203010
  • Loading branch information
emilio committed Feb 29, 2024
1 parent 506151a commit fb89acd
Show file tree
Hide file tree
Showing 22 changed files with 305 additions and 937 deletions.
4 changes: 0 additions & 4 deletions editor/composer/res/EditorOverride.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ label {
user-select: all !important;
}

::-moz-display-comboboxcontrol-frame {
user-select: text !important;
}

option {
user-select: text !important;
}
Expand Down
136 changes: 43 additions & 93 deletions layout/base/nsCSSFrameConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
ComputedStyle* aStyle);
nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);

#include "mozilla/dom/NodeInfo.h"
Expand Down Expand Up @@ -3012,91 +3013,33 @@ static inline void ClearLazyBits(nsIContent* aStartContent,
}
}

nsIFrame* nsCSSFrameConstructor::ConstructSelectFrame(
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindSelectData(const Element& aElement,
ComputedStyle& aStyle) {
// Construct a frame-based listbox or combobox
const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
MOZ_ASSERT(sel);
if (sel->IsCombobox()) {
static constexpr FrameConstructionData sComboboxData{
ToCreationFunc(NS_NewComboboxControlFrame), 0,
PseudoStyleType::buttonContent};
return &sComboboxData;
}
// FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
// and reuse ConstructScrollableBlock or so?
static constexpr FrameConstructionData sListBoxData{
&nsCSSFrameConstructor::ConstructListBoxSelectFrame};
return &sListBoxData;
}

nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
nsFrameConstructorState& aState, FrameConstructionItem& aItem,
nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
nsFrameList& aFrameList) {
nsIContent* const content = aItem.mContent;
ComputedStyle* const computedStyle = aItem.mComputedStyle;

// Construct a frame-based listbox or combobox
dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromNode(content);
MOZ_ASSERT(sel);
if (sel->IsCombobox()) {
// Construct a frame-based combo box.
// The frame-based combo box is built out of three parts. A display area, a
// button and a dropdown list. The display area and button are created
// through anonymous content. The drop-down list's frame is created
// explicitly. The combobox frame shares its content with the drop-down
// list.
nsComboboxControlFrame* comboboxFrame =
NS_NewComboboxControlFrame(mPresShell, computedStyle);

// Save the history state so we don't restore during construction
// since the complete tree is required before we restore.
nsILayoutHistoryState* historyState = aState.mFrameState;
aState.mFrameState = nullptr;
// Initialize the combobox frame
InitAndRestoreFrame(aState, content,
aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
comboboxFrame);

comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);

aState.AddChild(comboboxFrame, aFrameList, content, aParentFrame);

// Resolve pseudo element style for the dropdown list
RefPtr<ComputedStyle> listStyle =
mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
PseudoStyleType::dropDownList, computedStyle);

// child frames of combobox frame
nsFrameList childList;

// Create display and button frames from the combobox's anonymous content.
// The anonymous content is appended to existing anonymous content for this
// element (the scrollbars).
//
// nsComboboxControlFrame needs special frame creation behavior for its
// first piece of anonymous content, which means that we can't take the
// normal ProcessChildren path.
AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
DebugOnly<nsresult> rv =
GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
MOZ_ASSERT(NS_SUCCEEDED(rv));
MOZ_ASSERT(!newAnonymousItems.IsEmpty());

// Manually create a frame for the special NAC.
MOZ_ASSERT(newAnonymousItems[0].mContent ==
comboboxFrame->GetDisplayNode());
newAnonymousItems.RemoveElementAt(0);
nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
MOZ_ASSERT(customFrame);
childList.AppendFrame(nullptr, customFrame);

nsFrameConstructorSaveState floatSaveState;
aState.MaybePushFloatContainingBlock(comboboxFrame, floatSaveState);

// The other piece of NAC can take the normal path.
AutoFrameConstructionItemList fcItems(this);
AutoFrameConstructionPageName pageNameTracker(aState, comboboxFrame);
AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
fcItems, pageNameTracker);
ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
/* aParentIsWrapperAnonBox = */ false,
childList);

comboboxFrame->SetInitialChildList(FrameChildListID::Principal,
std::move(childList));

aState.mFrameState = historyState;
if (aState.mFrameState) {
// Restore frame state for the entire subtree of |comboboxFrame|.
RestoreFrameState(comboboxFrame, aState.mFrameState);
}
return comboboxFrame;
}

// Listbox, not combobox
nsContainerFrame* listFrame =
NS_NewListControlFrame(mPresShell, computedStyle);
Expand Down Expand Up @@ -3175,7 +3118,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(

const nsStyleDisplay* fieldsetContentDisplay =
fieldsetContentStyle->StyleDisplay();
bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
nsContainerFrame* scrollFrame = nullptr;
if (isScrollable) {
fieldsetContentStyle = BeginBuildingScrollFrame(
Expand Down Expand Up @@ -3499,11 +3442,18 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
"Unexpected parent for fieldset content anon box");

if (aElement.IsInNativeAnonymousSubtree() &&
aElement.NodeInfo()->NameAtom() == nsGkAtoms::label &&
static_cast<nsFileControlFrame*>(do_QueryFrame(aParentFrame))) {
static constexpr FrameConstructionData sFileLabelData(
NS_NewFileControlLabelFrame);
return &sFileLabelData;
aElement.NodeInfo()->NameAtom() == nsGkAtoms::label && aParentFrame) {
if (static_cast<nsFileControlFrame*>(do_QueryFrame(aParentFrame))) {
static constexpr FrameConstructionData sFileLabelData(
NS_NewFileControlLabelFrame);
return &sFileLabelData;
}
if (aParentFrame->GetParent() &&
aParentFrame->GetParent()->IsComboboxControlFrame()) {
static constexpr FrameConstructionData sComboboxLabelData(
NS_NewComboboxLabelFrame);
return &sComboboxLabelData;
}
}

static constexpr FrameConstructionDataByTag sHTMLData[] = {
Expand All @@ -3515,7 +3465,7 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData),
SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
COMPLEX_TAG_CREATE(fieldset,
Expand Down Expand Up @@ -5165,10 +5115,14 @@ static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
return false;
}

// Allow native anonymous content no matter what.
if (aChild.IsRootOfNativeAnonymousSubtree()) {
return false;
}

// Options with labels have their label text added in ::before by forms.css.
// Suppress frames for their child text.
if (aParent->IsHTMLElement(nsGkAtoms::option) &&
!aChild.IsRootOfNativeAnonymousSubtree()) {
if (aParent->IsHTMLElement(nsGkAtoms::option)) {
return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
}

Expand All @@ -5191,11 +5145,7 @@ static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
return false;
}

// Allow native anonymous content no matter what.
if (aChild.IsRootOfNativeAnonymousSubtree()) {
return false;
}

// Anything else is not ok.
return true;
}

Expand Down
16 changes: 8 additions & 8 deletions layout/base/nsCSSFrameConstructor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1388,14 +1388,6 @@ class nsCSSFrameConstructor final : public nsFrameManager {
nsFrameState aTypeBit);

private:
// ConstructSelectFrame puts the new frame in aFrameList and
// handles the kids of the select.
nsIFrame* ConstructSelectFrame(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsContainerFrame* aParentFrame,
const nsStyleDisplay* aStyleDisplay,
nsFrameList& aFrameList);

// ConstructFieldSetFrame puts the new frame in aFrameList and
// handles the kids of the fieldset
nsIFrame* ConstructFieldSetFrame(nsFrameConstructorState& aState,
Expand All @@ -1404,6 +1396,12 @@ class nsCSSFrameConstructor final : public nsFrameManager {
const nsStyleDisplay* aStyleDisplay,
nsFrameList& aFrameList);

nsIFrame* ConstructListBoxSelectFrame(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsContainerFrame* aParentFrame,
const nsStyleDisplay* aStyleDisplay,
nsFrameList& aFrameList);

// Creates a block frame wrapping an anonymous ruby frame.
nsIFrame* ConstructBlockRubyFrame(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
Expand Down Expand Up @@ -1450,6 +1448,8 @@ class nsCSSFrameConstructor final : public nsFrameManager {
nsIFrame* aParentFrame,
ComputedStyle&);
// HTML data-finding helper functions
static const FrameConstructionData* FindSelectData(const Element&,
ComputedStyle&);
static const FrameConstructionData* FindImgData(const Element&,
ComputedStyle&);
static const FrameConstructionData* FindGeneratedImageData(const Element&,
Expand Down
15 changes: 0 additions & 15 deletions layout/forms/nsButtonFrameRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
#include "nsCSSRendering.h"
#include "nsPresContext.h"
#include "nsPresContextInlines.h"
#include "nsGkAtoms.h"
#include "nsCSSPseudoElements.h"
#include "nsNameSpaceManager.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/Unused.h"
#include "nsDisplayList.h"
Expand Down Expand Up @@ -46,18 +43,6 @@ void nsButtonFrameRenderer::SetFrame(nsIFrame* aFrame,

nsIFrame* nsButtonFrameRenderer::GetFrame() { return mFrame; }

void nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool aNotify) {
dom::Element* element = mFrame->GetContent()->AsElement();
if (aDisabled)
element->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, u""_ns, aNotify);
else
element->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, aNotify);
}

bool nsButtonFrameRenderer::isDisabled() {
return mFrame->GetContent()->AsElement()->IsDisabled();
}

nsresult nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
nsDisplayList* aBackground,
nsDisplayList* aForeground) {
Expand Down
9 changes: 2 additions & 7 deletions layout/forms/nsButtonFrameRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class nsButtonFrameRenderer {
using nsDisplayList = mozilla::nsDisplayList;
using nsDisplayListBuilder = mozilla::nsDisplayListBuilder;

typedef mozilla::image::ImgDrawResult ImgDrawResult;
typedef mozilla::ComputedStyle ComputedStyle;
using ImgDrawResult = mozilla::image::ImgDrawResult;
using ComputedStyle = mozilla::ComputedStyle;

public:
nsButtonFrameRenderer();
Expand Down Expand Up @@ -60,11 +60,6 @@ class nsButtonFrameRenderer {

void SetFrame(nsIFrame* aFrame, nsPresContext* aPresContext);

void SetDisabled(bool aDisabled, bool notify);

bool isActive();
bool isDisabled();

void GetButtonInnerFocusRect(const nsRect& aRect, nsRect& aResult);

ComputedStyle* GetComputedStyle(int32_t aIndex) const;
Expand Down
Loading

0 comments on commit fb89acd

Please sign in to comment.