diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index b3d21d456510..88a41139e198 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -225,11 +225,11 @@ nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext) , mButtonFrame(nullptr) , mDropdownFrame(nullptr) , mListControlFrame(nullptr) - , mDisplayWidth(0) + , mDisplayISize(0) , mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX) , mDisplayedIndex(-1) - , mLastDropDownAboveScreenY(nscoord_MIN) - , mLastDropDownBelowScreenY(nscoord_MIN) + , mLastDropDownBeforeScreenBCoord(nscoord_MIN) + , mLastDropDownAfterScreenBCoord(nscoord_MIN) , mDroppedDown(false) , mInRedisplayText(false) , mDelayedShowDropDown(false) @@ -418,7 +418,7 @@ void nsComboboxControlFrame::ReflowDropdown(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { - // All we want out of it later on, really, is the height of a row, so we + // All we want out of it later on, really, is the block size of a row, so we // don't even need to cache mDropdownFrame's ascent or anything. If we don't // need to reflow it, just bail out here. if (!aReflowState.ShouldReflowAllKids() && @@ -426,23 +426,24 @@ nsComboboxControlFrame::ReflowDropdown(nsPresContext* aPresContext, return; } - // XXXbz this will, for small-height dropdowns, have extra space on the right - // edge for the scrollbar we don't show... but that's the best we can do here - // for now. + // XXXbz this will, for small-block-size dropdowns, have extra space + // on the appropriate edge for the scrollbar we don't show... but + // that's the best we can do here for now. WritingMode wm = mDropdownFrame->GetWritingMode(); LogicalSize availSize = aReflowState.AvailableSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mDropdownFrame, availSize); - // If the dropdown's intrinsic width is narrower than our specified width, - // then expand it out. We want our border-box width to end up the same as - // the dropdown's so account for both sets of mComputedBorderPadding. - nscoord forcedWidth = aReflowState.ComputedWidth() + - aReflowState.ComputedPhysicalBorderPadding().LeftRight() - - kidReflowState.ComputedPhysicalBorderPadding().LeftRight(); - kidReflowState.SetComputedWidth(std::max(kidReflowState.ComputedWidth(), - forcedWidth)); + // If the dropdown's intrinsic inline size is narrower than our + // specified inline size, then expand it out. We want our border-box + // inline size to end up the same as the dropdown's so account for + // both sets of mComputedBorderPadding. + nscoord forcedISize = aReflowState.ComputedISize() + + aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm) - + kidReflowState.ComputedLogicalBorderPadding().IStartEnd(wm); + kidReflowState.SetComputedISize(std::max(kidReflowState.ComputedISize(), + forcedISize)); // ensure we start off hidden if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { @@ -455,19 +456,26 @@ nsComboboxControlFrame::ReflowDropdown(nsPresContext* aPresContext, // Allow the child to move/size/change-visibility its view if it's currently // dropped down - int32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_VISIBILITY | NS_FRAME_NO_SIZE_VIEW; - if (mDroppedDown) { - flags = 0; - } - nsRect rect = mDropdownFrame->GetRect(); + int32_t flags = mDroppedDown ? 0 + : NS_FRAME_NO_MOVE_FRAME | + NS_FRAME_NO_VISIBILITY | + NS_FRAME_NO_SIZE_VIEW; + + //XXX Can this be different from the dropdown's writing mode? + // That would be odd! + // Note that we don't need to pass the true frame position or container width + // to ReflowChild or FinishReflowChild here; it will be positioned as needed + // by AbsolutelyPositionDropDown(). + WritingMode outerWM = GetWritingMode(); nsHTMLReflowMetrics desiredSize(aReflowState); nsReflowStatus ignoredStatus; ReflowChild(mDropdownFrame, aPresContext, desiredSize, - kidReflowState, rect.x, rect.y, flags, ignoredStatus); + kidReflowState, outerWM, LogicalPoint(outerWM), 0, + flags, ignoredStatus); // Set the child's width and height to its desired size - FinishReflowChild(mDropdownFrame, aPresContext, desiredSize, - &kidReflowState, rect.x, rect.y, flags); + FinishReflowChild(mDropdownFrame, aPresContext, desiredSize, &kidReflowState, + outerWM, LogicalPoint(outerWM), 0, flags); } nsPoint @@ -549,71 +557,81 @@ public: }; void -nsComboboxControlFrame::GetAvailableDropdownSpace(nscoord* aAbove, - nscoord* aBelow, - nsPoint* aTranslation) +nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM, + nscoord* aBefore, + nscoord* aAfter, + LogicalPoint* aTranslation) { - // Note: At first glance, it appears that you could simply get the absolute - // bounding box for the dropdown list by first getting its view, then getting - // the view's nsIWidget, then asking the nsIWidget for its AbsoluteBounds. - // The problem with this approach, is that the dropdown lists y location can - // change based on whether the dropdown is placed below or above the display - // frame. The approach, taken here is to get the absolute position of the - // display frame and use its location to determine if the dropdown will go - // offscreen. + // Note: At first glance, it appears that you could simply get the + // absolute bounding box for the dropdown list by first getting its + // view, then getting the view's nsIWidget, then asking the nsIWidget + // for its AbsoluteBounds. + // The problem with this approach, is that the dropdown list's bcoord + // location can change based on whether the dropdown is placed after + // or before the display frame. The approach taken here is to get the + // absolute position of the display frame and use its location to + // determine if the dropdown will go offscreen. // Normal frame geometry (eg GetOffsetTo, mRect) doesn't include transforms. // In the special case that our transform is only a 2D translation we // introduce this hack so that the dropdown will show up in the right place. - *aTranslation = GetCSSTransformTranslation(); - *aAbove = 0; - *aBelow = 0; + *aTranslation = LogicalPoint(aWM, GetCSSTransformTranslation(), 0); + *aBefore = 0; + *aAfter = 0; nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext()); - if (mLastDropDownBelowScreenY == nscoord_MIN) { - nsRect thisScreenRect = GetScreenRectInAppUnits(); - mLastDropDownBelowScreenY = thisScreenRect.YMost() + aTranslation->y; - mLastDropDownAboveScreenY = thisScreenRect.y + aTranslation->y; + nscoord containerWidth = screen.width; + LogicalRect logicalScreen(aWM, screen, containerWidth); + if (mLastDropDownAfterScreenBCoord == nscoord_MIN) { + LogicalRect thisScreenRect(aWM, GetScreenRectInAppUnits(), + containerWidth); + mLastDropDownAfterScreenBCoord = thisScreenRect.BEnd(aWM) + + aTranslation->B(aWM); + mLastDropDownBeforeScreenBCoord = thisScreenRect.BEnd(aWM) + + aTranslation->B(aWM); } - nscoord minY; + nscoord minBCoord; nsPresContext* pc = PresContext()->GetToplevelContentDocumentPresContext(); nsIFrame* root = pc ? pc->PresShell()->GetRootFrame() : nullptr; if (root) { - minY = root->GetScreenRectInAppUnits().y; - if (mLastDropDownBelowScreenY < minY) { - // Don't allow the drop-down to be placed above the content area. + minBCoord = LogicalRect(aWM, + root->GetScreenRectInAppUnits(), + containerWidth).BStart(aWM); + if (mLastDropDownAfterScreenBCoord < minBCoord) { + // Don't allow the drop-down to be placed before the content area. return; } } else { - minY = screen.y; + minBCoord = logicalScreen.BStart(aWM); } - nscoord below = screen.YMost() - mLastDropDownBelowScreenY; - nscoord above = mLastDropDownAboveScreenY - minY; + nscoord after = logicalScreen.BEnd(aWM) - mLastDropDownAfterScreenBCoord; + nscoord before = mLastDropDownBeforeScreenBCoord - minBCoord; - // If the difference between the space above and below is less - // than a row-height, then we favor the space below. - if (above >= below) { + // If the difference between the space before and after is less + // than a row-block-size, then we favor the space after. + if (before >= after) { nsListControlFrame* lcf = static_cast(mDropdownFrame); - nscoord rowHeight = lcf->GetHeightOfARow(); - if (above < below + rowHeight) { - above -= rowHeight; + nscoord rowBSize = lcf->GetBSizeOfARow(); + if (before < after + rowBSize) { + before -= rowBSize; } } - *aBelow = below; - *aAbove = above; + *aAfter = after; + *aBefore = before; } nsComboboxControlFrame::DropDownPositionState nsComboboxControlFrame::AbsolutelyPositionDropDown() { - nsPoint translation; - nscoord above, below; - mLastDropDownBelowScreenY = nscoord_MIN; - GetAvailableDropdownSpace(&above, &below, &translation); - if (above <= 0 && below <= 0) { + WritingMode wm = GetWritingMode(); + LogicalPoint translation(wm); + nscoord before, after; + mLastDropDownAfterScreenBCoord = nscoord_MIN; + GetAvailableDropdownSpace(wm, &before, &after, &translation); + if (before <= 0 && after <= 0) { if (IsDroppedDown()) { // Hide the view immediately to minimize flicker. nsView* view = mDropdownFrame->GetView(); @@ -623,17 +641,17 @@ nsComboboxControlFrame::AbsolutelyPositionDropDown() return eDropDownPositionSuppressed; } - nsSize dropdownSize = mDropdownFrame->GetSize(); - nscoord height = std::max(above, below); + LogicalSize dropdownSize = mDropdownFrame->GetLogicalSize(wm); + nscoord bSize = std::max(before, after); nsListControlFrame* lcf = static_cast(mDropdownFrame); - if (height < dropdownSize.height) { + if (bSize < dropdownSize.BSize(wm)) { if (lcf->GetNumDisplayRows() > 1) { // The drop-down doesn't fit and currently shows more than 1 row - // schedule a resize to show fewer rows. NS_DispatchToCurrentThread(new nsAsyncResize(this)); return eDropDownPositionPendingResize; } - } else if (height > (dropdownSize.height + lcf->GetHeightOfARow() * 1.5) && + } else if (bSize > (dropdownSize.BSize(wm) + lcf->GetBSizeOfARow() * 1.5) && lcf->GetDropdownCanGrow()) { // The drop-down fits but there is room for at least 1.5 more rows - // schedule a resize to show more rows if it has more rows to show. @@ -643,22 +661,20 @@ nsComboboxControlFrame::AbsolutelyPositionDropDown() return eDropDownPositionPendingResize; } - // Position the drop-down below if there is room, otherwise place it above + // Position the drop-down after if there is room, otherwise place it before // if there is room. If there is no room for it on either side then place - // it below (to avoid overlapping UI like the URL bar). - bool b = dropdownSize.height <= below || dropdownSize.height > above; - nsPoint dropdownPosition(0, b ? GetRect().height : -dropdownSize.height); - if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { - // Align the right edge of the drop-down with the right edge of the control. - dropdownPosition.x = GetRect().width - dropdownSize.width; - } + // it after (to avoid overlapping UI like the URL bar). + bool b = dropdownSize.BSize(wm)<= after || dropdownSize.BSize(wm) > before; + LogicalPoint dropdownPosition(wm, 0, b ? BSize(wm) : -dropdownSize.BSize(wm)); // Don't position the view unless the position changed since it might cause // a call to NotifyGeometryChange() and an infinite loop here. - const nsPoint currentPos = mDropdownFrame->GetPosition(); - const nsPoint newPos = dropdownPosition + translation; + nscoord containerWidth = GetRect().width; + const LogicalPoint currentPos = + mDropdownFrame->GetLogicalPosition(containerWidth); + const LogicalPoint newPos = dropdownPosition + translation; if (currentPos != newPos) { - mDropdownFrame->SetPosition(newPos); + mDropdownFrame->SetPosition(wm, newPos, containerWidth); nsContainerFrame::PositionFrameView(mDropdownFrame); } return eDropDownPositionFinal; @@ -716,63 +732,63 @@ nsComboboxControlFrame::GetIntrinsicISize(nsRenderingContext* aRenderingContext, presContext, aRenderingContext); } - nscoord displayWidth = 0; + nscoord displayISize = 0; if (MOZ_LIKELY(mDisplayFrame)) { - displayWidth = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + displayISize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, mDisplayFrame, aType); } if (mDropdownFrame) { - nscoord dropdownContentWidth; + nscoord dropdownContentISize; bool isUsingOverlayScrollbars = LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0; if (aType == nsLayoutUtils::MIN_ISIZE) { - dropdownContentWidth = mDropdownFrame->GetMinISize(aRenderingContext); + dropdownContentISize = mDropdownFrame->GetMinISize(aRenderingContext); if (isUsingOverlayScrollbars) { - dropdownContentWidth += scrollbarWidth; + dropdownContentISize += scrollbarWidth; } } else { NS_ASSERTION(aType == nsLayoutUtils::PREF_ISIZE, "Unexpected type"); - dropdownContentWidth = mDropdownFrame->GetPrefISize(aRenderingContext); + dropdownContentISize = mDropdownFrame->GetPrefISize(aRenderingContext); if (isUsingOverlayScrollbars) { - dropdownContentWidth += scrollbarWidth; + dropdownContentISize += scrollbarWidth; } } - dropdownContentWidth = NSCoordSaturatingSubtract(dropdownContentWidth, + dropdownContentISize = NSCoordSaturatingSubtract(dropdownContentISize, scrollbarWidth, nscoord_MAX); - displayWidth = std::max(dropdownContentWidth, displayWidth); + displayISize = std::max(dropdownContentISize, displayISize); } // add room for the dropmarker button if there is one if ((!IsThemed() || presContext->GetTheme()->ThemeNeedsComboboxDropmarker()) && StyleDisplay()->mAppearance != NS_THEME_NONE) { - displayWidth += scrollbarWidth; + displayISize += scrollbarWidth; } - return displayWidth; + return displayISize; } nscoord nsComboboxControlFrame::GetMinISize(nsRenderingContext *aRenderingContext) { - nscoord minWidth; - DISPLAY_MIN_WIDTH(this, minWidth); - minWidth = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE); - return minWidth; + nscoord minISize; + DISPLAY_MIN_WIDTH(this, minISize); + minISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE); + return minISize; } nscoord nsComboboxControlFrame::GetPrefISize(nsRenderingContext *aRenderingContext) { - nscoord prefWidth; - DISPLAY_PREF_WIDTH(this, prefWidth); - prefWidth = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE); - return prefWidth; + nscoord prefISize; + DISPLAY_PREF_WIDTH(this, prefISize); + prefISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE); + return prefISize; } void @@ -784,13 +800,13 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext, MarkInReflow(); // Constraints we try to satisfy: - // 1) Default width of button is the vertical scrollbar size - // 2) If the width of button is bigger than our width, set width of - // button to 0. - // 3) Default height of button is height of display area - // 4) Width of display area is whatever is left over from our width after - // allocating width for the button. - // 5) Height of display area is GetHeightOfARow() on the + // 1) Default inline size of button is the vertical scrollbar size + // 2) If the inline size of button is bigger than our inline size, set + // inline size of button to 0. + // 3) Default block size of button is block size of display area + // 4) Inline size of display area is whatever is left over from our + // inline size after allocating inline size for the button. + // 5) Block Size of display area is GetBSizeOfARow() on the // mListControlFrame. if (!mDisplayFrame || !mButtonFrame || !mDropdownFrame) { @@ -826,48 +842,45 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext, unused << resize.forget(); } - // Get the width of the vertical scrollbar. That will be the width of the - // dropdown button. - nscoord buttonWidth; + // Get the width of the vertical scrollbar. That will be the inline + // size of the dropdown button. + nscoord buttonISize; const nsStyleDisplay *disp = StyleDisplay(); if ((IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) || StyleDisplay()->mAppearance == NS_THEME_NONE) { - buttonWidth = 0; + buttonISize = 0; } else { nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame); NS_ASSERTION(scrollable, "List must be a scrollable frame"); - buttonWidth = scrollable->GetNondisappearingScrollbarWidth( + buttonISize = scrollable->GetNondisappearingScrollbarWidth( PresContext(), aReflowState.rendContext); - if (buttonWidth > aReflowState.ComputedWidth()) { - buttonWidth = 0; + if (buttonISize > aReflowState.ComputedISize()) { + buttonISize = 0; } } - mDisplayWidth = aReflowState.ComputedWidth() - buttonWidth; + mDisplayISize = aReflowState.ComputedISize() - buttonISize; nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); // The button should occupy the same space as a scrollbar - nsRect buttonRect = mButtonFrame->GetRect(); + WritingMode wm = aReflowState.GetWritingMode(); + nscoord containerWidth = aReflowState.ComputedWidth(); + LogicalRect buttonRect = mButtonFrame->GetLogicalRect(containerWidth); - if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { - buttonRect.x = aReflowState.ComputedPhysicalBorderPadding().left - - aReflowState.ComputedPhysicalPadding().left; - } - else { - buttonRect.x = aReflowState.ComputedPhysicalBorderPadding().LeftRight() + - mDisplayWidth - - (aReflowState.ComputedPhysicalBorderPadding().right - - aReflowState.ComputedPhysicalPadding().right); - } - buttonRect.width = buttonWidth; + buttonRect.IStart(wm) = + aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm) + + mDisplayISize - + (aReflowState.ComputedLogicalBorderPadding().IEnd(wm) - + aReflowState.ComputedLogicalPadding().IEnd(wm)); + buttonRect.ISize(wm) = buttonISize; - buttonRect.y = this->GetUsedBorder().top; - buttonRect.height = mDisplayFrame->GetRect().height + - this->GetUsedPadding().TopBottom(); + buttonRect.BStart(wm) = this->GetLogicalUsedBorder(wm).BStart(wm); + buttonRect.BSize(wm) = mDisplayFrame->BSize(wm) + + this->GetLogicalUsedPadding(wm).BStartEnd(wm); - mButtonFrame->SetRect(buttonRect); + mButtonFrame->SetRect(buttonRect, containerWidth); if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) && !NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { @@ -1019,7 +1032,7 @@ void nsComboboxControlFrame::ActuallyDisplayText(bool aNotify) { if (mDisplayedOptionText.IsEmpty()) { - // Have to use a non-breaking space for line-height calculations + // 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); @@ -1235,8 +1248,8 @@ public: mComboBox(aComboBox) {} - // Need this so that line layout knows that this block's width - // depends on the available width. + // Need this so that line layout knows that this block's inline size + // depends on the available inline size. virtual nsIAtom* GetType() const override; virtual bool IsFrameOfType(uint32_t aFlags) const override @@ -1273,18 +1286,19 @@ nsComboboxDisplayFrame::Reflow(nsPresContext* aPresContext, nsReflowStatus& aStatus) { nsHTMLReflowState state(aReflowState); - if (state.ComputedHeight() == NS_INTRINSICSIZE) { - // Note that the only way we can have a computed height here is if the - // combobox had a specified height. If it didn't, size based on what our - // rows look like, for lack of anything better. - state.SetComputedHeight(mComboBox->mListControlFrame->GetHeightOfARow()); + if (state.ComputedBSize() == NS_INTRINSICSIZE) { + // Note that the only way we can have a computed block size here is + // if the combobox had a specified block size. If it didn't, size + // based on what our rows look like, for lack of anything better. + state.SetComputedBSize(mComboBox->mListControlFrame->GetBSizeOfARow()); } - nscoord computedWidth = mComboBox->mDisplayWidth - - state.ComputedPhysicalBorderPadding().LeftRight(); - if (computedWidth < 0) { - computedWidth = 0; + WritingMode wm = aReflowState.GetWritingMode(); + nscoord computedISize = mComboBox->mDisplayISize - + state.ComputedLogicalBorderPadding().IStartEnd(wm); + if (computedISize < 0) { + computedISize = 0; } - state.SetComputedWidth(computedWidth); + state.SetComputedISize(computedISize); nsBlockFrame::Reflow(aPresContext, aDesiredSize, state, aStatus); aStatus = NS_FRAME_COMPLETE; // this type of frame can't be split } diff --git a/layout/forms/nsComboboxControlFrame.h b/layout/forms/nsComboboxControlFrame.h index e459c1783513..2fef6f0b582e 100644 --- a/layout/forms/nsComboboxControlFrame.h +++ b/layout/forms/nsComboboxControlFrame.h @@ -146,14 +146,15 @@ public: virtual void RollupFromList() override; /** - * Return the available space above and below this frame for + * Return the available space before and after this frame for * placing the drop-down list, and the current 2D translation. * Note that either or both can be less than or equal to zero, * if both are then the drop-down should be closed. */ - void GetAvailableDropdownSpace(nscoord* aAbove, - nscoord* aBelow, - nsPoint* aTranslation); + void GetAvailableDropdownSpace(mozilla::WritingMode aWM, + nscoord* aBefore, + nscoord* aAfter, + mozilla::LogicalPoint* aTranslation); virtual int32_t GetIndexOfDisplayArea() override; /** * @note This method might destroy |this|. @@ -271,9 +272,9 @@ protected: nsIFrame* mDropdownFrame; // dropdown list frame nsIListControlFrame * mListControlFrame; // ListControl Interface for the dropdown frame - // The width of our display area. Used by that frame's reflow to - // size to the full width except the drop-marker. - nscoord mDisplayWidth; + // The inline size of our display area. Used by that frame's reflow + // to size to the full inline size except the drop-marker. + nscoord mDisplayISize; nsRevocableEventPtr mRedisplayTextEvent; @@ -285,13 +286,13 @@ protected: // then open or close the combo box. nsCOMPtr mButtonListener; - // The last y-positions used for estimating available space above and - // below for the dropdown list in GetAvailableDropdownSpace. These are + // The last y-positions used for estimating available space before and + // after for the dropdown list in GetAvailableDropdownSpace. These are // reset to nscoord_MIN in AbsolutelyPositionDropDown when placing the // dropdown at its actual position. The GetAvailableDropdownSpace call // from nsListControlFrame::ReflowAsDropdown use the last position. - nscoord mLastDropDownAboveScreenY; - nscoord mLastDropDownBelowScreenY; + nscoord mLastDropDownBeforeScreenBCoord; + nscoord mLastDropDownAfterScreenBCoord; // Current state of the dropdown list, true is dropped down. bool mDroppedDown; // See comment in HandleRedisplayTextEvent(). diff --git a/layout/forms/nsIListControlFrame.h b/layout/forms/nsIListControlFrame.h index cfdb4e805790..bb91483580d7 100644 --- a/layout/forms/nsIListControlFrame.h +++ b/layout/forms/nsIListControlFrame.h @@ -54,10 +54,10 @@ public: virtual void CaptureMouseEvents(bool aGrabMouseEvents) = 0; /** - * Returns the height of a single row in the list. This is the - * maximum of the heights of all the options/optgroups. + * Returns the block size of a single row in the list. This is the + * maximum of the block sizes of all the options/optgroups. */ - virtual nscoord GetHeightOfARow() = 0; + virtual nscoord GetBSizeOfARow() = 0; /** * Returns the number of options in the listbox diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index fbfdf2472b76..703c82d1c210 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -97,7 +97,7 @@ nsListControlFrame::nsListControlFrame(nsStyleContext* aContext) mHasPendingInterruptAtStartOfReflow(false), mDropdownCanGrow(false), mForceSelection(false), - mLastDropdownComputedHeight(NS_UNCONSTRAINEDSIZE) + mLastDropdownComputedBSize(NS_UNCONSTRAINEDSIZE) { mComboboxFrame = nullptr; mChangesSinceDragStart = false; @@ -206,8 +206,13 @@ void nsListControlFrame::PaintFocus(nsRenderingContext& aRC, nsPoint aPt) } else { float inflation = nsLayoutUtils::FontSizeInflationFor(this); fRect.x = fRect.y = 0; - fRect.width = GetScrollPortRect().width; - fRect.height = CalcFallbackRowHeight(inflation); + if (GetWritingMode().IsVertical()) { + fRect.width = GetScrollPortRect().width; + fRect.height = CalcFallbackRowBSize(inflation); + } else { + fRect.width = CalcFallbackRowBSize(inflation); + fRect.height = GetScrollPortRect().height; + } fRect.MoveBy(containerFrame->GetOffsetTo(this)); } fRect += aPt; @@ -257,22 +262,22 @@ nsListControlFrame::AccessibleType() #endif static nscoord -GetMaxOptionHeight(nsIFrame* aContainer) +GetMaxOptionBSize(nsIFrame* aContainer, WritingMode aWM) { nscoord result = 0; for (nsIFrame* option = aContainer->GetFirstPrincipalChild(); option; option = option->GetNextSibling()) { - nscoord optionHeight; + nscoord optionBSize; if (nsCOMPtr (do_QueryInterface(option->GetContent()))) { // an optgroup - optionHeight = GetMaxOptionHeight(option); + optionBSize = GetMaxOptionBSize(option, aWM); } else { // an option - optionHeight = option->GetSize().height; + optionBSize = option->BSize(aWM); } - if (result < optionHeight) - result = optionHeight; + if (result < optionBSize) + result = optionBSize; } return result; } @@ -282,22 +287,24 @@ GetMaxOptionHeight(nsIFrame* aContainer) //----------------------------------------------------------------- nscoord -nsListControlFrame::CalcHeightOfARow() +nsListControlFrame::CalcBSizeOfARow() { - // Calculate the height of a single row in the listbox or dropdown list by - // using the tallest thing in the subtree, since there may be option groups - // in addition to option elements, either of which may be visible or - // invisible, may use different fonts, etc. - int32_t heightOfARow = GetMaxOptionHeight(GetOptionsContainer()); + // Calculate the block size in our writing mode of a single row in the + // listbox or dropdown list by using the tallest thing in the subtree, + // since there may be option groups in addition to option elements, + // either of which may be visible or invisible, may use different + // fonts, etc. + int32_t blockSizeOfARow = GetMaxOptionBSize(GetOptionsContainer(), + GetWritingMode()); // Check to see if we have zero items (and optimize by checking - // heightOfARow first) - if (heightOfARow == 0 && GetNumberOfOptions() == 0) { + // blockSizeOfARow first) + if (blockSizeOfARow == 0 && GetNumberOfOptions() == 0) { float inflation = nsLayoutUtils::FontSizeInflationFor(this); - heightOfARow = CalcFallbackRowHeight(inflation); + blockSizeOfARow = CalcFallbackRowBSize(inflation); } - return heightOfARow; + return blockSizeOfARow; } nscoord @@ -306,13 +313,15 @@ nsListControlFrame::GetPrefISize(nsRenderingContext *aRenderingContext) nscoord result; DISPLAY_PREF_WIDTH(this, result); - // Always add scrollbar widths to the pref-width of the scrolled - // content. Combobox frames depend on this happening in the dropdown, - // and standalone listboxes are overflow:scroll so they need it too. + // Always add scrollbar inline sizes to the pref-inline-size of the + // scrolled content. Combobox frames depend on this happening in the + // dropdown, and standalone listboxes are overflow:scroll so they need + // it too. + WritingMode wm = GetWritingMode(); result = GetScrolledFrame()->GetPrefISize(aRenderingContext); - result = NSCoordSaturatingAdd(result, - GetDesiredScrollbarSizes(PresContext(), aRenderingContext).LeftRight()); - + LogicalMargin scrollbarSize(wm, GetDesiredScrollbarSizes(PresContext(), + aRenderingContext)); + result = NSCoordSaturatingAdd(result, scrollbarSize.IStartEnd(wm)); return result; } @@ -322,11 +331,15 @@ nsListControlFrame::GetMinISize(nsRenderingContext *aRenderingContext) nscoord result; DISPLAY_MIN_WIDTH(this, result); - // Always add scrollbar widths to the min-width of the scrolled - // content. Combobox frames depend on this happening in the dropdown, - // and standalone listboxes are overflow:scroll so they need it too. + // Always add scrollbar inline sizes to the min-inline-size of the + // scrolled content. Combobox frames depend on this happening in the + // dropdown, and standalone listboxes are overflow:scroll so they need + // it too. + WritingMode wm = GetWritingMode(); result = GetScrolledFrame()->GetMinISize(aRenderingContext); - result += GetDesiredScrollbarSizes(PresContext(), aRenderingContext).LeftRight(); + LogicalMargin scrollbarSize(wm, GetDesiredScrollbarSizes(PresContext(), + aRenderingContext)); + result += scrollbarSize.IStartEnd(wm); return result; } @@ -337,8 +350,8 @@ nsListControlFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - NS_PRECONDITION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE, - "Must have a computed width"); + NS_PRECONDITION(aReflowState.ComputedISize() != NS_UNCONSTRAINEDSIZE, + "Must have a computed inline size"); SchedulePaint(); @@ -366,65 +379,69 @@ nsListControlFrame::Reflow(nsPresContext* aPresContext, MarkInReflow(); /* - * Due to the fact that our intrinsic height depends on the heights of our - * kids, we end up having to do two-pass reflow, in general -- the first pass - * to find the intrinsic height and a second pass to reflow the scrollframe - * at that height (which will size the scrollbars correctly, etc). + * Due to the fact that our intrinsic block size depends on the block + * sizes of our kids, we end up having to do two-pass reflow, in + * general -- the first pass to find the intrinsic block size and a + * second pass to reflow the scrollframe at that block size (which + * will size the scrollbars correctly, etc). * - * Naturaly, we want to avoid doing the second reflow as much as possible. - * We can skip it in the following cases (in all of which the first reflow is - * already happening at the right height): + * Naturally, we want to avoid doing the second reflow as much as + * possible. + * We can skip it in the following cases (in all of which the first + * reflow is already happening at the right block size): * - * - We're reflowing with a constrained computed height -- just use that - * height. - * - We're not dirty and have no dirty kids and shouldn't be reflowing all - * kids. In this case, our cached max height of a child is not going to - * change. - * - We do our first reflow using our cached max height of a child, then - * compute the new max height and it's the same as the old one. + * - We're reflowing with a constrained computed block size -- just + * use that block size. + * - We're not dirty and have no dirty kids and shouldn't be reflowing + * all kids. In this case, our cached max block size of a child is + * not going to change. + * - We do our first reflow using our cached max block size of a + * child, then compute the new max block size and it's the same as + * the old one. */ - bool autoHeight = (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE); + bool autoBSize = (aReflowState.ComputedBSize() == NS_UNCONSTRAINEDSIZE); - mMightNeedSecondPass = autoHeight && + mMightNeedSecondPass = autoBSize && (NS_SUBTREE_DIRTY(this) || aReflowState.ShouldReflowAllKids()); nsHTMLReflowState state(aReflowState); int32_t length = GetNumberOfRows(); - nscoord oldHeightOfARow = HeightOfARow(); + nscoord oldBSizeOfARow = BSizeOfARow(); - if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW) && autoHeight) { - // When not doing an initial reflow, and when the height is auto, start off - // with our computed height set to what we'd expect our height to be. - nscoord computedHeight = CalcIntrinsicBSize(oldHeightOfARow, length); - computedHeight = state.ApplyMinMaxHeight(computedHeight); - state.SetComputedHeight(computedHeight); + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW) && autoBSize) { + // When not doing an initial reflow, and when the block size is + // auto, start off with our computed block size set to what we'd + // expect our block size to be. + nscoord computedBSize = CalcIntrinsicBSize(oldBSizeOfARow, length); + computedBSize = state.ApplyMinMaxBSize(computedBSize); + state.SetComputedBSize(computedBSize); } nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize, state, aStatus); if (!mMightNeedSecondPass) { - NS_ASSERTION(!autoHeight || HeightOfARow() == oldHeightOfARow, - "How did our height of a row change if nothing was dirty?"); - NS_ASSERTION(!autoHeight || + NS_ASSERTION(!autoBSize || BSizeOfARow() == oldBSizeOfARow, + "How did our BSize of a row change if nothing was dirty?"); + NS_ASSERTION(!autoBSize || !(GetStateBits() & NS_FRAME_FIRST_REFLOW), "How do we not need a second pass during initial reflow at " - "auto height?"); + "auto BSize?"); NS_ASSERTION(!IsScrollbarUpdateSuppressed(), "Shouldn't be suppressing if we don't need a second pass!"); - if (!autoHeight) { - // Update our mNumDisplayRows based on our new row height now that we - // know it. Note that if autoHeight and we landed in this code then we - // already set mNumDisplayRows in CalcIntrinsicBSize. Also note that we - // can't use HeightOfARow() here because that just uses a cached value - // that we didn't compute. - nscoord rowHeight = CalcHeightOfARow(); - if (rowHeight == 0) { + if (!autoBSize) { + // Update our mNumDisplayRows based on our new row block size now + // that we know it. Note that if autoBSize and we landed in this + // code then we already set mNumDisplayRows in CalcIntrinsicBSize. + // Also note that we can't use BSizeOfARow() here because that + // just uses a cached value that we didn't compute. + nscoord rowBSize = CalcBSizeOfARow(); + if (rowBSize == 0) { // Just pick something mNumDisplayRows = 1; } else { - mNumDisplayRows = std::max(1, state.ComputedHeight() / rowHeight); + mNumDisplayRows = std::max(1, state.ComputedBSize() / rowBSize); } } @@ -433,12 +450,12 @@ nsListControlFrame::Reflow(nsPresContext* aPresContext, mMightNeedSecondPass = false; - // Now see whether we need a second pass. If we do, our nsSelectsAreaFrame - // will have suppressed the scrollbar update. + // Now see whether we need a second pass. If we do, our + // nsSelectsAreaFrame will have suppressed the scrollbar update. if (!IsScrollbarUpdateSuppressed()) { // All done. No need to do more reflow. NS_ASSERTION(!IsScrollbarUpdateSuppressed(), - "Shouldn't be suppressing if the height of a row has not " + "Shouldn't be suppressing if the block size of a row has not " "changed!"); return; } @@ -446,17 +463,18 @@ nsListControlFrame::Reflow(nsPresContext* aPresContext, SetSuppressScrollbarUpdate(false); // Gotta reflow again. - // XXXbz We're just changing the height here; do we need to dirty ourselves - // or anything like that? We might need to, per the letter of the reflow - // protocol, but things seem to work fine without it... Is that just an - // implementation detail of nsHTMLScrollFrame that we're depending on? + // XXXbz We're just changing the block size here; do we need to dirty + // ourselves or anything like that? We might need to, per the letter + // of the reflow protocol, but things seem to work fine without it... + // Is that just an implementation detail of nsHTMLScrollFrame that + // we're depending on? nsHTMLScrollFrame::DidReflow(aPresContext, &state, nsDidReflowStatus::FINISHED); - // Now compute the height we want to have - nscoord computedHeight = CalcIntrinsicBSize(HeightOfARow(), length); - computedHeight = state.ApplyMinMaxHeight(computedHeight); - state.SetComputedHeight(computedHeight); + // Now compute the block size we want to have + nscoord computedBSize = CalcIntrinsicBSize(BSizeOfARow(), length); + computedBSize = state.ApplyMinMaxBSize(computedBSize); + state.SetComputedBSize(computedBSize); // XXXbz to make the ascent really correct, we should add our // mComputedPadding.top to it (and subtract it from descent). Need that @@ -470,36 +488,39 @@ nsListControlFrame::ReflowAsDropdown(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - NS_PRECONDITION(aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE, - "We should not have a computed height here!"); + NS_PRECONDITION(aReflowState.ComputedBSize() == NS_UNCONSTRAINEDSIZE, + "We should not have a computed block size here!"); mMightNeedSecondPass = NS_SUBTREE_DIRTY(this) || aReflowState.ShouldReflowAllKids(); + WritingMode wm = aReflowState.GetWritingMode(); #ifdef DEBUG - nscoord oldHeightOfARow = HeightOfARow(); - nscoord oldVisibleHeight = (GetStateBits() & NS_FRAME_FIRST_REFLOW) ? - NS_UNCONSTRAINEDSIZE : GetScrolledFrame()->GetSize().height; + nscoord oldBSizeOfARow = BSizeOfARow(); + nscoord oldVisibleBSize = (GetStateBits() & NS_FRAME_FIRST_REFLOW) ? + NS_UNCONSTRAINEDSIZE : GetScrolledFrame()->BSize(wm); #endif nsHTMLReflowState state(aReflowState); if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { - // When not doing an initial reflow, and when the height is auto, start off - // with our computed height set to what we'd expect our height to be. - // Note: At this point, mLastDropdownComputedHeight can be - // NS_UNCONSTRAINEDSIZE in cases when last time we didn't have to constrain - // the height. That's fine; just do the same thing as last time. - state.SetComputedHeight(mLastDropdownComputedHeight); + // When not doing an initial reflow, and when the block size is + // auto, start off with our computed block size set to what we'd + // expect our block size to be. + // Note: At this point, mLastDropdownComputedBSize can be + // NS_UNCONSTRAINEDSIZE in cases when last time we didn't have to + // constrain the block size. That's fine; just do the same thing as + // last time. + state.SetComputedBSize(mLastDropdownComputedBSize); } nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize, state, aStatus); if (!mMightNeedSecondPass) { - NS_ASSERTION(oldVisibleHeight == GetScrolledFrame()->GetSize().height, - "How did our kid's height change if nothing was dirty?"); - NS_ASSERTION(HeightOfARow() == oldHeightOfARow, - "How did our height of a row change if nothing was dirty?"); + NS_ASSERTION(oldVisibleBSize == GetScrolledFrame()->BSize(wm), + "How did our kid's BSize change if nothing was dirty?"); + NS_ASSERTION(BSizeOfARow() == oldBSizeOfARow, + "How did our BSize of a row change if nothing was dirty?"); NS_ASSERTION(!IsScrollbarUpdateSuppressed(), "Shouldn't be suppressing if we don't need a second pass!"); NS_ASSERTION(!(GetStateBits() & NS_FRAME_FIRST_REFLOW), @@ -520,61 +541,64 @@ nsListControlFrame::ReflowAsDropdown(nsPresContext* aPresContext, SetSuppressScrollbarUpdate(false); - nscoord visibleHeight = GetScrolledFrame()->GetSize().height; - nscoord heightOfARow = HeightOfARow(); + nscoord visibleBSize = GetScrolledFrame()->BSize(wm); + nscoord blockSizeOfARow = BSizeOfARow(); // Gotta reflow again. - // XXXbz We're just changing the height here; do we need to dirty ourselves - // or anything like that? We might need to, per the letter of the reflow - // protocol, but things seem to work fine without it... Is that just an - // implementation detail of nsHTMLScrollFrame that we're depending on? + // XXXbz We're just changing the block size here; do we need to dirty + // ourselves or anything like that? We might need to, per the letter + // of the reflow protocol, but things seem to work fine without it... + // Is that just an implementation detail of nsHTMLScrollFrame that + // we're depending on? nsHTMLScrollFrame::DidReflow(aPresContext, &state, nsDidReflowStatus::FINISHED); - // Now compute the height we want to have. + // Now compute the block size we want to have. // Note: no need to apply min/max constraints, since we have no such // rules applied to the combobox dropdown. mDropdownCanGrow = false; - if (visibleHeight <= 0 || heightOfARow <= 0) { - // Looks like we have no options. Just size us to a single row height. - state.SetComputedHeight(heightOfARow); + if (visibleBSize <= 0 || blockSizeOfARow <= 0) { + // Looks like we have no options. Just size us to a single row + // block size. + state.SetComputedBSize(blockSizeOfARow); mNumDisplayRows = 1; } else { - nsComboboxControlFrame* combobox = static_cast(mComboboxFrame); - nsPoint translation; - nscoord above, below; - combobox->GetAvailableDropdownSpace(&above, &below, &translation); - if (above <= 0 && below <= 0) { - state.SetComputedHeight(heightOfARow); + nsComboboxControlFrame* combobox = + static_cast(mComboboxFrame); + LogicalPoint translation(wm); + nscoord before, after; + combobox->GetAvailableDropdownSpace(wm, &before, &after, &translation); + if (before <= 0 && after <= 0) { + state.SetComputedBSize(blockSizeOfARow); mNumDisplayRows = 1; mDropdownCanGrow = GetNumberOfRows() > 1; } else { - nscoord bp = aReflowState.ComputedPhysicalBorderPadding().TopBottom(); - nscoord availableHeight = std::max(above, below) - bp; - nscoord newHeight; + nscoord bp = aReflowState.ComputedLogicalBorderPadding().BStartEnd(wm); + nscoord availableBSize = std::max(before, after) - bp; + nscoord newBSize; uint32_t rows; - if (visibleHeight <= availableHeight) { - // The dropdown fits in the available height. + if (visibleBSize <= availableBSize) { + // The dropdown fits in the available block size. rows = GetNumberOfRows(); mNumDisplayRows = clamped(rows, 1, kMaxDropDownRows); if (mNumDisplayRows == rows) { - newHeight = visibleHeight; // use the exact height + newBSize = visibleBSize; // use the exact block size } else { - newHeight = mNumDisplayRows * heightOfARow; // approximate + newBSize = mNumDisplayRows * blockSizeOfARow; // approximate } } else { - rows = availableHeight / heightOfARow; + rows = availableBSize / blockSizeOfARow; mNumDisplayRows = clamped(rows, 1, kMaxDropDownRows); - newHeight = mNumDisplayRows * heightOfARow; // approximate + newBSize = mNumDisplayRows * blockSizeOfARow; // approximate } - state.SetComputedHeight(newHeight); - mDropdownCanGrow = visibleHeight - newHeight >= heightOfARow && + state.SetComputedBSize(newBSize); + mDropdownCanGrow = visibleBSize - newBSize >= blockSizeOfARow && mNumDisplayRows != kMaxDropDownRows; } } - mLastDropdownComputedHeight = state.ComputedHeight(); + mLastDropdownComputedBSize = state.ComputedBSize(); nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize, state, aStatus); } @@ -584,13 +608,17 @@ nsListControlFrame::GetScrollbarStyles() const { // We can't express this in the style system yet; when we can, this can go away // and GetScrollbarStyles can be devirtualized - int32_t verticalStyle = IsInDropDownMode() ? NS_STYLE_OVERFLOW_AUTO - : NS_STYLE_OVERFLOW_SCROLL; - return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, verticalStyle); + int32_t style = IsInDropDownMode() ? NS_STYLE_OVERFLOW_AUTO + : NS_STYLE_OVERFLOW_SCROLL; + if (GetWritingMode().IsVertical()) { + return ScrollbarStyles(style, NS_STYLE_OVERFLOW_HIDDEN); + } else { + return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, style); + } } bool -nsListControlFrame::ShouldPropagateComputedHeightToScrolledContent() const +nsListControlFrame::ShouldPropagateComputedBSizeToScrolledContent() const { return !IsInDropDownMode(); } @@ -1480,9 +1508,9 @@ nsListControlFrame::GetFrameName(nsAString& aResult) const #endif nscoord -nsListControlFrame::GetHeightOfARow() +nsListControlFrame::GetBSizeOfARow() { - return HeightOfARow(); + return BSizeOfARow(); } nsresult @@ -1515,23 +1543,23 @@ nsListControlFrame::IsLeftButton(nsIDOMEvent* aMouseEvent) } nscoord -nsListControlFrame::CalcFallbackRowHeight(float aFontSizeInflation) +nsListControlFrame::CalcFallbackRowBSize(float aFontSizeInflation) { - nscoord rowHeight = 0; + nscoord rowBSize = 0; nsRefPtr fontMet; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet), aFontSizeInflation); if (fontMet) { - rowHeight = fontMet->MaxHeight(); + rowBSize = fontMet->MaxHeight(); } - return rowHeight; + return rowBSize; } nscoord -nsListControlFrame::CalcIntrinsicBSize(nscoord aHeightOfARow, - int32_t aNumberOfOptions) +nsListControlFrame::CalcIntrinsicBSize(nscoord aBSizeOfARow, + int32_t aNumberOfOptions) { NS_PRECONDITION(!IsInDropDownMode(), "Shouldn't be in dropdown mode when we call this"); @@ -1548,7 +1576,7 @@ nsListControlFrame::CalcIntrinsicBSize(nscoord aHeightOfARow, mNumDisplayRows = 4; } - return mNumDisplayRows * aHeightOfARow; + return mNumDisplayRows * aBSizeOfARow; } //---------------------------------------------------------------------- diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h index 53133c9e1064..4482be340cb8 100644 --- a/layout/forms/nsListControlFrame.h +++ b/layout/forms/nsListControlFrame.h @@ -109,7 +109,7 @@ public: virtual void SetFocus(bool aOn = true, bool aRepaint = false) override; virtual mozilla::ScrollbarStyles GetScrollbarStyles() const override; - virtual bool ShouldPropagateComputedHeightToScrolledContent() const override; + virtual bool ShouldPropagateComputedBSizeToScrolledContent() const override; // for accessibility purposes #ifdef ACCESSIBILITY @@ -129,7 +129,7 @@ public: virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) override; virtual void CaptureMouseEvents(bool aGrabMouseEvents) override; - virtual nscoord GetHeightOfARow() override; + virtual nscoord GetBSizeOfARow() override; virtual uint32_t GetNumberOfOptions() override; virtual void AboutToDropDown() override; @@ -203,10 +203,11 @@ public: void InvalidateFocus(); /** - * Function to calculate the height a row, for use with the "size" attribute. + * Function to calculate the block size of a row, for use with the + * "size" attribute. * Can't be const because GetNumberOfOptions() isn't const. */ - nscoord CalcHeightOfARow(); + nscoord CalcBSizeOfARow(); /** * Function to ask whether we're currently in what might be the @@ -327,12 +328,13 @@ protected: bool CheckIfAllFramesHere(); bool IsLeftButton(nsIDOMEvent* aMouseEvent); - // guess at a row height based on our own style. - nscoord CalcFallbackRowHeight(float aFontSizeInflation); + // guess at a row block size based on our own style. + nscoord CalcFallbackRowBSize(float aFontSizeInflation); - // CalcIntrinsicBSize computes our intrinsic height (taking the "size" - // attribute into account). This should only be called in non-dropdown mode. - nscoord CalcIntrinsicBSize(nscoord aHeightOfARow, int32_t aNumberOfOptions); + // CalcIntrinsicBSize computes our intrinsic block size (taking the + // "size" attribute into account). This should only be called in + // non-dropdown mode. + nscoord CalcIntrinsicBSize(nscoord aBSizeOfARow, int32_t aNumberOfOptions); // Dropped down stuff void SetComboboxItem(int32_t aIndex); @@ -378,8 +380,8 @@ public: } protected: - nscoord HeightOfARow() { - return GetOptionsContainer()->HeightOfARow(); + nscoord BSizeOfARow() { + return GetOptionsContainer()->BSizeOfARow(); } /** @@ -425,10 +427,11 @@ protected: // True if the selection can be set to nothing or disabled options. bool mForceSelection:1; - // The last computed height we reflowed at if we're a combobox dropdown. + // The last computed block size we reflowed at if we're a combobox + // dropdown. // XXXbz should we be using a subclass here? Or just not worry // about the extra member on listboxes? - nscoord mLastDropdownComputedHeight; + nscoord mLastDropdownComputedBSize; // At the time of our last dropdown, the backstop color to draw in case we // are translucent. diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index b06775199833..c1bd774c4339 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -6,6 +6,9 @@ #include "nsIContent.h" #include "nsListControlFrame.h" #include "nsDisplayList.h" +#include "WritingModes.h" + +using namespace mozilla; nsContainerFrame* NS_NewSelectsAreaFrame(nsIPresShell* aShell, nsStyleContext* aContext, nsFrameState aFlags) @@ -164,35 +167,38 @@ nsSelectsAreaFrame::Reflow(nsPresContext* aPresContext, 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. - nscoord oldHeight; + WritingMode wm = aReflowState.GetWritingMode(); + nscoord oldBSize; if (isInDropdownMode) { - // Store the height now in case it changes during + // Store the block size now in case it changes during // nsBlockFrame::Reflow for some odd reason. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { - oldHeight = GetSize().height; + oldBSize = BSize(wm); } else { - oldHeight = NS_UNCONSTRAINEDSIZE; + oldBSize = NS_UNCONSTRAINEDSIZE; } } - + nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - // Check whether we need to suppress scrollbar updates. We want to do that if - // we're in a possible first pass and our height of a row has changed. + // 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 newHeightOfARow = list->CalcHeightOfARow(); - // We'll need a second pass if our height of a row changed. For - // comboboxes, we'll also need it if our height changed. If we're going - // to do a second pass, suppress scrollbar updates for this pass. - if (newHeightOfARow != mHeightOfARow || - (isInDropdownMode && (oldHeight != aDesiredSize.Height() || - oldHeight != GetSize().height))) { - mHeightOfARow = newHeightOfARow; + 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); } } diff --git a/layout/forms/nsSelectsAreaFrame.h b/layout/forms/nsSelectsAreaFrame.h index c00b63e5b48f..7212c2dbc7b0 100644 --- a/layout/forms/nsSelectsAreaFrame.h +++ b/layout/forms/nsSelectsAreaFrame.h @@ -30,19 +30,20 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) override; - nscoord HeightOfARow() const { return mHeightOfARow; } + nscoord BSizeOfARow() const { return mBSizeOfARow; } protected: explicit nsSelectsAreaFrame(nsStyleContext* aContext) : nsBlockFrame(aContext), - mHeightOfARow(0) + mBSizeOfARow(0) {} - // We cache the height of a single row so that changes to the "size" - // attribute, padding, etc. can all be handled with only one reflow. We'll - // have to reflow twice if someone changes our font size or something like - // that, so that the heights of our options will change. - nscoord mHeightOfARow; + // We cache the block size of a single row so that changes to the + // "size" attribute, padding, etc. can all be handled with only one + // reflow. We'll have to reflow twice if someone changes our font + // size or something like that, so that the block size of our options + // will change. + nscoord mBSizeOfARow; }; #endif /* nsSelectsAreaFrame_h___ */ diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index d405bfe0da34..4f1856bd0661 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -438,7 +438,7 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState, nscoord computedBSize = aState->mReflowState.ComputedBSize(); nscoord computedMinBSize = aState->mReflowState.ComputedMinBSize(); nscoord computedMaxBSize = aState->mReflowState.ComputedMaxBSize(); - if (!ShouldPropagateComputedHeightToScrolledContent()) { + if (!ShouldPropagateComputedBSizeToScrolledContent()) { computedBSize = NS_UNCONSTRAINEDSIZE; computedMinBSize = 0; computedMaxBSize = NS_UNCONSTRAINEDSIZE; diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 563d1ab10da7..55d94e344b68 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -939,11 +939,11 @@ protected: bool InInitialReflow() const; /** - * Override this to return false if computed height/min-height/max-height + * Override this to return false if computed bsize/min-bsize/max-bsize * should NOT be propagated to child content. * nsListControlFrame uses this. */ - virtual bool ShouldPropagateComputedHeightToScrolledContent() const { return true; } + virtual bool ShouldPropagateComputedBSizeToScrolledContent() const { return true; } private: friend class mozilla::ScrollFrameHelper; diff --git a/layout/style/forms.css b/layout/style/forms.css index 0b11c9b26bc8..d3379999b3d4 100644 --- a/layout/style/forms.css +++ b/layout/style/forms.css @@ -192,7 +192,6 @@ textarea:-moz-read-write { } select { - writing-mode: horizontal-tb !important; /* XXX remove when bug 1112954 is fixed */ margin: 0; border-color: ThreeDFace; background-color: -moz-Combobox;