forked from 1b-agent/opencadstudio-upstream
fix(mtext): support arabic cursive shaping and bidirectional rtl text layout
- Enable fallback font metrics for HarfBuzz shaping in TTF glyph resolver - Implement Unicode Bidirectional Algorithm (UBA) paragraph base direction detection - Anchor right-to-left paragraphs to right container boundaries by default - Reorder line atoms with base direction level to preserve neutral punctuation attachment - Right-align RTL single-line TEXT and handle editor caret placement on RTL glyphs
This commit is contained in:
1 parent
ef189d7781
commit
f1d5284fb9
8 files changed
+577
-73
No files matched your search
@@ -491,10 +491,7 @@ fn build_shaped(_family: &str, text: &str) -> Option<ShapedRun> {
|
||||
fn build_shaped(family: &str, text: &str) -> Option<ShapedRun> {
|
||||
use cosmic_text::{Attrs, Buffer, Family, Metrics, Shaping};
|
||||
|
||||
// Cap height / units-per-em of the requested family set the normalization:
|
||||
// its capital letters become CAP_UNITS tall, and every fallback glyph is
|
||||
// scaled into the same pixel-per-unit so sizes stay consistent.
|
||||
let (upem_p, cap_p) = sysfont::with_face_data(family, |data, idx| {
|
||||
let mut primary_metrics = sysfont::with_face_data(family, |data, idx| {
|
||||
let f = ttf_parser::Face::parse(data, idx).ok()?;
|
||||
let upem = f.units_per_em() as f32;
|
||||
let cap = f
|
||||
@@ -504,18 +501,50 @@ fn build_shaped(family: &str, text: &str) -> Option<ShapedRun> {
|
||||
.unwrap_or(0.7 * upem);
|
||||
Some((upem, cap))
|
||||
})
|
||||
.flatten()?;
|
||||
// Pixel (at SHAPE_FS) → 9-unit cap-height factor.
|
||||
let px_to_9 = CAP_UNITS * upem_p / (SHAPE_FS * cap_p);
|
||||
.flatten();
|
||||
|
||||
let mut fs = font_system().lock().unwrap();
|
||||
let attrs = Attrs::new().family(Family::Name(family));
|
||||
let attrs = if family.is_empty() {
|
||||
Attrs::new()
|
||||
} else {
|
||||
Attrs::new().family(Family::Name(family))
|
||||
};
|
||||
let mut buf = Buffer::new(&mut fs, Metrics::new(SHAPE_FS, SHAPE_FS));
|
||||
// No wrapping: a run is a single line.
|
||||
buf.set_size(&mut fs, None, None);
|
||||
buf.set_text(&mut fs, text, &attrs, Shaping::Advanced, None);
|
||||
buf.shape_until_scroll(&mut fs, false);
|
||||
|
||||
if primary_metrics.is_none() {
|
||||
for run in buf.layout_runs() {
|
||||
for g in run.glyphs.iter() {
|
||||
if g.glyph_id == 0 {
|
||||
continue;
|
||||
}
|
||||
let face_index = fs.db_mut().face(g.font_id).map(|f| f.index).unwrap_or(0);
|
||||
if let Some(font) = fs.get_font(g.font_id, g.font_weight) {
|
||||
if let Ok(face) = ttf_parser::Face::parse(font.data(), face_index) {
|
||||
let upem = face.units_per_em() as f32;
|
||||
let cap = face
|
||||
.capital_height()
|
||||
.filter(|&c| c > 0)
|
||||
.map(|c| c as f32)
|
||||
.unwrap_or(0.7 * upem);
|
||||
primary_metrics = Some((upem, cap));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if primary_metrics.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (upem_p, cap_p) = primary_metrics.unwrap_or((1000.0, 700.0));
|
||||
// Pixel (at SHAPE_FS) → 9-unit cap-height factor.
|
||||
let px_to_9 = CAP_UNITS * upem_p / (SHAPE_FS * cap_p);
|
||||
|
||||
let mut glyphs: Vec<PlacedGlyph> = Vec::new();
|
||||
let mut advance = 0.0_f32;
|
||||
for run in buf.layout_runs() {
|
||||
|
||||
+15
-23
@@ -167,29 +167,21 @@ pub fn primary_script() -> Script {
|
||||
}
|
||||
|
||||
pub fn requires_shaping(text: &str) -> bool {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
return text.chars().any(|ch| {
|
||||
matches!(
|
||||
ch as u32,
|
||||
0x0590..=0x05FF
|
||||
| 0x0600..=0x06FF
|
||||
| 0x0750..=0x077F
|
||||
| 0x08A0..=0x08FF
|
||||
| 0x0900..=0x097F
|
||||
| 0x0E00..=0x0E7F
|
||||
| 0xA8E0..=0xA8FF
|
||||
| 0xFB1D..=0xFB4F
|
||||
| 0xFB50..=0xFDFF
|
||||
| 0xFE70..=0xFEFF
|
||||
)
|
||||
});
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = text;
|
||||
false
|
||||
}
|
||||
text.chars().any(|ch| {
|
||||
matches!(
|
||||
ch as u32,
|
||||
0x0590..=0x05FF
|
||||
| 0x0600..=0x06FF
|
||||
| 0x0750..=0x077F
|
||||
| 0x08A0..=0x08FF
|
||||
| 0x0900..=0x097F
|
||||
| 0x0E00..=0x0E7F
|
||||
| 0xA8E0..=0xA8FF
|
||||
| 0xFB1D..=0xFB4F
|
||||
| 0xFB50..=0xFDFF
|
||||
| 0xFE70..=0xFEFF
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
||||
Reference in new issue
Block a user