New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add parsing code for the Font Features, as well as new command #3
Conversation
For example:
|
commands/features.go
Outdated
"github.com/ConradIrwin/font/sfnt" | ||
) | ||
|
||
func layoutTable(font *sfnt.Font, tag sfnt.Tag, name string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback. Good point. Fixed.
(The rest of this PR is awesome, nice work!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted a couple typos.
commands/features.go
Outdated
"github.com/ConradIrwin/font/sfnt" | ||
) | ||
|
||
// Features prints the gpos/gsub tables (contins font features). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/contins/contains/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
main.go
Outdated
|
||
features: prints the gpos/gsub tables (contins font features) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/contins/contains/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
sfnt/table_feature.go
Outdated
} | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bramp might be worth preserving the number here (e.g. Character Variables 01)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, should we do the same parsing for ss01
...? )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, will fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, panic'ng sucks. After this I'd be happy to change the whole library to pass back the errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd be incredible 😻
commands/features.go
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you email me that font?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bramp Why is this here but commented out? Should we uncomment it or delete it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.