Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
小雨青年
freetype
提交
2bf22ccf
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看板
提交
2bf22ccf
编写于
7月 09, 2012
作者:
N
Nigel Tao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
freetype/truetype: vector set/gets, store ops, roll/max/min ops.
R=bsiegert CC=golang-dev
http://codereview.appspot.com/6354080
上级
9e927de7
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
242 addition
and
42 deletion
+242
-42
freetype/truetype/hint.go
freetype/truetype/hint.go
+149
-16
freetype/truetype/hint_test.go
freetype/truetype/hint_test.go
+67
-0
freetype/truetype/opcodes.go
freetype/truetype/opcodes.go
+26
-26
未找到文件。
freetype/truetype/hint.go
浏览文件 @
2bf22ccf
...
...
@@ -13,12 +13,34 @@ import (
)
type
hinter
struct
{
// TODO: variable sized stack and store slices based on the maxp section?
// Should the arrays for the stack and store be combined? For now, fixed
// maximum sizes seem to work in practice.
stack
[
800
]
int32
// The graphics state is described at https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html
roundPeriod
,
roundPhase
,
roundThreshold
int32
store
[
128
]
int32
// The fields below constitue the graphics state, which is described at
// https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html
// Projection vector, freedom vector and dual projection vector.
pv
,
fv
,
dv
[
2
]
f2dot14
// Minimum distance.
minDist
f26dot6
// Loop count.
loop
int32
// Rounding policy.
roundPeriod
,
roundPhase
,
roundThreshold
f26dot6
}
func
(
h
*
hinter
)
run
(
program
[]
byte
)
error
{
// The default vectors are along the X axis.
h
.
pv
=
[
2
]
f2dot14
{
0x4000
,
0
}
h
.
fv
=
[
2
]
f2dot14
{
0x4000
,
0
}
h
.
dv
=
[
2
]
f2dot14
{
0x4000
,
0
}
// The default minimum distance is 1.
h
.
minDist
=
1
<<
6
// The default loop count is 1.
h
.
loop
=
1
// The default rounding policy is round to grid.
h
.
roundPeriod
=
1
<<
6
h
.
roundPhase
=
0
...
...
@@ -31,7 +53,7 @@ func (h *hinter) run(program []byte) error {
steps
,
pc
,
top
int
opcode
uint8
)
for
0
<=
pc
&&
int
(
pc
)
<
len
(
program
)
{
for
0
<=
pc
&&
pc
<
len
(
program
)
{
steps
++
if
steps
==
100000
{
return
errors
.
New
(
"truetype: hinting: too many steps"
)
...
...
@@ -45,6 +67,69 @@ func (h *hinter) run(program []byte) error {
}
switch
opcode
{
case
opSVTCA0
:
h
.
pv
=
[
2
]
f2dot14
{
0
,
0x4000
}
h
.
fv
=
[
2
]
f2dot14
{
0
,
0x4000
}
// TODO: h.dv = h.pv ??
case
opSVTCA1
:
h
.
pv
=
[
2
]
f2dot14
{
0x4000
,
0
}
h
.
fv
=
[
2
]
f2dot14
{
0x4000
,
0
}
// TODO: h.dv = h.pv ??
case
opSPVTCA0
:
h
.
pv
=
[
2
]
f2dot14
{
0
,
0x4000
}
// TODO: h.dv = h.pv ??
case
opSPVTCA1
:
h
.
pv
=
[
2
]
f2dot14
{
0x4000
,
0
}
// TODO: h.dv = h.pv ??
case
opSFVTCA0
:
h
.
fv
=
[
2
]
f2dot14
{
0
,
0x4000
}
case
opSFVTCA1
:
h
.
fv
=
[
2
]
f2dot14
{
0x4000
,
0
}
case
opSPVFS
:
top
-=
2
h
.
pv
[
0
]
=
f2dot14
(
h
.
stack
[
top
+
0
])
h
.
pv
[
1
]
=
f2dot14
(
h
.
stack
[
top
+
1
])
// TODO: normalize h.pv ??
// TODO: h.dv = h.pv ??
case
opSFVFS
:
top
-=
2
h
.
fv
[
0
]
=
f2dot14
(
h
.
stack
[
top
+
0
])
h
.
fv
[
1
]
=
f2dot14
(
h
.
stack
[
top
+
1
])
// TODO: normalize h.fv ??
case
opGPV
:
if
top
+
1
>=
len
(
h
.
stack
)
{
return
errors
.
New
(
"truetype: hinting: stack overflow"
)
}
h
.
stack
[
top
+
0
]
=
int32
(
h
.
pv
[
0
])
h
.
stack
[
top
+
1
]
=
int32
(
h
.
pv
[
1
])
top
+=
2
case
opGFV
:
if
top
+
1
>=
len
(
h
.
stack
)
{
return
errors
.
New
(
"truetype: hinting: stack overflow"
)
}
h
.
stack
[
top
+
0
]
=
int32
(
h
.
fv
[
0
])
h
.
stack
[
top
+
1
]
=
int32
(
h
.
fv
[
1
])
top
+=
2
case
opSFVTPV
:
h
.
fv
=
h
.
pv
case
opSLOOP
:
top
--
if
h
.
stack
[
top
]
<=
0
{
return
errors
.
New
(
"truetype: hinting: invalid data"
)
}
h
.
loop
=
h
.
stack
[
top
]
case
opRTG
:
h
.
roundPeriod
=
1
<<
6
h
.
roundPhase
=
0
...
...
@@ -55,6 +140,10 @@ func (h *hinter) run(program []byte) error {
h
.
roundPhase
=
1
<<
5
h
.
roundThreshold
=
1
<<
5
case
opSMD
:
top
--
h
.
minDist
=
f26dot6
(
h
.
stack
[
top
])
case
opELSE
:
opcode
=
1
goto
ifelse
...
...
@@ -65,7 +154,7 @@ func (h *hinter) run(program []byte) error {
continue
case
opDUP
:
if
int
(
top
)
>=
len
(
h
.
stack
)
{
if
top
>=
len
(
h
.
stack
)
{
return
errors
.
New
(
"truetype: hinting: stack overflow"
)
}
h
.
stack
[
top
]
=
h
.
stack
[
top
-
1
]
...
...
@@ -81,7 +170,7 @@ func (h *hinter) run(program []byte) error {
h
.
stack
[
top
-
1
],
h
.
stack
[
top
-
2
]
=
h
.
stack
[
top
-
2
],
h
.
stack
[
top
-
1
]
case
opDEPTH
:
if
int
(
top
)
>=
len
(
h
.
stack
)
{
if
top
>=
len
(
h
.
stack
)
{
return
errors
.
New
(
"truetype: hinting: stack overflow"
)
}
h
.
stack
[
top
]
=
int32
(
top
)
...
...
@@ -111,6 +200,21 @@ func (h *hinter) run(program []byte) error {
opcode
=
0x80
goto
push
case
opWS
:
top
-=
2
i
:=
int
(
h
.
stack
[
top
])
if
i
<
0
||
len
(
h
.
store
)
<=
i
{
return
errors
.
New
(
"truetype: hinting: invalid data"
)
}
h
.
store
[
i
]
=
h
.
stack
[
top
+
1
]
case
opRS
:
i
:=
int
(
h
.
stack
[
top
-
1
])
if
i
<
0
||
len
(
h
.
store
)
<=
i
{
return
errors
.
New
(
"truetype: hinting: invalid data"
)
}
h
.
stack
[
top
-
1
]
=
h
.
store
[
i
]
case
opDEBUG
:
// No-op.
...
...
@@ -172,11 +276,11 @@ func (h *hinter) run(program []byte) error {
if
h
.
stack
[
top
]
==
0
{
return
errors
.
New
(
"truetype: hinting: division by zero"
)
}
h
.
stack
[
top
-
1
]
=
div
(
h
.
stack
[
top
-
1
],
h
.
stack
[
top
]
)
h
.
stack
[
top
-
1
]
=
int32
(
f26dot6
(
h
.
stack
[
top
-
1
])
.
div
(
f26dot6
(
h
.
stack
[
top
]))
)
case
opMUL
:
top
--
h
.
stack
[
top
-
1
]
=
mul
(
h
.
stack
[
top
-
1
],
h
.
stack
[
top
]
)
h
.
stack
[
top
-
1
]
=
int32
(
f26dot6
(
h
.
stack
[
top
-
1
])
.
mul
(
f26dot6
(
h
.
stack
[
top
]))
)
case
opABS
:
if
h
.
stack
[
top
-
1
]
<
0
{
...
...
@@ -196,7 +300,7 @@ func (h *hinter) run(program []byte) error {
case
opROUND00
,
opROUND01
,
opROUND10
,
opROUND11
:
// The four flavors of opROUND are equivalent. See the comment below on
// opNROUND for the rationale.
h
.
stack
[
top
-
1
]
=
h
.
round
(
h
.
stack
[
top
-
1
]
)
h
.
stack
[
top
-
1
]
=
int32
(
h
.
round
(
f26dot6
(
h
.
stack
[
top
-
1
]))
)
case
opNROUND00
,
opNROUND01
,
opNROUND10
,
opNROUND11
:
// No-op. The spec says to add one of four "compensations for the engine
...
...
@@ -221,9 +325,9 @@ func (h *hinter) run(program []byte) error {
h
.
roundPeriod
*=
46341
h
.
roundPeriod
/=
65536
}
h
.
roundPhase
=
h
.
roundPeriod
*
((
h
.
stack
[
top
]
>>
4
)
&
0x03
)
/
4
h
.
roundPhase
=
h
.
roundPeriod
*
f26dot6
((
h
.
stack
[
top
]
>>
4
)
&
0x03
)
/
4
if
x
:=
h
.
stack
[
top
]
&
0x0f
;
x
!=
0
{
h
.
roundThreshold
=
h
.
roundPeriod
*
(
x
-
4
)
/
8
h
.
roundThreshold
=
h
.
roundPeriod
*
f26dot6
(
x
-
4
)
/
8
}
else
{
h
.
roundThreshold
=
h
.
roundPeriod
-
1
}
...
...
@@ -257,6 +361,29 @@ func (h *hinter) run(program []byte) error {
h
.
roundPhase
=
0
h
.
roundThreshold
=
0
case
opSANGW
,
opAA
:
// These ops are "anachronistic" and no longer used.
top
--
case
opIDEF
:
// IDEF is for ancient versions of the bytecode interpreter, and is no longer used.
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
]
case
opMAX
:
top
--
if
h
.
stack
[
top
-
1
]
<
h
.
stack
[
top
]
{
h
.
stack
[
top
-
1
]
=
h
.
stack
[
top
]
}
case
opMIN
:
top
--
if
h
.
stack
[
top
-
1
]
>
h
.
stack
[
top
]
{
h
.
stack
[
top
-
1
]
=
h
.
stack
[
top
]
}
case
opPUSHB000
,
opPUSHB001
,
opPUSHB010
,
opPUSHB011
,
opPUSHB100
,
opPUSHB101
,
opPUSHB110
,
opPUSHB111
:
opcode
-=
opPUSHB000
-
1
goto
push
...
...
@@ -332,7 +459,7 @@ func (h *hinter) run(program []byte) error {
}
if
opcode
==
0
{
pc
++
if
int
(
pc
)
>=
len
(
program
)
{
if
pc
>=
len
(
program
)
{
return
errors
.
New
(
"truetype: hinting: insufficient data"
)
}
opcode
=
program
[
pc
]
...
...
@@ -359,19 +486,25 @@ func (h *hinter) run(program []byte) error {
return
nil
}
// f2dot14 is a 2.14 fixed point number.
type
f2dot14
int16
// f26dot6 is a 26.6 fixed point number.
type
f26dot6
int32
// div returns x/y in 26.6 fixed point arithmetic.
func
div
(
x
,
y
int32
)
int32
{
return
int32
((
int64
(
x
)
<<
6
)
/
int64
(
y
))
func
(
x
f26dot6
)
div
(
y
f26dot6
)
f26dot6
{
return
f26dot6
((
int64
(
x
)
<<
6
)
/
int64
(
y
))
}
// mul returns x*y in 26.6 fixed point arithmetic.
func
mul
(
x
,
y
int32
)
int32
{
return
int32
(
int64
(
x
)
*
int64
(
y
)
>>
6
)
func
(
x
f26dot6
)
mul
(
y
f26dot6
)
f26dot6
{
return
f26dot6
(
int64
(
x
)
*
int64
(
y
)
>>
6
)
}
// round rounds the given number. The rounding algorithm is described at
// https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
func
(
h
*
hinter
)
round
(
x
int32
)
int32
{
func
(
h
*
hinter
)
round
(
x
f26dot6
)
f26dot6
{
if
h
.
roundPeriod
==
0
{
return
x
}
...
...
freetype/truetype/hint_test.go
浏览文件 @
2bf22ccf
...
...
@@ -48,6 +48,25 @@ func TestBytecode(t *testing.T) {
nil
,
"unbalanced"
,
},
{
"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 ]
1
,
opGFV
,
// [ 0x4000, 0, 1, 0, -0x4000 ]
opPUSHB000
,
// [ 0x4000, 0, 1, 0, -0x4000, 2 ]
2
,
},
[]
int32
{
0x4000
,
0
,
1
,
0
,
-
0x4000
,
2
},
""
,
},
{
"jumps"
,
[]
byte
{
...
...
@@ -126,6 +145,23 @@ func TestBytecode(t *testing.T) {
[]
int32
{
255
,
-
2
,
253
,
1
,
2
,
0x0405
,
0x0607
,
0x0809
},
""
,
},
{
"store ops"
,
[]
byte
{
opPUSHB011
,
// [1, 22, 3, 44]
1
,
22
,
3
,
44
,
opWS
,
// [1, 22]
opWS
,
// []
opPUSHB000
,
// [3]
3
,
opRS
,
// [44]
},
[]
int32
{
44
},
""
,
},
{
"comparison ops"
,
[]
byte
{
...
...
@@ -418,6 +454,37 @@ func TestBytecode(t *testing.T) {
[]
int32
{
-
112
,
-
48
,
-
48
,
-
48
,
16
,
16
,
16
,
80
},
""
,
},
{
"roll"
,
[]
byte
{
opPUSHB010
,
// [1, 2, 3]
1
,
2
,
3
,
opROLL
,
// [2, 3, 1]
},
[]
int32
{
2
,
3
,
1
},
""
,
},
{
"max/min"
,
[]
byte
{
opPUSHW001
,
// [-2, -3]
0xff
,
0xfe
,
0xff
,
0xfd
,
opMAX
,
// [-2]
opPUSHW001
,
// [-2, -4, -5]
0xff
,
0xfc
,
0xff
,
0xfb
,
opMIN
,
// [-2, -5]
},
[]
int32
{
-
2
,
-
5
},
""
,
},
}
for
_
,
tc
:=
range
testCases
{
...
...
freetype/truetype/opcodes.go
浏览文件 @
2bf22ccf
...
...
@@ -10,21 +10,21 @@ package truetype
// TODO: the opXXX constants without end-of-line comments are not yet implemented.
const
(
opSVTCA0
=
0x00
opSVTCA1
=
0x01
opSPVTCA0
=
0x02
opSPVTCA1
=
0x03
opSFVTCA0
=
0x04
opSFVTCA1
=
0x05
opSVTCA0
=
0x00
// Set freedom and projection Vectors To Coordinate Axis
opSVTCA1
=
0x01
// .
opSPVTCA0
=
0x02
// Set Projection Vector To Coordinate Axis
opSPVTCA1
=
0x03
// .
opSFVTCA0
=
0x04
// Set Freedom Vector to Coordinate Axis
opSFVTCA1
=
0x05
// .
opSPVTL0
=
0x06
opSPVTL1
=
0x07
opSFVTL0
=
0x08
opSFVTL1
=
0x09
opS
FVFS
=
0x0b
opS
PVFS
=
0x0a
opGPV
=
0x0c
opGFV
=
0x0d
opSFVTPV
=
0x0e
opS
PVFS
=
0x0a
// Set Projection Vector From Stack
opS
FVFS
=
0x0b
// Set Freedom Vector From Stack
opGPV
=
0x0c
// Get Projection Vector
opGFV
=
0x0d
// Get Freedom Vector
opSFVTPV
=
0x0e
// Set Freedom Vector To Projection Vector
opISECT
=
0x0f
opSRP0
=
0x10
opSRP1
=
0x11
...
...
@@ -33,10 +33,10 @@ const (
opSZP1
=
0x14
opSZP2
=
0x15
opSZPS
=
0x16
opSLOOP
=
0x17
opSLOOP
=
0x17
// Set LOOP variable
opRTG
=
0x18
// Round To Grid
opRTHG
=
0x19
// Round To Half Grid
opSMD
=
0x1a
opSMD
=
0x1a
// Set Minimum Distance
opELSE
=
0x1b
// ELSE clause
opJMPR
=
0x1c
// JuMP Relative
opSCVTCI
=
0x1d
...
...
@@ -76,8 +76,8 @@ const (
opMIAP1
=
0x3f
opNPUSHB
=
0x40
// PUSH N Bytes
opNPUSHW
=
0x41
// PUSH N Words
opWS
=
0x42
opRS
=
0x43
opWS
=
0x42
// Write Store
opRS
=
0x43
// Read Store
opWCVTP
=
0x44
opRCVT
=
0x45
opGC0
=
0x46
...
...
@@ -136,8 +136,8 @@ const (
op_0x7b
=
0x7b
opRUTG
=
0x7c
// Round Up To Grid
opRDTG
=
0x7d
// Round Down To Grid
opSANGW
=
0x7e
opAA
=
0x7f
opSANGW
=
0x7e
// Set ANGle Weight
opAA
=
0x7f
// Adjust Angle
opFLIPPT
=
0x80
opFLIPRGON
=
0x81
opFLIPRGOFF
=
0x82
...
...
@@ -147,10 +147,10 @@ const (
opSDPVTL0
=
0x86
opSDPVTL1
=
0x87
opGETINFO
=
0x88
opI
FDEF
=
0x89
opROLL
=
0x8a
opMAX
=
0x8b
opMIN
=
0x8c
opI
DEF
=
0x89
// Instruction DEFinition
opROLL
=
0x8a
// ROLL the top three stack elements
opMAX
=
0x8b
// MAXimum of top two stack elements
opMIN
=
0x8c
// MINimum of top two stack elements
opSCANTYPE
=
0x8d
opINSTCTRL
=
0x8e
op_0x8f
=
0x8f
...
...
@@ -271,15 +271,15 @@ const (
// popCount is the number of stack elements that each opcode pops.
var
popCount
=
[
256
]
uint8
{
// 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
// 0x00 - 0x0f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
0
,
q
,
0
,
1
,
q
,
q
,
q
,
// 0x10 - 0x1f
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
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
q
,
q
,
// 0x30 - 0x3f
0
,
0
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
// 0x40 - 0x4f
0
,
0
,
2
,
1
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
0
,
// 0x40 - 0x4f
2
,
2
,
2
,
2
,
2
,
2
,
q
,
q
,
1
,
0
,
2
,
2
,
1
,
q
,
q
,
q
,
// 0x50 - 0x5f
2
,
2
,
2
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
// 0x60 - 0x6f
q
,
q
,
q
,
q
,
q
,
q
,
1
,
1
,
2
,
2
,
0
,
q
,
0
,
0
,
q
,
q
,
// 0x70 - 0x7f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
// 0x80 - 0x8f
q
,
q
,
q
,
q
,
q
,
q
,
1
,
1
,
2
,
2
,
0
,
q
,
0
,
0
,
1
,
1
,
// 0x70 - 0x7f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
1
,
3
,
2
,
2
,
q
,
q
,
q
,
// 0x80 - 0x8f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
// 0x90 - 0x9f
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
q
,
// 0xa0 - 0xaf
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
// 0xb0 - 0xbf
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录