Add measurement stage
This commit is contained in:
parent
569defdb36
commit
37554dd719
45
measure.go
Normal file
45
measure.go
Normal file
@ -0,0 +1,45 @@
|
||||
package typeset
|
||||
|
||||
import "golang.org/x/image/font"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
|
||||
func measure (tokens []token, face font.Face) {
|
||||
var lastRune rune
|
||||
for index, token := range tokens {
|
||||
var x fixed.Int26_6
|
||||
for index, runl := range token.runes {
|
||||
advance, ok := face.GlyphAdvance(runl.run)
|
||||
if !ok { advance = tofuAdvance(face) }
|
||||
advance += face.Kern(lastRune, runl.run)
|
||||
|
||||
runl.x = x
|
||||
x += advance
|
||||
lastRune = runl.run
|
||||
token.runes[index] = runl
|
||||
}
|
||||
token.width = x
|
||||
tokens[index] = token
|
||||
}
|
||||
}
|
||||
|
||||
const tofuStandinRune = 'M'
|
||||
const fallbackTofuAdvance = 16
|
||||
const fallbackTofuWidth = 14
|
||||
const fallbackTofuAscend = 16
|
||||
|
||||
func tofuAdvance (face font.Face) fixed.Int26_6 {
|
||||
if advance, ok := face.GlyphAdvance(tofuStandinRune); ok {
|
||||
return advance
|
||||
} else {
|
||||
return fallbackTofuAdvance
|
||||
}
|
||||
}
|
||||
|
||||
func tofuBounds (face font.Face) (fixed.Rectangle26_6, fixed.Int26_6) {
|
||||
if bounds, advance, ok := face.GlyphBounds(tofuStandinRune); ok {
|
||||
return bounds, advance
|
||||
} else {
|
||||
return fixed.R(0, -fallbackTofuAscend, fallbackTofuWidth, 0),
|
||||
fallbackTofuAdvance
|
||||
}
|
||||
}
|
70
measure_test.go
Normal file
70
measure_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
package typeset
|
||||
|
||||
import "testing"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "golang.org/x/image/font/basicfont"
|
||||
|
||||
const basicfontFace7x13advance = 7
|
||||
|
||||
func tkw (kind tokenKind, value string, width fixed.Int26_6) token {
|
||||
tok := tk(kind, value)
|
||||
tok.width = width
|
||||
for index, runl := range tok.runes {
|
||||
runl.x = fixed.I(basicfontFace7x13advance * index)
|
||||
tok.runes[index] = runl
|
||||
}
|
||||
return tok
|
||||
}
|
||||
|
||||
func TestMeasure (test *testing.T) {
|
||||
// ---- processing ----
|
||||
tokens := []token {
|
||||
tk(tokenKindWord, "hello"),
|
||||
tk(tokenKindSpace, " "),
|
||||
tk(tokenKindWord, "\rworld!"),
|
||||
tk(tokenKindLineBreak, "\n"),
|
||||
tk(tokenKindWord, "foo"),
|
||||
tk(tokenKindLineBreak, "\n"),
|
||||
tk(tokenKindLineBreak, "\r\n"),
|
||||
tk(tokenKindWord, "bar"),
|
||||
tk(tokenKindTab, "\t"),
|
||||
tk(tokenKindWord, "baz"),
|
||||
tk(tokenKindTab, "\t\t"),
|
||||
tk(tokenKindWord, "something"),
|
||||
}
|
||||
measure(tokens, basicfont.Face7x13)
|
||||
|
||||
// ---- correct data ----
|
||||
correctTokens := []token {
|
||||
tkw(tokenKindWord, "hello", fixed.I(35)),
|
||||
tkw(tokenKindSpace, " ", fixed.I( 7)),
|
||||
tkw(tokenKindWord, "\rworld!", fixed.I(49)),
|
||||
tkw(tokenKindLineBreak, "\n", fixed.I( 7)),
|
||||
tkw(tokenKindWord, "foo", fixed.I(21)),
|
||||
tkw(tokenKindLineBreak, "\n", fixed.I( 7)),
|
||||
tkw(tokenKindLineBreak, "\r\n", fixed.I(14)),
|
||||
tkw(tokenKindWord, "bar", fixed.I(21)),
|
||||
tkw(tokenKindTab, "\t", fixed.I( 7)),
|
||||
tkw(tokenKindWord, "baz", fixed.I(21)),
|
||||
tkw(tokenKindTab, "\t\t", fixed.I(14)),
|
||||
tkw(tokenKindWord, "something", fixed.I(63)),
|
||||
}
|
||||
|
||||
// ---- testing ----
|
||||
if len(tokens) != len(correctTokens) {
|
||||
test.Logf("len(tokens) != len(correctTokens): %d, %d", len(tokens), len(correctTokens))
|
||||
test.Log("GOT")
|
||||
logTokens(test, tokens)
|
||||
test.Log("CORRECT")
|
||||
logTokens(test, correctTokens)
|
||||
test.FailNow()
|
||||
}
|
||||
if !compareTokens(tokens, correctTokens) {
|
||||
test.Log("tokens != correctTokens:")
|
||||
test.Log("GOT")
|
||||
logTokens(test, tokens)
|
||||
test.Log("CORRECT")
|
||||
logTokens(test, correctTokens)
|
||||
test.FailNow()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user