googlefonts / fontations

Reading and writing font files
Apache License 2.0
396 stars 26 forks source link

[skrifa] Please add a glyph name function #1261

Open simoncozens opened 12 hours ago

simoncozens commented 12 hours ago

I find myself carrying this bit of code everywhere I go:

    fn glyph_name_for_id_impl(&self, gid: impl Into<GlyphId>, synthesize: bool) -> Option<String> {
        let gid: GlyphId = gid.into();
        if self._glyphnames.borrow().is_empty() {
            if let Ok(post) = self.font().post() {
                match post.version() {
                    Version16Dot16::VERSION_1_0 => {
                        let names = DEFAULT_GLYPH_NAMES.into_iter().map(|x| Some(x.to_string()));
                        self._glyphnames.borrow_mut().extend(names);
                    }
                    Version16Dot16::VERSION_2_0 => {
                        let strings: Vec<Option<read_fonts::tables::post::PString>> =
                            post.string_data()?.iter().map(|x| x.ok()).collect();
                        if let Some(index) = post.glyph_name_index() {
                            let names = (0..self.glyph_count).map(|gid| {
                                let idx = index.get(gid)?.get() as usize;
                                if idx < 258 {
                                    Some(DEFAULT_GLYPH_NAMES[idx].to_string())
                                } else {
                                    let entry = strings.get(idx - 258)?;
                                    entry.map(|x| x.to_string())
                                }
                            });
                            self._glyphnames.borrow_mut().extend(names);
                        }
                    }
                    _ => {}
                }
            }
        }
        if let Some(Some(n)) = self._glyphnames.borrow().get(gid.to_u32() as usize) {
            Some(n.to_string())
        } else if synthesize {
            Some(format!("gid{:}", gid))
        } else {
            None
        }
    }

(Note that this gets all the glyph names at once and then uses a _glyphnames cache because random access on the post table is unpleasantly slow #1106; I guess in a library function you may have to bite the bullet and do random access, and end users can cache it if they want to.)