Fix crash from overflowing values given to NumberInput widgets (#1377)

* Added hints for brush tool size

* Added hints for brush tool size

* Solved the user being able to crash the editor by overflowing NumberInputs
This commit is contained in:
Omar Magdy 2023-08-11 12:31:28 +03:00 committed by Keavon Chambers
parent 1c11ebcc4e
commit fd338c945f
16 changed files with 47 additions and 4 deletions

View file

@ -94,6 +94,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
NumberInput::new(Some(self.scale_factor))
.unit(" ")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.disabled(self.file_type == FileType::Svg)
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
.widget_holder(),

View file

@ -75,6 +75,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
.label("W")
.unit(" px")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.is_integer(true)
.disabled(self.infinite)
.min_width(100)
@ -85,6 +86,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
.label("H")
.unit(" px")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.is_integer(true)
.disabled(self.infinite)
.min_width(100)

View file

@ -58,6 +58,7 @@ impl PreferencesDialogMessageHandler {
NumberInput::new(Some(preferences.imaginate_refresh_frequency))
.unit(" seconds")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.min_width(200)
.on_update(|number_input: &NumberInput| PreferencesMessage::ImaginateRefreshFrequency { seconds: number_input.value.unwrap() }.into())
.widget_holder(),

View file

@ -183,7 +183,7 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
panic!("Invalid string found when updating `NumberInput`")
}
},
_ => panic!("Invalid type found when updating `NumberInput`"),
_ => {} // If it's some other type we could just ignore it and leave the value as is
},
Widget::OptionalInput(optional_input) => {
let update_value = value.as_bool().expect("OptionalInput update was not of type: bool");

View file

@ -273,7 +273,6 @@ impl NumberInput {
pub fn max(mut self, val: f64) -> Self {
self.max = Some(val);
self.range_max = Some(val);
self.mode = NumberInputMode::Range;
self
}
pub fn mode_range(mut self) -> Self {
@ -289,7 +288,7 @@ impl NumberInput {
self
}
pub fn percentage(self) -> Self {
self.min(0.).max(100.).unit("%").display_decimal_places(2)
self.min(0.).max(100.).mode_range().unit("%").display_decimal_places(2)
}
}

View file

@ -144,12 +144,16 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
NumberInput::new(Some(vec2.x))
.label(x)
.unit(unit)
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(input.value.unwrap(), vec2.y)), node_id, index))
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
NumberInput::new(Some(vec2.y))
.label(y)
.unit(unit)
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(vec2.x, input.value.unwrap())), node_id, index))
.widget_holder(),
]);
@ -166,6 +170,8 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
.int()
.label(x)
.unit(unit)
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(update_value(update_x, node_id, index))
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
@ -173,6 +179,8 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
.int()
.label(y)
.unit(unit)
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(update_value(update_y, node_id, index))
.widget_holder(),
]);
@ -1756,7 +1764,7 @@ pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context:
pub fn layer_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let name = text_widget(document_node, node_id, 1, "Name", true);
let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true);
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().min(0.).max(100.).unit("%"), true);
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().percentage(), true);
let visible = bool_widget(document_node, node_id, 4, "Visible", true);
let locked = bool_widget(document_node, node_id, 5, "Locked", true);
let collapsed = bool_widget(document_node, node_id, 6, "Collapsed", true);

View file

@ -98,6 +98,8 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
NumberInput::new(Some(layer.transform.x() + pivot.x))
.label("X")
.unit(" px")
.min(1.)
.max(std::i32::MAX as f64)
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap() - pivot.x,
@ -110,6 +112,8 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
NumberInput::new(Some(layer.transform.y() + pivot.y))
.label("Y")
.unit(" px")
.min(1.)
.max(std::i32::MAX as f64)
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap() - pivot.y,
@ -137,6 +141,7 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
.unit(" px")
.is_integer(true)
.min(1.)
.max(std::i32::MAX as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -151,6 +156,7 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
.unit(" px")
.is_integer(true)
.min(1.)
.max(std::i32::MAX as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -301,6 +307,8 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.transform.x() + pivot.x))
.label("X")
.unit(" px")
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap() - pivot.x,
@ -313,6 +321,8 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.transform.y() + pivot.y))
.label("Y")
.unit(" px")
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap() - pivot.y,
@ -361,6 +371,8 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.transform.scale_x()))
.label("X")
.unit("")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -373,6 +385,7 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.transform.scale_y()))
.label("Y")
.unit("")
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -394,6 +407,7 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.bounding_transform(&render_data).scale_x()))
.label("W")
.unit(" px")
.max((1u64 << f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -406,6 +420,7 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
NumberInput::new(Some(layer.bounding_transform(&render_data).scale_y()))
.label("H")
.unit(" px")
.max((1u64 << f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap(),
@ -682,6 +697,7 @@ fn node_section_stroke(stroke: &Stroke) -> LayoutGroup {
NumberInput::new(Some(stroke.weight()))
.is_integer(false)
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.unit(" px")
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyStroke {
@ -722,6 +738,7 @@ fn node_section_stroke(stroke: &Stroke) -> LayoutGroup {
NumberInput::new(Some(stroke.dash_offset()))
.is_integer(true)
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.unit(" px")
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyStroke {
@ -808,6 +825,7 @@ fn node_section_stroke(stroke: &Stroke) -> LayoutGroup {
NumberInput::new(Some(stroke.line_join_miter_limit() as f64))
.is_integer(true)
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.unit("")
.on_update(move |number_input: &NumberInput| {
PropertiesPanelMessage::ModifyStroke {

View file

@ -37,6 +37,8 @@ const EXPOSED_BLEND_MODES: &[&[BlendMode]] = {
]
};
const BRUSH_MAX_SIZE: f64 = 5000.;
fn blend_mode_dropdown_idx(target_blend_mode: BlendMode) -> Option<u32> {
let mut i = 0;
for group in EXPOSED_BLEND_MODES {
@ -145,6 +147,7 @@ impl LayoutHolder for BrushTool {
NumberInput::new(Some(self.options.diameter))
.label("Diameter")
.min(1.)
.max(BRUSH_MAX_SIZE) /* Anything bigger would cause the application to be unresponsive and eventually die */
.unit(" px")
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Diameter(number_input.value.unwrap())).into())
.widget_holder(),
@ -153,6 +156,7 @@ impl LayoutHolder for BrushTool {
.label("Hardness")
.min(0.)
.max(100.)
.mode_range()
.unit("%")
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Hardness(number_input.value.unwrap())).into())
.widget_holder(),
@ -161,6 +165,7 @@ impl LayoutHolder for BrushTool {
.label("Flow")
.min(1.)
.max(100.)
.mode_range()
.unit("%")
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Flow(number_input.value.unwrap())).into())
.widget_holder(),
@ -169,6 +174,7 @@ impl LayoutHolder for BrushTool {
.label("Spacing")
.min(1.)
.max(100.)
.mode_range()
.unit("%")
.on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Spacing(number_input.value.unwrap())).into())
.widget_holder(),

View file

@ -87,6 +87,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| EllipseToolMessage::UpdateOptions(EllipseOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -90,6 +90,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(1.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -89,6 +89,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| LineToolMessage::UpdateOptions(LineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -111,6 +111,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -118,6 +118,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| PolygonToolMessage::UpdateOptions(PolygonOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -74,6 +74,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| RectangleToolMessage::UpdateOptions(RectangleOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -95,6 +95,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
.unit(" px")
.label("Weight")
.min(0.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
.widget_holder()
}

View file

@ -122,6 +122,7 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
.label("Size")
.int()
.min(1.)
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FontSize(number_input.value.unwrap() as u32)).into())
.widget_holder();
vec![