Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
小雨青年
freetype
提交
e3b4bc4c
F
freetype
项目概览
小雨青年
/
freetype
通知
14
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
freetype
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
e3b4bc4c
编写于
7月 30, 2013
作者:
N
Nigel Tao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
freetype/truetype: function call opcodes.
R=bsiegert CC=golang-dev
https://codereview.appspot.com/11983043
上级
28cc5fbc
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
227 addition
and
46 deletion
+227
-46
freetype/truetype/glyph.go
freetype/truetype/glyph.go
+3
-0
freetype/truetype/hint.go
freetype/truetype/hint.go
+153
-28
freetype/truetype/hint_test.go
freetype/truetype/hint_test.go
+57
-11
freetype/truetype/opcodes.go
freetype/truetype/opcodes.go
+5
-5
freetype/truetype/truetype.go
freetype/truetype/truetype.go
+9
-2
未找到文件。
freetype/truetype/glyph.go
浏览文件 @
e3b4bc4c
...
...
@@ -124,6 +124,9 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h *Hinter) error {
g
.
Point
[
i
]
.
Y
=
f
.
scale
(
scale
*
g
.
Point
[
i
]
.
Y
)
}
if
h
!=
nil
{
if
err
:=
h
.
init
(
f
,
scale
);
err
!=
nil
{
return
err
}
// TODO: invoke h.
}
return
nil
...
...
freetype/truetype/hint.go
浏览文件 @
e3b4bc4c
...
...
@@ -12,12 +12,28 @@ import (
"errors"
)
// callStackEntry is a bytecode call stack entry.
type
callStackEntry
struct
{
program
[]
byte
pc
int
loopCount
int32
}
// Hinter implements bytecode hinting. Pass a Hinter to GlyphBuf.Load to hint
// the resulting glyph. A Hinter can be re-used to hint a series of glyphs from
// a Font.
type
Hinter
struct
{
stack
,
store
[]
int32
// functions is a map from function number to bytecode.
functions
map
[
int32
][]
byte
// font and scale are the font and scale last used for this Hinter.
// Changing the font will require running the new font's fpgm bytecode.
// Changing either will require running the font's prep bytecode.
font
*
Font
scale
int32
// The fields below constitue the graphics state, which is described at
// https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html
...
...
@@ -31,17 +47,44 @@ type Hinter struct {
roundPeriod
,
roundPhase
,
roundThreshold
f26dot6
}
func
(
h
*
Hinter
)
init
(
f
*
Font
)
{
if
x
:=
int
(
f
.
maxStackElements
);
x
>
len
(
h
.
stack
)
{
x
+=
255
x
&^=
255
h
.
stack
=
make
([]
int32
,
x
)
func
(
h
*
Hinter
)
init
(
f
*
Font
,
scale
int32
)
error
{
rescale
:=
h
.
scale
!=
scale
if
h
.
font
!=
f
{
h
.
font
,
rescale
=
f
,
true
if
h
.
functions
==
nil
{
h
.
functions
=
make
(
map
[
int32
][]
byte
)
}
else
{
for
k
:=
range
h
.
functions
{
delete
(
h
.
functions
,
k
)
}
}
if
x
:=
int
(
f
.
maxStackElements
);
x
>
len
(
h
.
stack
)
{
x
+=
255
x
&^=
255
h
.
stack
=
make
([]
int32
,
x
)
}
if
x
:=
int
(
f
.
maxStorage
);
x
>
len
(
h
.
store
)
{
x
+=
15
x
&^=
15
h
.
store
=
make
([]
int32
,
x
)
}
if
len
(
f
.
fpgm
)
!=
0
{
if
err
:=
h
.
run
(
f
.
fpgm
);
err
!=
nil
{
return
err
}
}
}
if
x
:=
int
(
f
.
maxStorage
);
x
>
len
(
h
.
store
)
{
x
+=
15
x
&^=
15
h
.
store
=
make
([]
int32
,
x
)
if
rescale
{
h
.
scale
=
scale
if
len
(
f
.
prep
)
!=
0
{
if
err
:=
h
.
run
(
f
.
prep
);
err
!=
nil
{
return
err
}
}
}
return
nil
}
func
(
h
*
Hinter
)
run
(
program
[]
byte
)
error
{
...
...
@@ -64,7 +107,11 @@ func (h *Hinter) run(program []byte) error {
var
(
steps
,
pc
,
top
int
opcode
uint8
callStack
[
32
]
callStackEntry
callStackTop
int
)
for
0
<=
pc
&&
pc
<
len
(
program
)
{
steps
++
if
steps
==
100000
{
...
...
@@ -199,6 +246,65 @@ func (h *Hinter) run(program []byte) error {
top
--
}
case
opLOOPCALL
,
opCALL
:
if
callStackTop
>=
len
(
callStack
)
{
return
errors
.
New
(
"truetype: hinting: call stack overflow"
)
}
top
--
f
,
ok
:=
h
.
functions
[
h
.
stack
[
top
]]
if
!
ok
{
return
errors
.
New
(
"truetype: hinting: undefined function"
)
}
callStack
[
callStackTop
]
=
callStackEntry
{
program
,
pc
,
1
}
if
opcode
==
opLOOPCALL
{
top
--
if
h
.
stack
[
top
]
==
0
{
break
}
callStack
[
callStackTop
]
.
loopCount
=
h
.
stack
[
top
]
}
callStackTop
++
program
,
pc
=
f
,
0
continue
case
opFDEF
:
// Save all bytecode up until the next ENDF.
startPC
:=
pc
+
1
fdefloop
:
for
{
pc
++
if
pc
>=
len
(
program
)
{
return
errors
.
New
(
"truetype: hinting: unbalanced FDEF"
)
}
switch
program
[
pc
]
{
case
opFDEF
:
return
errors
.
New
(
"truetype: hinting: nested FDEF"
)
case
opENDF
:
top
--
h
.
functions
[
h
.
stack
[
top
]]
=
program
[
startPC
:
pc
+
1
]
break
fdefloop
default
:
var
ok
bool
pc
,
ok
=
skipInstructionPayload
(
program
,
pc
)
if
!
ok
{
return
errors
.
New
(
"truetype: hinting: unbalanced FDEF"
)
}
}
}
case
opENDF
:
if
callStackTop
==
0
{
return
errors
.
New
(
"truetype: hinting: call stack underflow"
)
}
callStackTop
--
callStack
[
callStackTop
]
.
loopCount
--
if
callStack
[
callStackTop
]
.
loopCount
!=
0
{
callStackTop
++
pc
=
0
continue
}
program
,
pc
=
callStack
[
callStackTop
]
.
program
,
callStack
[
callStackTop
]
.
pc
case
opRTDG
:
h
.
roundPeriod
=
1
<<
5
h
.
roundPhase
=
0
...
...
@@ -386,7 +492,8 @@ func (h *Hinter) run(program []byte) error {
return
errors
.
New
(
"truetype: hinting: unsupported IDEF instruction"
)
case
opROLL
:
h
.
stack
[
top
-
1
],
h
.
stack
[
top
-
3
],
h
.
stack
[
top
-
2
]
=
h
.
stack
[
top
-
3
],
h
.
stack
[
top
-
2
],
h
.
stack
[
top
-
1
]
h
.
stack
[
top
-
1
],
h
.
stack
[
top
-
3
],
h
.
stack
[
top
-
2
]
=
h
.
stack
[
top
-
3
],
h
.
stack
[
top
-
2
],
h
.
stack
[
top
-
1
]
case
opMAX
:
top
--
...
...
@@ -400,11 +507,15 @@ func (h *Hinter) run(program []byte) error {
h
.
stack
[
top
-
1
]
=
h
.
stack
[
top
]
}
case
opPUSHB000
,
opPUSHB001
,
opPUSHB010
,
opPUSHB011
,
opPUSHB100
,
opPUSHB101
,
opPUSHB110
,
opPUSHB111
:
case
opPUSHB000
,
opPUSHB001
,
opPUSHB010
,
opPUSHB011
,
opPUSHB100
,
opPUSHB101
,
opPUSHB110
,
opPUSHB111
:
opcode
-=
opPUSHB000
-
1
goto
push
case
opPUSHW000
,
opPUSHW001
,
opPUSHW010
,
opPUSHW011
,
opPUSHW100
,
opPUSHW101
,
opPUSHW110
,
opPUSHW111
:
case
opPUSHW000
,
opPUSHW001
,
opPUSHW010
,
opPUSHW011
,
opPUSHW100
,
opPUSHW101
,
opPUSHW110
,
opPUSHW111
:
opcode
-=
opPUSHW000
-
1
opcode
+=
0x80
goto
push
...
...
@@ -438,24 +549,12 @@ func (h *Hinter) run(program []byte) error {
if
depth
<
0
{
break
ifelseloop
}
case
opNPUSHB
:
pc
++
if
pc
>=
len
(
program
)
{
return
errors
.
New
(
"truetype: hinting: unbalanced IF or ELSE"
)
}
pc
+=
int
(
program
[
pc
])
case
opNPUSHW
:
pc
++
if
pc
>=
len
(
program
)
{
default
:
var
ok
bool
pc
,
ok
=
skipInstructionPayload
(
program
,
pc
)
if
!
ok
{
return
errors
.
New
(
"truetype: hinting: unbalanced IF or ELSE"
)
}
pc
+=
2
*
int
(
program
[
pc
])
case
opPUSHB000
,
opPUSHB001
,
opPUSHB010
,
opPUSHB011
,
opPUSHB100
,
opPUSHB101
,
opPUSHB110
,
opPUSHB111
:
pc
+=
int
(
program
[
pc
]
-
(
opPUSHB000
-
1
))
case
opPUSHW000
,
opPUSHW001
,
opPUSHW010
,
opPUSHW011
,
opPUSHW100
,
opPUSHW101
,
opPUSHW110
,
opPUSHW111
:
pc
+=
2
*
int
(
program
[
pc
]
-
(
opPUSHW000
-
1
))
default
:
// No-op.
}
}
pc
++
...
...
@@ -502,6 +601,32 @@ func (h *Hinter) run(program []byte) error {
return
nil
}
// skipInstructionPayload increments pc by the extra data that follows a
// variable length PUSHB or PUSHW instruction.
func
skipInstructionPayload
(
program
[]
byte
,
pc
int
)
(
newPC
int
,
ok
bool
)
{
switch
program
[
pc
]
{
case
opNPUSHB
:
pc
++
if
pc
>=
len
(
program
)
{
return
0
,
false
}
pc
+=
int
(
program
[
pc
])
case
opNPUSHW
:
pc
++
if
pc
>=
len
(
program
)
{
return
0
,
false
}
pc
+=
2
*
int
(
program
[
pc
])
case
opPUSHB000
,
opPUSHB001
,
opPUSHB010
,
opPUSHB011
,
opPUSHB100
,
opPUSHB101
,
opPUSHB110
,
opPUSHB111
:
pc
+=
int
(
program
[
pc
]
-
(
opPUSHB000
-
1
))
case
opPUSHW000
,
opPUSHW001
,
opPUSHW010
,
opPUSHW011
,
opPUSHW100
,
opPUSHW101
,
opPUSHW110
,
opPUSHW111
:
pc
+=
2
*
int
(
program
[
pc
]
-
(
opPUSHW000
-
1
))
}
return
pc
,
true
}
// f2dot14 is a 2.14 fixed point number.
type
f2dot14
int16
...
...
freetype/truetype/hint_test.go
浏览文件 @
e3b4bc4c
...
...
@@ -52,16 +52,16 @@ func TestBytecode(t *testing.T) {
"vector set/gets"
,
[]
byte
{
opSVTCA1
,
// []
opGPV
,
// [
0x4000, 0
]
opSVTCA0
,
// [
0x4000, 0
]
opGFV
,
// [
0x4000, 0, 0, 0x4000
]
opNEG
,
// [
0x4000, 0, 0, -0x4000
]
opSPVFS
,
// [
0x4000, 0
]
opSFVTPV
,
// [
0x4000, 0
]
opPUSHB000
,
// [
0x4000, 0, 1
]
opGPV
,
// [
0x4000, 0
]
opSVTCA0
,
// [
0x4000, 0
]
opGFV
,
// [
0x4000, 0, 0, 0x4000
]
opNEG
,
// [
0x4000, 0, 0, -0x4000
]
opSPVFS
,
// [
0x4000, 0
]
opSFVTPV
,
// [
0x4000, 0
]
opPUSHB000
,
// [
0x4000, 0, 1
]
1
,
opGFV
,
// [
0x4000, 0, 1, 0, -0x4000
]
opPUSHB000
,
// [
0x4000, 0, 1, 0, -0x4000, 2
]
opGFV
,
// [
0x4000, 0, 1, 0, -0x4000
]
opPUSHB000
,
// [
0x4000, 0, 1, 0, -0x4000, 2
]
2
,
},
[]
int32
{
0x4000
,
0
,
1
,
0
,
-
0x4000
,
2
},
...
...
@@ -505,6 +505,52 @@ func TestBytecode(t *testing.T) {
[]
int32
{
-
2
,
-
5
},
""
,
},
{
"functions"
,
[]
byte
{
opPUSHB011
,
// [3, 7, 0, 3]
3
,
7
,
0
,
3
,
opFDEF
,
// Function #3 (not called)
opPUSHB000
,
98
,
opENDF
,
opFDEF
,
// Function #0
opDUP
,
opADD
,
opENDF
,
opFDEF
,
// Function #7
opPUSHB001
,
10
,
0
,
opCALL
,
opDUP
,
opENDF
,
opFDEF
,
// Function #3 (again)
opPUSHB000
,
99
,
opENDF
,
opPUSHB001
,
// [2, 0]
2
,
0
,
opCALL
,
// [4]
opPUSHB000
,
// [4, 3]
3
,
opLOOPCALL
,
// [99, 99, 99, 99]
opPUSHB000
,
// [99, 99, 99, 99, 7]
7
,
opCALL
,
// [99, 99, 99, 99, 20, 20]
},
[]
int32
{
99
,
99
,
99
,
99
,
20
,
20
},
""
,
},
}
for
_
,
tc
:=
range
testCases
{
...
...
@@ -512,7 +558,7 @@ func TestBytecode(t *testing.T) {
h
.
init
(
&
Font
{
maxStorage
:
32
,
maxStackElements
:
100
,
})
}
,
768
)
err
,
errStr
:=
h
.
run
(
tc
.
prog
),
""
if
err
!=
nil
{
errStr
=
err
.
Error
()
...
...
@@ -531,7 +577,7 @@ func TestBytecode(t *testing.T) {
}
got
:=
h
.
stack
[
:
len
(
tc
.
want
)]
if
!
reflect
.
DeepEqual
(
got
,
tc
.
want
)
{
t
.
Errorf
(
"
got %v, want %v"
,
got
,
tc
.
want
)
t
.
Errorf
(
"
%s: got %v, want %v"
,
tc
.
desc
,
got
,
tc
.
want
)
continue
}
}
...
...
freetype/truetype/opcodes.go
浏览文件 @
e3b4bc4c
...
...
@@ -52,10 +52,10 @@ const (
opALIGNPTS
=
0x27
op_0x28
=
0x28
opUTP
=
0x29
opLOOPCALL
=
0x2a
opCALL
=
0x2b
opFDEF
=
0x2c
opENDF
=
0x2d
opLOOPCALL
=
0x2a
// LOOP and CALL function
opCALL
=
0x2b
// CALL function
opFDEF
=
0x2c
// Function DEFinition
opENDF
=
0x2d
// END Function definition
opMDAP0
=
0x2e
opMDAP1
=
0x2f
opIUP0
=
0x30
...
...
@@ -273,7 +273,7 @@ var popCount = [256]uint8{
// 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
0
,
0
,
0
,
0
,
0
,
0
,
q
,
q
,
q
,
q
,
2
,
2
,
0
,
0
,
0
,
q
,
// 0x00 - 0x0f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
1
,
0
,
0
,
1
,
0
,
1
,
q
,
q
,
q
,
// 0x10 - 0x1f
1
,
1
,
0
,
2
,
0
,
1
,
1
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
// 0x20 - 0x2f
1
,
1
,
0
,
2
,
0
,
1
,
1
,
q
,
q
,
q
,
2
,
1
,
1
,
0
,
q
,
q
,
// 0x20 - 0x2f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
q
,
q
,
// 0x30 - 0x3f
0
,
0
,
2
,
1
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
// 0x40 - 0x4f
2
,
2
,
2
,
2
,
2
,
2
,
1
,
1
,
1
,
0
,
2
,
2
,
1
,
q
,
q
,
q
,
// 0x50 - 0x5f
...
...
freetype/truetype/truetype.go
浏览文件 @
e3b4bc4c
...
...
@@ -94,8 +94,9 @@ type cm struct {
type
Font
struct
{
// Tables sliced from the TTF data. The different tables are documented
// at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
cmap
,
glyf
,
head
,
hhea
,
hmtx
,
kern
,
loca
,
maxp
[]
byte
cmapIndexes
[]
byte
cmap
,
cvt
,
fpgm
,
glyf
,
head
,
hhea
,
hmtx
,
kern
,
loca
,
maxp
,
prep
[]
byte
cmapIndexes
[]
byte
// Cached values derived from the raw ttf data.
cm
[]
cm
...
...
@@ -411,6 +412,10 @@ func parse(ttf []byte, offset int) (font *Font, err error) {
switch
string
(
ttf
[
x
:
x
+
4
])
{
case
"cmap"
:
f
.
cmap
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"cvt "
:
f
.
cvt
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"fpgm"
:
f
.
fpgm
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"glyf"
:
f
.
glyf
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"head"
:
...
...
@@ -425,6 +430,8 @@ func parse(ttf []byte, offset int) (font *Font, err error) {
f
.
loca
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"maxp"
:
f
.
maxp
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
case
"prep"
:
f
.
prep
,
err
=
readTable
(
ttf
,
ttf
[
x
+
8
:
x
+
16
])
}
if
err
!=
nil
{
return
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录