Pre-strip HTML from HTML tags, rather than skipping them.
This commit is contained in:
parent
7d225f8b55
commit
18516c8eac
|
@ -55,11 +55,34 @@ impl<'gc> EditText<'gc> {
|
||||||
let is_multiline = swf_tag.is_multiline;
|
let is_multiline = swf_tag.is_multiline;
|
||||||
let is_word_wrap = swf_tag.is_word_wrap;
|
let is_word_wrap = swf_tag.is_word_wrap;
|
||||||
|
|
||||||
|
let text = if swf_tag.is_html {
|
||||||
|
let mut result = String::new();
|
||||||
|
let tag_text = swf_tag.initial_text.clone().unwrap_or_default();
|
||||||
|
let mut chars = tag_text.chars().peekable();
|
||||||
|
|
||||||
|
while let Some(c) = chars.next() {
|
||||||
|
// TODO: SWF text fields can contain a limited subset of HTML (and often do in SWF versions >6).
|
||||||
|
// This is a quicky-and-dirty way to skip the HTML tags. This is obviously not correct
|
||||||
|
// and we will need to properly parse and handle the HTML at some point.
|
||||||
|
// See SWF19 pp. 173-174 for supported HTML tags.
|
||||||
|
if c == '<' {
|
||||||
|
// Skip characters until we see a close bracket.
|
||||||
|
chars.by_ref().skip_while(|&x| x != '>').next();
|
||||||
|
} else {
|
||||||
|
result.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
swf_tag.initial_text.clone().unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
EditText(GcCell::allocate(
|
EditText(GcCell::allocate(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
EditTextData {
|
EditTextData {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
text: swf_tag.initial_text.clone().unwrap_or_default(),
|
text,
|
||||||
new_format: TextFormat::default(),
|
new_format: TextFormat::default(),
|
||||||
static_data: gc_arena::Gc::allocate(context.gc_context, EditTextStatic(swf_tag)),
|
static_data: gc_arena::Gc::allocate(context.gc_context, EditTextStatic(swf_tag)),
|
||||||
is_multiline,
|
is_multiline,
|
||||||
|
@ -271,12 +294,9 @@ impl<'gc> EditText<'gc> {
|
||||||
breakpoints.push(break_base);
|
breakpoints.push(break_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
for breakpoint in font.split_wrapped_lines(
|
for breakpoint in
|
||||||
natural_line,
|
font.split_wrapped_lines(natural_line, height, self.line_width())
|
||||||
height,
|
{
|
||||||
self.line_width(),
|
|
||||||
edit_text.static_data.0.is_html,
|
|
||||||
) {
|
|
||||||
breakpoints.push(break_base + breakpoint);
|
breakpoints.push(break_base + breakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +369,7 @@ impl<'gc> EditText<'gc> {
|
||||||
.unwrap_or_else(|| font.scale());
|
.unwrap_or_else(|| font.scale());
|
||||||
|
|
||||||
for chunk in chunks {
|
for chunk in chunks {
|
||||||
let chunk_size = font.measure(chunk, height, edit_text.static_data.0.is_html);
|
let chunk_size = font.measure(chunk, height);
|
||||||
|
|
||||||
size.0 = size.0.max(chunk_size.0);
|
size.0 = size.0.max(chunk_size.0);
|
||||||
if let Some(layout) = &static_data.layout {
|
if let Some(layout) = &static_data.layout {
|
||||||
|
@ -449,7 +469,6 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
chunk,
|
chunk,
|
||||||
text_transform.clone(),
|
text_transform.clone(),
|
||||||
height,
|
height,
|
||||||
edit_text.static_data.0.is_html,
|
|
||||||
|transform, glyph: &Glyph| {
|
|transform, glyph: &Glyph| {
|
||||||
// Render glyph.
|
// Render glyph.
|
||||||
context.transform_stack.push(transform);
|
context.transform_stack.push(transform);
|
||||||
|
|
|
@ -133,7 +133,6 @@ impl<'gc> Font<'gc> {
|
||||||
text: &str,
|
text: &str,
|
||||||
mut transform: Transform,
|
mut transform: Transform,
|
||||||
height: f32,
|
height: f32,
|
||||||
is_html: bool,
|
|
||||||
mut glyph_func: FGlyph,
|
mut glyph_func: FGlyph,
|
||||||
) where
|
) where
|
||||||
FGlyph: FnMut(&Transform, &Glyph),
|
FGlyph: FnMut(&Transform, &Glyph),
|
||||||
|
@ -146,14 +145,7 @@ impl<'gc> Font<'gc> {
|
||||||
let mut chars = text.chars().peekable();
|
let mut chars = text.chars().peekable();
|
||||||
let has_kerning_info = self.has_kerning_info();
|
let has_kerning_info = self.has_kerning_info();
|
||||||
while let Some(c) = chars.next() {
|
while let Some(c) = chars.next() {
|
||||||
// TODO: SWF text fields can contain a limited subset of HTML (and often do in SWF versions >6).
|
if let Some(glyph) = self.get_glyph_for_char(c) {
|
||||||
// This is a quicky-and-dirty way to skip the HTML tags. This is obviously not correct
|
|
||||||
// and we will need to properly parse and handle the HTML at some point.
|
|
||||||
// See SWF19 pp. 173-174 for supported HTML tags.
|
|
||||||
if is_html && c == '<' {
|
|
||||||
// Skip characters until we see a close bracket.
|
|
||||||
chars.by_ref().skip_while(|&x| x != '>').next();
|
|
||||||
} else if let Some(glyph) = self.get_glyph_for_char(c) {
|
|
||||||
glyph_func(&transform, &glyph);
|
glyph_func(&transform, &glyph);
|
||||||
// Step horizontally.
|
// Step horizontally.
|
||||||
let mut advance = f32::from(glyph.advance);
|
let mut advance = f32::from(glyph.advance);
|
||||||
|
@ -168,21 +160,15 @@ impl<'gc> Font<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Measure a particular string's metrics (width and height).
|
/// Measure a particular string's metrics (width and height).
|
||||||
pub fn measure(self, text: &str, height: f32, is_html: bool) -> (f32, f32) {
|
pub fn measure(self, text: &str, height: f32) -> (f32, f32) {
|
||||||
let mut size = (0.0, 0.0);
|
let mut size = (0.0, 0.0);
|
||||||
|
|
||||||
self.evaluate(
|
self.evaluate(text, Default::default(), height, |transform, _glyph| {
|
||||||
text,
|
|
||||||
Default::default(),
|
|
||||||
height,
|
|
||||||
is_html,
|
|
||||||
|transform, _glyph| {
|
|
||||||
let tx = transform.matrix.tx / Twips::TWIPS_PER_PIXEL as f32;
|
let tx = transform.matrix.tx / Twips::TWIPS_PER_PIXEL as f32;
|
||||||
let ty = transform.matrix.ty / Twips::TWIPS_PER_PIXEL as f32;
|
let ty = transform.matrix.ty / Twips::TWIPS_PER_PIXEL as f32;
|
||||||
size.0 = f32::max(size.0, tx);
|
size.0 = f32::max(size.0, tx);
|
||||||
size.1 = f32::max(size.1, ty);
|
size.1 = f32::max(size.1, ty);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
|
@ -192,19 +178,13 @@ impl<'gc> Font<'gc> {
|
||||||
///
|
///
|
||||||
/// This function assumes only `" "` is valid whitespace to split words on,
|
/// This function assumes only `" "` is valid whitespace to split words on,
|
||||||
/// and will not attempt to break words that are longer than `width`.
|
/// and will not attempt to break words that are longer than `width`.
|
||||||
pub fn split_wrapped_lines(
|
pub fn split_wrapped_lines(self, text: &str, height: f32, width: f32) -> Vec<usize> {
|
||||||
self,
|
|
||||||
text: &str,
|
|
||||||
height: f32,
|
|
||||||
width: f32,
|
|
||||||
is_html: bool,
|
|
||||||
) -> Vec<usize> {
|
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
let mut current_width = width;
|
let mut current_width = width;
|
||||||
let mut current_word = &text[0..0];
|
let mut current_word = &text[0..0];
|
||||||
|
|
||||||
for word in text.split(' ') {
|
for word in text.split(' ') {
|
||||||
let measure = self.measure(word, height, is_html);
|
let measure = self.measure(word, height);
|
||||||
let line_start = current_word.as_ptr() as usize - text.as_ptr() as usize;
|
let line_start = current_word.as_ptr() as usize - text.as_ptr() as usize;
|
||||||
let line_end = if (line_start + current_word.len() + 1) < text.len() {
|
let line_end = if (line_start + current_word.len() + 1) < text.len() {
|
||||||
line_start + current_word.len() + 1
|
line_start + current_word.len() + 1
|
||||||
|
|
Loading…
Reference in New Issue