提交 a8a5cfeb 编写于 作者: N Nigel Tao

freetype: respect the ROUND_XY_TO_GRID compound glyph flag.

Also add a test that freetype-go derives the same glyph points as
the C freetype implementation.

R=bsiegert
CC=golang-dev
https://codereview.appspot.com/12670046
上级 43c4b0b0
/*
gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out
*/
#include <stdio.h>
#include <ft2build.h>
#include FT_FREETYPE_H
static int font_size = 12;
static int no_hinting = 0;
int main(int argc, char** argv) {
FT_Error error;
FT_Library library;
FT_Face face;
FT_Outline* o;
int i, j;
error = FT_Init_FreeType(&library);
if (error) {
printf("FT_Init_FreeType: error #%d\n", error);
return 1;
}
error = FT_New_Face(library, "../../luxi-fonts/luxisr.ttf", 0, &face);
if (error) {
printf("FT_New_Face: error #%d\n", error);
return 1;
}
error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0);
if (error) {
printf("FT_Set_Char_Size: error #%d\n", error);
return 1;
}
for (i = 0; i < face->num_glyphs; i++) {
error = FT_Load_Glyph(face, i, no_hinting ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT);
if (error) {
printf("FT_Load_Glyph: glyph %d: error #%d\n", i, error);
return 1;
}
if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
printf("glyph format for glyph %d is not FT_GLYPH_FORMAT_OUTLINE\n", i);
return 1;
}
o = &face->glyph->outline;
for (j = 0; j < o->n_points; j++) {
if (j != 0) {
printf(", ");
}
printf("%ld %ld %d", o->points[j].x, o->points[j].y, o->tags[j] & 0x01);
}
printf("\n");
}
}
......@@ -113,17 +113,13 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h *Hinter) error {
g.B = Bounds{}
g.Point = g.Point[:0]
g.End = g.End[:0]
if err := g.load(f, i, 0); err != nil {
if err := g.load(f, scale, i, 0, 0, false, 0); err != nil {
return err
}
g.B.XMin = f.scale(scale * g.B.XMin)
g.B.YMin = f.scale(scale * g.B.YMin)
g.B.XMax = f.scale(scale * g.B.XMax)
g.B.YMax = f.scale(scale * g.B.YMax)
for i := range g.Point {
g.Point[i].X = f.scale(scale * g.Point[i].X)
g.Point[i].Y = f.scale(scale * g.Point[i].Y)
}
if h != nil {
if err := h.init(f, scale); err != nil {
return err
......@@ -134,7 +130,9 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h *Hinter) error {
}
// loadCompound loads a glyph that is composed of other glyphs.
func (g *GlyphBuf) loadCompound(f *Font, glyf []byte, offset, recursion int) error {
func (g *GlyphBuf) loadCompound(f *Font, scale int32, glyf []byte, offset int,
dx, dy int32, recursion int) error {
// Flags for decoding a compound glyph. These flags are documented at
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
const (
......@@ -153,14 +151,14 @@ func (g *GlyphBuf) loadCompound(f *Font, glyf []byte, offset, recursion int) err
for {
flags := u16(glyf, offset)
component := u16(glyf, offset+2)
var dx, dy int16
dx1, dy1 := dx, dy
if flags&flagArg1And2AreWords != 0 {
dx = int16(u16(glyf, offset+4))
dy = int16(u16(glyf, offset+6))
dx1 += int32(int16(u16(glyf, offset+4)))
dy1 += int32(int16(u16(glyf, offset+6)))
offset += 8
} else {
dx = int16(int8(glyf[offset+4]))
dy = int16(int8(glyf[offset+5]))
dx1 += int32(int16(int8(glyf[offset+4])))
dy1 += int32(int16(int8(glyf[offset+5])))
offset += 6
}
if flags&flagArgsAreXYValues == 0 {
......@@ -169,12 +167,8 @@ func (g *GlyphBuf) loadCompound(f *Font, glyf []byte, offset, recursion int) err
if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 {
return UnsupportedError("compound glyph scale/transform")
}
b0, i0 := g.B, len(g.Point)
g.load(f, Index(component), recursion+1)
for i := i0; i < len(g.Point); i++ {
g.Point[i].X += int32(dx)
g.Point[i].Y += int32(dy)
}
b0 := g.B
g.load(f, scale, Index(component), dx1, dy1, flags&flagRoundXYToGrid != 0, recursion+1)
if flags&flagUseMyMetrics == 0 {
g.B = b0
}
......@@ -186,7 +180,9 @@ func (g *GlyphBuf) loadCompound(f *Font, glyf []byte, offset, recursion int) err
}
// load appends a glyph's contours to this GlyphBuf.
func (g *GlyphBuf) load(f *Font, i Index, recursion int) error {
func (g *GlyphBuf) load(f *Font, scale int32, i Index,
dx, dy int32, roundDxDy bool, recursion int) error {
if recursion >= 4 {
return UnsupportedError("excessive compound glyph recursion")
}
......@@ -211,7 +207,7 @@ func (g *GlyphBuf) load(f *Font, i Index, recursion int) error {
g.B.YMax = int32(int16(u16(glyf, 8)))
offset := 10
if ne == -1 {
return g.loadCompound(f, glyf, offset, recursion)
return g.loadCompound(f, scale, glyf, offset, dx, dy, recursion)
} else if ne < 0 {
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that
// "the values -2, -3, and so forth, are reserved for future use."
......@@ -240,6 +236,19 @@ func (g *GlyphBuf) load(f *Font, i Index, recursion int) error {
}
offset = g.decodeFlags(glyf, offset, np0)
g.decodeCoords(glyf, offset, np0)
if roundDxDy {
dx = (f.scale(scale*dx) + 32) &^ 63
dy = (f.scale(scale*dy) + 32) &^ 63
for i := np0; i < np; i++ {
g.Point[i].X = dx + f.scale(scale*g.Point[i].X)
g.Point[i].Y = dy + f.scale(scale*g.Point[i].Y)
}
} else {
for i := np0; i < np; i++ {
g.Point[i].X = f.scale(scale * (g.Point[i].X + dx))
g.Point[i].Y = f.scale(scale * (g.Point[i].Y + dy))
}
}
return nil
}
......
......@@ -6,8 +6,13 @@
package truetype
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
)
......@@ -68,3 +73,64 @@ func TestParse(t *testing.T) {
t.Errorf("GlyphBuf:\ngot %v\nwant %v", got, want)
}
}
func testScaling(t *testing.T, filename string) {
b, err := ioutil.ReadFile("../../luxi-fonts/luxisr.ttf")
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
font, err := Parse(b)
if err != nil {
t.Fatalf("Parse: %v", err)
}
f, err := os.Open("../../luxi-fonts/" + filename)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
wants := [][]Point{}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
text := scanner.Text()
if text == "" {
wants = append(wants, []Point{})
continue
}
ss := strings.Split(text, ",")
points := make([]Point, len(ss))
for i, s := range ss {
p := &points[i]
if _, err := fmt.Sscanf(s, "%d %d %d", &p.X, &p.Y, &p.Flags); err != nil {
t.Fatalf("Sscanf: %v", err)
}
}
wants = append(wants, points)
}
if err := scanner.Err(); err != nil && err != io.EOF {
t.Fatalf("Scanner: %v", err)
}
const fontSize = 12
glyphBuf := NewGlyphBuf()
for i, want := range wants {
if err = glyphBuf.Load(font, fontSize*64, Index(i), nil); err != nil {
t.Fatalf("Load: %v", err)
}
got := glyphBuf.Point
for i := range got {
got[i].Flags &= 0x01
}
if !reflect.DeepEqual(got, want) {
t.Errorf("glyph #%d:\ngot %v\nwant %v\n", i, got, want)
}
}
}
func TestScalingSansHinting(t *testing.T) {
testScaling(t, "luxisr-12pt-sans-hinting.txt")
}
func TestScalingWithHinting(t *testing.T) {
// TODO.
}
......@@ -9,3 +9,5 @@ The *.ttx files in this directory were generated from the *.ttf files
by the ttx command-line tool.
http://www.letterror.com/code/ttx/index.html
The *-hinting.txt files in this directory were generated from the *.ttf files
by the ../cmd/print-glyph-points command-line tool.
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册