no_std support

This commit is contained in:
Jeremy Soller 2022-11-08 08:43:27 -07:00
parent e95671f68f
commit 268805ba0c
18 changed files with 190 additions and 38 deletions

View file

@ -9,19 +9,34 @@ documentation = "https://docs.rs/cosmic-text/latest/cosmic_text/"
repository = "https://github.com/pop-os/cosmic-text"
[dependencies]
fontdb = "0.9.3"
fontdb = { version = "0.10", default-features = false }
libm = "0.2"
log = "0.4"
ouroboros = "0.15.5"
rustybuzz = "0.5"
rustybuzz = { version = "0.5", default-features = false, features = ["libm"]}
swash = { version = "0.1", optional = true }
sys-locale = "0.2"
unicode-bidi = "0.3"
sys-locale = { version = "0.2", optional = true }
unicode-linebreak = "0.1"
unicode-script = "0.5"
unicode-segmentation = "1.7"
[dependencies.unicode-bidi]
version = "0.3"
default-features = false
features = ["hardcoded-data"]
[features]
default = ["swash"]
default = ["std", "swash"]
no_std = [
"rustybuzz/libm",
]
std = [
"fontdb/memmap",
"fontdb/std",
"rustybuzz/std",
"sys-locale",
"unicode-bidi/std",
]
[workspace]
members = [

View file

@ -1,3 +1,5 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use cosmic_text::{Attrs, Color, FontSystem, SwashCache, Buffer, Metrics};
use std::cmp;
use termion::{
@ -92,9 +94,9 @@ fn main() {
print!(
"{} {}",
color::Bg(color::Rgb(
scale(color.b()),
scale(color.g()),
scale(color.r()),
scale(color.g()),
scale(color.b()),
)),
color::Bg(color::Reset),
);

View file

@ -1,6 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::ops::Range;
#[cfg(not(feature = "std"))]
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::ops::Range;
pub use fontdb::{Family, Stretch, Style, Weight};

View file

@ -1,13 +1,19 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::{
#[cfg(not(feature = "std"))]
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{
cmp,
fmt,
time::Instant,
};
use unicode_segmentation::UnicodeSegmentation;
use crate::{Attrs, AttrsList, BufferLine, Color, FontSystem, LayoutGlyph, LayoutLine, ShapeLine};
use crate::{Attrs, AttrsList, BufferLine, FontSystem, LayoutGlyph, LayoutLine, ShapeLine};
#[cfg(feature = "swash")]
use crate::Color;
/// Current cursor location
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
@ -170,7 +176,8 @@ impl<'a> Buffer<'a> {
}
fn relayout(&mut self) {
let instant = Instant::now();
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
for line in self.lines.iter_mut() {
if line.shape_opt().is_some() {
@ -185,13 +192,14 @@ impl<'a> Buffer<'a> {
self.redraw = true;
let duration = instant.elapsed();
log::debug!("relayout: {:?}", duration);
#[cfg(feature = "std")]
log::debug!("relayout: {:?}", instant.elapsed());
}
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
pub fn shape_until(&mut self, lines: i32) -> i32 {
let instant = Instant::now();
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
let mut reshaped = 0;
let mut total_layout = 0;
@ -211,9 +219,9 @@ impl<'a> Buffer<'a> {
total_layout += layout.len() as i32;
}
let duration = instant.elapsed();
if reshaped > 0 {
log::debug!("shape_until {}: {:?}", reshaped, duration);
#[cfg(feature = "std")]
log::debug!("shape_until {}: {:?}", reshaped, instant.elapsed());
self.redraw = true;
}
@ -222,7 +230,8 @@ impl<'a> Buffer<'a> {
/// Shape lines until cursor, also scrolling to include cursor in view
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
let instant = Instant::now();
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
let mut reshaped = 0;
let mut layout_i = 0;
@ -248,9 +257,9 @@ impl<'a> Buffer<'a> {
}
}
let duration = instant.elapsed();
if reshaped > 0 {
log::debug!("shape_until_cursor {}: {:?}", reshaped, duration);
#[cfg(feature = "std")]
log::debug!("shape_until_cursor {}: {:?}", reshaped, instant.elapsed());
self.redraw = true;
}
@ -409,7 +418,8 @@ impl<'a> Buffer<'a> {
/// Convert x, y position to Cursor (hit detection)
pub fn hit(&self, x: i32, y: i32) -> Option<Cursor> {
let instant = Instant::now();
#[cfg(feature = "std")]
let instant = std::time::Instant::now();
let font_size = self.metrics.font_size;
let line_height = self.metrics.line_height;
@ -485,8 +495,8 @@ impl<'a> Buffer<'a> {
}
}
let duration = instant.elapsed();
log::trace!("click({}, {}): {:?}", x, y, duration);
#[cfg(feature = "std")]
log::trace!("click({}, {}): {:?}", x, y, instant.elapsed());
new_cursor_opt
}

View file

@ -1,3 +1,9 @@
#[cfg(not(feature = "std"))]
use alloc::{
string::String,
vec::Vec,
};
use crate::{AttrsList, FontSystem, LayoutLine, ShapeLine};
/// A line (or paragraph) of text that is shaped and laid out

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
/// Key for building a glyph cache
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CacheKey {
/// Font ID
pub font_id: fontdb::ID,
@ -39,7 +39,7 @@ impl CacheKey {
}
/// Binning of subpixel position for cache optimization
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum SubpixelBin {
Zero,
One,
@ -49,8 +49,8 @@ pub enum SubpixelBin {
impl SubpixelBin {
pub fn new(pos: f32) -> (i32, Self) {
let trunc = pos.trunc() as i32;
let fract = pos.fract();
let (fract, truncf) = libm::modff(pos);
let trunc = truncf as i32;
if pos.is_sign_negative() {
if fract > -0.125 {
(trunc, Self::Zero)

View file

@ -1,9 +1,14 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::cmp;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
#[cfg(feature = "swash")]
use core::cmp;
use unicode_segmentation::UnicodeSegmentation;
use crate::{AttrsList, Buffer, BufferLine, Color, Cursor, LayoutCursor};
use crate::{AttrsList, Buffer, BufferLine, Cursor, LayoutCursor};
#[cfg(feature = "swash")]
use crate::Color;
/// An action to perform on an [Editor]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]

View file

@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::sync::Arc;
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use unicode_script::Script;
use crate::Font;

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::ops::Deref;
use core::ops::Deref;
pub struct Font<'a> {
pub info: &'a fontdb::FaceInfo,
@ -14,10 +14,12 @@ impl<'a> Font<'a> {
pub fn new(info: &'a fontdb::FaceInfo) -> Option<Self> {
let data = match &info.source {
fontdb::Source::Binary(data) => data.deref().as_ref(),
#[cfg(feature = "std")]
fontdb::Source::File(path) => {
log::warn!("Unsupported fontdb Source::File('{}')", path.display());
return None;
}
#[cfg(feature = "std")]
fontdb::Source::SharedFile(_path, data) => data.deref().as_ref(),
};

View file

@ -1,6 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::sync::Arc;
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::{
string::String,
vec::Vec,
};
use crate::Font;

9
src/font/system/mod.rs Normal file
View file

@ -0,0 +1,9 @@
#[cfg(not(feature = "std"))]
pub use self::no_std::*;
#[cfg(not(feature = "std"))]
mod no_std;
#[cfg(feature = "std")]
pub use self::std::*;
#[cfg(feature = "std")]
mod std;

75
src/font/system/no_std.rs Normal file
View file

@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use alloc::{
string::{String, ToString},
sync::Arc,
vec::Vec,
};
use crate::{Attrs, Font, FontMatches};
/// Access system fonts
pub struct FontSystem{
locale: String,
db: fontdb::Database,
}
impl FontSystem {
pub fn new() -> Self {
//TODO: get locale from argument?
let locale = "en-US".to_string();
//TODO: allow loading fonts from memory
let mut db = fontdb::Database::new();
{
//TODO: configurable default fonts
db.set_monospace_family("Fira Mono");
db.set_sans_serif_family("Fira Sans");
db.set_serif_family("DejaVu Serif");
}
Self {
locale,
db,
}
}
pub fn locale(&self) -> &str {
&self.locale
}
pub fn db(&self) -> &fontdb::Database {
&self.db
}
pub fn get_font<'a>(&'a self, id: fontdb::ID) -> Option<Arc<Font<'a>>> {
let face = self.db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
}
pub fn get_font_matches<'a>(&'a self, attrs: Attrs) -> Arc<FontMatches<'a>> {
let mut fonts = Vec::new();
for face in self.db.faces() {
if !attrs.matches(face) {
continue;
}
match self.get_font(face.id) {
Some(font) => fonts.push(font),
None => (),
}
}
Arc::new(FontMatches {
locale: &self.locale,
default_family: self.db.family_name(&attrs.family).to_string(),
fonts
})
}
}

View file

@ -1,5 +1,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::{CacheKey, Color};
/// A laid out glyph

View file

@ -54,6 +54,10 @@
//! });
//! ```
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
pub use self::attrs::*;
mod attrs;

View file

@ -1,5 +1,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::mem;
use unicode_script::{Script, UnicodeScript};
use unicode_segmentation::UnicodeSegmentation;
@ -592,7 +595,7 @@ impl ShapeLine {
};
if word_wrap && !wrap_simple && !glyphs.is_empty() {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,
@ -616,7 +619,7 @@ impl ShapeLine {
if glyph_wrap {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,
@ -643,7 +646,7 @@ impl ShapeLine {
if wrap {
let mut glyphs_swap = Vec::new();
std::mem::swap(&mut glyphs, &mut glyphs_swap);
mem::swap(&mut glyphs, &mut glyphs_swap);
layout_lines.push(
LayoutLine {
glyphs: glyphs_swap,

View file

@ -1,6 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::collections::HashMap;
#[cfg(not(feature = "std"))]
use alloc::collections::BTreeMap as Map;
#[cfg(feature = "std")]
use std::collections::HashMap as Map;
use swash::scale::{ScaleContext, image::Content};
use swash::scale::{Render, Source, StrikeWith};
use swash::zeno::{Format, Vector};
@ -51,7 +54,7 @@ fn swash_image<'a>(font_system: &'a FontSystem, context: &mut ScaleContext, cach
pub struct SwashCache<'a> {
font_system: &'a FontSystem,
context: ScaleContext,
pub image_cache: HashMap<CacheKey, Option<SwashImage>>,
pub image_cache: Map<CacheKey, Option<SwashImage>>,
}
impl<'a> SwashCache<'a> {
@ -60,7 +63,7 @@ impl<'a> SwashCache<'a> {
Self {
font_system: font_system,
context: ScaleContext::new(),
image_cache: HashMap::new()
image_cache: Map::new()
}
}

View file

@ -4,5 +4,8 @@ set -ex
cargo doc
cargo test
cargo build --release --no-default-features
cargo build --release --no-default-features --features std
cargo build --release --no-default-features --features swash
cargo build --release --all
env RUST_LOG=editor_test=info target/release/editor-test