Add parsing code for the Font Features, as well as new command - #3
Conversation
|
For example: |
| "github.com/ConradIrwin/font/sfnt" | ||
| ) | ||
|
|
||
| func layoutTable(font *sfnt.Font, tag sfnt.Tag, name string) { |
There was a problem hiding this comment.
I’d suggest moving layoutTable to the bottom, under Features, rather than on top.
In Go, it’s common to order code from higher level functions first to lower level helpers second. That way, when reading code, you first encounter higher level, easier to understand code that helps provide context for the helpers. Then, once you're familiar with how a helper is being used and why it’s needed, reading its code is easier.
There was a problem hiding this comment.
Thanks for the feedback. Good point. Fixed.
|
(The rest of this PR is awesome, nice work!) |
dmitshur
left a comment
There was a problem hiding this comment.
Spotted a couple typos.
| "github.com/ConradIrwin/font/sfnt" | ||
| ) | ||
|
|
||
| // Features prints the gpos/gsub tables (contins font features). |
| Usage: font [scrub|info|stats] font.[otf,ttf,woff] | ||
| Usage: font [features|info|metrics|scrub|stats] font.[otf,ttf,woff] | ||
|
|
||
| features: prints the gpos/gsub tables (contins font features) |
| } | ||
|
|
||
| if len(tag) == 4 && tag[0] == 'c' && tag[1] == 'v' && tag[2] >= '0' && tag[2] <= '9' && tag[3] >= '0' && tag[3] <= '9' { | ||
| return "Character Variants" |
There was a problem hiding this comment.
@bramp might be worth preserving the number here (e.g. Character Variables 01)
There was a problem hiding this comment.
(Also, should we do the same parsing for ss01...? )
There was a problem hiding this comment.
Added numeric suffix, plus added support for ss01... and added a test.
| // Features prints the gpos/gsub tables (contains font features). | ||
| func Features() { | ||
| if len(os.Args) < 2 { | ||
| panic(fmt.Errorf("Specify a font file")) |
There was a problem hiding this comment.
Can we start to improve the code for handling these errors, we should make it clear how to fix the problem, and make the error message more legible. (I appreciate the other commands aren't yet very good).
fmt.Printf("Usage: font features <font-file>")
os.Exit(1)
There was a problem hiding this comment.
I'll do that in a later PR.
| if font.HasTable(tag) { | ||
| fmt.Printf("%s:\n", name) | ||
|
|
||
| t := font.Table(tag).(*sfnt.TableLayout) |
There was a problem hiding this comment.
@bramp This will panic if parsing fails. I'm not sure what to do about that except maybe change the library so that it parses tables on-demand instead of up-front so we can return a sensible error. Any better ideas?
There was a problem hiding this comment.
Yes, panic'ng sucks. After this I'd be happy to change the whole library to pass back the errors.
|
|
||
| t := font.Table(tag).(*sfnt.TableLayout) | ||
| for _, script := range t.Scripts { | ||
| fmt.Printf("\tScript %q (%s):\n", script.Tag, script.String()) |
There was a problem hiding this comment.
When I run this on a font I see a weird:
Script " " ():
Do you know why? Can we make it clearer what it means?
There was a problem hiding this comment.
Would you email me that font?
There was a problem hiding this comment.
it's here: https://gist.github.com/ConradIrwin/a85f8e432fedf2cd4ea400286a796b5e
If you have the gist tool installed (brew install gist) you can get the file with: gist -r a85f8e432fedf2cd4ea400286a796b5e | base64 --decode > adelle.ttf
There was a problem hiding this comment.
So that font has a script who's tag is 0x20202020 (four space characters). The spec says nothing about what this means, so I suspect it is just some weird artefact.
I've changed the tool to not display the () if the name is unknown.
| type scriptTable struct { | ||
| DefaultLangSys uint16 // Offset to default LangSys table, from beginning of Script table — may be NULL | ||
| LangSysCount uint16 // Number of LangSysRecords for this script — excluding the default LangSys | ||
| // langSysRecords[langSysCount] langSysRecord // Array of LangSysRecords, listed alphabetically by LangSys tag |
There was a problem hiding this comment.
@bramp Why is this here but commented out? Should we uncomment it or delete it?
There was a problem hiding this comment.
Ah yes, perhaps unclear. The ondisk format has a variable length array as the last element. I explicitly deal with that in the code, but left the field commented to indicate it was there.
I can drop the comment, or make it clear why it's there.
| return nil, io.ErrUnexpectedEOF | ||
| } | ||
|
|
||
| b = b[record.Offset:] |
There was a problem hiding this comment.
@bramp Is there a byte length on the record? I'm worried about the parsing code reading beyond the length of the record.
There was a problem hiding this comment.
nope, there is sadly no length for any of these fields. I suspect they are all contained within the single table.
There was a problem hiding this comment.
ah yes, all the records are within the same table, and that b array only contains the current table:
buffer := io.NewSectionReader(file, int64(entry.Offset), int64(entry.Length))
table, err := parseTable(entry.Tag, buffer)
...
b, err := ioutil.ReadAll(buffer)
...
b = b[record.Offset:]|
Otherwise this looks great. If you have the time, a test would be great, but happy to merge without. |
|
(Thanks for the other view @shurcooL ) |
|
P.S I added you both as collaborators to this repository. Please notify me for PRs with large changes or API changes — but happy if you want to merge your own PRs for tweaks to code-style / error messages. |
|
I've pushed my changes, if you want to make one more pass before merging? |
|
Thanks! |
No description provided.