Giter Site home page Giter Site logo

razrfalcon / ttf-parser Goto Github PK

View Code? Open in Web Editor NEW
583.0 583.0 61.0 1.77 MB

A high-level, safe, zero-allocation TrueType font parser.

License: Apache License 2.0

Rust 92.58% Python 0.36% C 2.87% Meson 0.12% C++ 3.96% QMake 0.12%
opentype otf truetype ttf

ttf-parser's Introduction

SWUbanner

vshymanskyy's GitHub stats

ttf-parser's People

Contributors

asibahi avatar csmulhern avatar dhardy avatar dzamkov avatar ebraminio avatar fschutt avatar fuzzyzilla avatar laurenzv avatar laurmaedje avatar leedehai avatar orionnebula avatar pietrek14 avatar razrfalcon avatar ruifengx avatar shubhamj280 avatar skalt avatar wezm avatar wjian23 avatar xnuk avatar yisibl avatar zimond avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ttf-parser's Issues

Point direction request

I ran into this font which defines and uses glyphs in the CFF and glyf tables: https://github.com/emilk/egui/blob/master/egui/fonts/Comfortaa-Regular.ttf

My rasterizer needs to know the point winding before it can run outline_glyph. For TrueType, a counter clockwise contour will always define the outside edge of a filled area, and a clockwise contour will always define the inside edge of a filled area. This is reversed for OpenType fonts.

Is there a way to know if for a given GlyphId, the glyph is from an OpenType table or TrueType table?

bug: ttf width is not parsed correctly

in os2.rs#width(), due to the default number in Rust is i32, here Stream::read_at will read 4 bytes instead of the length of width (which is u16, 2 bytes), leading to width never correctly parsed

Port GPOS/GSUB from rustybuzz

These three tables are key to modern fonts, especially for non-latin scripts.

rustybuzz already parses these tables to do glyph substitution and positioning, so the parsing code simply needs to be refactored for use in this library.

(If there's some reason keep the parsing of said tables in rustybuzz, it should be documented in the README)

bbox fallback regression in 0.12.2

I have a regression test for #49 that's been broken by 0.12.2.

For example for airstrip GlyphId(89).

0.12.1

Rect {
    x_min: 0,
    y_min: -3,
    x_max: 1102,
    y_max: 1301,
}

0.12.2

Rect {
    x_min: 0,
    y_min: 0,
    x_max: 0,
    y_max: 0,
}

Support a check for when a glyph has no outline, ie is invisible

During glyph layout (in glyph_brush_layout) I check if a glyph is invisible or not which can impact whether a word can fit into a line or not.

This check is currently done by see if the glyph has a bounding box or not, which is fast for the ttf fonts that are currently supported. Looking forward to using .otf this will no longer be a generally fast method.

Is there a quick way of checking this in general for .otf?

Another related idea is to switching the full compute OutlineBuilder with an OutlineIterator. If we had that presumably it would be possible to call:

let invisible = g.outline_iter().next().is_none()

How to get maximum character width?

I'm trying to render a text entry box that allows for up to 30 characters to be entered. To calculate its width, I need to know the max possible width of a 30-character string. Assuming nothing funny happens with spacing between letters, I think I can just multiply 30 by the max width of any character in that font.

I found global_bounding_box, and so I'm trying this:

let font_id = ...;
let font_size = 21;
fontdb.with_face_data(font_id, |data, face_index| {
        let font = ttf_parser::Face::from_slice(data, face_index).unwrap();
        let scale = (font_size as f64) / (font.units_per_em().unwrap() as f64);
        scale * font.global_bounding_box().width() as f64
})

For the Overpass regular font, I get 30.4 from this, which seems visually to be too wide for most of the alphanumeric characters I'm trying out. Is there maybe an outlier character that's especially wide, or is this calculation incorrect? I'm not sure what units global_bounding_box returns, nor if my understanding of units_per_em is correct.

Thanks!

Outline utilities

Hi!

I'm playing around with replacing FreeType with tff-parser in one of my projects.
I've made a couple of changes to be able to embolden and slant an outline.
The embolden algorithm is ported directly from the FreeType sources. To change
as little as possible of the original source I added a new method (that does nothing by default)
on the OutlineBuilder trait. The rest of the functionality lives in it's own module.

You can check my commit in this branch if interested:

https://github.com/chrsan/ttf-parser/tree/outline_utils

Iterating through all kerning values

The ttf_parser::kern::Subtable API allows you to get the kerning information for two ordered glyphs.

Given stateful kerning (format 1) is unsupported, would it be reasonable to add API to iterate through all kerning pairs in a subtable? This is definitely trivial for format 0, but I haven't looked into 2 and 3.

make c wrapper no_std

I am getting

/usr/bin/ld: subprojects/ttf-parser/libttf_parser_capi.a(std-205127404fcba336.std.595pxchd-cgu.0.rcgu.o): undefined reference to symbol 'pthread_getattr_np@@GLIBC_2.2.5'

and

/usr/bin/ld: subprojects/ttf-parser/libttf_parser_capi.a(std-205127404fcba336.std.595pxchd-cgu.0.rcgu.o): in function 'std::sys::unix::weak::fetch': /rustc/49cae55760da0a43428eba73abcb659bb70cf2e4//src/libstd/sys/unix/weak.rs:61: undefined reference to 'dlsym'

if I don't pass thread_dep, cpp.find_library('dl') (which currently I am) and guess those are coming from rust's std, can c-api also become no_std so I can avoid passing https://github.com/harfbuzz/harfbuzz/pull/2510/files#diff-9356922ca3ded90602b144c3b5851dd2R8 pthread and libdl to it? Or is it something you are interested in at all so I can also have a look?

Thanks!

Cmap ignores platform/encoding

You're ignoring the encoding ID but accepting a Unicode char as the lookup. This is incorrect behavior. If the encoding is some windows code page instead, and you lookup the Unicode 'a', whatever you get back is worthless. If you do get a mapping for it, it's definitely not for the letter a.

It's likely that fonts that use non-unicode encodings are rare in the wild, but this library will silently do the wrong thing as it stands.

Font fallbacks

@RazrFalcon have you thought about font fallbacks? As I understand, there are two parts: selecting fallback fonts, and building a virtual font pulling glyphs from the first supporting font. The second part could be supported here or could be left to a higher-level library.

The Face struct has several classes of methods:

  • from_slice constructor
  • has_table, table_data, character_mapping_subtables, ... — low-level stuff which it doesn't make sense to expose in a virtual "fallback font"
  • is_regular, is_monospaced, weight, ascender, ... — properties which could be taken from the first font (or perhaps in some cases combined via a func like max)
  • glyph_index(char), glyph_hor_advance(glyph_id), outline_glyph(glyph_id, builder), ... — glyph-specific functionality abstracted over by the virtual fallback font

The GlyphId type currently uses a u16 which is likely insufficient for the fallback font — this type could be made an associated type of a trait or simply larger.

Given the above, it might make more sense to implement font fallback at a higher level, e.g. via the ab_glyph::Font trait (if @alexheretic wishes to support font fallbacks), but I thought it would make sense to ask here first since (a) you (@RazrFalcon) may have already considered this and (b) whatever choice is made here has implications for downstream libraries (e.g. whether GlyphId becomes an associated type).

[CFF] OffSize value of zero used in tests is invalid

Hi, I am working on porting ttf-parser's CharString porting code to Allsorts. I noticed that in the CharString tests CFF fonts are built with an OffSize in the header of zero, which Allsorts rejects. This works in ttf-parser because this value is skipped. The comment on that line (and in the tests) suggest that perhaps is value has been misinterpreted as it's not an absolute offset but the size in bytes of absolute offsets with valid values being 1–4.

This is what the CFF1 reference says:

Screenshot from 2021-01-14 13-47-48

CFF2 says:

Name Range Description
OffSize 1 to 4 1-byte unsigned number specifies the size of an Offset field or fields

Anyway not a huge issue since the value is unused but I thought I'd mention it anyway.

Fails to outline 'i' in Carlito font

I've been wondering why 'i' does not get rendered with this font (most glyphs do render). Is this hitting an unsupported feature?

Code: https://gist.github.com/dhardy/60ef7de0e291e54ef7b4e2f8b95e1819
Font: /usr/share/fonts/google-carlito-fonts/Carlito-Regular.ttf

Output:

ttf-parser index: 98
ttf-parser bounding box: Rect { x_min: 110, y_min: 0, x_max: 357, y_max: 1409 }
ttf-parser failed to outline glyph
fontdue index: 98
fontdue metrics: Metrics { xmin: 0, ymin: 0, width: 0, height: 0, advance_width: 9.1796875, advance_height: 0.0, bounds: OutlineBounds { xmin: 0.0, ymin: 0.0, width: 0.0, height: 0.0 } }

Why ttf_parser::Face need a lifetime?

https://github.com/RazrFalcon/ttf-parser/blob/master/src/lib.rs#L580

pub struct Face<'a> {
    ...
}
impl<'a> Face<'a> {
    pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> { 
    }
}

It seems Face need reference the bytes for a long time.
I can not understand of the lifetime here, why it is necessity?
Is font parse not one-time action?

For this reason, I can't simply define a struct attr like:

pub struct Renderer {
    font: Face,     // <---- error!!! must gave a lifetime
}

This puts a lot of restrictions on the code design.
But i really can't figure it out.

Providing a get_glyph_extents like API

Something equivalent to hb_font_get_glyph_extents from ttf-parser would be nice so I can use in benchmarking, there is ttfp_get_glyph_{hor,ver}_{advance,side_bearing} which I guess won't be good enough for comparison to that API.

Should typographic ascender/descender be default for fonts with OS/2 table version < 4?

Hello,

A recent of upgrade of the ttf-parser dependency in the femtovg crate has caused an issue with alignment of the icons (provided by characters in the entypo font), as can be seen here: femtovg/femtovg#56.

As noted in the issue, this problem has been tracked down to d32a5de, which added windows acender/ descender if the USE_TYPO_METRICS flag is not set.

Looking into this I think the problem may be in the is_use_typo_metrics() function here:

pub fn is_use_typo_metrics(&self) -> bool {
if self.version < 4 {
false
} else {
SelectionFlags(self.fs_selection()).use_typo_metrics()
}
}

This function returns false is the OS/2 table version is less than 4, which makes sense because the USE_TYPO_METRICS flag was only introduced in version 4, but this means that the above function will cause the selection of ascender/descender to default to windows. The entypo font has an OS/2 table which is version 3. Now I can't find anything in the docs to suggest what the default ascender/descender selection should be for fonts with a version less than 4, but since it seems to be broken I would guess that maybe it should default to typographic.

My knowledge of font tables is limited so let me know if I'm way off here and if the solution should be on the femtovg usage side of things. Thanks.

Symbola.ttf invalid glyph bounds

This font has glyph(s) that produce return invalid bounding boxes, e.g. with y_min == y_max. I'd expect these to return None when calling outline_glyph.

Presumably this font is dodgy. Should ttf-parser handle this or should I downstream?

Reproduce

// [dependencies]
// ttf-parser = "0.12"

/// https://github.com/gearit/ttf-symbola/raw/master/Symbola.ttf
const FONT: &[u8] = include_bytes!("../Symbola.ttf");

fn main() {
    let face = ttf_parser::Face::from_slice(FONT, 0).unwrap();
    let gid = ttf_parser::GlyphId(893);

    let bounds = face.outline_glyph(gid, &mut OutlinePrinter);
    eprintln!("outline_glyph({:?}, _) = {:?}", gid, bounds);
    if let Some(b) = bounds {
        assert!(b.x_min < b.x_max && b.y_min < b.y_max);
    }
}

struct OutlinePrinter;

impl ttf_parser::OutlineBuilder for OutlinePrinter {
    fn move_to(&mut self, x: f32, y: f32) {
        eprintln!("outline-move_to({}, {})", x, y);
    }
    fn line_to(&mut self, x: f32, y: f32) {
        eprintln!("outline-line_to({}, {})", x, y);
    }
    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
        eprintln!("outline-quad_to({}, {}, {}, {})", x1, y1, x, y);
    }
    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
        eprintln!(
            "outline-curve_to({}, {}, {}, {}, {}, {})",
            x1, y1, x2, y2, x, y
        );
    }
    fn close(&mut self) {
        eprintln!("outline-close");
    }
}
outline-move_to(0, 1606)
outline-line_to(0, 1606)
outline-close
outline-move_to(2048, 1606)
outline-line_to(2048, 1606)
outline-close
outline_glyph(GlyphId(893), _) = Some(Rect { x_min: 0, y_min: 1606, x_max: 2048, y_max: 1606 })
thread 'main' panicked at 'assertion failed: b.x_min < b.x_max && b.y_min < b.y_max', src/main.rs:14:9

ab-glyph issue: alexheretic/ab-glyph#32

Add glyf bbox fallback

Using airstrip.ttf https://dl.dafont.com/dl/?f=airstrip_four character v returns a zero bounding box result from outline_glyph which seems wrong.

Reproduce

const AIRSTRIP: &[u8] = include_bytes!("../airstrip.ttf");

fn main() {
    let airstrip = ttf_parser::Face::from_slice(AIRSTRIP, 0).unwrap();

    let v = airstrip.glyph_index('v').unwrap();
    let bounds = airstrip.outline_glyph(v, &mut OutlinePrinter);

    dbg!(bounds);
}

struct OutlinePrinter;

impl ttf_parser::OutlineBuilder for OutlinePrinter {
    fn move_to(&mut self, x: f32, y: f32) {
        eprintln!("outline-move_to({}, {})", x, y);
    }
    fn line_to(&mut self, x: f32, y: f32) {
        eprintln!("outline-line_to({}, {})", x, y);
    }
    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
        eprintln!("outline-quad_to({}, {}, {}, {})", x1, y1, x, y);
    }
    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
        eprintln!("outline-curve_to({}, {}, {}, {}, {}, {})", x1, y1, x2, y2, x, y);
    }
    fn close(&mut self) {
        eprintln!("outline-close");
    }
}
outline-move_to(955, 1301)
outline-quad_to(864, 1298, 833, 1247)
outline-quad_to(802, 1196, 552, 447)
outline-quad_to(300, 1196, 272.5, 1248.5)
outline-quad_to(245, 1301, 150, 1301)
outline-quad_to(0, 1301, 0, 1151)
outline-line_to(401, 99)
outline-quad_to(443, 14, 493.5, 5.5)
outline-quad_to(544, -3, 602.5, 2.5)
outline-quad_to(661, 8, 697, 99)
outline-line_to(1102, 1149)
outline-quad_to(1102, 1301, 955, 1301)
outline-close
[src/main.rs:11] bounds = Some(
    Rect {
        x_min: 0,
        y_min: 0,
        x_max: 0,
        y_max: 0,
    },
)

Are there plans to support COLR/CPAL tables?

COLR format fonts are part of the OpenType specification. It is the perfect companion for emoji and font icons in usage scenarios. This has become so popular that all major browsers support COLRv0.

image

And Chrome will soon ship COLRv1, which will bring many new features such as gradients, transforms and compositing.

2023-09-21

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.