mirror of
https://github.com/lexmount/moli.git
synced 2026-11-13 08:08:10 +00:00
fix(fonts): stop CRLF pairing at inline objects
This commit is contained in:
@@ -2916,6 +2916,55 @@ fn bidi_controls(bidi: InlineUnicodeBidi, direction: InlineDirection) -> Vec<(ch
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn carriage_returns_separate_space_styles_at_atomic_and_float_objects() {
|
||||
let root = LayoutBoxId::from_index(0);
|
||||
let prefix = LayoutBoxId::from_index(1);
|
||||
let object = LayoutBoxId::from_index(2);
|
||||
let tail = LayoutBoxId::from_index(3);
|
||||
for (role, expected, tail_spaces) in [
|
||||
(InlineObjectRole::Atomic, "a b", 1),
|
||||
(InlineObjectRole::Float, "a b", 1),
|
||||
(InlineObjectRole::OutOfFlow, "a b", 0),
|
||||
(InlineObjectRole::StartEdge, "a b", 0),
|
||||
(InlineObjectRole::EndEdge, "a b", 0),
|
||||
] {
|
||||
let mut normalizer = InlineNormalizer::new(root);
|
||||
normalizer.push_text(
|
||||
prefix,
|
||||
"a\r",
|
||||
InlineWhiteSpaceCollapse::Collapse,
|
||||
InlineTextTransform::None,
|
||||
&[root],
|
||||
);
|
||||
let kind = match role {
|
||||
InlineObjectRole::Float => InlineBoxKind::CustomOutOfFlow,
|
||||
InlineObjectRole::OutOfFlow => InlineBoxKind::OutOfFlow,
|
||||
_ => InlineBoxKind::InFlow,
|
||||
};
|
||||
normalizer.push_object(object, role, kind, &[root], InlineVerticalAlign::default());
|
||||
normalizer.push_text(
|
||||
tail,
|
||||
"\nb",
|
||||
InlineWhiteSpaceCollapse::Collapse,
|
||||
InlineTextTransform::None,
|
||||
&[root],
|
||||
);
|
||||
let input = normalizer.finish();
|
||||
assert_eq!(input.text, expected, "{role:?}");
|
||||
assert_eq!(
|
||||
input
|
||||
.units
|
||||
.iter()
|
||||
.filter(|unit| unit.style_box == tail
|
||||
&& &input.text[unit.output_range.clone()] == " ")
|
||||
.count(),
|
||||
tail_spaces,
|
||||
"{role:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capitalize_keeps_boundaries_across_segment_breaks_and_text_runs() {
|
||||
for (runs, expected) in [
|
||||
|
||||
@@ -258,6 +258,9 @@ impl TextCollector<'_> {
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// The CR has already contributed a normalized newline. An object
|
||||
// ends CRLF pairing before saving the surrounding text context.
|
||||
self.context.carriage_return = false;
|
||||
if !out_of_flow {
|
||||
if floated || display.outside() == DisplayOutside::Inline {
|
||||
self.flush_space();
|
||||
|
||||
@@ -3,6 +3,7 @@ use base64::Engine;
|
||||
use std::time::Duration;
|
||||
|
||||
mod automatic;
|
||||
mod automatic_boundaries;
|
||||
mod automatic_controls;
|
||||
mod automatic_lists;
|
||||
mod automatic_normalization;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
use super::automatic_controls::font_usage_vm;
|
||||
use super::selection_order::order_font_data;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn automatic_fonts_end_crlf_pairing_at_rendered_inline_objects() {
|
||||
let (_, wide) = order_font_data();
|
||||
for (object, expected) in [
|
||||
(
|
||||
"<i style='display:inline-block;width:5px;height:5px'></i>",
|
||||
"loaded",
|
||||
),
|
||||
(
|
||||
"<i style='display:inline-flex;width:5px;height:5px'></i>",
|
||||
"loaded",
|
||||
),
|
||||
(
|
||||
"<i style='display:inline-block;width:5px;height:5px'>x</i>",
|
||||
"loaded",
|
||||
),
|
||||
("<img width='5' height='5'>", "loaded"),
|
||||
("<input value='x'>", "loaded"),
|
||||
("<select><option>x</option></select>", "loaded"),
|
||||
("<i style='float:left;width:5px;height:5px'></i>", "loaded"),
|
||||
// Out-of-flow objects and inline edges keep the first pending space's
|
||||
// font. Their LF still collapses with the CR's ordinary-font space.
|
||||
(
|
||||
"<i style='position:absolute;width:5px;height:5px'></i>",
|
||||
"unloaded",
|
||||
),
|
||||
("<i></i>", "unloaded"),
|
||||
("<i style='display:contents'></i>", "unloaded"),
|
||||
("<i style='display:none'></i>", "unloaded"),
|
||||
] {
|
||||
let mut vm = font_usage_vm();
|
||||
let object = serde_json::to_string(object).unwrap();
|
||||
vm.eval(&format!(r#"
|
||||
const container=document.createElement('div');
|
||||
container.append(document.createTextNode('a\r'));
|
||||
container.insertAdjacentHTML('beforeend',{object});
|
||||
const tail=document.createElement('span');
|
||||
tail.style.cssText='display:contents;font-family:SpaceFace';
|
||||
tail.textContent='\nb';container.append(tail);document.body.append(container);
|
||||
globalThis.face=new FontFace('SpaceFace','url(data:font/ttf;base64,{wide})',{{unicodeRange:'U+0020'}});
|
||||
document.fonts.add(face);
|
||||
"#)).unwrap();
|
||||
vm.reconcile_document_font_resources();
|
||||
vm.eval("document.fonts.ready.then(()=>globalThis.ready=true)")
|
||||
.unwrap();
|
||||
run_font_tasks(&mut vm);
|
||||
assert_eq!(vm.eval("face.status").unwrap(), expected, "{object}");
|
||||
assert_eq!(vm.eval("globalThis.ready===true").unwrap(), "true");
|
||||
assert_eq!(vm.layout_pass_observability_for_test().1, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user