Skip to content
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

Merged
merged 7 commits into from Jan 23, 2018

Conversation

bramp
Copy link
Collaborator

@bramp bramp commented Jan 21, 2018

No description provided.

@bramp
Copy link
Collaborator Author

bramp commented Jan 21, 2018

For example:

$ go run main.go features ~/path/to/font.woff 

Glyph Substitution Table (GSUB):
	Script "DFLT" (Default):
		Default Language:
			Feature "aalt" (Access All Alternates)
			Feature "c2sc" (Small Capitals From Capitals)
			Feature "case" (Case-Sensitive Forms)
			Feature "crcy" (Currency (Deprecated))
		Language "AZE " (Azerbaijani):
			Feature "smcp" (Small Capitals)
	Script "cyrl" (Cyrillic):
		Default Language:
			Feature "aalt" (Access All Alternates)
			Feature "c2sc" (Small Capitals From Capitals)
			Feature "case" (Case-Sensitive Forms)
			Feature "crcy" (Currency (Deprecated))

Glyph Positioning Table (GPOS):
	Script "DFLT" (Default):
		Default Language:
			Feature "kern" (Kerning)
	Script "cyrl" (Cyrillic):
		Default Language:
			Feature "kern" (Kerning)
	Script "latn" (Latin):
		Default Language:
			Feature "kern" (Kerning)
		Language "AZE " (Azerbaijani):
			Feature "kern" (Kerning)

"github.com/ConradIrwin/font/sfnt"
)

func layoutTable(font *sfnt.Font, tag sfnt.Tag, name string) {
Copy link
Collaborator

@dmitshur dmitshur Jan 21, 2018

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.

Copy link
Collaborator Author

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.

@dmitshur
Copy link
Collaborator

(The rest of this PR is awesome, nice work!)

Copy link
Collaborator

@dmitshur dmitshur left a 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.

"github.com/ConradIrwin/font/sfnt"
)

// Features prints the gpos/gsub tables (contins font features).
Copy link
Collaborator

@dmitshur dmitshur Jan 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/contins/contains/

Copy link
Collaborator Author

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)
Copy link
Collaborator

@dmitshur dmitshur Jan 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/contins/contains/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

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"
Copy link
Owner

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)

Copy link
Owner

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...? )

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will fix.

Copy link
Collaborator Author

@bramp bramp Jan 23, 2018

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"))
Copy link
Owner

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)

Copy link
Collaborator Author

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)
Copy link
Owner

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?

Copy link
Collaborator Author

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.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be incredible 😻


t := font.Table(tag).(*sfnt.TableLayout)
for _, script := range t.Scripts {
fmt.Printf("\tScript %q (%s):\n", script.Tag, script.String())
Copy link
Owner

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?

Copy link
Collaborator Author

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?

Copy link
Owner

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

Copy link
Collaborator Author

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
Copy link
Owner

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?

Copy link
Collaborator Author

@bramp bramp Jan 23, 2018

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:]
Copy link
Owner

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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:]

@ConradIrwin
Copy link
Owner

Otherwise this looks great.

If you have the time, a test would be great, but happy to merge without.

@ConradIrwin
Copy link
Owner

(Thanks for the other view @shurcooL )

@ConradIrwin
Copy link
Owner

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.

@bramp
Copy link
Collaborator Author

bramp commented Jan 23, 2018

I've pushed my changes, if you want to make one more pass before merging?

@ConradIrwin
Copy link
Owner

Thanks!

@ConradIrwin ConradIrwin merged commit 03e4be4 into ConradIrwin:master Jan 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants