Bug 1803118 - Snap mouse to <input type=range> tick marks r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D163780
This commit is contained in:
Zach Hoffman
2022-12-08 12:27:22 +00:00
parent ae8fef394e
commit 4a78925c90
8 changed files with 235 additions and 6 deletions

View File

@@ -6,6 +6,7 @@
#include "mozilla/dom/HTMLInputElement.h"
#include "Units.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/BasePrincipal.h"
@@ -3276,7 +3277,8 @@ void HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent) {
// have changed it by then).
GetValue(mFocusedValue, CallerType::System);
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent),
SnapToTickMarks::Yes);
}
void HTMLInputElement::FinishRangeThumbDrag(WidgetGUIEvent* aEvent) {
@@ -3287,7 +3289,8 @@ void HTMLInputElement::FinishRangeThumbDrag(WidgetGUIEvent* aEvent) {
}
if (aEvent) {
nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent),
SnapToTickMarks::Yes);
}
mIsDraggingRange = false;
FireChangeEventIfNeeded();
@@ -3301,7 +3304,8 @@ void HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent) {
PresShell::ReleaseCapturingContent();
}
if (aIsForUserEvent) {
SetValueOfRangeForUserEvent(mRangeThumbDragStartValue);
SetValueOfRangeForUserEvent(mRangeThumbDragStartValue,
SnapToTickMarks::Yes);
} else {
// Don't dispatch an 'input' event - at least not using
// DispatchTrustedEvent.
@@ -3322,8 +3326,12 @@ void HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent) {
}
}
void HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue) {
void HTMLInputElement::SetValueOfRangeForUserEvent(
Decimal aValue, SnapToTickMarks aSnapToTickMarks) {
MOZ_ASSERT(aValue.isFinite());
if (aSnapToTickMarks == SnapToTickMarks::Yes) {
MaybeSnapToTickMark(aValue);
}
Decimal oldValue = GetValueAsDecimal();
@@ -4156,7 +4164,8 @@ void HTMLInputElement::PostHandleEventForRangeThumb(
break;
}
SetValueOfRangeForUserEvent(
rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()));
rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()),
SnapToTickMarks::Yes);
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
break;
@@ -4542,6 +4551,33 @@ void HTMLInputElement::HandleTypeChange(FormControlType aNewType,
}
}
void HTMLInputElement::MaybeSnapToTickMark(Decimal& aValue) {
nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
if (!rangeFrame) {
return;
}
auto tickMark = rangeFrame->NearestTickMark(aValue);
if (tickMark.isNaN()) {
return;
}
auto rangeFrameSize = CSSPixel::FromAppUnits(rangeFrame->GetSize());
CSSCoord rangeTrackLength;
if (rangeFrame->IsHorizontal()) {
rangeTrackLength = rangeFrameSize.width;
} else {
rangeTrackLength = rangeFrameSize.height;
}
auto stepBase = GetStepBase();
auto distanceToTickMark =
rangeTrackLength * float(rangeFrame->GetDoubleAsFractionOfRange(
stepBase + (tickMark - aValue).abs()));
const CSSCoord magnetEffectRange(
StaticPrefs::dom_range_element_magnet_effect_threshold());
if (distanceToTickMark <= magnetEffectRange) {
aValue = tickMark;
}
}
void HTMLInputElement::SanitizeValue(nsAString& aValue,
ForValueGetter aForGetter) {
NS_ASSERTION(mDoneCreating, "The element creation should be finished!");