--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3253,20 +3253,20 @@ nsCSSFrameConstructor::ConstructSelectFr
// 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).
nsFrameItems childItems;
// 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;
+ AutoTArray<nsIAnonymousContentCreator::ContentInfo, 3> newAnonymousItems;
DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
MOZ_ASSERT(NS_SUCCEEDED(rv));
- MOZ_ASSERT(newAnonymousItems.Length() == 2);
+ MOZ_ASSERT(newAnonymousItems.Length() == 3);
// 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);
customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
childItems.AddChild(customFrame);
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -222,16 +222,17 @@ static int32_t gReflowInx = -1;
//------------------------------------------------------
//-- Done with macros
//------------------------------------------------------
nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext)
: nsBlockFrame(aContext, kClassID)
, mDisplayFrame(nullptr)
, mButtonFrame(nullptr)
+ , mAppearanceFrame(nullptr)
, mDropdownFrame(nullptr)
, mListControlFrame(nullptr)
, mDisplayISize(0)
, mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX)
, mDisplayedIndex(-1)
, mLastDropDownBeforeScreenBCoord(nscoord_MIN)
, mLastDropDownAfterScreenBCoord(nscoord_MIN)
, mDroppedDown(false)
@@ -813,16 +814,29 @@ nscoord
nsComboboxControlFrame::GetPrefISize(gfxContext *aRenderingContext)
{
nscoord prefISize;
DISPLAY_PREF_WIDTH(this, prefISize);
prefISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE);
return prefISize;
}
+bool nsComboboxControlFrame::IsMenulistAppearance() {
+ return this->StyleDisplay()->mAppearance == NS_THEME_MENULIST;
+}
+
+nsAtom* nsComboboxControlFrame::GetSupportAppearanceType() {
+ switch (this->StyleDisplay()->mAppearance) {
+ case NS_THEME_BUTTON:
+ return nsGkAtoms::button;
+ default:
+ return nsGkAtoms::none;
+ }
+}
+
void
nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus)
{
MarkInReflow();
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
@@ -858,53 +872,71 @@ nsComboboxControlFrame::Reflow(nsPresCon
// The reflow callback queue doesn't AddRef so we keep it alive until
// it's released in its ReflowFinished / ReflowCallbackCanceled.
Unused << resize.forget();
}
// Get the width of the vertical scrollbar. That will be the inline
// size of the dropdown button.
WritingMode wm = aReflowInput.GetWritingMode();
- nscoord buttonISize;
+ nscoord buttonISize, appearanceISize;
const nsStyleDisplay *disp = StyleDisplay();
if ((IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) ||
StyleDisplay()->mAppearance == NS_THEME_NONE) {
buttonISize = 0;
}
else {
nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
NS_ASSERTION(scrollable, "List must be a scrollable frame");
buttonISize = scrollable->GetNondisappearingScrollbarWidth(
PresContext(), aReflowInput.mRenderingContext, wm);
if (buttonISize > aReflowInput.ComputedISize()) {
buttonISize = 0;
}
}
- mDisplayISize = aReflowInput.ComputedISize() - buttonISize;
+ if (!IsThemed() && !IsMenulistAppearance()) {
+ mDisplayISize = aReflowInput.ComputedISize();
+ buttonISize = 0;
+ appearanceISize = mDisplayISize;
+ } else {
+ mDisplayISize = aReflowInput.ComputedISize() - buttonISize;
+ appearanceISize = 0;
+ }
+
nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
// The button should occupy the same space as a scrollbar
nsSize containerSize = aDesiredSize.PhysicalSize();
LogicalRect buttonRect = mButtonFrame->GetLogicalRect(containerSize);
+ LogicalRect apprRect = mAppearanceFrame->GetLogicalRect(containerSize);
buttonRect.IStart(wm) =
aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm) +
mDisplayISize -
(aReflowInput.ComputedLogicalBorderPadding().IEnd(wm) -
aReflowInput.ComputedLogicalPadding().IEnd(wm));
buttonRect.ISize(wm) = buttonISize;
buttonRect.BStart(wm) = this->GetLogicalUsedBorder(wm).BStart(wm);
buttonRect.BSize(wm) = mDisplayFrame->BSize(wm) +
this->GetLogicalUsedPadding(wm).BStartEnd(wm);
mButtonFrame->SetRect(buttonRect, containerSize);
+ apprRect.IStart(wm) = aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm);
+ apprRect.ISize(wm) = appearanceISize;
+
+ apprRect.BStart(wm) = this->GetLogicalUsedBorder(wm).BStart(wm);
+ apprRect.BSize(wm) = mDisplayFrame->BSize(wm) +
+ this->GetLogicalUsedPadding(wm).BStartEnd(wm);
+
+ mAppearanceFrame->SetRect(apprRect, containerSize);
+
if (!aStatus.IsInlineBreakBefore() &&
!aStatus.IsFullyComplete()) {
// This frame didn't fit inside a fragmentation container. Splitting
// a nsComboboxControlFrame makes no sense, so we override the status here.
aStatus.Reset();
}
}
@@ -1051,23 +1083,30 @@ nsComboboxControlFrame::HandleRedisplayT
NS_FRAME_IS_DIRTY);
mInRedisplayText = false;
}
void
nsComboboxControlFrame::ActuallyDisplayText(bool aNotify)
{
+ // Have to use a non-breaking space for line-block-size calculations
+ // to be right
+ static const char16_t space = 0xA0;
if (mDisplayedOptionTextOrPreview.IsEmpty()) {
- // Have to use a non-breaking space for line-block-size calculations
- // to be right
- static const char16_t space = 0xA0;
mDisplayContent->SetText(&space, 1, aNotify);
+ mTextContent->SetText(&space, 1, aNotify);
} else {
- mDisplayContent->SetText(mDisplayedOptionTextOrPreview, aNotify);
+ if (!IsThemed() && !IsMenulistAppearance()) {
+ mDisplayContent->SetText(&space, 1, aNotify);
+ mTextContent->SetText(mDisplayedOptionTextOrPreview, aNotify);
+ } else {
+ mDisplayContent->SetText(mDisplayedOptionTextOrPreview, aNotify);
+ mTextContent->SetText(&space, 1, aNotify);
+ }
}
}
int32_t
nsComboboxControlFrame::GetIndexOfDisplayArea()
{
return mDisplayedIndex;
}
@@ -1225,17 +1264,16 @@ nsComboboxControlFrame::CreateAnonymousC
mDisplayContent = new nsTextNode(nimgr);
// set the value of the text node
mDisplayedIndex = mListControlFrame->GetSelectedIndex();
if (mDisplayedIndex != -1) {
mListControlFrame->GetOptionText(mDisplayedIndex, mDisplayedOptionTextOrPreview);
}
- ActuallyDisplayText(false);
if (!aElements.AppendElement(mDisplayContent))
return NS_ERROR_OUT_OF_MEMORY;
mButtonContent = mContent->OwnerDoc()->CreateHTMLElement(nsGkAtoms::button);
if (!mButtonContent)
return NS_ERROR_OUT_OF_MEMORY;
@@ -1257,30 +1295,59 @@ nsComboboxControlFrame::CreateAnonymousC
wm.IsVerticalRL() ? NS_LITERAL_STRING("left")
: NS_LITERAL_STRING("right"),
false);
}
if (!aElements.AppendElement(mButtonContent))
return NS_ERROR_OUT_OF_MEMORY;
+ nsAtom* apprType = GetSupportAppearanceType();
+ mAppearanceContent = mContent->OwnerDoc()->CreateHTMLElement(apprType);
+ if (!mAppearanceContent)
+ return NS_ERROR_OUT_OF_MEMORY;
+ mButtonListener = new nsComboButtonListener(this);
+ mAppearanceContent->AddEventListener(NS_LITERAL_STRING("click"),
+ mButtonListener, false, false);
+
+ mAppearanceContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
+ NS_LITERAL_STRING("-1"), false);
+
+ if (wm.IsVertical()) {
+ mAppearanceContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orientation,
+ wm.IsVerticalRL() ? NS_LITERAL_STRING("left")
+ : NS_LITERAL_STRING("right"),
+ false);
+ }
+
+ mTextContent = new nsTextNode(mAppearanceContent->NodeInfo()->NodeInfoManager());
+ mAppearanceContent->AppendChildTo(mTextContent, false);
+
+ if (!aElements.AppendElement(mAppearanceContent))
+ return NS_ERROR_OUT_OF_MEMORY;
+ ActuallyDisplayText(false);
+
return NS_OK;
}
void
nsComboboxControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter)
{
if (mDisplayContent) {
aElements.AppendElement(mDisplayContent);
}
if (mButtonContent) {
aElements.AppendElement(mButtonContent);
}
+
+ if (mAppearanceContent) {
+ aElements.AppendElement(mAppearanceContent);
+ }
}
// XXXbz this is a for-now hack. Now that display:inline-block works,
// need to revisit this.
class nsComboboxDisplayFrame : public nsBlockFrame {
public:
NS_DECL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
@@ -1414,16 +1481,17 @@ nsComboboxControlFrame::DestroyFrom(nsIF
widget->CaptureRollupEvents(this, false);
}
}
// Cleanup frames in popup child list
mPopupFrames.DestroyFramesFrom(aDestructRoot, aPostDestroyData);
aPostDestroyData.AddAnonymousContent(mDisplayContent.forget());
aPostDestroyData.AddAnonymousContent(mButtonContent.forget());
+ aPostDestroyData.AddAnonymousContent(mAppearanceContent.forget());
nsBlockFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}
const nsFrameList&
nsComboboxControlFrame::GetChildList(ChildListID aListID) const
{
if (kSelectPopupList == aListID) {
return mPopupFrames;
@@ -1445,16 +1513,18 @@ nsComboboxControlFrame::SetInitialChildL
if (kSelectPopupList == aListID) {
mPopupFrames.SetFrames(aChildList);
} else {
for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
nsCOMPtr<nsIFormControl> formControl =
do_QueryInterface(e.get()->GetContent());
if (formControl && formControl->ControlType() == NS_FORM_BUTTON_BUTTON) {
mButtonFrame = e.get();
+ e.Next();
+ mAppearanceFrame = e.get();
break;
}
}
NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
nsBlockFrame::SetInitialChildList(aListID, aChildList);
}
}