Bug 1157142 - Support logical (inline/block) in addition to physical orientation for the <input type=range> element; make inline the default behavior so that range sliders respect writing mode. r=jwatt

This commit is contained in:
Jonathan Kew 2015-04-29 08:18:54 +01:00
parent 5fcbbd1ad3
commit 7ae17d117a
4 changed files with 76 additions and 43 deletions

View File

@ -541,7 +541,7 @@ nsRangeFrame::GetValueAtEventPoint(WidgetGUIEvent* aEvent)
nscoord posAtEnd = posAtStart + traversableDistance;
nscoord posOfPoint = mozilla::clamped(point.x, posAtStart, posAtEnd);
fraction = Decimal(posOfPoint - posAtStart) / Decimal(traversableDistance);
if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
if (IsRightToLeft()) {
fraction = Decimal(1) - fraction;
}
} else {
@ -619,13 +619,11 @@ nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
double fraction = GetValueAsFractionOfRange();
MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
// We are called under Reflow, so we need to pass IsHorizontal a valid rect.
nsSize frameSizeOverride(aRangeSize.width, aRangeSize.height);
if (IsHorizontal(&frameSizeOverride)) {
if (IsHorizontal()) {
if (thumbSize.width < rangeContentBoxSize.width) {
nscoord traversableDistance =
rangeContentBoxSize.width - thumbSize.width;
if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
if (IsRightToLeft()) {
newPosition.x += NSToCoordRound((1.0 - fraction) * traversableDistance);
} else {
newPosition.x += NSToCoordRound(fraction * traversableDistance);
@ -670,11 +668,9 @@ nsRangeFrame::DoUpdateRangeProgressFrame(nsIFrame* aRangeProgressFrame,
double fraction = GetValueAsFractionOfRange();
MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
// We are called under Reflow, so we need to pass IsHorizontal a valid rect.
nsSize frameSizeOverride(aRangeSize.width, aRangeSize.height);
if (IsHorizontal(&frameSizeOverride)) {
if (IsHorizontal()) {
nscoord progLength = NSToCoordRound(fraction * rangeContentBoxSize.width);
if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
if (IsRightToLeft()) {
progRect.x += rangeContentBoxSize.width - progLength;
}
progRect.y += (rangeContentBoxSize.height - progSize.height)/2;
@ -741,10 +737,7 @@ nsRangeFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
nscoord oneEm = NSToCoordRound(StyleFont()->mFont.size *
nsLayoutUtils::FontSizeInflationFor(this)); // 1em
// frameSizeOverride values just gets us to fall back to being horizontal
// (the actual values are irrelevant, as long as width > height):
nsSize frameSizeOverride(10,1);
bool isInlineOriented = IsHorizontal(&frameSizeOverride);
bool isInlineOriented = IsInlineOriented();
const WritingMode wm = GetWritingMode();
LogicalSize autoSize(wm);
@ -778,34 +771,38 @@ nsRangeFrame::GetMinISize(nsRenderingContext *aRenderingContext)
nscoord
nsRangeFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
{
// frameSizeOverride values just gets us to fall back to being horizontal:
nsSize frameSizeOverride(10,1);
bool isHorizontal = IsHorizontal(&frameSizeOverride);
bool isInline = IsInlineOriented();
if (!isHorizontal && IsThemed()) {
if (!isInline && IsThemed()) {
// nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
// given too small a size when we're natively themed. We return zero and
// depend on that correction to get our "natuaral" width when we're a
// depend on that correction to get our "natural" width when we're a
// vertical slider.
return 0;
}
nscoord prefWidth = NSToCoordRound(StyleFont()->mFont.size *
nscoord prefISize = NSToCoordRound(StyleFont()->mFont.size *
nsLayoutUtils::FontSizeInflationFor(this)); // 1em
if (isHorizontal) {
prefWidth *= LONG_SIDE_TO_SHORT_SIDE_RATIO;
if (isInline) {
prefISize *= LONG_SIDE_TO_SHORT_SIDE_RATIO;
}
return prefWidth;
return prefISize;
}
bool
nsRangeFrame::IsHorizontal(const nsSize *aFrameSizeOverride) const
nsRangeFrame::IsHorizontal() const
{
dom::HTMLInputElement* element = static_cast<dom::HTMLInputElement*>(mContent);
return !element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
nsGkAtoms::vertical, eCaseMatters);
dom::HTMLInputElement* element =
static_cast<dom::HTMLInputElement*>(mContent);
return element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
nsGkAtoms::horizontal, eCaseMatters) ||
(!element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
nsGkAtoms::vertical, eCaseMatters) &&
GetWritingMode().IsVertical() ==
element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
nsGkAtoms::block, eCaseMatters));
}
double

View File

@ -99,14 +99,25 @@ public:
/**
* Returns true if the slider's thumb moves horizontally, or else false if it
* moves vertically.
*
* aOverrideFrameSize If specified, this will be used instead of the size of
* the frame's rect (i.e. the frame's border-box size) if the frame's
* rect would have otherwise been examined. This should only be specified
* during reflow when the frame's [new] border-box size has not yet been
* stored in its mRect.
*/
bool IsHorizontal(const nsSize *aFrameSizeOverride = nullptr) const;
bool IsHorizontal() const;
/**
* Returns true if the slider is oriented along the inline axis.
*/
bool IsInlineOriented() const {
return IsHorizontal() != GetWritingMode().IsVertical();
}
/**
* Returns true if the slider's thumb moves right-to-left for increasing
* values; only relevant when IsHorizontal() is true.
*/
bool IsRightToLeft() const {
MOZ_ASSERT(IsHorizontal());
mozilla::WritingMode wm = GetWritingMode();
return wm.IsVertical() ? wm.IsVerticalRL() : !wm.IsBidiLTR();
}
double GetMin() const;
double GetMax() const;

View File

@ -825,9 +825,12 @@ meter {
input[type=range] {
-moz-appearance: range;
display: inline-block;
width: 12em; /* XXX how does orient attribute relate to vertical mode? */
height: 1.3em;
margin: 0 0.7em;
inline-size: 12em;
block-size: 1.3em;
margin-inline-start: 0.7em;
margin-inline-end: 0.7em;
margin-block-start: 0;
margin-block-end: 0;
/* Override some rules that apply on all input types: */
cursor: default;
background: none;
@ -837,9 +840,25 @@ input[type=range] {
-moz-user-select: none ! important;
}
input[type=range][orient=block] {
inline-size: 1.3em;
block-size: 12em;
margin-inline-start: 0;
margin-inline-end: 0;
margin-block-start: 0.7em;
margin-block-end: 0.7em;
}
input[type=range][orient=horizontal] {
width: 12em;
height: 1.3em;
margin: 0 0.7em;
}
input[type=range][orient=vertical] {
width: 1.3em;
height: 12em;
margin: 0.7em 0;
}
/**
@ -868,15 +887,23 @@ input[type=range]::-moz-range-track {
position: static !important;
border: none;
background-color: #999;
width: 100%;
height: 0.2em;
inline-size: 100%;
block-size: 0.2em;
/* Prevent nsFrame::HandlePress setting mouse capture to this element. */
-moz-user-select: none ! important;
}
input[type=range][orient=block]::-moz-range-track {
inline-size: 0.2em;
block-size: 100%;
}
input[type=range][orient=horizontal]::-moz-range-track {
width: 100%;
height: 0.2em;
}
input[type=range][orient=vertical]::-moz-range-track {
border-top: none;
border-bottom: none;
width: 0.2em;
height: 100%;
}

View File

@ -2761,9 +2761,7 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
int32_t min = 0;
int32_t max = 1000;
bool isVertical = !IsRangeHorizontal(aFrame);
bool reverseDir =
isVertical ||
rangeFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
bool reverseDir = isVertical || rangeFrame->IsRightToLeft();
DrawScale(cgContext, macRect, eventState, isVertical, reverseDir,
value, min, max, aFrame);
break;