Skip to content

Commit

Permalink
Merge 21853f5 into e2600b3
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverpool committed May 4, 2020
2 parents e2600b3 + 21853f5 commit 8b9f6ac
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 157 deletions.
4 changes: 2 additions & 2 deletions canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"os"
)

const mmPerPt = 0.3527777777777778
const ptPerMm = 2.8346456692913384
const mmPerPt = 25.4 / 72
const ptPerMm = 72 / 25.4
const mmPerInch = 25.4
const inchPerMm = 1 / 25.4

Expand Down
22 changes: 20 additions & 2 deletions font.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,25 @@ func (f *Font) Raw() (string, []byte) {
return f.mimetype, f.raw
}

func (f *Font) pdfInfo() (Rect, float64, float64, float64, float64, []int) {
// Kerning returns the horizontal adjustment for the rune pair. A positive kern means to move the glyphs further apart.
func (f *Font) Kerning(left, right rune, ppem float64) (float64, error) {
var sfntBuffer sfnt.Buffer

iLeft, err := f.sfnt.GlyphIndex(&sfntBuffer, left)
if err != nil {
return 0, err
}
iRight, err := f.sfnt.GlyphIndex(&sfntBuffer, right)
if err != nil {
return 0, err
}

kern, err := f.sfnt.Kern(&sfntBuffer, iLeft, iRight, toI26_6(ppem), font.HintingNone)

return fromI26_6(kern), err
}

func (f *Font) PdfInfo() (Rect, float64, float64, float64, float64, []int) {
buffer := &sfnt.Buffer{}
units := float64(f.sfnt.UnitsPerEm())

Expand Down Expand Up @@ -106,7 +124,7 @@ func (f *Font) pdfInfo() (Rect, float64, float64, float64, float64, []int) {
return bounds, italicAngle, ascent, descent, capHeight, widths
}

func (f *Font) toIndices(s string) []uint16 {
func (f *Font) IndicesOf(s string) []uint16 {
buffer := &sfnt.Buffer{}
runes := []rune(s)
indices := make([]uint16, len(runes))
Expand Down
2 changes: 1 addition & 1 deletion font_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestParseTTF(t *testing.T) {
test.Float(t, capHeight, -729.00390625)
test.T(t, len(widths), 3528)

indices := font.toIndices("test")
indices := font.IndicesOf("test")
test.T(t, len(indices), 4)
}

Expand Down
74 changes: 30 additions & 44 deletions fontface.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,41 +164,41 @@ func (family *FontFamily) Face(size float64, col color.Color, style FontStyle, v
r, g, b, a := col.RGBA()
return FontFace{
family: family,
font: font,
Font: font,
Size: size,
Style: style,
Variant: variant,
Color: color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)},
deco: deco,
Scale: scale,
Voffset: voffset,
fauxItalic: fauxItalic,
fauxBold: fauxBold * size * scale,
FauxItalic: fauxItalic,
FauxBold: fauxBold * size * scale,
}
}

// FontFace defines a font face from a given font. It allows setting the font size, its color, faux styles and font decorations.
type FontFace struct {
family *FontFamily
font *Font
Font *Font

Size float64
Style FontStyle
Variant FontVariant
Color color.RGBA
deco []FontDecorator

Scale, Voffset, fauxBold, fauxItalic float64 // consequences of font style and variant
Scale, Voffset, FauxBold, FauxItalic float64 // consequences of font style and variant
}

// Equals returns true when two font face are equal. In particular this allows two adjacent text spans that use the same decoration to allow the decoration to span both elements instead of two separately.
func (ff FontFace) Equals(other FontFace) bool {
return ff.font == other.font && ff.Size == other.Size && ff.Style == other.Style && ff.Variant == other.Variant && ff.Color == other.Color && reflect.DeepEqual(ff.deco, other.deco)
return ff.Font == other.Font && ff.Size == other.Size && ff.Style == other.Style && ff.Variant == other.Variant && ff.Color == other.Color && reflect.DeepEqual(ff.deco, other.deco)
}

// Name returns the name of the underlying font
func (ff FontFace) Name() string {
return ff.font.name
return ff.Font.name
}

// FontMetrics contains a number of metrics that define a font face.
Expand All @@ -214,7 +214,7 @@ type FontMetrics struct {
// Metrics returns the font metrics. See https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png for an explanation of the different metrics.
func (ff FontFace) Metrics() FontMetrics {
buffer := &sfnt.Buffer{}
m, _ := ff.font.sfnt.Metrics(buffer, toI26_6(ff.Size*ff.Scale), font.HintingNone)
m, _ := ff.Font.sfnt.Metrics(buffer, toI26_6(ff.Size*ff.Scale), font.HintingNone)
return FontMetrics{
Size: ff.Size,
LineHeight: math.Abs(fromI26_6(m.Height)),
Expand All @@ -227,22 +227,8 @@ func (ff FontFace) Metrics() FontMetrics {

// Kerning returns the kerning between two runes in mm (ie. the adjustment on the advance).
func (ff FontFace) Kerning(rPrev, rNext rune) float64 {
buffer := &sfnt.Buffer{}
prevIndex, err := ff.font.sfnt.GlyphIndex(buffer, rPrev)
if err != nil {
return 0.0
}

nextIndex, err := ff.font.sfnt.GlyphIndex(buffer, rNext)
if err != nil {
return 0.0
}

kern, err := ff.font.sfnt.Kern(buffer, prevIndex, nextIndex, toI26_6(ff.Size*ff.Scale), font.HintingNone)
if err == nil {
return fromI26_6(kern)
}
return 0.0
k, _ := ff.Font.Kerning(rPrev, rNext, ff.Size*ff.Scale)
return k
}

// TextWidth returns the width of a given string in mm.
Expand All @@ -251,18 +237,18 @@ func (ff FontFace) TextWidth(s string) float64 {
w := 0.0
var prevIndex sfnt.GlyphIndex
for i, r := range s {
index, err := ff.font.sfnt.GlyphIndex(buffer, r)
index, err := ff.Font.sfnt.GlyphIndex(buffer, r)
if err != nil {
continue
}

if i != 0 {
kern, err := ff.font.sfnt.Kern(buffer, prevIndex, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
kern, err := ff.Font.sfnt.Kern(buffer, prevIndex, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
if err == nil {
w += fromI26_6(kern)
}
}
advance, err := ff.font.sfnt.GlyphAdvance(buffer, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
advance, err := ff.Font.sfnt.GlyphAdvance(buffer, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
if err == nil {
w += fromI26_6(advance)
}
Expand All @@ -289,12 +275,12 @@ func (ff FontFace) ToPath(s string) (*Path, float64) {
x := 0.0
var prevIndex sfnt.GlyphIndex
for i, r := range s {
index, err := ff.font.sfnt.GlyphIndex(buffer, r)
index, err := ff.Font.sfnt.GlyphIndex(buffer, r)
if err != nil {
return p, 0.0
}

segments, err := ff.font.sfnt.LoadGlyph(buffer, index, toI26_6(ff.Size*ff.Scale), nil)
segments, err := ff.Font.sfnt.LoadGlyph(buffer, index, toI26_6(ff.Size*ff.Scale), nil)
if err != nil {
return p, 0.0
}
Expand All @@ -307,43 +293,43 @@ func (ff FontFace) ToPath(s string) (*Path, float64) {
p.Close()
}
end = fromP26_6(segment.Args[0])
end.X += ff.fauxItalic * -end.Y
end.X += ff.FauxItalic * -end.Y
p.MoveTo(x+end.X, ff.Voffset-end.Y)
start0 = end
case sfnt.SegmentOpLineTo:
end = fromP26_6(segment.Args[0])
end.X += ff.fauxItalic * -end.Y
end.X += ff.FauxItalic * -end.Y
p.LineTo(x+end.X, ff.Voffset-end.Y)
case sfnt.SegmentOpQuadTo:
cp := fromP26_6(segment.Args[0])
end = fromP26_6(segment.Args[1])
cp.X += ff.fauxItalic * -cp.Y
end.X += ff.fauxItalic * -end.Y
cp.X += ff.FauxItalic * -cp.Y
end.X += ff.FauxItalic * -end.Y
p.QuadTo(x+cp.X, ff.Voffset-cp.Y, x+end.X, ff.Voffset-end.Y)
case sfnt.SegmentOpCubeTo:
cp1 := fromP26_6(segment.Args[0])
cp2 := fromP26_6(segment.Args[1])
end = fromP26_6(segment.Args[2])
cp1.X += ff.fauxItalic * -cp1.Y
cp2.X += ff.fauxItalic * -cp2.Y
end.X += ff.fauxItalic * -end.Y
cp1.X += ff.FauxItalic * -cp1.Y
cp2.X += ff.FauxItalic * -cp2.Y
end.X += ff.FauxItalic * -end.Y
p.CubeTo(x+cp1.X, ff.Voffset-cp1.Y, x+cp2.X, ff.Voffset-cp2.Y, x+end.X, ff.Voffset-end.Y)
}
}
if !p.Empty() && start0.Equals(end) {
p.Close()
}
if ff.fauxBold != 0.0 {
p = p.Offset(ff.fauxBold, NonZero)
if ff.FauxBold != 0.0 {
p = p.Offset(ff.FauxBold, NonZero)
}

if i != 0 {
kern, err := ff.font.sfnt.Kern(buffer, prevIndex, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
kern, err := ff.Font.sfnt.Kern(buffer, prevIndex, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
if err == nil {
x += fromI26_6(kern)
}
}
advance, err := ff.font.sfnt.GlyphAdvance(buffer, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
advance, err := ff.Font.sfnt.GlyphAdvance(buffer, index, toI26_6(ff.Size*ff.Scale), font.HintingNone)
if err == nil {
x += fromI26_6(advance)
}
Expand Down Expand Up @@ -414,8 +400,8 @@ func (overline) Decorate(ff FontFace, w float64) *Path {
r := ff.Metrics().Size * underlineThickness
y := ff.Metrics().XHeight + ff.Metrics().Size*underlineDistance

dx := ff.fauxItalic * y
w += ff.fauxItalic * y
dx := ff.FauxItalic * y
w += ff.FauxItalic * y

p := &Path{}
p.MoveTo(dx, y)
Expand All @@ -432,8 +418,8 @@ func (strikethrough) Decorate(ff FontFace, w float64) *Path {
r := ff.Metrics().Size * underlineThickness
y := ff.Metrics().XHeight / 2.0

dx := ff.fauxItalic * y
w += ff.fauxItalic * y
dx := ff.FauxItalic * y
w += ff.FauxItalic * y

p := &Path{}
p.MoveTo(dx, y)
Expand Down
10 changes: 5 additions & 5 deletions fontface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ func TestFontFamily(t *testing.T) {
family.LoadFontFile("font/DejaVuSerif.ttf", FontRegular)

face := family.Face(12.0*ptPerMm, Black, FontRegular, FontNormal)
test.Float(t, face.fauxBold, 0.0)
test.Float(t, face.FauxBold, 0.0)
test.T(t, face.Boldness(), 400)

face = family.Face(12.0*ptPerMm, Black, FontBold|FontItalic, FontNormal)
test.Float(t, face.fauxBold, 0.24)
test.Float(t, face.fauxItalic, 0.3)
test.Float(t, face.FauxBold, 0.24)
test.Float(t, face.FauxItalic, 0.3)
test.T(t, face.Boldness(), 700)

face = family.Face(12.0*ptPerMm, Black, FontBold|FontItalic, FontSubscript)
test.Float(t, face.Voffset, -12.0*0.33)
test.Float(t, face.fauxBold, 0.48*0.583)
test.Float(t, face.fauxItalic, 0.3)
test.Float(t, face.FauxBold, 0.48*0.583)
test.Float(t, face.FauxItalic, 0.3)
test.T(t, face.Boldness(), 1000)
}

Expand Down

0 comments on commit 8b9f6ac

Please sign in to comment.