core: Add string_utils char boundary functions

This commit is contained in:
jmckiern 2020-12-15 22:57:28 +00:00 committed by Mike Welsh
parent b81cb1a3eb
commit beed570475
3 changed files with 35 additions and 31 deletions

View File

@ -10,6 +10,7 @@ use crate::font::{round_down_to_pixel, Glyph};
use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, TextFormat};
use crate::prelude::*;
use crate::shape_utils::DrawCommand;
use crate::string_utils;
use crate::tag_utils::SwfMovie;
use crate::transform::Transform;
use crate::types::{Degrees, Percent};
@ -1023,11 +1024,7 @@ impl<'gc> EditText<'gc> {
&& local_position.1 <= params.height()
{
if local_position.0 >= x + (advance / 2) {
let mut idx = pos + 1;
while !text.is_char_boundary(idx) {
idx += 1;
}
result = Some(idx);
result = Some(string_utils::next_char_boundary(text, pos));
} else {
result = Some(pos);
}
@ -1065,10 +1062,7 @@ impl<'gc> EditText<'gc> {
if selection.start() > 0 {
// Delete previous character
let text = self.text();
let mut start = selection.start() - 1;
while !text.is_char_boundary(start) {
start -= 1;
}
let start = string_utils::prev_char_boundary(&text, selection.start());
self.replace_text(start, selection.start(), "", context);
self.set_selection(
Some(TextSelection::for_position(start)),
@ -1082,10 +1076,7 @@ impl<'gc> EditText<'gc> {
if selection.end() < self.text_length() {
// Delete next character
let text = self.text();
let mut end = selection.start() + 1;
while !text.is_char_boundary(end) {
end += 1;
}
let end = string_utils::next_char_boundary(&text, selection.start());
self.replace_text(selection.start(), end, "", context);
// No need to change selection
changed = true;
@ -1450,19 +1441,13 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
let length = text.len();
match key_code {
ButtonKeyCode::Left if selection.to > 0 => {
selection.to -= 1;
while !text.is_char_boundary(selection.to) {
selection.to -= 1;
}
selection.to = string_utils::prev_char_boundary(text, selection.to);
if !context.input.is_key_down(KeyCode::Shift) {
selection.from = selection.to;
}
}
ButtonKeyCode::Right if selection.to < length => {
selection.to += 1;
while !text.is_char_boundary(selection.to) {
selection.to += 1;
}
selection.to = string_utils::next_char_boundary(text, selection.to);
if !context.input.is_key_down(KeyCode::Shift) {
selection.from = selection.to;
}

View File

@ -7,6 +7,7 @@ use crate::font::{EvalParameters, Font};
use crate::html::dimensions::{BoxBounds, Position, Size};
use crate::html::text_format::{FormatSpans, TextFormat, TextSpan};
use crate::shape_utils::DrawCommand;
use crate::string_utils;
use crate::tag_utils::SwfMovie;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cmp::{max, min};
@ -720,16 +721,10 @@ impl<'gc> LayoutBox<'gc> {
// This ensures that the space causing the line break
// is included in the line it broke.
let next_breakpoint = if last_breakpoint + breakpoint + 1 >= text.len()
{
text.len()
} else {
let mut nb = last_breakpoint + breakpoint + 1;
while !text.is_char_boundary(nb) {
nb += 1;
}
nb
};
let next_breakpoint = string_utils::next_char_boundary(
text,
last_breakpoint + breakpoint,
);
layout_context.append_text(
&text[last_breakpoint..next_breakpoint],

View File

@ -1,5 +1,29 @@
///! Utilities for operating on strings in SWF files.
/// Gets the position of the previous char
/// `pos` must already lie on a char boundary
pub fn prev_char_boundary(slice: &str, pos: usize) -> usize {
if pos == 0 {
return pos;
}
let mut idx = pos - 1;
while !slice.is_char_boundary(idx) {
idx -= 1;
}
idx
}
/// Gets the byte position of the next char
/// `pos` must already lie on a char boundary
pub fn next_char_boundary(slice: &str, pos: usize) -> usize {
if let Some(c) = slice[pos..].chars().next() {
pos + c.len_utf8()
} else {
slice.len()
}
}
/// Creates a `String` from an iterator of UTF-16 code units.
/// TODO: Unpaired surrogates will get replaced with the Unicode replacement character.
pub fn utf16_iter_to_string<I: Iterator<Item = u16>>(it: I) -> String {