mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Merge remote-tracking branch 'mattermost/master' into patch-1
This commit is contained in:
91
Godeps/Godeps.json
generated
91
Godeps/Godeps.json
generated
@@ -1,17 +1,7 @@
|
||||
{
|
||||
"ImportPath": "github.com/mattermost/platform",
|
||||
"GoVersion": "go1.4.2",
|
||||
"GoVersion": "go1.5.1",
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go-uuid/uuid",
|
||||
"Comment": "null-15",
|
||||
"Rev": "35bc42037350f0078e3c974c6ea690f1926603ab"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go.crypto/bcrypt",
|
||||
"Comment": "null-236",
|
||||
"Rev": "69e2a90ed92d03812364aeb947b7068dc42e561e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/log4go",
|
||||
"Comment": "go.weekly.2012-02-22-1",
|
||||
@@ -23,43 +13,47 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/braintree/manners",
|
||||
"Comment": "0.3.1-2-g5280e25",
|
||||
"Rev": "5280e250f2795914acbeb2bf3b55dd5a2d1fba52"
|
||||
"Comment": "0.4.0-9-g3fdfada",
|
||||
"Rev": "3fdfadabc96863ceec055bd73ab1e80324e72706"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/disintegration/imaging",
|
||||
"Rev": "493653de80c32beeae336f3a3a3a125e7603459b"
|
||||
"Rev": "546cb3c5137b3f1232e123a26aa033aade6b3066"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/garyburd/redigo/internal",
|
||||
"Rev": "a47585eaae68b1d14b02940d2af1b9194f3caa9c"
|
||||
"Rev": "6ece6e0a09f28cc399b21550cbf37ab39ba63cce"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/garyburd/redigo/redis",
|
||||
"Rev": "a47585eaae68b1d14b02940d2af1b9194f3caa9c"
|
||||
"Rev": "6ece6e0a09f28cc399b21550cbf37ab39ba63cce"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-gorp/gorp",
|
||||
"Comment": "v1.7-65-g3c15f67",
|
||||
"Rev": "3c15f6739b94dc357e2797a7297a2853ec79f4fa"
|
||||
"Comment": "v1.7-146-gc391a3d",
|
||||
"Rev": "c391a3da75cf2003f4bf4763d0b5755c4500aef1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
"Comment": "v1.2-97-g0cc29e9",
|
||||
"Rev": "0cc29e9fe8e25c2c58cf47bcab566e029bbaa88b"
|
||||
"Comment": "v1.2-125-gd512f20",
|
||||
"Rev": "d512f204a577a4ab037a1816604c48c9c13210be"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/goamz/goamz/aws",
|
||||
"Rev": "ad637a587dd8314770a1084481dd7b5d4fa1232f"
|
||||
"Rev": "be371d06631a6ea076cccefc6654fa5c29be074d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/goamz/goamz/s3",
|
||||
"Rev": "ad637a587dd8314770a1084481dd7b5d4fa1232f"
|
||||
"Rev": "be371d06631a6ea076cccefc6654fa5c29be074d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/freetype",
|
||||
"Comment": "release-116-g41fa49a",
|
||||
"Rev": "41fa49aa5b23cc7c4082c9aaaf2da41e195602d9"
|
||||
"Comment": "release-120-gf29eb11",
|
||||
"Rev": "f29eb116deb328d02ee5c573f02d442ca67d5532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/groupcache/lru",
|
||||
@@ -67,25 +61,33 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/context",
|
||||
"Rev": "215affda49addc4c8ef7e2534915df2c8c35c6cd"
|
||||
"Rev": "1c83b3eabd45b6d76072b66b746c20815fb2872d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/mux",
|
||||
"Rev": "94903de8c98a68d8b4483c529b26a5d146e386a2"
|
||||
"Rev": "9c068cf16d982f8bd444b8c352acbeec34c4fe5b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/websocket",
|
||||
"Rev": "6fd0f867fef40c540fa05c59f86396de10a632a6"
|
||||
"Rev": "361d4c0ffd78338ebe0a9e6320cdbe115d7dc026"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/lib/pq",
|
||||
"Comment": "go1.0-cutoff-56-gdc50b6a",
|
||||
"Rev": "dc50b6ad2d3ee836442cf3389009c7cd1e64bb43"
|
||||
"Comment": "go1.0-cutoff-61-g83c4f41",
|
||||
"Rev": "83c4f410d0aed80a0f44bac6a576a7f2435791f3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mssola/user_agent",
|
||||
"Comment": "v0.4.1-4-ga163d6a",
|
||||
"Rev": "a163d6a569f1cd264d2f8b2bf3c5d04ace5995eb"
|
||||
"Comment": "v0.4.1-5-g783ec61",
|
||||
"Rev": "783ec61292aee3fc2f442ce740aa491e4849b794"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Rev": "cccd189d45f7ac3368a0d127efb7f4d08ae0b655"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pmezard/go-difflib/difflib",
|
||||
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rwcarlsen/goexif/exif",
|
||||
@@ -97,27 +99,29 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/objx",
|
||||
"Rev": "cbeaeb16a013161a98496fad62933b1d21786672"
|
||||
"Rev": "1a9d0bb9f541897e62256577b352fdbc1fb4fd94"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/assert",
|
||||
"Rev": "dab07ac62d4905d3e48d17dc549c684ac3b7c15a"
|
||||
"Comment": "v1.0-83-gd797d25",
|
||||
"Rev": "d797d25e0fa6d53be3b1a216d24e868d6a1912ef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/mock",
|
||||
"Rev": "dab07ac62d4905d3e48d17dc549c684ac3b7c15a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/throttled/throttled",
|
||||
"Rev": "fe4c91d601f05354c8a7feba917ab9d3b634f68d"
|
||||
"Comment": "v1.0-83-gd797d25",
|
||||
"Rev": "d797d25e0fa6d53be3b1a216d24e868d6a1912ef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vaughan0/go-ini",
|
||||
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||
"Rev": "beef0f4390813b96e8e68fd78570396d0f4751fc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||
"Rev": "74f810a0152f4c50a16195f6b9ff44afc35594e8"
|
||||
"Rev": "beef0f4390813b96e8e68fd78570396d0f4751fc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/image/bmp",
|
||||
@@ -137,8 +141,13 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fsnotify.v1",
|
||||
"Comment": "v1.2.0",
|
||||
"Rev": "96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0"
|
||||
"Comment": "v1.2.5",
|
||||
"Rev": "2cdd39bd6129c6a49c74fb07fb9d77ba1271c572"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/throttled/throttled.v1",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "74e328a1af88a9b54f9eca1397d74ad98572a6df"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/00changelog.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/00changelog.i
generated
vendored
Binary file not shown.
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/branch
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/branch
generated
vendored
@@ -1 +0,0 @@
|
||||
default
|
||||
2
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/branch2-served
generated
vendored
2
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/branch2-served
generated
vendored
@@ -1,2 +0,0 @@
|
||||
46c3056cafbb4da11c4087a892c7d2bfa4224a8f 128
|
||||
46c3056cafbb4da11c4087a892c7d2bfa4224a8f o default
|
||||
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/rbc-names-v1
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/rbc-names-v1
generated
vendored
@@ -1 +0,0 @@
|
||||
default
|
||||
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/rbc-revs-v1
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/cache/rbc-revs-v1
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/dirstate
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/dirstate
generated
vendored
Binary file not shown.
14
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/hgrc
generated
vendored
14
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/hgrc
generated
vendored
@@ -1,14 +0,0 @@
|
||||
# example repository config (see "hg help config" for more info)
|
||||
[paths]
|
||||
default = https://code.google.com/p/freetype-go/
|
||||
|
||||
# path aliases to other clones of this repo in URLs or filesystem paths
|
||||
# (see "hg help config.paths" for more info)
|
||||
#
|
||||
# default-push = ssh://jdoe@example.net/hg/jdoes-fork
|
||||
# my-fork = ssh://jdoe@example.net/hg/jdoes-fork
|
||||
# my-clone = /home/jdoe/jdoes-clone
|
||||
|
||||
[ui]
|
||||
# name and email (local to this repository, optional), e.g.
|
||||
# username = Jane Doe <jdoe@example.com>
|
||||
4
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/requires
generated
vendored
4
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/requires
generated
vendored
@@ -1,4 +0,0 @@
|
||||
dotencode
|
||||
fncache
|
||||
revlogv1
|
||||
store
|
||||
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/00changelog.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/00changelog.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/00manifest.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/00manifest.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_a_u_t_h_o_r_s.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_a_u_t_h_o_r_s.i
generated
vendored
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_l_i_c_e_n_s_e.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_l_i_c_e_n_s_e.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_makefile.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_makefile.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_r_e_a_d_m_e.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/_r_e_a_d_m_e.i
generated
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/gamma/main.go.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/gamma/main.go.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/raster/main.go.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/raster/main.go.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/round/main.go.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/example/round/main.go.i
generated
vendored
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/_makefile.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/_makefile.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/freetype.go.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/freetype.go.i
generated
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/raster/geom.go.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/freetype/raster/geom.go.i
generated
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/licenses/ftl.txt.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/licenses/ftl.txt.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/licenses/gpl.txt.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/licenses/gpl.txt.i
generated
vendored
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/_r_e_a_d_m_e.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/_r_e_a_d_m_e.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luximr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luximr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luximr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luximr.ttx.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxirr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxirr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxirr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxirr.ttx.i
generated
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxisr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxisr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxisr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/luxi-fonts/luxisr.ttx.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/_c_o_p_y_i_n_g.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/_c_o_p_y_i_n_g.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/_r_e_a_d_m_e.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/_r_e_a_d_m_e.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luximr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luximr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luximr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luximr.ttx.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxirr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxirr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxirr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxirr.ttx.i
generated
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxisr.ttf.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxisr.ttf.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxisr.ttx.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/testdata/luxisr.ttx.i
generated
vendored
Binary file not shown.
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/~2ehgignore.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/~2ehgignore.i
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/~2ehgtags.i
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/data/~2ehgtags.i
generated
vendored
Binary file not shown.
52
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/fncache
generated
vendored
52
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/fncache
generated
vendored
@@ -1,52 +0,0 @@
|
||||
data/testdata/luxisr.ttf.i
|
||||
data/testdata/luximr.ttx.i
|
||||
data/freetype/raster/geom.go.i
|
||||
data/AUTHORS.i
|
||||
data/CONTRIBUTORS.i
|
||||
data/freetype/truetype/Makefile.i
|
||||
data/testdata/luxisr-12pt-with-hinting.txt.i
|
||||
data/luxi-fonts/luxisr-12pt-sans-hinting.txt.i
|
||||
data/example/freetype/main.go.i
|
||||
data/luxi-fonts/luxirr.ttf.i
|
||||
data/testdata/COPYING.i
|
||||
data/example/gamma/main.go.i
|
||||
data/freetype/Makefile.i
|
||||
data/testdata/luxirr.ttx.i
|
||||
data/freetype/freetype_test.go.i
|
||||
data/example/truetype/main.go.i
|
||||
data/Makefile.i
|
||||
data/freetype/freetype.go.i
|
||||
data/luxi-fonts/luximr.ttx.i
|
||||
data/example/round/main.go.i
|
||||
data/freetype/raster/paint.go.i
|
||||
data/luxi-fonts/luximr.ttf.i
|
||||
data/luxi-fonts/luxisr.ttx.i
|
||||
data/example/raster/main.go.i
|
||||
data/lib/codereview/codereview.cfg.i
|
||||
data/testdata/luximr.ttf.i
|
||||
data/luxi-fonts/README.i
|
||||
data/testdata/luxisr.ttx.i
|
||||
data/luxi-fonts/luxisr-12pt-with-hinting.txt.i
|
||||
data/freetype/truetype/hint_test.go.i
|
||||
data/testdata/make-other-hinting-txts.sh.i
|
||||
data/luxi-fonts/COPYING.i
|
||||
data/licenses/ftl.txt.i
|
||||
data/freetype/truetype/opcodes.go.i
|
||||
data/.hgignore.i
|
||||
data/freetype/truetype/truetype.go.i
|
||||
data/testdata/luxirr.ttf.i
|
||||
data/freetype/truetype/truetype_test.go.i
|
||||
data/LICENSE.i
|
||||
data/freetype/raster/stroke.go.i
|
||||
data/luxi-fonts/luxirr.ttx.i
|
||||
data/licenses/gpl.txt.i
|
||||
data/freetype/raster/raster.go.i
|
||||
data/freetype/truetype/hint.go.i
|
||||
data/testdata/luxisr-12pt-sans-hinting.txt.i
|
||||
data/.hgtags.i
|
||||
data/README.i
|
||||
data/freetype/raster/Makefile.i
|
||||
data/testdata/README.i
|
||||
data/luxi-fonts/luxisr.ttf.i
|
||||
data/cmd/print-glyph-points/main.c.i
|
||||
data/freetype/truetype/glyph.go.i
|
||||
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/phaseroots
generated
vendored
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/phaseroots
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo.backupfiles
generated
vendored
BIN
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo.backupfiles
generated
vendored
Binary file not shown.
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo.phaseroots
generated
vendored
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/store/undo.phaseroots
generated
vendored
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.bookmarks
generated
vendored
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.bookmarks
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.branch
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.branch
generated
vendored
@@ -1 +0,0 @@
|
||||
default
|
||||
3
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.desc
generated
vendored
3
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.desc
generated
vendored
@@ -1,3 +0,0 @@
|
||||
0
|
||||
pull
|
||||
https://code.google.com/p/freetype-go/
|
||||
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.dirstate
generated
vendored
0
Godeps/_workspace/src/code.google.com/p/freetype-go/.hg/undo.dirstate
generated
vendored
35
Godeps/_workspace/src/code.google.com/p/freetype-go/.hgignore
generated
vendored
35
Godeps/_workspace/src/code.google.com/p/freetype-go/.hgignore
generated
vendored
@@ -1,35 +0,0 @@
|
||||
syntax:glob
|
||||
.DS_Store
|
||||
.git
|
||||
.gitignore
|
||||
*.[568ao]
|
||||
*.a[568o]
|
||||
*.so
|
||||
*.pyc
|
||||
._*
|
||||
.nfs.*
|
||||
[568a].out
|
||||
*~
|
||||
*.orig
|
||||
*.rej
|
||||
*.exe
|
||||
.*.swp
|
||||
core
|
||||
*.cgo*.go
|
||||
*.cgo*.c
|
||||
_cgo_*
|
||||
_obj
|
||||
_test
|
||||
_testmain.go
|
||||
build.out
|
||||
test.out
|
||||
goinstall.log
|
||||
last-change
|
||||
VERSION.cache
|
||||
out.png
|
||||
|
||||
syntax:regexp
|
||||
^bin/
|
||||
^pkg/
|
||||
^src/cmd/(.*)/6?\1$
|
||||
^.*/core.[0-9]*$
|
||||
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hgtags
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/.hgtags
generated
vendored
@@ -1 +0,0 @@
|
||||
96d0c07904d187405d9f34a3654ce06b0238f31d release
|
||||
17
Godeps/_workspace/src/code.google.com/p/freetype-go/AUTHORS
generated
vendored
17
Godeps/_workspace/src/code.google.com/p/freetype-go/AUTHORS
generated
vendored
@@ -1,17 +0,0 @@
|
||||
# This is the official list of Freetype-Go authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
#
|
||||
# Freetype-Go is derived from Freetype, which is written in C. The latter
|
||||
# is copyright 1996-2010 David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Google Inc.
|
||||
Jeff R. Allen <jra@nella.org>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||
Roger Peppe <rogpeppe@gmail.com>
|
||||
35
Godeps/_workspace/src/code.google.com/p/freetype-go/CONTRIBUTORS
generated
vendored
35
Godeps/_workspace/src/code.google.com/p/freetype-go/CONTRIBUTORS
generated
vendored
@@ -1,35 +0,0 @@
|
||||
# This is the official list of people who can contribute
|
||||
# (and typically have contributed) code to the Freetype-Go repository.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# The submission process automatically checks to make sure
|
||||
# that people submitting code are listed in this file (by email address).
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
|
||||
Nigel Tao <nigeltao@golang.org>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
||||
Rob Pike <r@golang.org>
|
||||
Roger Peppe <rogpeppe@gmail.com>
|
||||
Russ Cox <rsc@golang.org>
|
||||
12
Godeps/_workspace/src/code.google.com/p/freetype-go/LICENSE
generated
vendored
12
Godeps/_workspace/src/code.google.com/p/freetype-go/LICENSE
generated
vendored
@@ -1,12 +0,0 @@
|
||||
Use of the Freetype-Go software is subject to your choice of exactly one of
|
||||
the following two licenses:
|
||||
* The FreeType License, which is similar to the original BSD license with
|
||||
an advertising clause, or
|
||||
* The GNU General Public License (GPL), version 2 or later.
|
||||
|
||||
The text of these licenses are available in the licenses/ftl.txt and the
|
||||
licenses/gpl.txt files respectively. They are also available at
|
||||
http://freetype.sourceforge.net/license.html
|
||||
|
||||
The Luxi fonts in the testdata directory are licensed separately. See the
|
||||
testdata/COPYING file for details.
|
||||
22
Godeps/_workspace/src/code.google.com/p/freetype-go/README
generated
vendored
22
Godeps/_workspace/src/code.google.com/p/freetype-go/README
generated
vendored
@@ -1,22 +0,0 @@
|
||||
This is a port of the Freetype font rasterizer (www.freetype.org) to the Go
|
||||
programming language (golang.org).
|
||||
|
||||
To download and install from source:
|
||||
$ go get code.google.com/p/freetype-go/freetype
|
||||
|
||||
It is an incomplete port:
|
||||
* It only supports TrueType fonts, and not Type 1 fonts nor bitmap fonts.
|
||||
* It only supports the Unicode encoding.
|
||||
|
||||
There are also some implementation differences:
|
||||
* It uses a 24.8 fixed point co-ordinate system everywhere internally,
|
||||
as opposed to the original Freetype's mix of 26.6 (or 10.6 for 16-bit
|
||||
systems) in some places, and 24.8 in the "smooth" rasterizer.
|
||||
|
||||
Freetype-Go is derived from Freetype, which is written in C. Freetype is
|
||||
copyright 1996-2010 David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Freetype-Go is copyright The Freetype-Go Authors, who are listed in the
|
||||
AUTHORS file.
|
||||
|
||||
The Freetype-Go homepage is http://code.google.com/p/freetype-go/
|
||||
|
||||
87
Godeps/_workspace/src/code.google.com/p/freetype-go/cmd/print-glyph-points/main.c
generated
vendored
87
Godeps/_workspace/src/code.google.com/p/freetype-go/cmd/print-glyph-points/main.c
generated
vendored
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxisr.ttf with_hinting
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
void usage(char** argv) {
|
||||
fprintf(stderr, "usage: %s font_size font_file [with_hinting|sans_hinting]\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
FT_Error error;
|
||||
FT_Library library;
|
||||
FT_Face face;
|
||||
FT_Glyph_Metrics* m;
|
||||
FT_Outline* o;
|
||||
FT_Int major, minor, patch;
|
||||
int i, j, font_size, no_hinting;
|
||||
|
||||
if (argc != 4) {
|
||||
usage(argv);
|
||||
return 1;
|
||||
}
|
||||
font_size = atoi(argv[1]);
|
||||
if (font_size <= 0) {
|
||||
fprintf(stderr, "invalid font_size\n");
|
||||
usage(argv);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(argv[3], "with_hinting")) {
|
||||
no_hinting = 0;
|
||||
} else if (!strcmp(argv[3], "sans_hinting")) {
|
||||
no_hinting = 1;
|
||||
} else {
|
||||
fprintf(stderr, "neither \"with_hinting\" nor \"sans_hinting\"\n");
|
||||
usage(argv);
|
||||
return 1;
|
||||
};
|
||||
error = FT_Init_FreeType(&library);
|
||||
if (error) {
|
||||
fprintf(stderr, "FT_Init_FreeType: error #%d\n", error);
|
||||
return 1;
|
||||
}
|
||||
FT_Library_Version(library, &major, &minor, &patch);
|
||||
printf("freetype version %d.%d.%d\n", major, minor, patch);
|
||||
error = FT_New_Face(library, argv[2], 0, &face);
|
||||
if (error) {
|
||||
fprintf(stderr, "FT_New_Face: error #%d\n", error);
|
||||
return 1;
|
||||
}
|
||||
error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0);
|
||||
if (error) {
|
||||
fprintf(stderr, "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) {
|
||||
fprintf(stderr, "FT_Load_Glyph: glyph %d: error #%d\n", i, error);
|
||||
return 1;
|
||||
}
|
||||
if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
|
||||
fprintf(stderr, "glyph format for glyph %d is not FT_GLYPH_FORMAT_OUTLINE\n", i);
|
||||
return 1;
|
||||
}
|
||||
m = &face->glyph->metrics;
|
||||
/* Print what Go calls the AdvanceWidth, and then: XMin, YMin, XMax, YMax. */
|
||||
printf("%ld %ld %ld %ld %ld;",
|
||||
m->horiAdvance,
|
||||
m->horiBearingX,
|
||||
m->horiBearingY - m->height,
|
||||
m->horiBearingX + m->width,
|
||||
m->horiBearingY);
|
||||
/* Print the glyph points. */
|
||||
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");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
143
Godeps/_workspace/src/code.google.com/p/freetype-go/example/freetype/main.go
generated
vendored
143
Godeps/_workspace/src/code.google.com/p/freetype-go/example/freetype/main.go
generated
vendored
@@ -1,143 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype"
|
||||
)
|
||||
|
||||
var (
|
||||
dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
|
||||
fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
|
||||
hinting = flag.String("hinting", "none", "none | full")
|
||||
size = flag.Float64("size", 12, "font size in points")
|
||||
spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
|
||||
wonb = flag.Bool("whiteonblack", false, "white text on a black background")
|
||||
)
|
||||
|
||||
var text = []string{
|
||||
"’Twas brillig, and the slithy toves",
|
||||
"Did gyre and gimble in the wabe;",
|
||||
"All mimsy were the borogoves,",
|
||||
"And the mome raths outgrabe.",
|
||||
"",
|
||||
"“Beware the Jabberwock, my son!",
|
||||
"The jaws that bite, the claws that catch!",
|
||||
"Beware the Jubjub bird, and shun",
|
||||
"The frumious Bandersnatch!”",
|
||||
"",
|
||||
"He took his vorpal sword in hand:",
|
||||
"Long time the manxome foe he sought—",
|
||||
"So rested he by the Tumtum tree,",
|
||||
"And stood awhile in thought.",
|
||||
"",
|
||||
"And as in uffish thought he stood,",
|
||||
"The Jabberwock, with eyes of flame,",
|
||||
"Came whiffling through the tulgey wood,",
|
||||
"And burbled as it came!",
|
||||
"",
|
||||
"One, two! One, two! and through and through",
|
||||
"The vorpal blade went snicker-snack!",
|
||||
"He left it dead, and with its head",
|
||||
"He went galumphing back.",
|
||||
"",
|
||||
"“And hast thou slain the Jabberwock?",
|
||||
"Come to my arms, my beamish boy!",
|
||||
"O frabjous day! Callooh! Callay!”",
|
||||
"He chortled in his joy.",
|
||||
"",
|
||||
"’Twas brillig, and the slithy toves",
|
||||
"Did gyre and gimble in the wabe;",
|
||||
"All mimsy were the borogoves,",
|
||||
"And the mome raths outgrabe.",
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Read the font data.
|
||||
fontBytes, err := ioutil.ReadFile(*fontfile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
font, err := freetype.ParseFont(fontBytes)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize the context.
|
||||
fg, bg := image.Black, image.White
|
||||
ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
|
||||
if *wonb {
|
||||
fg, bg = image.White, image.Black
|
||||
ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
|
||||
}
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, 640, 480))
|
||||
draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
|
||||
c := freetype.NewContext()
|
||||
c.SetDPI(*dpi)
|
||||
c.SetFont(font)
|
||||
c.SetFontSize(*size)
|
||||
c.SetClip(rgba.Bounds())
|
||||
c.SetDst(rgba)
|
||||
c.SetSrc(fg)
|
||||
switch *hinting {
|
||||
default:
|
||||
c.SetHinting(freetype.NoHinting)
|
||||
case "full":
|
||||
c.SetHinting(freetype.FullHinting)
|
||||
}
|
||||
|
||||
// Draw the guidelines.
|
||||
for i := 0; i < 200; i++ {
|
||||
rgba.Set(10, 10+i, ruler)
|
||||
rgba.Set(10+i, 10, ruler)
|
||||
}
|
||||
|
||||
// Draw the text.
|
||||
pt := freetype.Pt(10, 10+int(c.PointToFix32(*size)>>8))
|
||||
for _, s := range text {
|
||||
_, err = c.DrawString(s, pt)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
pt.Y += c.PointToFix32(*size * *spacing)
|
||||
}
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
f, err := os.Create("out.png")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, rgba)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Wrote out.png OK.")
|
||||
}
|
||||
79
Godeps/_workspace/src/code.google.com/p/freetype-go/example/gamma/main.go
generated
vendored
79
Godeps/_workspace/src/code.google.com/p/freetype-go/example/gamma/main.go
generated
vendored
@@ -1,79 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
)
|
||||
|
||||
func p(x, y int) raster.Point {
|
||||
return raster.Point{
|
||||
X: raster.Fix32(x * 256),
|
||||
Y: raster.Fix32(y * 256),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Draw a rounded corner that is one pixel wide.
|
||||
r := raster.NewRasterizer(50, 50)
|
||||
r.Start(p(5, 5))
|
||||
r.Add1(p(5, 25))
|
||||
r.Add2(p(5, 45), p(25, 45))
|
||||
r.Add1(p(45, 45))
|
||||
r.Add1(p(45, 44))
|
||||
r.Add1(p(26, 44))
|
||||
r.Add2(p(6, 44), p(6, 24))
|
||||
r.Add1(p(6, 5))
|
||||
r.Add1(p(5, 5))
|
||||
|
||||
// Rasterize that curve multiple times at different gammas.
|
||||
const (
|
||||
w = 600
|
||||
h = 200
|
||||
)
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
draw.Draw(rgba, image.Rect(0, 0, w, h/2), image.Black, image.ZP, draw.Src)
|
||||
draw.Draw(rgba, image.Rect(0, h/2, w, h), image.White, image.ZP, draw.Src)
|
||||
mask := image.NewAlpha(image.Rect(0, 0, 50, 50))
|
||||
painter := raster.NewAlphaSrcPainter(mask)
|
||||
gammas := []float64{1.0 / 10.0, 1.0 / 3.0, 1.0 / 2.0, 2.0 / 3.0, 4.0 / 5.0, 1.0, 5.0 / 4.0, 3.0 / 2.0, 2.0, 3.0, 10.0}
|
||||
for i, g := range gammas {
|
||||
draw.Draw(mask, mask.Bounds(), image.Transparent, image.ZP, draw.Src)
|
||||
r.Rasterize(raster.NewGammaCorrectionPainter(painter, g))
|
||||
x, y := 50*i+25, 25
|
||||
draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.White, image.ZP, mask, image.ZP, draw.Over)
|
||||
y += 100
|
||||
draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.Black, image.ZP, mask, image.ZP, draw.Over)
|
||||
}
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
f, err := os.Create("out.png")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, rgba)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Wrote out.png OK.")
|
||||
}
|
||||
178
Godeps/_workspace/src/code.google.com/p/freetype-go/example/raster/main.go
generated
vendored
178
Godeps/_workspace/src/code.google.com/p/freetype-go/example/raster/main.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
x, y, degree int
|
||||
}
|
||||
|
||||
// These contours "outside" and "inside" are from the `A' glyph from the Droid
|
||||
// Serif Regular font.
|
||||
|
||||
var outside = []node{
|
||||
node{414, 489, 1},
|
||||
node{336, 274, 2},
|
||||
node{327, 250, 0},
|
||||
node{322, 226, 2},
|
||||
node{317, 203, 0},
|
||||
node{317, 186, 2},
|
||||
node{317, 134, 0},
|
||||
node{350, 110, 2},
|
||||
node{384, 86, 0},
|
||||
node{453, 86, 1},
|
||||
node{500, 86, 1},
|
||||
node{500, 0, 1},
|
||||
node{0, 0, 1},
|
||||
node{0, 86, 1},
|
||||
node{39, 86, 2},
|
||||
node{69, 86, 0},
|
||||
node{90, 92, 2},
|
||||
node{111, 99, 0},
|
||||
node{128, 117, 2},
|
||||
node{145, 135, 0},
|
||||
node{160, 166, 2},
|
||||
node{176, 197, 0},
|
||||
node{195, 246, 1},
|
||||
node{649, 1462, 1},
|
||||
node{809, 1462, 1},
|
||||
node{1272, 195, 2},
|
||||
node{1284, 163, 0},
|
||||
node{1296, 142, 2},
|
||||
node{1309, 121, 0},
|
||||
node{1326, 108, 2},
|
||||
node{1343, 96, 0},
|
||||
node{1365, 91, 2},
|
||||
node{1387, 86, 0},
|
||||
node{1417, 86, 1},
|
||||
node{1444, 86, 1},
|
||||
node{1444, 0, 1},
|
||||
node{881, 0, 1},
|
||||
node{881, 86, 1},
|
||||
node{928, 86, 2},
|
||||
node{1051, 86, 0},
|
||||
node{1051, 184, 2},
|
||||
node{1051, 201, 0},
|
||||
node{1046, 219, 2},
|
||||
node{1042, 237, 0},
|
||||
node{1034, 260, 1},
|
||||
node{952, 489, 1},
|
||||
node{414, 489, -1},
|
||||
}
|
||||
|
||||
var inside = []node{
|
||||
node{686, 1274, 1},
|
||||
node{453, 592, 1},
|
||||
node{915, 592, 1},
|
||||
node{686, 1274, -1},
|
||||
}
|
||||
|
||||
func p(n node) raster.Point {
|
||||
x, y := 20+n.x/4, 380-n.y/4
|
||||
return raster.Point{
|
||||
X: raster.Fix32(x * 256),
|
||||
Y: raster.Fix32(y * 256),
|
||||
}
|
||||
}
|
||||
|
||||
func contour(r *raster.Rasterizer, ns []node) {
|
||||
if len(ns) == 0 {
|
||||
return
|
||||
}
|
||||
i := 0
|
||||
r.Start(p(ns[i]))
|
||||
for {
|
||||
switch ns[i].degree {
|
||||
case -1:
|
||||
// -1 signifies end-of-contour.
|
||||
return
|
||||
case 1:
|
||||
i += 1
|
||||
r.Add1(p(ns[i]))
|
||||
case 2:
|
||||
i += 2
|
||||
r.Add2(p(ns[i-1]), p(ns[i]))
|
||||
default:
|
||||
panic("bad degree")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showNodes(m *image.RGBA, ns []node) {
|
||||
for _, n := range ns {
|
||||
p := p(n)
|
||||
x, y := int(p.X)/256, int(p.Y)/256
|
||||
if !(image.Point{x, y}).In(m.Bounds()) {
|
||||
continue
|
||||
}
|
||||
var c color.Color
|
||||
switch n.degree {
|
||||
case 0:
|
||||
c = color.RGBA{0, 255, 255, 255}
|
||||
case 1:
|
||||
c = color.RGBA{255, 0, 0, 255}
|
||||
case 2:
|
||||
c = color.RGBA{255, 0, 0, 255}
|
||||
}
|
||||
if c != nil {
|
||||
m.Set(x, y, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Rasterize the contours to a mask image.
|
||||
const (
|
||||
w = 400
|
||||
h = 400
|
||||
)
|
||||
r := raster.NewRasterizer(w, h)
|
||||
contour(r, outside)
|
||||
contour(r, inside)
|
||||
mask := image.NewAlpha(image.Rect(0, 0, w, h))
|
||||
p := raster.NewAlphaSrcPainter(mask)
|
||||
r.Rasterize(p)
|
||||
|
||||
// Draw the mask image (in gray) onto an RGBA image.
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
gray := image.NewUniform(color.Alpha{0x1f})
|
||||
draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src)
|
||||
draw.DrawMask(rgba, rgba.Bounds(), gray, image.ZP, mask, image.ZP, draw.Over)
|
||||
showNodes(rgba, outside)
|
||||
showNodes(rgba, inside)
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
f, err := os.Create("out.png")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, rgba)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Wrote out.png OK.")
|
||||
}
|
||||
96
Godeps/_workspace/src/code.google.com/p/freetype-go/example/round/main.go
generated
vendored
96
Godeps/_workspace/src/code.google.com/p/freetype-go/example/round/main.go
generated
vendored
@@ -1,96 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
// This program visualizes the quadratic approximation to the circle, used to
|
||||
// implement round joins when stroking paths. The approximation is used in the
|
||||
// stroking code for arcs between 0 and 45 degrees, but is visualized here
|
||||
// between 0 and 90 degrees. The discrepancy between the approximation and the
|
||||
// true circle is clearly visible at angles above 65 degrees.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
n = 17
|
||||
r = 256 * 80
|
||||
)
|
||||
s := raster.Fix32(r * math.Sqrt(2) / 2)
|
||||
t := raster.Fix32(r * math.Tan(math.Pi/8))
|
||||
|
||||
m := image.NewRGBA(image.Rect(0, 0, 800, 600))
|
||||
draw.Draw(m, m.Bounds(), image.NewUniform(color.RGBA{63, 63, 63, 255}), image.ZP, draw.Src)
|
||||
mp := raster.NewRGBAPainter(m)
|
||||
mp.SetColor(image.Black)
|
||||
z := raster.NewRasterizer(800, 600)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
cx := raster.Fix32(25600 + 51200*(i%4))
|
||||
cy := raster.Fix32(2560 + 32000*(i/4))
|
||||
c := raster.Point{X: cx, Y: cy}
|
||||
theta := math.Pi * (0.5 + 0.5*float64(i)/(n-1))
|
||||
dx := raster.Fix32(r * math.Cos(theta))
|
||||
dy := raster.Fix32(r * math.Sin(theta))
|
||||
d := raster.Point{X: dx, Y: dy}
|
||||
// Draw a quarter-circle approximated by two quadratic segments,
|
||||
// with each segment spanning 45 degrees.
|
||||
z.Start(c)
|
||||
z.Add1(c.Add(raster.Point{X: r, Y: 0}))
|
||||
z.Add2(c.Add(raster.Point{X: r, Y: t}), c.Add(raster.Point{X: s, Y: s}))
|
||||
z.Add2(c.Add(raster.Point{X: t, Y: r}), c.Add(raster.Point{X: 0, Y: r}))
|
||||
// Add another quadratic segment whose angle ranges between 0 and 90 degrees.
|
||||
// For an explanation of the magic constants 22, 150, 181 and 256, read the
|
||||
// comments in the freetype/raster package.
|
||||
dot := 256 * d.Dot(raster.Point{X: 0, Y: r}) / (r * r)
|
||||
multiple := raster.Fix32(150 - 22*(dot-181)/(256-181))
|
||||
z.Add2(c.Add(raster.Point{X: dx, Y: r + dy}.Mul(multiple)), c.Add(d))
|
||||
// Close the curve.
|
||||
z.Add1(c)
|
||||
}
|
||||
z.Rasterize(mp)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
cx := raster.Fix32(25600 + 51200*(i%4))
|
||||
cy := raster.Fix32(2560 + 32000*(i/4))
|
||||
for j := 0; j < n; j++ {
|
||||
theta := math.Pi * float64(j) / (n - 1)
|
||||
dx := raster.Fix32(r * math.Cos(theta))
|
||||
dy := raster.Fix32(r * math.Sin(theta))
|
||||
m.Set(int((cx+dx)/256), int((cy+dy)/256), color.RGBA{255, 255, 0, 255})
|
||||
}
|
||||
}
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
f, err := os.Create("out.png")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, m)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Wrote out.png OK.")
|
||||
}
|
||||
73
Godeps/_workspace/src/code.google.com/p/freetype-go/example/truetype/main.go
generated
vendored
73
Godeps/_workspace/src/code.google.com/p/freetype-go/example/truetype/main.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/truetype"
|
||||
)
|
||||
|
||||
var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
|
||||
|
||||
func printBounds(b truetype.Bounds) {
|
||||
fmt.Printf("XMin:%d YMin:%d XMax:%d YMax:%d\n", b.XMin, b.YMin, b.XMax, b.YMax)
|
||||
}
|
||||
|
||||
func printGlyph(g *truetype.GlyphBuf) {
|
||||
printBounds(g.B)
|
||||
fmt.Print("Points:\n---\n")
|
||||
e := 0
|
||||
for i, p := range g.Point {
|
||||
fmt.Printf("%4d, %4d", p.X, p.Y)
|
||||
if p.Flags&0x01 != 0 {
|
||||
fmt.Print(" on\n")
|
||||
} else {
|
||||
fmt.Print(" off\n")
|
||||
}
|
||||
if i+1 == int(g.End[e]) {
|
||||
fmt.Print("---\n")
|
||||
e++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
fmt.Printf("Loading fontfile %q\n", *fontfile)
|
||||
b, err := ioutil.ReadFile(*fontfile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
font, err := truetype.Parse(b)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
fupe := font.FUnitsPerEm()
|
||||
printBounds(font.Bounds(fupe))
|
||||
fmt.Printf("FUnitsPerEm:%d\n\n", fupe)
|
||||
|
||||
c0, c1 := 'A', 'V'
|
||||
|
||||
i0 := font.Index(c0)
|
||||
hm := font.HMetric(fupe, i0)
|
||||
g := truetype.NewGlyphBuf()
|
||||
err = g.Load(font, fupe, i0, truetype.NoHinting)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("'%c' glyph\n", c0)
|
||||
fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
|
||||
printGlyph(g)
|
||||
i1 := font.Index(c1)
|
||||
fmt.Printf("\n'%c', '%c' Kerning:%d\n", c0, c1, font.Kerning(fupe, i0, i1))
|
||||
}
|
||||
349
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/freetype.go
generated
vendored
349
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/freetype.go
generated
vendored
@@ -1,349 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
// The freetype package provides a convenient API to draw text onto an image.
|
||||
// Use the freetype/raster and freetype/truetype packages for lower level
|
||||
// control over rasterization and TrueType parsing.
|
||||
package freetype
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
"code.google.com/p/freetype-go/freetype/truetype"
|
||||
)
|
||||
|
||||
// These constants determine the size of the glyph cache. The cache is keyed
|
||||
// primarily by the glyph index modulo nGlyphs, and secondarily by sub-pixel
|
||||
// position for the mask image. Sub-pixel positions are quantized to
|
||||
// nXFractions possible values in both the x and y directions.
|
||||
const (
|
||||
nGlyphs = 256
|
||||
nXFractions = 4
|
||||
nYFractions = 1
|
||||
)
|
||||
|
||||
// An entry in the glyph cache is keyed explicitly by the glyph index and
|
||||
// implicitly by the quantized x and y fractional offset. It maps to a mask
|
||||
// image and an offset.
|
||||
type cacheEntry struct {
|
||||
valid bool
|
||||
glyph truetype.Index
|
||||
advanceWidth raster.Fix32
|
||||
mask *image.Alpha
|
||||
offset image.Point
|
||||
}
|
||||
|
||||
// ParseFont just calls the Parse function from the freetype/truetype package.
|
||||
// It is provided here so that code that imports this package doesn't need
|
||||
// to also include the freetype/truetype package.
|
||||
func ParseFont(b []byte) (*truetype.Font, error) {
|
||||
return truetype.Parse(b)
|
||||
}
|
||||
|
||||
// Pt converts from a co-ordinate pair measured in pixels to a raster.Point
|
||||
// co-ordinate pair measured in raster.Fix32 units.
|
||||
func Pt(x, y int) raster.Point {
|
||||
return raster.Point{
|
||||
X: raster.Fix32(x << 8),
|
||||
Y: raster.Fix32(y << 8),
|
||||
}
|
||||
}
|
||||
|
||||
// Hinting is the policy for snapping a glyph's contours to pixel boundaries.
|
||||
type Hinting int32
|
||||
|
||||
const (
|
||||
// NoHinting means to not perform any hinting.
|
||||
NoHinting = Hinting(truetype.NoHinting)
|
||||
// FullHinting means to use the font's hinting instructions.
|
||||
FullHinting = Hinting(truetype.FullHinting)
|
||||
)
|
||||
|
||||
// A Context holds the state for drawing text in a given font and size.
|
||||
type Context struct {
|
||||
r *raster.Rasterizer
|
||||
font *truetype.Font
|
||||
glyphBuf *truetype.GlyphBuf
|
||||
// clip is the clip rectangle for drawing.
|
||||
clip image.Rectangle
|
||||
// dst and src are the destination and source images for drawing.
|
||||
dst draw.Image
|
||||
src image.Image
|
||||
// fontSize and dpi are used to calculate scale. scale is the number of
|
||||
// 26.6 fixed point units in 1 em. hinting is the hinting policy.
|
||||
fontSize, dpi float64
|
||||
scale int32
|
||||
hinting Hinting
|
||||
// cache is the glyph cache.
|
||||
cache [nGlyphs * nXFractions * nYFractions]cacheEntry
|
||||
}
|
||||
|
||||
// PointToFix32 converts the given number of points (as in ``a 12 point font'')
|
||||
// into fixed point units.
|
||||
func (c *Context) PointToFix32(x float64) raster.Fix32 {
|
||||
return raster.Fix32(x * float64(c.dpi) * (256.0 / 72.0))
|
||||
}
|
||||
|
||||
// drawContour draws the given closed contour with the given offset.
|
||||
func (c *Context) drawContour(ps []truetype.Point, dx, dy raster.Fix32) {
|
||||
if len(ps) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// The low bit of each point's Flags value is whether the point is on the
|
||||
// curve. Truetype fonts only have quadratic Bézier curves, not cubics.
|
||||
// Thus, two consecutive off-curve points imply an on-curve point in the
|
||||
// middle of those two.
|
||||
//
|
||||
// See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details.
|
||||
|
||||
// ps[0] is a truetype.Point measured in FUnits and positive Y going
|
||||
// upwards. start is the same thing measured in fixed point units and
|
||||
// positive Y going downwards, and offset by (dx, dy).
|
||||
start := raster.Point{
|
||||
X: dx + raster.Fix32(ps[0].X<<2),
|
||||
Y: dy - raster.Fix32(ps[0].Y<<2),
|
||||
}
|
||||
others := []truetype.Point(nil)
|
||||
if ps[0].Flags&0x01 != 0 {
|
||||
others = ps[1:]
|
||||
} else {
|
||||
last := raster.Point{
|
||||
X: dx + raster.Fix32(ps[len(ps)-1].X<<2),
|
||||
Y: dy - raster.Fix32(ps[len(ps)-1].Y<<2),
|
||||
}
|
||||
if ps[len(ps)-1].Flags&0x01 != 0 {
|
||||
start = last
|
||||
others = ps[:len(ps)-1]
|
||||
} else {
|
||||
start = raster.Point{
|
||||
X: (start.X + last.X) / 2,
|
||||
Y: (start.Y + last.Y) / 2,
|
||||
}
|
||||
others = ps
|
||||
}
|
||||
}
|
||||
c.r.Start(start)
|
||||
q0, on0 := start, true
|
||||
for _, p := range others {
|
||||
q := raster.Point{
|
||||
X: dx + raster.Fix32(p.X<<2),
|
||||
Y: dy - raster.Fix32(p.Y<<2),
|
||||
}
|
||||
on := p.Flags&0x01 != 0
|
||||
if on {
|
||||
if on0 {
|
||||
c.r.Add1(q)
|
||||
} else {
|
||||
c.r.Add2(q0, q)
|
||||
}
|
||||
} else {
|
||||
if on0 {
|
||||
// No-op.
|
||||
} else {
|
||||
mid := raster.Point{
|
||||
X: (q0.X + q.X) / 2,
|
||||
Y: (q0.Y + q.Y) / 2,
|
||||
}
|
||||
c.r.Add2(q0, mid)
|
||||
}
|
||||
}
|
||||
q0, on0 = q, on
|
||||
}
|
||||
// Close the curve.
|
||||
if on0 {
|
||||
c.r.Add1(start)
|
||||
} else {
|
||||
c.r.Add2(q0, start)
|
||||
}
|
||||
}
|
||||
|
||||
// rasterize returns the advance width, glyph mask and integer-pixel offset
|
||||
// to render the given glyph at the given sub-pixel offsets.
|
||||
// The 24.8 fixed point arguments fx and fy must be in the range [0, 1).
|
||||
func (c *Context) rasterize(glyph truetype.Index, fx, fy raster.Fix32) (
|
||||
raster.Fix32, *image.Alpha, image.Point, error) {
|
||||
|
||||
if err := c.glyphBuf.Load(c.font, c.scale, glyph, truetype.Hinting(c.hinting)); err != nil {
|
||||
return 0, nil, image.Point{}, err
|
||||
}
|
||||
// Calculate the integer-pixel bounds for the glyph.
|
||||
xmin := int(fx+raster.Fix32(c.glyphBuf.B.XMin<<2)) >> 8
|
||||
ymin := int(fy-raster.Fix32(c.glyphBuf.B.YMax<<2)) >> 8
|
||||
xmax := int(fx+raster.Fix32(c.glyphBuf.B.XMax<<2)+0xff) >> 8
|
||||
ymax := int(fy-raster.Fix32(c.glyphBuf.B.YMin<<2)+0xff) >> 8
|
||||
if xmin > xmax || ymin > ymax {
|
||||
return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph")
|
||||
}
|
||||
// A TrueType's glyph's nodes can have negative co-ordinates, but the
|
||||
// rasterizer clips anything left of x=0 or above y=0. xmin and ymin
|
||||
// are the pixel offsets, based on the font's FUnit metrics, that let
|
||||
// a negative co-ordinate in TrueType space be non-negative in
|
||||
// rasterizer space. xmin and ymin are typically <= 0.
|
||||
fx += raster.Fix32(-xmin << 8)
|
||||
fy += raster.Fix32(-ymin << 8)
|
||||
// Rasterize the glyph's vectors.
|
||||
c.r.Clear()
|
||||
e0 := 0
|
||||
for _, e1 := range c.glyphBuf.End {
|
||||
c.drawContour(c.glyphBuf.Point[e0:e1], fx, fy)
|
||||
e0 = e1
|
||||
}
|
||||
a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin))
|
||||
c.r.Rasterize(raster.NewAlphaSrcPainter(a))
|
||||
return raster.Fix32(c.glyphBuf.AdvanceWidth << 2), a, image.Point{xmin, ymin}, nil
|
||||
}
|
||||
|
||||
// glyph returns the advance width, glyph mask and integer-pixel offset to
|
||||
// render the given glyph at the given sub-pixel point. It is a cache for the
|
||||
// rasterize method. Unlike rasterize, p's co-ordinates do not have to be in
|
||||
// the range [0, 1).
|
||||
func (c *Context) glyph(glyph truetype.Index, p raster.Point) (
|
||||
raster.Fix32, *image.Alpha, image.Point, error) {
|
||||
|
||||
// Split p.X and p.Y into their integer and fractional parts.
|
||||
ix, fx := int(p.X>>8), p.X&0xff
|
||||
iy, fy := int(p.Y>>8), p.Y&0xff
|
||||
// Calculate the index t into the cache array.
|
||||
tg := int(glyph) % nGlyphs
|
||||
tx := int(fx) / (256 / nXFractions)
|
||||
ty := int(fy) / (256 / nYFractions)
|
||||
t := ((tg*nXFractions)+tx)*nYFractions + ty
|
||||
// Check for a cache hit.
|
||||
if e := c.cache[t]; e.valid && e.glyph == glyph {
|
||||
return e.advanceWidth, e.mask, e.offset.Add(image.Point{ix, iy}), nil
|
||||
}
|
||||
// Rasterize the glyph and put the result into the cache.
|
||||
advanceWidth, mask, offset, err := c.rasterize(glyph, fx, fy)
|
||||
if err != nil {
|
||||
return 0, nil, image.Point{}, err
|
||||
}
|
||||
c.cache[t] = cacheEntry{true, glyph, advanceWidth, mask, offset}
|
||||
return advanceWidth, mask, offset.Add(image.Point{ix, iy}), nil
|
||||
}
|
||||
|
||||
// DrawString draws s at p and returns p advanced by the text extent. The text
|
||||
// is placed so that the left edge of the em square of the first character of s
|
||||
// and the baseline intersect at p. The majority of the affected pixels will be
|
||||
// above and to the right of the point, but some may be below or to the left.
|
||||
// For example, drawing a string that starts with a 'J' in an italic font may
|
||||
// affect pixels below and left of the point.
|
||||
// p is a raster.Point and can therefore represent sub-pixel positions.
|
||||
func (c *Context) DrawString(s string, p raster.Point) (raster.Point, error) {
|
||||
if c.font == nil {
|
||||
return raster.Point{}, errors.New("freetype: DrawText called with a nil font")
|
||||
}
|
||||
prev, hasPrev := truetype.Index(0), false
|
||||
for _, rune := range s {
|
||||
index := c.font.Index(rune)
|
||||
if hasPrev {
|
||||
kern := raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
|
||||
if c.hinting != NoHinting {
|
||||
kern = (kern + 128) &^ 255
|
||||
}
|
||||
p.X += kern
|
||||
}
|
||||
advanceWidth, mask, offset, err := c.glyph(index, p)
|
||||
if err != nil {
|
||||
return raster.Point{}, err
|
||||
}
|
||||
p.X += advanceWidth
|
||||
glyphRect := mask.Bounds().Add(offset)
|
||||
dr := c.clip.Intersect(glyphRect)
|
||||
if !dr.Empty() {
|
||||
mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y}
|
||||
draw.DrawMask(c.dst, dr, c.src, image.ZP, mask, mp, draw.Over)
|
||||
}
|
||||
prev, hasPrev = index, true
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// recalc recalculates scale and bounds values from the font size, screen
|
||||
// resolution and font metrics, and invalidates the glyph cache.
|
||||
func (c *Context) recalc() {
|
||||
c.scale = int32(c.fontSize * c.dpi * (64.0 / 72.0))
|
||||
if c.font == nil {
|
||||
c.r.SetBounds(0, 0)
|
||||
} else {
|
||||
// Set the rasterizer's bounds to be big enough to handle the largest glyph.
|
||||
b := c.font.Bounds(c.scale)
|
||||
xmin := +int(b.XMin) >> 6
|
||||
ymin := -int(b.YMax) >> 6
|
||||
xmax := +int(b.XMax+63) >> 6
|
||||
ymax := -int(b.YMin-63) >> 6
|
||||
c.r.SetBounds(xmax-xmin, ymax-ymin)
|
||||
}
|
||||
for i := range c.cache {
|
||||
c.cache[i] = cacheEntry{}
|
||||
}
|
||||
}
|
||||
|
||||
// SetDPI sets the screen resolution in dots per inch.
|
||||
func (c *Context) SetDPI(dpi float64) {
|
||||
if c.dpi == dpi {
|
||||
return
|
||||
}
|
||||
c.dpi = dpi
|
||||
c.recalc()
|
||||
}
|
||||
|
||||
// SetFont sets the font used to draw text.
|
||||
func (c *Context) SetFont(font *truetype.Font) {
|
||||
if c.font == font {
|
||||
return
|
||||
}
|
||||
c.font = font
|
||||
c.recalc()
|
||||
}
|
||||
|
||||
// SetFontSize sets the font size in points (as in ``a 12 point font'').
|
||||
func (c *Context) SetFontSize(fontSize float64) {
|
||||
if c.fontSize == fontSize {
|
||||
return
|
||||
}
|
||||
c.fontSize = fontSize
|
||||
c.recalc()
|
||||
}
|
||||
|
||||
// SetHinting sets the hinting policy.
|
||||
func (c *Context) SetHinting(hinting Hinting) {
|
||||
c.hinting = hinting
|
||||
for i := range c.cache {
|
||||
c.cache[i] = cacheEntry{}
|
||||
}
|
||||
}
|
||||
|
||||
// SetDst sets the destination image for draw operations.
|
||||
func (c *Context) SetDst(dst draw.Image) {
|
||||
c.dst = dst
|
||||
}
|
||||
|
||||
// SetSrc sets the source image for draw operations. This is typically an
|
||||
// image.Uniform.
|
||||
func (c *Context) SetSrc(src image.Image) {
|
||||
c.src = src
|
||||
}
|
||||
|
||||
// SetClip sets the clip rectangle for drawing.
|
||||
func (c *Context) SetClip(clip image.Rectangle) {
|
||||
c.clip = clip
|
||||
}
|
||||
|
||||
// TODO(nigeltao): implement Context.SetGamma.
|
||||
|
||||
// NewContext creates a new Context.
|
||||
func NewContext() *Context {
|
||||
return &Context{
|
||||
r: raster.NewRasterizer(0, 0),
|
||||
glyphBuf: truetype.NewGlyphBuf(),
|
||||
fontSize: 12,
|
||||
dpi: 72,
|
||||
scale: 12 << 6,
|
||||
}
|
||||
}
|
||||
59
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/freetype_test.go
generated
vendored
59
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/freetype_test.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package freetype
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkDrawString(b *testing.B) {
|
||||
data, err := ioutil.ReadFile("../licenses/gpl.txt")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
data, err = ioutil.ReadFile("../testdata/luxisr.ttf")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
font, err := ParseFont(data)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
dst := image.NewRGBA(image.Rect(0, 0, 800, 600))
|
||||
draw.Draw(dst, dst.Bounds(), image.White, image.ZP, draw.Src)
|
||||
|
||||
c := NewContext()
|
||||
c.SetDst(dst)
|
||||
c.SetClip(dst.Bounds())
|
||||
c.SetSrc(image.Black)
|
||||
c.SetFont(font)
|
||||
|
||||
var ms runtime.MemStats
|
||||
runtime.ReadMemStats(&ms)
|
||||
mallocs := ms.Mallocs
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j, line := range lines {
|
||||
_, err := c.DrawString(line, Pt(0, (j*16)%600))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
runtime.ReadMemStats(&ms)
|
||||
mallocs = ms.Mallocs - mallocs
|
||||
b.Logf("%d iterations, %d mallocs per iteration\n", b.N, int(mallocs)/b.N)
|
||||
}
|
||||
280
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go
generated
vendored
280
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go
generated
vendored
@@ -1,280 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package raster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// A Fix32 is a 24.8 fixed point number.
|
||||
type Fix32 int32
|
||||
|
||||
// A Fix64 is a 48.16 fixed point number.
|
||||
type Fix64 int64
|
||||
|
||||
// String returns a human-readable representation of a 24.8 fixed point number.
|
||||
// For example, the number one-and-a-quarter becomes "1:064".
|
||||
func (x Fix32) String() string {
|
||||
if x < 0 {
|
||||
x = -x
|
||||
return fmt.Sprintf("-%d:%03d", int32(x/256), int32(x%256))
|
||||
}
|
||||
return fmt.Sprintf("%d:%03d", int32(x/256), int32(x%256))
|
||||
}
|
||||
|
||||
// String returns a human-readable representation of a 48.16 fixed point number.
|
||||
// For example, the number one-and-a-quarter becomes "1:16384".
|
||||
func (x Fix64) String() string {
|
||||
if x < 0 {
|
||||
x = -x
|
||||
return fmt.Sprintf("-%d:%05d", int64(x/65536), int64(x%65536))
|
||||
}
|
||||
return fmt.Sprintf("%d:%05d", int64(x/65536), int64(x%65536))
|
||||
}
|
||||
|
||||
// maxAbs returns the maximum of abs(a) and abs(b).
|
||||
func maxAbs(a, b Fix32) Fix32 {
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
if b < 0 {
|
||||
b = -b
|
||||
}
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// A Point represents a two-dimensional point or vector, in 24.8 fixed point
|
||||
// format.
|
||||
type Point struct {
|
||||
X, Y Fix32
|
||||
}
|
||||
|
||||
// String returns a human-readable representation of a Point.
|
||||
func (p Point) String() string {
|
||||
return "(" + p.X.String() + ", " + p.Y.String() + ")"
|
||||
}
|
||||
|
||||
// Add returns the vector p + q.
|
||||
func (p Point) Add(q Point) Point {
|
||||
return Point{p.X + q.X, p.Y + q.Y}
|
||||
}
|
||||
|
||||
// Sub returns the vector p - q.
|
||||
func (p Point) Sub(q Point) Point {
|
||||
return Point{p.X - q.X, p.Y - q.Y}
|
||||
}
|
||||
|
||||
// Mul returns the vector k * p.
|
||||
func (p Point) Mul(k Fix32) Point {
|
||||
return Point{p.X * k / 256, p.Y * k / 256}
|
||||
}
|
||||
|
||||
// Neg returns the vector -p, or equivalently p rotated by 180 degrees.
|
||||
func (p Point) Neg() Point {
|
||||
return Point{-p.X, -p.Y}
|
||||
}
|
||||
|
||||
// Dot returns the dot product p·q.
|
||||
func (p Point) Dot(q Point) Fix64 {
|
||||
px, py := int64(p.X), int64(p.Y)
|
||||
qx, qy := int64(q.X), int64(q.Y)
|
||||
return Fix64(px*qx + py*qy)
|
||||
}
|
||||
|
||||
// Len returns the length of the vector p.
|
||||
func (p Point) Len() Fix32 {
|
||||
// TODO(nigeltao): use fixed point math.
|
||||
x := float64(p.X)
|
||||
y := float64(p.Y)
|
||||
return Fix32(math.Sqrt(x*x + y*y))
|
||||
}
|
||||
|
||||
// Norm returns the vector p normalized to the given length, or the zero Point
|
||||
// if p is degenerate.
|
||||
func (p Point) Norm(length Fix32) Point {
|
||||
d := p.Len()
|
||||
if d == 0 {
|
||||
return Point{}
|
||||
}
|
||||
s, t := int64(length), int64(d)
|
||||
x := int64(p.X) * s / t
|
||||
y := int64(p.Y) * s / t
|
||||
return Point{Fix32(x), Fix32(y)}
|
||||
}
|
||||
|
||||
// Rot45CW returns the vector p rotated clockwise by 45 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot45CW is {1/√2, 1/√2}.
|
||||
func (p Point) Rot45CW() Point {
|
||||
// 181/256 is approximately 1/√2, or sin(π/4).
|
||||
px, py := int64(p.X), int64(p.Y)
|
||||
qx := (+px - py) * 181 / 256
|
||||
qy := (+px + py) * 181 / 256
|
||||
return Point{Fix32(qx), Fix32(qy)}
|
||||
}
|
||||
|
||||
// Rot90CW returns the vector p rotated clockwise by 90 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}.
|
||||
func (p Point) Rot90CW() Point {
|
||||
return Point{-p.Y, p.X}
|
||||
}
|
||||
|
||||
// Rot135CW returns the vector p rotated clockwise by 135 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot135CW is {-1/√2, 1/√2}.
|
||||
func (p Point) Rot135CW() Point {
|
||||
// 181/256 is approximately 1/√2, or sin(π/4).
|
||||
px, py := int64(p.X), int64(p.Y)
|
||||
qx := (-px - py) * 181 / 256
|
||||
qy := (+px - py) * 181 / 256
|
||||
return Point{Fix32(qx), Fix32(qy)}
|
||||
}
|
||||
|
||||
// Rot45CCW returns the vector p rotated counter-clockwise by 45 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}.
|
||||
func (p Point) Rot45CCW() Point {
|
||||
// 181/256 is approximately 1/√2, or sin(π/4).
|
||||
px, py := int64(p.X), int64(p.Y)
|
||||
qx := (+px + py) * 181 / 256
|
||||
qy := (-px + py) * 181 / 256
|
||||
return Point{Fix32(qx), Fix32(qy)}
|
||||
}
|
||||
|
||||
// Rot90CCW returns the vector p rotated counter-clockwise by 90 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot90CCW is {0, -1}.
|
||||
func (p Point) Rot90CCW() Point {
|
||||
return Point{p.Y, -p.X}
|
||||
}
|
||||
|
||||
// Rot135CCW returns the vector p rotated counter-clockwise by 135 degrees.
|
||||
// Note that the Y-axis grows downwards, so {1, 0}.Rot135CCW is {-1/√2, -1/√2}.
|
||||
func (p Point) Rot135CCW() Point {
|
||||
// 181/256 is approximately 1/√2, or sin(π/4).
|
||||
px, py := int64(p.X), int64(p.Y)
|
||||
qx := (-px + py) * 181 / 256
|
||||
qy := (-px - py) * 181 / 256
|
||||
return Point{Fix32(qx), Fix32(qy)}
|
||||
}
|
||||
|
||||
// An Adder accumulates points on a curve.
|
||||
type Adder interface {
|
||||
// Start starts a new curve at the given point.
|
||||
Start(a Point)
|
||||
// Add1 adds a linear segment to the current curve.
|
||||
Add1(b Point)
|
||||
// Add2 adds a quadratic segment to the current curve.
|
||||
Add2(b, c Point)
|
||||
// Add3 adds a cubic segment to the current curve.
|
||||
Add3(b, c, d Point)
|
||||
}
|
||||
|
||||
// A Path is a sequence of curves, and a curve is a start point followed by a
|
||||
// sequence of linear, quadratic or cubic segments.
|
||||
type Path []Fix32
|
||||
|
||||
// String returns a human-readable representation of a Path.
|
||||
func (p Path) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(p); {
|
||||
if i != 0 {
|
||||
s += " "
|
||||
}
|
||||
switch p[i] {
|
||||
case 0:
|
||||
s += "S0" + fmt.Sprint([]Fix32(p[i+1:i+3]))
|
||||
i += 4
|
||||
case 1:
|
||||
s += "A1" + fmt.Sprint([]Fix32(p[i+1:i+3]))
|
||||
i += 4
|
||||
case 2:
|
||||
s += "A2" + fmt.Sprint([]Fix32(p[i+1:i+5]))
|
||||
i += 6
|
||||
case 3:
|
||||
s += "A3" + fmt.Sprint([]Fix32(p[i+1:i+7]))
|
||||
i += 8
|
||||
default:
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Clear cancels any previous calls to p.Start or p.AddXxx.
|
||||
func (p *Path) Clear() {
|
||||
*p = (*p)[:0]
|
||||
}
|
||||
|
||||
// Start starts a new curve at the given point.
|
||||
func (p *Path) Start(a Point) {
|
||||
*p = append(*p, 0, a.X, a.Y, 0)
|
||||
}
|
||||
|
||||
// Add1 adds a linear segment to the current curve.
|
||||
func (p *Path) Add1(b Point) {
|
||||
*p = append(*p, 1, b.X, b.Y, 1)
|
||||
}
|
||||
|
||||
// Add2 adds a quadratic segment to the current curve.
|
||||
func (p *Path) Add2(b, c Point) {
|
||||
*p = append(*p, 2, b.X, b.Y, c.X, c.Y, 2)
|
||||
}
|
||||
|
||||
// Add3 adds a cubic segment to the current curve.
|
||||
func (p *Path) Add3(b, c, d Point) {
|
||||
*p = append(*p, 3, b.X, b.Y, c.X, c.Y, d.X, d.Y, 3)
|
||||
}
|
||||
|
||||
// AddPath adds the Path q to p.
|
||||
func (p *Path) AddPath(q Path) {
|
||||
*p = append(*p, q...)
|
||||
}
|
||||
|
||||
// AddStroke adds a stroked Path.
|
||||
func (p *Path) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
|
||||
Stroke(p, q, width, cr, jr)
|
||||
}
|
||||
|
||||
// firstPoint returns the first point in a non-empty Path.
|
||||
func (p Path) firstPoint() Point {
|
||||
return Point{p[1], p[2]}
|
||||
}
|
||||
|
||||
// lastPoint returns the last point in a non-empty Path.
|
||||
func (p Path) lastPoint() Point {
|
||||
return Point{p[len(p)-3], p[len(p)-2]}
|
||||
}
|
||||
|
||||
// addPathReversed adds q reversed to p.
|
||||
// For example, if q consists of a linear segment from A to B followed by a
|
||||
// quadratic segment from B to C to D, then the values of q looks like:
|
||||
// index: 01234567890123
|
||||
// value: 0AA01BB12CCDD2
|
||||
// So, when adding q backwards to p, we want to Add2(C, B) followed by Add1(A).
|
||||
func addPathReversed(p Adder, q Path) {
|
||||
if len(q) == 0 {
|
||||
return
|
||||
}
|
||||
i := len(q) - 1
|
||||
for {
|
||||
switch q[i] {
|
||||
case 0:
|
||||
return
|
||||
case 1:
|
||||
i -= 4
|
||||
p.Add1(Point{q[i-2], q[i-1]})
|
||||
case 2:
|
||||
i -= 6
|
||||
p.Add2(Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
|
||||
case 3:
|
||||
i -= 8
|
||||
p.Add3(Point{q[i+4], q[i+5]}, Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
|
||||
default:
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
}
|
||||
}
|
||||
292
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go
generated
vendored
292
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go
generated
vendored
@@ -1,292 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"math"
|
||||
)
|
||||
|
||||
// A Span is a horizontal segment of pixels with constant alpha. X0 is an
|
||||
// inclusive bound and X1 is exclusive, the same as for slices. A fully
|
||||
// opaque Span has A == 1<<32 - 1.
|
||||
type Span struct {
|
||||
Y, X0, X1 int
|
||||
A uint32
|
||||
}
|
||||
|
||||
// A Painter knows how to paint a batch of Spans. Rasterization may involve
|
||||
// Painting multiple batches, and done will be true for the final batch.
|
||||
// The Spans' Y values are monotonically increasing during a rasterization.
|
||||
// Paint may use all of ss as scratch space during the call.
|
||||
type Painter interface {
|
||||
Paint(ss []Span, done bool)
|
||||
}
|
||||
|
||||
// The PainterFunc type adapts an ordinary function to the Painter interface.
|
||||
type PainterFunc func(ss []Span, done bool)
|
||||
|
||||
// Paint just delegates the call to f.
|
||||
func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
|
||||
|
||||
// An AlphaOverPainter is a Painter that paints Spans onto an image.Alpha
|
||||
// using the Over Porter-Duff composition operator.
|
||||
type AlphaOverPainter struct {
|
||||
Image *image.Alpha
|
||||
}
|
||||
|
||||
// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
|
||||
func (r AlphaOverPainter) Paint(ss []Span, done bool) {
|
||||
b := r.Image.Bounds()
|
||||
for _, s := range ss {
|
||||
if s.Y < b.Min.Y {
|
||||
continue
|
||||
}
|
||||
if s.Y >= b.Max.Y {
|
||||
return
|
||||
}
|
||||
if s.X0 < b.Min.X {
|
||||
s.X0 = b.Min.X
|
||||
}
|
||||
if s.X1 > b.Max.X {
|
||||
s.X1 = b.Max.X
|
||||
}
|
||||
if s.X0 >= s.X1 {
|
||||
continue
|
||||
}
|
||||
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
|
||||
p := r.Image.Pix[base+s.X0 : base+s.X1]
|
||||
a := int(s.A >> 24)
|
||||
for i, c := range p {
|
||||
v := int(c)
|
||||
p[i] = uint8((v*255 + (255-v)*a) / 255)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
|
||||
func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
|
||||
return AlphaOverPainter{m}
|
||||
}
|
||||
|
||||
// An AlphaSrcPainter is a Painter that paints Spans onto an image.Alpha
|
||||
// using the Src Porter-Duff composition operator.
|
||||
type AlphaSrcPainter struct {
|
||||
Image *image.Alpha
|
||||
}
|
||||
|
||||
// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
|
||||
func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
|
||||
b := r.Image.Bounds()
|
||||
for _, s := range ss {
|
||||
if s.Y < b.Min.Y {
|
||||
continue
|
||||
}
|
||||
if s.Y >= b.Max.Y {
|
||||
return
|
||||
}
|
||||
if s.X0 < b.Min.X {
|
||||
s.X0 = b.Min.X
|
||||
}
|
||||
if s.X1 > b.Max.X {
|
||||
s.X1 = b.Max.X
|
||||
}
|
||||
if s.X0 >= s.X1 {
|
||||
continue
|
||||
}
|
||||
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
|
||||
p := r.Image.Pix[base+s.X0 : base+s.X1]
|
||||
color := uint8(s.A >> 24)
|
||||
for i := range p {
|
||||
p[i] = color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
|
||||
func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
|
||||
return AlphaSrcPainter{m}
|
||||
}
|
||||
|
||||
type RGBAPainter struct {
|
||||
// The image to compose onto.
|
||||
Image *image.RGBA
|
||||
// The Porter-Duff composition operator.
|
||||
Op draw.Op
|
||||
// The 16-bit color to paint the spans.
|
||||
cr, cg, cb, ca uint32
|
||||
}
|
||||
|
||||
// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
|
||||
func (r *RGBAPainter) Paint(ss []Span, done bool) {
|
||||
b := r.Image.Bounds()
|
||||
for _, s := range ss {
|
||||
if s.Y < b.Min.Y {
|
||||
continue
|
||||
}
|
||||
if s.Y >= b.Max.Y {
|
||||
return
|
||||
}
|
||||
if s.X0 < b.Min.X {
|
||||
s.X0 = b.Min.X
|
||||
}
|
||||
if s.X1 > b.Max.X {
|
||||
s.X1 = b.Max.X
|
||||
}
|
||||
if s.X0 >= s.X1 {
|
||||
continue
|
||||
}
|
||||
// This code is similar to drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go.
|
||||
ma := s.A >> 16
|
||||
const m = 1<<16 - 1
|
||||
i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
|
||||
i1 := i0 + (s.X1-s.X0)*4
|
||||
if r.Op == draw.Over {
|
||||
for i := i0; i < i1; i += 4 {
|
||||
dr := uint32(r.Image.Pix[i+0])
|
||||
dg := uint32(r.Image.Pix[i+1])
|
||||
db := uint32(r.Image.Pix[i+2])
|
||||
da := uint32(r.Image.Pix[i+3])
|
||||
a := (m - (r.ca * ma / m)) * 0x101
|
||||
r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
|
||||
r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
|
||||
r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
|
||||
r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
|
||||
}
|
||||
} else {
|
||||
for i := i0; i < i1; i += 4 {
|
||||
r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
|
||||
r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
|
||||
r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
|
||||
r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetColor sets the color to paint the spans.
|
||||
func (r *RGBAPainter) SetColor(c color.Color) {
|
||||
r.cr, r.cg, r.cb, r.ca = c.RGBA()
|
||||
}
|
||||
|
||||
// NewRGBAPainter creates a new RGBAPainter for the given image.
|
||||
func NewRGBAPainter(m *image.RGBA) *RGBAPainter {
|
||||
return &RGBAPainter{Image: m}
|
||||
}
|
||||
|
||||
// A MonochromePainter wraps another Painter, quantizing each Span's alpha to
|
||||
// be either fully opaque or fully transparent.
|
||||
type MonochromePainter struct {
|
||||
Painter Painter
|
||||
y, x0, x1 int
|
||||
}
|
||||
|
||||
// Paint delegates to the wrapped Painter after quantizing each Span's alpha
|
||||
// value and merging adjacent fully opaque Spans.
|
||||
func (m *MonochromePainter) Paint(ss []Span, done bool) {
|
||||
// We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
|
||||
j := 0
|
||||
for _, s := range ss {
|
||||
if s.A >= 1<<31 {
|
||||
if m.y == s.Y && m.x1 == s.X0 {
|
||||
m.x1 = s.X1
|
||||
} else {
|
||||
ss[j] = Span{m.y, m.x0, m.x1, 1<<32 - 1}
|
||||
j++
|
||||
m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
|
||||
}
|
||||
}
|
||||
}
|
||||
if done {
|
||||
// Flush the accumulated Span.
|
||||
finalSpan := Span{m.y, m.x0, m.x1, 1<<32 - 1}
|
||||
if j < len(ss) {
|
||||
ss[j] = finalSpan
|
||||
j++
|
||||
m.Painter.Paint(ss[:j], true)
|
||||
} else if j == len(ss) {
|
||||
m.Painter.Paint(ss, false)
|
||||
if cap(ss) > 0 {
|
||||
ss = ss[:1]
|
||||
} else {
|
||||
ss = make([]Span, 1)
|
||||
}
|
||||
ss[0] = finalSpan
|
||||
m.Painter.Paint(ss, true)
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
// Reset the accumulator, so that this Painter can be re-used.
|
||||
m.y, m.x0, m.x1 = 0, 0, 0
|
||||
} else {
|
||||
m.Painter.Paint(ss[:j], false)
|
||||
}
|
||||
}
|
||||
|
||||
// NewMonochromePainter creates a new MonochromePainter that wraps the given
|
||||
// Painter.
|
||||
func NewMonochromePainter(p Painter) *MonochromePainter {
|
||||
return &MonochromePainter{Painter: p}
|
||||
}
|
||||
|
||||
// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
|
||||
// on each Span's alpha value.
|
||||
type GammaCorrectionPainter struct {
|
||||
// The wrapped Painter.
|
||||
Painter Painter
|
||||
// Precomputed alpha values for linear interpolation, with fully opaque == 1<<16-1.
|
||||
a [256]uint16
|
||||
// Whether gamma correction is a no-op.
|
||||
gammaIsOne bool
|
||||
}
|
||||
|
||||
// Paint delegates to the wrapped Painter after performing gamma-correction
|
||||
// on each Span.
|
||||
func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
|
||||
if !g.gammaIsOne {
|
||||
const (
|
||||
M = 0x1010101 // 255*M == 1<<32-1
|
||||
N = 0x8080 // N = M>>9, and N < 1<<16-1
|
||||
)
|
||||
for i, s := range ss {
|
||||
if s.A == 0 || s.A == 1<<32-1 {
|
||||
continue
|
||||
}
|
||||
p, q := s.A/M, (s.A%M)>>9
|
||||
// The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
|
||||
a := uint32(g.a[p])*(N-q) + uint32(g.a[p+1])*q
|
||||
a = (a + N/2) / N
|
||||
// Convert the alpha from 16-bit (which is g.a's range) to 32-bit.
|
||||
a |= a << 16
|
||||
ss[i].A = a
|
||||
}
|
||||
}
|
||||
g.Painter.Paint(ss, done)
|
||||
}
|
||||
|
||||
// SetGamma sets the gamma value.
|
||||
func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
|
||||
if gamma == 1.0 {
|
||||
g.gammaIsOne = true
|
||||
return
|
||||
}
|
||||
g.gammaIsOne = false
|
||||
for i := 0; i < 256; i++ {
|
||||
a := float64(i) / 0xff
|
||||
a = math.Pow(a, gamma)
|
||||
g.a[i] = uint16(0xffff * a)
|
||||
}
|
||||
}
|
||||
|
||||
// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
|
||||
// the given Painter.
|
||||
func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
|
||||
g := &GammaCorrectionPainter{Painter: p}
|
||||
g.SetGamma(gamma)
|
||||
return g
|
||||
}
|
||||
579
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go
generated
vendored
579
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go
generated
vendored
@@ -1,579 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
// The raster package provides an anti-aliasing 2-D rasterizer.
|
||||
//
|
||||
// It is part of the larger Freetype-Go suite of font-related packages,
|
||||
// but the raster package is not specific to font rasterization, and can
|
||||
// be used standalone without any other Freetype-Go package.
|
||||
//
|
||||
// Rasterization is done by the same area/coverage accumulation algorithm
|
||||
// as the Freetype "smooth" module, and the Anti-Grain Geometry library.
|
||||
// A description of the area/coverage algorithm is at
|
||||
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
|
||||
package raster
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// A cell is part of a linked list (for a given yi co-ordinate) of accumulated
|
||||
// area/coverage for the pixel at (xi, yi).
|
||||
type cell struct {
|
||||
xi int
|
||||
area, cover int
|
||||
next int
|
||||
}
|
||||
|
||||
type Rasterizer struct {
|
||||
// If false, the default behavior is to use the even-odd winding fill
|
||||
// rule during Rasterize.
|
||||
UseNonZeroWinding bool
|
||||
// An offset (in pixels) to the painted spans.
|
||||
Dx, Dy int
|
||||
|
||||
// The width of the Rasterizer. The height is implicit in len(cellIndex).
|
||||
width int
|
||||
// splitScaleN is the scaling factor used to determine how many times
|
||||
// to decompose a quadratic or cubic segment into a linear approximation.
|
||||
splitScale2, splitScale3 int
|
||||
|
||||
// The current pen position.
|
||||
a Point
|
||||
// The current cell and its area/coverage being accumulated.
|
||||
xi, yi int
|
||||
area, cover int
|
||||
|
||||
// Saved cells.
|
||||
cell []cell
|
||||
// Linked list of cells, one per row.
|
||||
cellIndex []int
|
||||
// Buffers.
|
||||
cellBuf [256]cell
|
||||
cellIndexBuf [64]int
|
||||
spanBuf [64]Span
|
||||
}
|
||||
|
||||
// findCell returns the index in r.cell for the cell corresponding to
|
||||
// (r.xi, r.yi). The cell is created if necessary.
|
||||
func (r *Rasterizer) findCell() int {
|
||||
if r.yi < 0 || r.yi >= len(r.cellIndex) {
|
||||
return -1
|
||||
}
|
||||
xi := r.xi
|
||||
if xi < 0 {
|
||||
xi = -1
|
||||
} else if xi > r.width {
|
||||
xi = r.width
|
||||
}
|
||||
i, prev := r.cellIndex[r.yi], -1
|
||||
for i != -1 && r.cell[i].xi <= xi {
|
||||
if r.cell[i].xi == xi {
|
||||
return i
|
||||
}
|
||||
i, prev = r.cell[i].next, i
|
||||
}
|
||||
c := len(r.cell)
|
||||
if c == cap(r.cell) {
|
||||
buf := make([]cell, c, 4*c)
|
||||
copy(buf, r.cell)
|
||||
r.cell = buf[0 : c+1]
|
||||
} else {
|
||||
r.cell = r.cell[0 : c+1]
|
||||
}
|
||||
r.cell[c] = cell{xi, 0, 0, i}
|
||||
if prev == -1 {
|
||||
r.cellIndex[r.yi] = c
|
||||
} else {
|
||||
r.cell[prev].next = c
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// saveCell saves any accumulated r.area/r.cover for (r.xi, r.yi).
|
||||
func (r *Rasterizer) saveCell() {
|
||||
if r.area != 0 || r.cover != 0 {
|
||||
i := r.findCell()
|
||||
if i != -1 {
|
||||
r.cell[i].area += r.area
|
||||
r.cell[i].cover += r.cover
|
||||
}
|
||||
r.area = 0
|
||||
r.cover = 0
|
||||
}
|
||||
}
|
||||
|
||||
// setCell sets the (xi, yi) cell that r is accumulating area/coverage for.
|
||||
func (r *Rasterizer) setCell(xi, yi int) {
|
||||
if r.xi != xi || r.yi != yi {
|
||||
r.saveCell()
|
||||
r.xi, r.yi = xi, yi
|
||||
}
|
||||
}
|
||||
|
||||
// scan accumulates area/coverage for the yi'th scanline, going from
|
||||
// x0 to x1 in the horizontal direction (in 24.8 fixed point co-ordinates)
|
||||
// and from y0f to y1f fractional vertical units within that scanline.
|
||||
func (r *Rasterizer) scan(yi int, x0, y0f, x1, y1f Fix32) {
|
||||
// Break the 24.8 fixed point X co-ordinates into integral and fractional parts.
|
||||
x0i := int(x0) / 256
|
||||
x0f := x0 - Fix32(256*x0i)
|
||||
x1i := int(x1) / 256
|
||||
x1f := x1 - Fix32(256*x1i)
|
||||
|
||||
// A perfectly horizontal scan.
|
||||
if y0f == y1f {
|
||||
r.setCell(x1i, yi)
|
||||
return
|
||||
}
|
||||
dx, dy := x1-x0, y1f-y0f
|
||||
// A single cell scan.
|
||||
if x0i == x1i {
|
||||
r.area += int((x0f + x1f) * dy)
|
||||
r.cover += int(dy)
|
||||
return
|
||||
}
|
||||
// There are at least two cells. Apart from the first and last cells,
|
||||
// all intermediate cells go through the full width of the cell,
|
||||
// or 256 units in 24.8 fixed point format.
|
||||
var (
|
||||
p, q, edge0, edge1 Fix32
|
||||
xiDelta int
|
||||
)
|
||||
if dx > 0 {
|
||||
p, q = (256-x0f)*dy, dx
|
||||
edge0, edge1, xiDelta = 0, 256, 1
|
||||
} else {
|
||||
p, q = x0f*dy, -dx
|
||||
edge0, edge1, xiDelta = 256, 0, -1
|
||||
}
|
||||
yDelta, yRem := p/q, p%q
|
||||
if yRem < 0 {
|
||||
yDelta -= 1
|
||||
yRem += q
|
||||
}
|
||||
// Do the first cell.
|
||||
xi, y := x0i, y0f
|
||||
r.area += int((x0f + edge1) * yDelta)
|
||||
r.cover += int(yDelta)
|
||||
xi, y = xi+xiDelta, y+yDelta
|
||||
r.setCell(xi, yi)
|
||||
if xi != x1i {
|
||||
// Do all the intermediate cells.
|
||||
p = 256 * (y1f - y + yDelta)
|
||||
fullDelta, fullRem := p/q, p%q
|
||||
if fullRem < 0 {
|
||||
fullDelta -= 1
|
||||
fullRem += q
|
||||
}
|
||||
yRem -= q
|
||||
for xi != x1i {
|
||||
yDelta = fullDelta
|
||||
yRem += fullRem
|
||||
if yRem >= 0 {
|
||||
yDelta += 1
|
||||
yRem -= q
|
||||
}
|
||||
r.area += int(256 * yDelta)
|
||||
r.cover += int(yDelta)
|
||||
xi, y = xi+xiDelta, y+yDelta
|
||||
r.setCell(xi, yi)
|
||||
}
|
||||
}
|
||||
// Do the last cell.
|
||||
yDelta = y1f - y
|
||||
r.area += int((edge0 + x1f) * yDelta)
|
||||
r.cover += int(yDelta)
|
||||
}
|
||||
|
||||
// Start starts a new curve at the given point.
|
||||
func (r *Rasterizer) Start(a Point) {
|
||||
r.setCell(int(a.X/256), int(a.Y/256))
|
||||
r.a = a
|
||||
}
|
||||
|
||||
// Add1 adds a linear segment to the current curve.
|
||||
func (r *Rasterizer) Add1(b Point) {
|
||||
x0, y0 := r.a.X, r.a.Y
|
||||
x1, y1 := b.X, b.Y
|
||||
dx, dy := x1-x0, y1-y0
|
||||
// Break the 24.8 fixed point Y co-ordinates into integral and fractional parts.
|
||||
y0i := int(y0) / 256
|
||||
y0f := y0 - Fix32(256*y0i)
|
||||
y1i := int(y1) / 256
|
||||
y1f := y1 - Fix32(256*y1i)
|
||||
|
||||
if y0i == y1i {
|
||||
// There is only one scanline.
|
||||
r.scan(y0i, x0, y0f, x1, y1f)
|
||||
|
||||
} else if dx == 0 {
|
||||
// This is a vertical line segment. We avoid calling r.scan and instead
|
||||
// manipulate r.area and r.cover directly.
|
||||
var (
|
||||
edge0, edge1 Fix32
|
||||
yiDelta int
|
||||
)
|
||||
if dy > 0 {
|
||||
edge0, edge1, yiDelta = 0, 256, 1
|
||||
} else {
|
||||
edge0, edge1, yiDelta = 256, 0, -1
|
||||
}
|
||||
x0i, yi := int(x0)/256, y0i
|
||||
x0fTimes2 := (int(x0) - (256 * x0i)) * 2
|
||||
// Do the first pixel.
|
||||
dcover := int(edge1 - y0f)
|
||||
darea := int(x0fTimes2 * dcover)
|
||||
r.area += darea
|
||||
r.cover += dcover
|
||||
yi += yiDelta
|
||||
r.setCell(x0i, yi)
|
||||
// Do all the intermediate pixels.
|
||||
dcover = int(edge1 - edge0)
|
||||
darea = int(x0fTimes2 * dcover)
|
||||
for yi != y1i {
|
||||
r.area += darea
|
||||
r.cover += dcover
|
||||
yi += yiDelta
|
||||
r.setCell(x0i, yi)
|
||||
}
|
||||
// Do the last pixel.
|
||||
dcover = int(y1f - edge0)
|
||||
darea = int(x0fTimes2 * dcover)
|
||||
r.area += darea
|
||||
r.cover += dcover
|
||||
|
||||
} else {
|
||||
// There are at least two scanlines. Apart from the first and last scanlines,
|
||||
// all intermediate scanlines go through the full height of the row, or 256
|
||||
// units in 24.8 fixed point format.
|
||||
var (
|
||||
p, q, edge0, edge1 Fix32
|
||||
yiDelta int
|
||||
)
|
||||
if dy > 0 {
|
||||
p, q = (256-y0f)*dx, dy
|
||||
edge0, edge1, yiDelta = 0, 256, 1
|
||||
} else {
|
||||
p, q = y0f*dx, -dy
|
||||
edge0, edge1, yiDelta = 256, 0, -1
|
||||
}
|
||||
xDelta, xRem := p/q, p%q
|
||||
if xRem < 0 {
|
||||
xDelta -= 1
|
||||
xRem += q
|
||||
}
|
||||
// Do the first scanline.
|
||||
x, yi := x0, y0i
|
||||
r.scan(yi, x, y0f, x+xDelta, edge1)
|
||||
x, yi = x+xDelta, yi+yiDelta
|
||||
r.setCell(int(x)/256, yi)
|
||||
if yi != y1i {
|
||||
// Do all the intermediate scanlines.
|
||||
p = 256 * dx
|
||||
fullDelta, fullRem := p/q, p%q
|
||||
if fullRem < 0 {
|
||||
fullDelta -= 1
|
||||
fullRem += q
|
||||
}
|
||||
xRem -= q
|
||||
for yi != y1i {
|
||||
xDelta = fullDelta
|
||||
xRem += fullRem
|
||||
if xRem >= 0 {
|
||||
xDelta += 1
|
||||
xRem -= q
|
||||
}
|
||||
r.scan(yi, x, edge0, x+xDelta, edge1)
|
||||
x, yi = x+xDelta, yi+yiDelta
|
||||
r.setCell(int(x)/256, yi)
|
||||
}
|
||||
}
|
||||
// Do the last scanline.
|
||||
r.scan(yi, x, edge0, x1, y1f)
|
||||
}
|
||||
// The next lineTo starts from b.
|
||||
r.a = b
|
||||
}
|
||||
|
||||
// Add2 adds a quadratic segment to the current curve.
|
||||
func (r *Rasterizer) Add2(b, c Point) {
|
||||
// Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
|
||||
// Specifically, how much the middle point b deviates from (a+c)/2.
|
||||
dev := maxAbs(r.a.X-2*b.X+c.X, r.a.Y-2*b.Y+c.Y) / Fix32(r.splitScale2)
|
||||
nsplit := 0
|
||||
for dev > 0 {
|
||||
dev /= 4
|
||||
nsplit++
|
||||
}
|
||||
// dev is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
|
||||
const maxNsplit = 16
|
||||
if nsplit > maxNsplit {
|
||||
panic("freetype/raster: Add2 nsplit too large: " + strconv.Itoa(nsplit))
|
||||
}
|
||||
// Recursively decompose the curve nSplit levels deep.
|
||||
var (
|
||||
pStack [2*maxNsplit + 3]Point
|
||||
sStack [maxNsplit + 1]int
|
||||
i int
|
||||
)
|
||||
sStack[0] = nsplit
|
||||
pStack[0] = c
|
||||
pStack[1] = b
|
||||
pStack[2] = r.a
|
||||
for i >= 0 {
|
||||
s := sStack[i]
|
||||
p := pStack[2*i:]
|
||||
if s > 0 {
|
||||
// Split the quadratic curve p[:3] into an equivalent set of two shorter curves:
|
||||
// p[:3] and p[2:5]. The new p[4] is the old p[2], and p[0] is unchanged.
|
||||
mx := p[1].X
|
||||
p[4].X = p[2].X
|
||||
p[3].X = (p[4].X + mx) / 2
|
||||
p[1].X = (p[0].X + mx) / 2
|
||||
p[2].X = (p[1].X + p[3].X) / 2
|
||||
my := p[1].Y
|
||||
p[4].Y = p[2].Y
|
||||
p[3].Y = (p[4].Y + my) / 2
|
||||
p[1].Y = (p[0].Y + my) / 2
|
||||
p[2].Y = (p[1].Y + p[3].Y) / 2
|
||||
// The two shorter curves have one less split to do.
|
||||
sStack[i] = s - 1
|
||||
sStack[i+1] = s - 1
|
||||
i++
|
||||
} else {
|
||||
// Replace the level-0 quadratic with a two-linear-piece approximation.
|
||||
midx := (p[0].X + 2*p[1].X + p[2].X) / 4
|
||||
midy := (p[0].Y + 2*p[1].Y + p[2].Y) / 4
|
||||
r.Add1(Point{midx, midy})
|
||||
r.Add1(p[0])
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add3 adds a cubic segment to the current curve.
|
||||
func (r *Rasterizer) Add3(b, c, d Point) {
|
||||
// Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
|
||||
dev2 := maxAbs(r.a.X-3*(b.X+c.X)+d.X, r.a.Y-3*(b.Y+c.Y)+d.Y) / Fix32(r.splitScale2)
|
||||
dev3 := maxAbs(r.a.X-2*b.X+d.X, r.a.Y-2*b.Y+d.Y) / Fix32(r.splitScale3)
|
||||
nsplit := 0
|
||||
for dev2 > 0 || dev3 > 0 {
|
||||
dev2 /= 8
|
||||
dev3 /= 4
|
||||
nsplit++
|
||||
}
|
||||
// devN is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
|
||||
const maxNsplit = 16
|
||||
if nsplit > maxNsplit {
|
||||
panic("freetype/raster: Add3 nsplit too large: " + strconv.Itoa(nsplit))
|
||||
}
|
||||
// Recursively decompose the curve nSplit levels deep.
|
||||
var (
|
||||
pStack [3*maxNsplit + 4]Point
|
||||
sStack [maxNsplit + 1]int
|
||||
i int
|
||||
)
|
||||
sStack[0] = nsplit
|
||||
pStack[0] = d
|
||||
pStack[1] = c
|
||||
pStack[2] = b
|
||||
pStack[3] = r.a
|
||||
for i >= 0 {
|
||||
s := sStack[i]
|
||||
p := pStack[3*i:]
|
||||
if s > 0 {
|
||||
// Split the cubic curve p[:4] into an equivalent set of two shorter curves:
|
||||
// p[:4] and p[3:7]. The new p[6] is the old p[3], and p[0] is unchanged.
|
||||
m01x := (p[0].X + p[1].X) / 2
|
||||
m12x := (p[1].X + p[2].X) / 2
|
||||
m23x := (p[2].X + p[3].X) / 2
|
||||
p[6].X = p[3].X
|
||||
p[5].X = m23x
|
||||
p[1].X = m01x
|
||||
p[2].X = (m01x + m12x) / 2
|
||||
p[4].X = (m12x + m23x) / 2
|
||||
p[3].X = (p[2].X + p[4].X) / 2
|
||||
m01y := (p[0].Y + p[1].Y) / 2
|
||||
m12y := (p[1].Y + p[2].Y) / 2
|
||||
m23y := (p[2].Y + p[3].Y) / 2
|
||||
p[6].Y = p[3].Y
|
||||
p[5].Y = m23y
|
||||
p[1].Y = m01y
|
||||
p[2].Y = (m01y + m12y) / 2
|
||||
p[4].Y = (m12y + m23y) / 2
|
||||
p[3].Y = (p[2].Y + p[4].Y) / 2
|
||||
// The two shorter curves have one less split to do.
|
||||
sStack[i] = s - 1
|
||||
sStack[i+1] = s - 1
|
||||
i++
|
||||
} else {
|
||||
// Replace the level-0 cubic with a two-linear-piece approximation.
|
||||
midx := (p[0].X + 3*(p[1].X+p[2].X) + p[3].X) / 8
|
||||
midy := (p[0].Y + 3*(p[1].Y+p[2].Y) + p[3].Y) / 8
|
||||
r.Add1(Point{midx, midy})
|
||||
r.Add1(p[0])
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddPath adds the given Path.
|
||||
func (r *Rasterizer) AddPath(p Path) {
|
||||
for i := 0; i < len(p); {
|
||||
switch p[i] {
|
||||
case 0:
|
||||
r.Start(Point{p[i+1], p[i+2]})
|
||||
i += 4
|
||||
case 1:
|
||||
r.Add1(Point{p[i+1], p[i+2]})
|
||||
i += 4
|
||||
case 2:
|
||||
r.Add2(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]})
|
||||
i += 6
|
||||
case 3:
|
||||
r.Add3(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]}, Point{p[i+5], p[i+6]})
|
||||
i += 8
|
||||
default:
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddStroke adds a stroked Path.
|
||||
func (r *Rasterizer) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
|
||||
Stroke(r, q, width, cr, jr)
|
||||
}
|
||||
|
||||
// Converts an area value to a uint32 alpha value. A completely filled pixel
|
||||
// corresponds to an area of 256*256*2, and an alpha of 1<<32-1. The
|
||||
// conversion of area values greater than this depends on the winding rule:
|
||||
// even-odd or non-zero.
|
||||
func (r *Rasterizer) areaToAlpha(area int) uint32 {
|
||||
// The C Freetype implementation (version 2.3.12) does "alpha := area>>1" without
|
||||
// the +1. Round-to-nearest gives a more symmetric result than round-down.
|
||||
// The C implementation also returns 8-bit alpha, not 32-bit alpha.
|
||||
a := (area + 1) >> 1
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
alpha := uint32(a)
|
||||
if r.UseNonZeroWinding {
|
||||
if alpha > 0xffff {
|
||||
alpha = 0xffff
|
||||
}
|
||||
} else {
|
||||
alpha &= 0x1ffff
|
||||
if alpha > 0x10000 {
|
||||
alpha = 0x20000 - alpha
|
||||
} else if alpha == 0x10000 {
|
||||
alpha = 0x0ffff
|
||||
}
|
||||
}
|
||||
alpha |= alpha << 16
|
||||
return alpha
|
||||
}
|
||||
|
||||
// Rasterize converts r's accumulated curves into Spans for p. The Spans
|
||||
// passed to p are non-overlapping, and sorted by Y and then X. They all
|
||||
// have non-zero width (and 0 <= X0 < X1 <= r.width) and non-zero A, except
|
||||
// for the final Span, which has Y, X0, X1 and A all equal to zero.
|
||||
func (r *Rasterizer) Rasterize(p Painter) {
|
||||
r.saveCell()
|
||||
s := 0
|
||||
for yi := 0; yi < len(r.cellIndex); yi++ {
|
||||
xi, cover := 0, 0
|
||||
for c := r.cellIndex[yi]; c != -1; c = r.cell[c].next {
|
||||
if cover != 0 && r.cell[c].xi > xi {
|
||||
alpha := r.areaToAlpha(cover * 256 * 2)
|
||||
if alpha != 0 {
|
||||
xi0, xi1 := xi, r.cell[c].xi
|
||||
if xi0 < 0 {
|
||||
xi0 = 0
|
||||
}
|
||||
if xi1 >= r.width {
|
||||
xi1 = r.width
|
||||
}
|
||||
if xi0 < xi1 {
|
||||
r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
|
||||
s++
|
||||
}
|
||||
}
|
||||
}
|
||||
cover += r.cell[c].cover
|
||||
alpha := r.areaToAlpha(cover*256*2 - r.cell[c].area)
|
||||
xi = r.cell[c].xi + 1
|
||||
if alpha != 0 {
|
||||
xi0, xi1 := r.cell[c].xi, xi
|
||||
if xi0 < 0 {
|
||||
xi0 = 0
|
||||
}
|
||||
if xi1 >= r.width {
|
||||
xi1 = r.width
|
||||
}
|
||||
if xi0 < xi1 {
|
||||
r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
|
||||
s++
|
||||
}
|
||||
}
|
||||
if s > len(r.spanBuf)-2 {
|
||||
p.Paint(r.spanBuf[:s], false)
|
||||
s = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
p.Paint(r.spanBuf[:s], true)
|
||||
}
|
||||
|
||||
// Clear cancels any previous calls to r.Start or r.AddXxx.
|
||||
func (r *Rasterizer) Clear() {
|
||||
r.a = Point{}
|
||||
r.xi = 0
|
||||
r.yi = 0
|
||||
r.area = 0
|
||||
r.cover = 0
|
||||
r.cell = r.cell[:0]
|
||||
for i := 0; i < len(r.cellIndex); i++ {
|
||||
r.cellIndex[i] = -1
|
||||
}
|
||||
}
|
||||
|
||||
// SetBounds sets the maximum width and height of the rasterized image and
|
||||
// calls Clear. The width and height are in pixels, not Fix32 units.
|
||||
func (r *Rasterizer) SetBounds(width, height int) {
|
||||
if width < 0 {
|
||||
width = 0
|
||||
}
|
||||
if height < 0 {
|
||||
height = 0
|
||||
}
|
||||
// Use the same ssN heuristic as the C Freetype implementation.
|
||||
// The C implementation uses the values 32, 16, but those are in
|
||||
// 26.6 fixed point units, and we use 24.8 fixed point everywhere.
|
||||
ss2, ss3 := 128, 64
|
||||
if width > 24 || height > 24 {
|
||||
ss2, ss3 = 2*ss2, 2*ss3
|
||||
if width > 120 || height > 120 {
|
||||
ss2, ss3 = 2*ss2, 2*ss3
|
||||
}
|
||||
}
|
||||
r.width = width
|
||||
r.splitScale2 = ss2
|
||||
r.splitScale3 = ss3
|
||||
r.cell = r.cellBuf[:0]
|
||||
if height > len(r.cellIndexBuf) {
|
||||
r.cellIndex = make([]int, height)
|
||||
} else {
|
||||
r.cellIndex = r.cellIndexBuf[:height]
|
||||
}
|
||||
r.Clear()
|
||||
}
|
||||
|
||||
// NewRasterizer creates a new Rasterizer with the given bounds.
|
||||
func NewRasterizer(width, height int) *Rasterizer {
|
||||
r := new(Rasterizer)
|
||||
r.SetBounds(width, height)
|
||||
return r
|
||||
}
|
||||
466
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go
generated
vendored
466
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go
generated
vendored
@@ -1,466 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package raster
|
||||
|
||||
// Two points are considered practically equal if the square of the distance
|
||||
// between them is less than one quarter (i.e. 16384 / 65536 in Fix64).
|
||||
const epsilon = 16384
|
||||
|
||||
// A Capper signifies how to begin or end a stroked path.
|
||||
type Capper interface {
|
||||
// Cap adds a cap to p given a pivot point and the normal vector of a
|
||||
// terminal segment. The normal's length is half of the stroke width.
|
||||
Cap(p Adder, halfWidth Fix32, pivot, n1 Point)
|
||||
}
|
||||
|
||||
// The CapperFunc type adapts an ordinary function to be a Capper.
|
||||
type CapperFunc func(Adder, Fix32, Point, Point)
|
||||
|
||||
func (f CapperFunc) Cap(p Adder, halfWidth Fix32, pivot, n1 Point) {
|
||||
f(p, halfWidth, pivot, n1)
|
||||
}
|
||||
|
||||
// A Joiner signifies how to join interior nodes of a stroked path.
|
||||
type Joiner interface {
|
||||
// Join adds a join to the two sides of a stroked path given a pivot
|
||||
// point and the normal vectors of the trailing and leading segments.
|
||||
// Both normals have length equal to half of the stroke width.
|
||||
Join(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point)
|
||||
}
|
||||
|
||||
// The JoinerFunc type adapts an ordinary function to be a Joiner.
|
||||
type JoinerFunc func(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point)
|
||||
|
||||
func (f JoinerFunc) Join(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point) {
|
||||
f(lhs, rhs, halfWidth, pivot, n0, n1)
|
||||
}
|
||||
|
||||
// RoundCapper adds round caps to a stroked path.
|
||||
var RoundCapper Capper = CapperFunc(roundCapper)
|
||||
|
||||
func roundCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
|
||||
// The cubic Bézier approximation to a circle involves the magic number
|
||||
// (√2 - 1) * 4/3, which is approximately 141/256.
|
||||
const k = 141
|
||||
e := n1.Rot90CCW()
|
||||
side := pivot.Add(e)
|
||||
start, end := pivot.Sub(n1), pivot.Add(n1)
|
||||
d, e := n1.Mul(k), e.Mul(k)
|
||||
p.Add3(start.Add(e), side.Sub(d), side)
|
||||
p.Add3(side.Add(d), end.Add(e), end)
|
||||
}
|
||||
|
||||
// ButtCapper adds butt caps to a stroked path.
|
||||
var ButtCapper Capper = CapperFunc(buttCapper)
|
||||
|
||||
func buttCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
|
||||
p.Add1(pivot.Add(n1))
|
||||
}
|
||||
|
||||
// SquareCapper adds square caps to a stroked path.
|
||||
var SquareCapper Capper = CapperFunc(squareCapper)
|
||||
|
||||
func squareCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
|
||||
e := n1.Rot90CCW()
|
||||
side := pivot.Add(e)
|
||||
p.Add1(side.Sub(n1))
|
||||
p.Add1(side.Add(n1))
|
||||
p.Add1(pivot.Add(n1))
|
||||
}
|
||||
|
||||
// RoundJoiner adds round joins to a stroked path.
|
||||
var RoundJoiner Joiner = JoinerFunc(roundJoiner)
|
||||
|
||||
func roundJoiner(lhs, rhs Adder, haflWidth Fix32, pivot, n0, n1 Point) {
|
||||
dot := n0.Rot90CW().Dot(n1)
|
||||
if dot >= 0 {
|
||||
addArc(lhs, pivot, n0, n1)
|
||||
rhs.Add1(pivot.Sub(n1))
|
||||
} else {
|
||||
lhs.Add1(pivot.Add(n1))
|
||||
addArc(rhs, pivot, n0.Neg(), n1.Neg())
|
||||
}
|
||||
}
|
||||
|
||||
// BevelJoiner adds bevel joins to a stroked path.
|
||||
var BevelJoiner Joiner = JoinerFunc(bevelJoiner)
|
||||
|
||||
func bevelJoiner(lhs, rhs Adder, haflWidth Fix32, pivot, n0, n1 Point) {
|
||||
lhs.Add1(pivot.Add(n1))
|
||||
rhs.Add1(pivot.Sub(n1))
|
||||
}
|
||||
|
||||
// addArc adds a circular arc from pivot+n0 to pivot+n1 to p. The shorter of
|
||||
// the two possible arcs is taken, i.e. the one spanning <= 180 degrees.
|
||||
// The two vectors n0 and n1 must be of equal length.
|
||||
func addArc(p Adder, pivot, n0, n1 Point) {
|
||||
// r2 is the square of the length of n0.
|
||||
r2 := n0.Dot(n0)
|
||||
if r2 < epsilon {
|
||||
// The arc radius is so small that we collapse to a straight line.
|
||||
p.Add1(pivot.Add(n1))
|
||||
return
|
||||
}
|
||||
// We approximate the arc by 0, 1, 2 or 3 45-degree quadratic segments plus
|
||||
// a final quadratic segment from s to n1. Each 45-degree segment has control
|
||||
// points {1, 0}, {1, tan(π/8)} and {1/√2, 1/√2} suitably scaled, rotated and
|
||||
// translated. tan(π/8) is approximately 106/256.
|
||||
const tpo8 = 106
|
||||
var s Point
|
||||
// We determine which octant the angle between n0 and n1 is in via three dot products.
|
||||
// m0, m1 and m2 are n0 rotated clockwise by 45, 90 and 135 degrees.
|
||||
m0 := n0.Rot45CW()
|
||||
m1 := n0.Rot90CW()
|
||||
m2 := m0.Rot90CW()
|
||||
if m1.Dot(n1) >= 0 {
|
||||
if n0.Dot(n1) >= 0 {
|
||||
if m2.Dot(n1) <= 0 {
|
||||
// n1 is between 0 and 45 degrees clockwise of n0.
|
||||
s = n0
|
||||
} else {
|
||||
// n1 is between 45 and 90 degrees clockwise of n0.
|
||||
p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0))
|
||||
s = m0
|
||||
}
|
||||
} else {
|
||||
pm1, n0t := pivot.Add(m1), n0.Mul(tpo8)
|
||||
p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0))
|
||||
p.Add2(pm1.Add(n0t), pm1)
|
||||
if m0.Dot(n1) >= 0 {
|
||||
// n1 is between 90 and 135 degrees clockwise of n0.
|
||||
s = m1
|
||||
} else {
|
||||
// n1 is between 135 and 180 degrees clockwise of n0.
|
||||
p.Add2(pm1.Sub(n0t), pivot.Add(m2))
|
||||
s = m2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if n0.Dot(n1) >= 0 {
|
||||
if m0.Dot(n1) >= 0 {
|
||||
// n1 is between 0 and 45 degrees counter-clockwise of n0.
|
||||
s = n0
|
||||
} else {
|
||||
// n1 is between 45 and 90 degrees counter-clockwise of n0.
|
||||
p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2))
|
||||
s = m2.Neg()
|
||||
}
|
||||
} else {
|
||||
pm1, n0t := pivot.Sub(m1), n0.Mul(tpo8)
|
||||
p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2))
|
||||
p.Add2(pm1.Add(n0t), pm1)
|
||||
if m2.Dot(n1) <= 0 {
|
||||
// n1 is between 90 and 135 degrees counter-clockwise of n0.
|
||||
s = m1.Neg()
|
||||
} else {
|
||||
// n1 is between 135 and 180 degrees counter-clockwise of n0.
|
||||
p.Add2(pm1.Sub(n0t), pivot.Sub(m0))
|
||||
s = m0.Neg()
|
||||
}
|
||||
}
|
||||
}
|
||||
// The final quadratic segment has two endpoints s and n1 and the middle
|
||||
// control point is a multiple of s.Add(n1), i.e. it is on the angle bisector
|
||||
// of those two points. The multiple ranges between 128/256 and 150/256 as
|
||||
// the angle between s and n1 ranges between 0 and 45 degrees.
|
||||
// When the angle is 0 degrees (i.e. s and n1 are coincident) then s.Add(n1)
|
||||
// is twice s and so the middle control point of the degenerate quadratic
|
||||
// segment should be half s.Add(n1), and half = 128/256.
|
||||
// When the angle is 45 degrees then 150/256 is the ratio of the lengths of
|
||||
// the two vectors {1, tan(π/8)} and {1 + 1/√2, 1/√2}.
|
||||
// d is the normalized dot product between s and n1. Since the angle ranges
|
||||
// between 0 and 45 degrees then d ranges between 256/256 and 181/256.
|
||||
d := 256 * s.Dot(n1) / r2
|
||||
multiple := Fix32(150 - 22*(d-181)/(256-181))
|
||||
p.Add2(pivot.Add(s.Add(n1).Mul(multiple)), pivot.Add(n1))
|
||||
}
|
||||
|
||||
// midpoint returns the midpoint of two Points.
|
||||
func midpoint(a, b Point) Point {
|
||||
return Point{(a.X + b.X) / 2, (a.Y + b.Y) / 2}
|
||||
}
|
||||
|
||||
// angleGreaterThan45 returns whether the angle between two vectors is more
|
||||
// than 45 degrees.
|
||||
func angleGreaterThan45(v0, v1 Point) bool {
|
||||
v := v0.Rot45CCW()
|
||||
return v.Dot(v1) < 0 || v.Rot90CW().Dot(v1) < 0
|
||||
}
|
||||
|
||||
// interpolate returns the point (1-t)*a + t*b.
|
||||
func interpolate(a, b Point, t Fix64) Point {
|
||||
s := 65536 - t
|
||||
x := s*Fix64(a.X) + t*Fix64(b.X)
|
||||
y := s*Fix64(a.Y) + t*Fix64(b.Y)
|
||||
return Point{Fix32(x >> 16), Fix32(y >> 16)}
|
||||
}
|
||||
|
||||
// curviest2 returns the value of t for which the quadratic parametric curve
|
||||
// (1-t)²*a + 2*t*(1-t).b + t²*c has maximum curvature.
|
||||
//
|
||||
// The curvature of the parametric curve f(t) = (x(t), y(t)) is
|
||||
// |x′y″-y′x″| / (x′²+y′²)^(3/2).
|
||||
//
|
||||
// Let d = b-a and e = c-2*b+a, so that f′(t) = 2*d+2*e*t and f″(t) = 2*e.
|
||||
// The curvature's numerator is (2*dx+2*ex*t)*(2*ey)-(2*dy+2*ey*t)*(2*ex),
|
||||
// which simplifies to 4*dx*ey-4*dy*ex, which is constant with respect to t.
|
||||
//
|
||||
// Thus, curvature is extreme where the denominator is extreme, i.e. where
|
||||
// (x′²+y′²) is extreme. The first order condition is that
|
||||
// 2*x′*x″+2*y′*y″ = 0, or (dx+ex*t)*ex + (dy+ey*t)*ey = 0.
|
||||
// Solving for t gives t = -(dx*ex+dy*ey) / (ex*ex+ey*ey).
|
||||
func curviest2(a, b, c Point) Fix64 {
|
||||
dx := int64(b.X - a.X)
|
||||
dy := int64(b.Y - a.Y)
|
||||
ex := int64(c.X - 2*b.X + a.X)
|
||||
ey := int64(c.Y - 2*b.Y + a.Y)
|
||||
if ex == 0 && ey == 0 {
|
||||
return 32768
|
||||
}
|
||||
return Fix64(-65536 * (dx*ex + dy*ey) / (ex*ex + ey*ey))
|
||||
}
|
||||
|
||||
// A stroker holds state for stroking a path.
|
||||
type stroker struct {
|
||||
// p is the destination that records the stroked path.
|
||||
p Adder
|
||||
// u is the half-width of the stroke.
|
||||
u Fix32
|
||||
// cr and jr specify how to end and connect path segments.
|
||||
cr Capper
|
||||
jr Joiner
|
||||
// r is the reverse path. Stroking a path involves constructing two
|
||||
// parallel paths 2*u apart. The first path is added immediately to p,
|
||||
// the second path is accumulated in r and eventually added in reverse.
|
||||
r Path
|
||||
// a is the most recent segment point. anorm is the segment normal of
|
||||
// length u at that point.
|
||||
a, anorm Point
|
||||
}
|
||||
|
||||
// addNonCurvy2 adds a quadratic segment to the stroker, where the segment
|
||||
// defined by (k.a, b, c) achieves maximum curvature at either k.a or c.
|
||||
func (k *stroker) addNonCurvy2(b, c Point) {
|
||||
// We repeatedly divide the segment at its middle until it is straight
|
||||
// enough to approximate the stroke by just translating the control points.
|
||||
// ds and ps are stacks of depths and points. t is the top of the stack.
|
||||
const maxDepth = 5
|
||||
var (
|
||||
ds [maxDepth + 1]int
|
||||
ps [2*maxDepth + 3]Point
|
||||
t int
|
||||
)
|
||||
// Initially the ps stack has one quadratic segment of depth zero.
|
||||
ds[0] = 0
|
||||
ps[2] = k.a
|
||||
ps[1] = b
|
||||
ps[0] = c
|
||||
anorm := k.anorm
|
||||
var cnorm Point
|
||||
|
||||
for {
|
||||
depth := ds[t]
|
||||
a := ps[2*t+2]
|
||||
b := ps[2*t+1]
|
||||
c := ps[2*t+0]
|
||||
ab := b.Sub(a)
|
||||
bc := c.Sub(b)
|
||||
abIsSmall := ab.Dot(ab) < Fix64(1<<16)
|
||||
bcIsSmall := bc.Dot(bc) < Fix64(1<<16)
|
||||
if abIsSmall && bcIsSmall {
|
||||
// Approximate the segment by a circular arc.
|
||||
cnorm = bc.Norm(k.u).Rot90CCW()
|
||||
mac := midpoint(a, c)
|
||||
addArc(k.p, mac, anorm, cnorm)
|
||||
addArc(&k.r, mac, anorm.Neg(), cnorm.Neg())
|
||||
} else if depth < maxDepth && angleGreaterThan45(ab, bc) {
|
||||
// Divide the segment in two and push both halves on the stack.
|
||||
mab := midpoint(a, b)
|
||||
mbc := midpoint(b, c)
|
||||
t++
|
||||
ds[t+0] = depth + 1
|
||||
ds[t-1] = depth + 1
|
||||
ps[2*t+2] = a
|
||||
ps[2*t+1] = mab
|
||||
ps[2*t+0] = midpoint(mab, mbc)
|
||||
ps[2*t-1] = mbc
|
||||
continue
|
||||
} else {
|
||||
// Translate the control points.
|
||||
bnorm := c.Sub(a).Norm(k.u).Rot90CCW()
|
||||
cnorm = bc.Norm(k.u).Rot90CCW()
|
||||
k.p.Add2(b.Add(bnorm), c.Add(cnorm))
|
||||
k.r.Add2(b.Sub(bnorm), c.Sub(cnorm))
|
||||
}
|
||||
if t == 0 {
|
||||
k.a, k.anorm = c, cnorm
|
||||
return
|
||||
}
|
||||
t--
|
||||
anorm = cnorm
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Add1 adds a linear segment to the stroker.
|
||||
func (k *stroker) Add1(b Point) {
|
||||
bnorm := b.Sub(k.a).Norm(k.u).Rot90CCW()
|
||||
if len(k.r) == 0 {
|
||||
k.p.Start(k.a.Add(bnorm))
|
||||
k.r.Start(k.a.Sub(bnorm))
|
||||
} else {
|
||||
k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, bnorm)
|
||||
}
|
||||
k.p.Add1(b.Add(bnorm))
|
||||
k.r.Add1(b.Sub(bnorm))
|
||||
k.a, k.anorm = b, bnorm
|
||||
}
|
||||
|
||||
// Add2 adds a quadratic segment to the stroker.
|
||||
func (k *stroker) Add2(b, c Point) {
|
||||
ab := b.Sub(k.a)
|
||||
bc := c.Sub(b)
|
||||
abnorm := ab.Norm(k.u).Rot90CCW()
|
||||
if len(k.r) == 0 {
|
||||
k.p.Start(k.a.Add(abnorm))
|
||||
k.r.Start(k.a.Sub(abnorm))
|
||||
} else {
|
||||
k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, abnorm)
|
||||
}
|
||||
|
||||
// Approximate nearly-degenerate quadratics by linear segments.
|
||||
abIsSmall := ab.Dot(ab) < epsilon
|
||||
bcIsSmall := bc.Dot(bc) < epsilon
|
||||
if abIsSmall || bcIsSmall {
|
||||
acnorm := c.Sub(k.a).Norm(k.u).Rot90CCW()
|
||||
k.p.Add1(c.Add(acnorm))
|
||||
k.r.Add1(c.Sub(acnorm))
|
||||
k.a, k.anorm = c, acnorm
|
||||
return
|
||||
}
|
||||
|
||||
// The quadratic segment (k.a, b, c) has a point of maximum curvature.
|
||||
// If this occurs at an end point, we process the segment as a whole.
|
||||
t := curviest2(k.a, b, c)
|
||||
if t <= 0 || t >= 65536 {
|
||||
k.addNonCurvy2(b, c)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we perform a de Casteljau decomposition at the point of
|
||||
// maximum curvature and process the two straighter parts.
|
||||
mab := interpolate(k.a, b, t)
|
||||
mbc := interpolate(b, c, t)
|
||||
mabc := interpolate(mab, mbc, t)
|
||||
|
||||
// If the vectors ab and bc are close to being in opposite directions,
|
||||
// then the decomposition can become unstable, so we approximate the
|
||||
// quadratic segment by two linear segments joined by an arc.
|
||||
bcnorm := bc.Norm(k.u).Rot90CCW()
|
||||
if abnorm.Dot(bcnorm) < -Fix64(k.u)*Fix64(k.u)*2047/2048 {
|
||||
pArc := abnorm.Dot(bc) < 0
|
||||
|
||||
k.p.Add1(mabc.Add(abnorm))
|
||||
if pArc {
|
||||
z := abnorm.Rot90CW()
|
||||
addArc(k.p, mabc, abnorm, z)
|
||||
addArc(k.p, mabc, z, bcnorm)
|
||||
}
|
||||
k.p.Add1(mabc.Add(bcnorm))
|
||||
k.p.Add1(c.Add(bcnorm))
|
||||
|
||||
k.r.Add1(mabc.Sub(abnorm))
|
||||
if !pArc {
|
||||
z := abnorm.Rot90CW()
|
||||
addArc(&k.r, mabc, abnorm.Neg(), z)
|
||||
addArc(&k.r, mabc, z, bcnorm.Neg())
|
||||
}
|
||||
k.r.Add1(mabc.Sub(bcnorm))
|
||||
k.r.Add1(c.Sub(bcnorm))
|
||||
|
||||
k.a, k.anorm = c, bcnorm
|
||||
return
|
||||
}
|
||||
|
||||
// Process the decomposed parts.
|
||||
k.addNonCurvy2(mab, mabc)
|
||||
k.addNonCurvy2(mbc, c)
|
||||
}
|
||||
|
||||
// Add3 adds a cubic segment to the stroker.
|
||||
func (k *stroker) Add3(b, c, d Point) {
|
||||
panic("freetype/raster: stroke unimplemented for cubic segments")
|
||||
}
|
||||
|
||||
// stroke adds the stroked Path q to p, where q consists of exactly one curve.
|
||||
func (k *stroker) stroke(q Path) {
|
||||
// Stroking is implemented by deriving two paths each k.u apart from q.
|
||||
// The left-hand-side path is added immediately to k.p; the right-hand-side
|
||||
// path is accumulated in k.r. Once we've finished adding the LHS to k.p,
|
||||
// we add the RHS in reverse order.
|
||||
k.r = make(Path, 0, len(q))
|
||||
k.a = Point{q[1], q[2]}
|
||||
for i := 4; i < len(q); {
|
||||
switch q[i] {
|
||||
case 1:
|
||||
k.Add1(Point{q[i+1], q[i+2]})
|
||||
i += 4
|
||||
case 2:
|
||||
k.Add2(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]})
|
||||
i += 6
|
||||
case 3:
|
||||
k.Add3(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]}, Point{q[i+5], q[i+6]})
|
||||
i += 8
|
||||
default:
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
}
|
||||
if len(k.r) == 0 {
|
||||
return
|
||||
}
|
||||
// TODO(nigeltao): if q is a closed curve then we should join the first and
|
||||
// last segments instead of capping them.
|
||||
k.cr.Cap(k.p, k.u, q.lastPoint(), k.anorm.Neg())
|
||||
addPathReversed(k.p, k.r)
|
||||
pivot := q.firstPoint()
|
||||
k.cr.Cap(k.p, k.u, pivot, pivot.Sub(Point{k.r[1], k.r[2]}))
|
||||
}
|
||||
|
||||
// Stroke adds q stroked with the given width to p. The result is typically
|
||||
// self-intersecting and should be rasterized with UseNonZeroWinding.
|
||||
// cr and jr may be nil, which defaults to a RoundCapper or RoundJoiner.
|
||||
func Stroke(p Adder, q Path, width Fix32, cr Capper, jr Joiner) {
|
||||
if len(q) == 0 {
|
||||
return
|
||||
}
|
||||
if cr == nil {
|
||||
cr = RoundCapper
|
||||
}
|
||||
if jr == nil {
|
||||
jr = RoundJoiner
|
||||
}
|
||||
if q[0] != 0 {
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
s := stroker{p: p, u: width / 2, cr: cr, jr: jr}
|
||||
i := 0
|
||||
for j := 4; j < len(q); {
|
||||
switch q[j] {
|
||||
case 0:
|
||||
s.stroke(q[i:j])
|
||||
i, j = j, j+4
|
||||
case 1:
|
||||
j += 4
|
||||
case 2:
|
||||
j += 6
|
||||
case 3:
|
||||
j += 8
|
||||
default:
|
||||
panic("freetype/raster: bad path")
|
||||
}
|
||||
}
|
||||
s.stroke(q[i:])
|
||||
}
|
||||
530
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go
generated
vendored
530
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go
generated
vendored
@@ -1,530 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package truetype
|
||||
|
||||
// Hinting is the policy for snapping a glyph's contours to pixel boundaries.
|
||||
type Hinting int32
|
||||
|
||||
const (
|
||||
// NoHinting means to not perform any hinting.
|
||||
NoHinting Hinting = iota
|
||||
// FullHinting means to use the font's hinting instructions.
|
||||
FullHinting
|
||||
|
||||
// TODO: implement VerticalHinting.
|
||||
)
|
||||
|
||||
// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
|
||||
// ``off'' control point.
|
||||
type Point struct {
|
||||
X, Y int32
|
||||
// The Flags' LSB means whether or not this Point is ``on'' the contour.
|
||||
// Other bits are reserved for internal use.
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a
|
||||
// series of glyphs from a Font.
|
||||
type GlyphBuf struct {
|
||||
// AdvanceWidth is the glyph's advance width.
|
||||
AdvanceWidth int32
|
||||
// B is the glyph's bounding box.
|
||||
B Bounds
|
||||
// Point contains all Points from all contours of the glyph. If
|
||||
// hinting was used to load a glyph then Unhinted contains those
|
||||
// Points before they were hinted, and InFontUnits contains those
|
||||
// Points before they were hinted and scaled.
|
||||
Point, Unhinted, InFontUnits []Point
|
||||
// End is the point indexes of the end point of each countour. The
|
||||
// length of End is the number of contours in the glyph. The i'th
|
||||
// contour consists of points Point[End[i-1]:End[i]], where End[-1]
|
||||
// is interpreted to mean zero.
|
||||
End []int
|
||||
|
||||
font *Font
|
||||
scale int32
|
||||
hinting Hinting
|
||||
hinter hinter
|
||||
// phantomPoints are the co-ordinates of the synthetic phantom points
|
||||
// used for hinting and bounding box calculations.
|
||||
phantomPoints [4]Point
|
||||
// pp1x is the X co-ordinate of the first phantom point. The '1' is
|
||||
// using 1-based indexing; pp1x is almost always phantomPoints[0].X.
|
||||
// TODO: eliminate this and consistently use phantomPoints[0].X.
|
||||
pp1x int32
|
||||
// metricsSet is whether the glyph's metrics have been set yet. For a
|
||||
// compound glyph, a sub-glyph may override the outer glyph's metrics.
|
||||
metricsSet bool
|
||||
// tmp is a scratch buffer.
|
||||
tmp []Point
|
||||
}
|
||||
|
||||
// Flags for decoding a glyph's contours. These flags are documented at
|
||||
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
|
||||
const (
|
||||
flagOnCurve = 1 << iota
|
||||
flagXShortVector
|
||||
flagYShortVector
|
||||
flagRepeat
|
||||
flagPositiveXShortVector
|
||||
flagPositiveYShortVector
|
||||
|
||||
// The remaining flags are for internal use.
|
||||
flagTouchedX
|
||||
flagTouchedY
|
||||
)
|
||||
|
||||
// The same flag bits (0x10 and 0x20) are overloaded to have two meanings,
|
||||
// dependent on the value of the flag{X,Y}ShortVector bits.
|
||||
const (
|
||||
flagThisXIsSame = flagPositiveXShortVector
|
||||
flagThisYIsSame = flagPositiveYShortVector
|
||||
)
|
||||
|
||||
// Load loads a glyph's contours from a Font, overwriting any previously
|
||||
// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point
|
||||
// units in 1 em, i is the glyph index, and h is the hinting policy.
|
||||
func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
|
||||
g.Point = g.Point[:0]
|
||||
g.Unhinted = g.Unhinted[:0]
|
||||
g.InFontUnits = g.InFontUnits[:0]
|
||||
g.End = g.End[:0]
|
||||
g.font = f
|
||||
g.hinting = h
|
||||
g.scale = scale
|
||||
g.pp1x = 0
|
||||
g.phantomPoints = [4]Point{}
|
||||
g.metricsSet = false
|
||||
|
||||
if h != NoHinting {
|
||||
if err := g.hinter.init(f, scale); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := g.load(0, i, true); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: this selection of either g.pp1x or g.phantomPoints[0].X isn't ideal,
|
||||
// and should be cleaned up once we have all the testScaling tests passing,
|
||||
// plus additional tests for Freetype-Go's bounding boxes matching C Freetype's.
|
||||
pp1x := g.pp1x
|
||||
if h != NoHinting {
|
||||
pp1x = g.phantomPoints[0].X
|
||||
}
|
||||
if pp1x != 0 {
|
||||
for i := range g.Point {
|
||||
g.Point[i].X -= pp1x
|
||||
}
|
||||
}
|
||||
|
||||
advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X
|
||||
if h != NoHinting {
|
||||
if len(f.hdmx) >= 8 {
|
||||
if n := u32(f.hdmx, 4); n > 3+uint32(i) {
|
||||
for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] {
|
||||
if int32(hdmx[0]) == scale>>6 {
|
||||
advanceWidth = int32(hdmx[2+i]) << 6
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
advanceWidth = (advanceWidth + 32) &^ 63
|
||||
}
|
||||
g.AdvanceWidth = advanceWidth
|
||||
|
||||
// Set g.B to the 'control box', which is the bounding box of the Bézier
|
||||
// curves' control points. This is easier to calculate, no smaller than
|
||||
// and often equal to the tightest possible bounding box of the curves
|
||||
// themselves. This approach is what C Freetype does. We can't just scale
|
||||
// the nominal bounding box in the glyf data as the hinting process and
|
||||
// phantom point adjustment may move points outside of that box.
|
||||
if len(g.Point) == 0 {
|
||||
g.B = Bounds{}
|
||||
} else {
|
||||
p := g.Point[0]
|
||||
g.B.XMin = p.X
|
||||
g.B.XMax = p.X
|
||||
g.B.YMin = p.Y
|
||||
g.B.YMax = p.Y
|
||||
for _, p := range g.Point[1:] {
|
||||
if g.B.XMin > p.X {
|
||||
g.B.XMin = p.X
|
||||
} else if g.B.XMax < p.X {
|
||||
g.B.XMax = p.X
|
||||
}
|
||||
if g.B.YMin > p.Y {
|
||||
g.B.YMin = p.Y
|
||||
} else if g.B.YMax < p.Y {
|
||||
g.B.YMax = p.Y
|
||||
}
|
||||
}
|
||||
// Snap the box to the grid, if hinting is on.
|
||||
if h != NoHinting {
|
||||
g.B.XMin &^= 63
|
||||
g.B.YMin &^= 63
|
||||
g.B.XMax += 63
|
||||
g.B.XMax &^= 63
|
||||
g.B.YMax += 63
|
||||
g.B.YMax &^= 63
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) {
|
||||
// The recursion limit here is arbitrary, but defends against malformed glyphs.
|
||||
if recursion >= 32 {
|
||||
return UnsupportedError("excessive compound glyph recursion")
|
||||
}
|
||||
// Find the relevant slice of g.font.glyf.
|
||||
var g0, g1 uint32
|
||||
if g.font.locaOffsetFormat == locaOffsetFormatShort {
|
||||
g0 = 2 * uint32(u16(g.font.loca, 2*int(i)))
|
||||
g1 = 2 * uint32(u16(g.font.loca, 2*int(i)+2))
|
||||
} else {
|
||||
g0 = u32(g.font.loca, 4*int(i))
|
||||
g1 = u32(g.font.loca, 4*int(i)+4)
|
||||
}
|
||||
|
||||
// Decode the contour count and nominal bounding box, from the first
|
||||
// 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4
|
||||
// and 6, are unused.
|
||||
glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, int32(0), int32(0)
|
||||
if g0+10 <= g1 {
|
||||
glyf = g.font.glyf[g0:g1]
|
||||
ne = int(int16(u16(glyf, 0)))
|
||||
boundsXMin = int32(int16(u16(glyf, 2)))
|
||||
boundsYMax = int32(int16(u16(glyf, 8)))
|
||||
}
|
||||
|
||||
// Create the phantom points.
|
||||
uhm, pp1x := g.font.unscaledHMetric(i), int32(0)
|
||||
uvm := g.font.unscaledVMetric(i, boundsYMax)
|
||||
g.phantomPoints = [4]Point{
|
||||
{X: boundsXMin - uhm.LeftSideBearing},
|
||||
{X: boundsXMin - uhm.LeftSideBearing + uhm.AdvanceWidth},
|
||||
{X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing},
|
||||
{X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing - uvm.AdvanceHeight},
|
||||
}
|
||||
if len(glyf) == 0 {
|
||||
g.addPhantomsAndScale(len(g.Point), len(g.Point), true, true)
|
||||
copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
|
||||
g.Point = g.Point[:len(g.Point)-4]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load and hint the contours.
|
||||
if ne < 0 {
|
||||
if ne != -1 {
|
||||
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that
|
||||
// "the values -2, -3, and so forth, are reserved for future use."
|
||||
return UnsupportedError("negative number of contours")
|
||||
}
|
||||
pp1x = g.font.scale(g.scale * (boundsXMin - uhm.LeftSideBearing))
|
||||
if err := g.loadCompound(recursion, uhm, i, glyf, useMyMetrics); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
np0, ne0 := len(g.Point), len(g.End)
|
||||
program := g.loadSimple(glyf, ne)
|
||||
g.addPhantomsAndScale(np0, np0, true, true)
|
||||
pp1x = g.Point[len(g.Point)-4].X
|
||||
if g.hinting != NoHinting {
|
||||
if len(program) != 0 {
|
||||
err := g.hinter.run(
|
||||
program,
|
||||
g.Point[np0:],
|
||||
g.Unhinted[np0:],
|
||||
g.InFontUnits[np0:],
|
||||
g.End[ne0:],
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Drop the four phantom points.
|
||||
g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4]
|
||||
g.Unhinted = g.Unhinted[:len(g.Unhinted)-4]
|
||||
}
|
||||
if useMyMetrics {
|
||||
copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
|
||||
}
|
||||
g.Point = g.Point[:len(g.Point)-4]
|
||||
if np0 != 0 {
|
||||
// The hinting program expects the []End values to be indexed relative
|
||||
// to the inner glyph, not the outer glyph, so we delay adding np0 until
|
||||
// after the hinting program (if any) has run.
|
||||
for i := ne0; i < len(g.End); i++ {
|
||||
g.End[i] += np0
|
||||
}
|
||||
}
|
||||
}
|
||||
if useMyMetrics && !g.metricsSet {
|
||||
g.metricsSet = true
|
||||
g.pp1x = pp1x
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadOffset is the initial offset for loadSimple and loadCompound. The first
|
||||
// 10 bytes are the number of contours and the bounding box.
|
||||
const loadOffset = 10
|
||||
|
||||
func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
|
||||
offset := loadOffset
|
||||
for i := 0; i < ne; i++ {
|
||||
g.End = append(g.End, 1+int(u16(glyf, offset)))
|
||||
offset += 2
|
||||
}
|
||||
|
||||
// Note the TrueType hinting instructions.
|
||||
instrLen := int(u16(glyf, offset))
|
||||
offset += 2
|
||||
program = glyf[offset : offset+instrLen]
|
||||
offset += instrLen
|
||||
|
||||
np0 := len(g.Point)
|
||||
np1 := np0 + int(g.End[len(g.End)-1])
|
||||
|
||||
// Decode the flags.
|
||||
for i := np0; i < np1; {
|
||||
c := uint32(glyf[offset])
|
||||
offset++
|
||||
g.Point = append(g.Point, Point{Flags: c})
|
||||
i++
|
||||
if c&flagRepeat != 0 {
|
||||
count := glyf[offset]
|
||||
offset++
|
||||
for ; count > 0; count-- {
|
||||
g.Point = append(g.Point, Point{Flags: c})
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the co-ordinates.
|
||||
var x int16
|
||||
for i := np0; i < np1; i++ {
|
||||
f := g.Point[i].Flags
|
||||
if f&flagXShortVector != 0 {
|
||||
dx := int16(glyf[offset])
|
||||
offset++
|
||||
if f&flagPositiveXShortVector == 0 {
|
||||
x -= dx
|
||||
} else {
|
||||
x += dx
|
||||
}
|
||||
} else if f&flagThisXIsSame == 0 {
|
||||
x += int16(u16(glyf, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].X = int32(x)
|
||||
}
|
||||
var y int16
|
||||
for i := np0; i < np1; i++ {
|
||||
f := g.Point[i].Flags
|
||||
if f&flagYShortVector != 0 {
|
||||
dy := int16(glyf[offset])
|
||||
offset++
|
||||
if f&flagPositiveYShortVector == 0 {
|
||||
y -= dy
|
||||
} else {
|
||||
y += dy
|
||||
}
|
||||
} else if f&flagThisYIsSame == 0 {
|
||||
y += int16(u16(glyf, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].Y = int32(y)
|
||||
}
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
|
||||
glyf []byte, useMyMetrics bool) error {
|
||||
|
||||
// Flags for decoding a compound glyph. These flags are documented at
|
||||
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
|
||||
const (
|
||||
flagArg1And2AreWords = 1 << iota
|
||||
flagArgsAreXYValues
|
||||
flagRoundXYToGrid
|
||||
flagWeHaveAScale
|
||||
flagUnused
|
||||
flagMoreComponents
|
||||
flagWeHaveAnXAndYScale
|
||||
flagWeHaveATwoByTwo
|
||||
flagWeHaveInstructions
|
||||
flagUseMyMetrics
|
||||
flagOverlapCompound
|
||||
)
|
||||
np0, ne0 := len(g.Point), len(g.End)
|
||||
offset := loadOffset
|
||||
for {
|
||||
flags := u16(glyf, offset)
|
||||
component := Index(u16(glyf, offset+2))
|
||||
dx, dy, transform, hasTransform := int32(0), int32(0), [4]int32{}, false
|
||||
if flags&flagArg1And2AreWords != 0 {
|
||||
dx = int32(int16(u16(glyf, offset+4)))
|
||||
dy = int32(int16(u16(glyf, offset+6)))
|
||||
offset += 8
|
||||
} else {
|
||||
dx = int32(int16(int8(glyf[offset+4])))
|
||||
dy = int32(int16(int8(glyf[offset+5])))
|
||||
offset += 6
|
||||
}
|
||||
if flags&flagArgsAreXYValues == 0 {
|
||||
return UnsupportedError("compound glyph transform vector")
|
||||
}
|
||||
if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 {
|
||||
hasTransform = true
|
||||
switch {
|
||||
case flags&flagWeHaveAScale != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[3] = transform[0]
|
||||
offset += 2
|
||||
case flags&flagWeHaveAnXAndYScale != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[3] = int32(int16(u16(glyf, offset+2)))
|
||||
offset += 4
|
||||
case flags&flagWeHaveATwoByTwo != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[1] = int32(int16(u16(glyf, offset+2)))
|
||||
transform[2] = int32(int16(u16(glyf, offset+4)))
|
||||
transform[3] = int32(int16(u16(glyf, offset+6)))
|
||||
offset += 8
|
||||
}
|
||||
}
|
||||
savedPP := g.phantomPoints
|
||||
np0 := len(g.Point)
|
||||
componentUMM := useMyMetrics && (flags&flagUseMyMetrics != 0)
|
||||
if err := g.load(recursion+1, component, componentUMM); err != nil {
|
||||
return err
|
||||
}
|
||||
if flags&flagUseMyMetrics == 0 {
|
||||
g.phantomPoints = savedPP
|
||||
}
|
||||
if hasTransform {
|
||||
for j := np0; j < len(g.Point); j++ {
|
||||
p := &g.Point[j]
|
||||
newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) +
|
||||
int32((int64(p.Y)*int64(transform[2])+1<<13)>>14)
|
||||
newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) +
|
||||
int32((int64(p.Y)*int64(transform[3])+1<<13)>>14)
|
||||
p.X, p.Y = newX, newY
|
||||
}
|
||||
}
|
||||
dx = g.font.scale(g.scale * dx)
|
||||
dy = g.font.scale(g.scale * dy)
|
||||
if flags&flagRoundXYToGrid != 0 {
|
||||
dx = (dx + 32) &^ 63
|
||||
dy = (dy + 32) &^ 63
|
||||
}
|
||||
for j := np0; j < len(g.Point); j++ {
|
||||
p := &g.Point[j]
|
||||
p.X += dx
|
||||
p.Y += dy
|
||||
}
|
||||
// TODO: also adjust g.InFontUnits and g.Unhinted?
|
||||
if flags&flagMoreComponents == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
instrLen := 0
|
||||
if g.hinting != NoHinting && offset+2 <= len(glyf) {
|
||||
instrLen = int(u16(glyf, offset))
|
||||
offset += 2
|
||||
}
|
||||
|
||||
g.addPhantomsAndScale(np0, len(g.Point), false, instrLen > 0)
|
||||
points, ends := g.Point[np0:], g.End[ne0:]
|
||||
g.Point = g.Point[:len(g.Point)-4]
|
||||
for j := range points {
|
||||
points[j].Flags &^= flagTouchedX | flagTouchedY
|
||||
}
|
||||
|
||||
if instrLen == 0 {
|
||||
if !g.metricsSet {
|
||||
copy(g.phantomPoints[:], points[len(points)-4:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hint the compound glyph.
|
||||
program := glyf[offset : offset+instrLen]
|
||||
// Temporarily adjust the ends to be relative to this compound glyph.
|
||||
if np0 != 0 {
|
||||
for i := range ends {
|
||||
ends[i] -= np0
|
||||
}
|
||||
}
|
||||
// Hinting instructions of a composite glyph completely refer to the
|
||||
// (already) hinted subglyphs.
|
||||
g.tmp = append(g.tmp[:0], points...)
|
||||
if err := g.hinter.run(program, points, g.tmp, g.tmp, ends); err != nil {
|
||||
return err
|
||||
}
|
||||
if np0 != 0 {
|
||||
for i := range ends {
|
||||
ends[i] += np0
|
||||
}
|
||||
}
|
||||
if !g.metricsSet {
|
||||
copy(g.phantomPoints[:], points[len(points)-4:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GlyphBuf) addPhantomsAndScale(np0, np1 int, simple, adjust bool) {
|
||||
// Add the four phantom points.
|
||||
g.Point = append(g.Point, g.phantomPoints[:]...)
|
||||
// Scale the points.
|
||||
if simple && g.hinting != NoHinting {
|
||||
g.InFontUnits = append(g.InFontUnits, g.Point[np1:]...)
|
||||
}
|
||||
for i := np1; i < len(g.Point); i++ {
|
||||
p := &g.Point[i]
|
||||
p.X = g.font.scale(g.scale * p.X)
|
||||
p.Y = g.font.scale(g.scale * p.Y)
|
||||
}
|
||||
if g.hinting == NoHinting {
|
||||
return
|
||||
}
|
||||
// Round the 1st phantom point to the grid, shifting all other points equally.
|
||||
// Note that "all other points" starts from np0, not np1.
|
||||
// TODO: delete this adjustment and the np0/np1 distinction, when
|
||||
// we update the compatibility tests to C Freetype 2.5.3.
|
||||
// See http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=05c786d990390a7ca18e62962641dac740bacb06
|
||||
if adjust {
|
||||
pp1x := g.Point[len(g.Point)-4].X
|
||||
if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 {
|
||||
for i := np0; i < len(g.Point); i++ {
|
||||
g.Point[i].X += dx
|
||||
}
|
||||
}
|
||||
}
|
||||
if simple {
|
||||
g.Unhinted = append(g.Unhinted, g.Point[np1:]...)
|
||||
}
|
||||
// Round the 2nd and 4th phantom point to the grid.
|
||||
p := &g.Point[len(g.Point)-3]
|
||||
p.X = (p.X + 32) &^ 63
|
||||
p = &g.Point[len(g.Point)-1]
|
||||
p.Y = (p.Y + 32) &^ 63
|
||||
}
|
||||
|
||||
// TODO: is this necessary? The zero-valued GlyphBuf is perfectly usable.
|
||||
|
||||
// NewGlyphBuf returns a newly allocated GlyphBuf.
|
||||
func NewGlyphBuf() *GlyphBuf {
|
||||
return &GlyphBuf{
|
||||
Point: make([]Point, 0, 256),
|
||||
End: make([]int, 0, 32),
|
||||
}
|
||||
}
|
||||
1764
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go
generated
vendored
1764
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go
generated
vendored
File diff suppressed because it is too large
Load Diff
673
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go
generated
vendored
673
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go
generated
vendored
@@ -1,673 +0,0 @@
|
||||
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package truetype
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBytecode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
prog []byte
|
||||
want []int32
|
||||
errStr string
|
||||
}{
|
||||
{
|
||||
"underflow",
|
||||
[]byte{
|
||||
opDUP,
|
||||
},
|
||||
nil,
|
||||
"underflow",
|
||||
},
|
||||
{
|
||||
"infinite loop",
|
||||
[]byte{
|
||||
opPUSHW000, // [-1]
|
||||
0xff,
|
||||
0xff,
|
||||
opDUP, // [-1, -1]
|
||||
opJMPR, // [-1]
|
||||
},
|
||||
nil,
|
||||
"too many steps",
|
||||
},
|
||||
{
|
||||
"unbalanced if/else",
|
||||
[]byte{
|
||||
opPUSHB000, // [0]
|
||||
0,
|
||||
opIF,
|
||||
},
|
||||
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{
|
||||
opPUSHB001, // [10, 2]
|
||||
10,
|
||||
2,
|
||||
opJMPR, // [10]
|
||||
opDUP, // not executed
|
||||
opDUP, // [10, 10]
|
||||
opPUSHB010, // [10, 10, 20, 2, 1]
|
||||
20,
|
||||
2,
|
||||
1,
|
||||
opJROT, // [10, 10, 20]
|
||||
opDUP, // not executed
|
||||
opDUP, // [10, 10, 20, 20]
|
||||
opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
|
||||
30,
|
||||
2,
|
||||
1,
|
||||
opJROF, // [10, 10, 20, 20, 30]
|
||||
opDUP, // [10, 10, 20, 20, 30, 30]
|
||||
opDUP, // [10, 10, 20, 20, 30, 30, 30]
|
||||
},
|
||||
[]int32{10, 10, 20, 20, 30, 30, 30},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"stack ops",
|
||||
[]byte{
|
||||
opPUSHB010, // [10, 20, 30]
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
opCLEAR, // []
|
||||
opPUSHB010, // [40, 50, 60]
|
||||
40,
|
||||
50,
|
||||
60,
|
||||
opSWAP, // [40, 60, 50]
|
||||
opDUP, // [40, 60, 50, 50]
|
||||
opDUP, // [40, 60, 50, 50, 50]
|
||||
opPOP, // [40, 60, 50, 50]
|
||||
opDEPTH, // [40, 60, 50, 50, 4]
|
||||
opCINDEX, // [40, 60, 50, 50, 40]
|
||||
opPUSHB000, // [40, 60, 50, 50, 40, 4]
|
||||
4,
|
||||
opMINDEX, // [40, 50, 50, 40, 60]
|
||||
},
|
||||
[]int32{40, 50, 50, 40, 60},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"push ops",
|
||||
[]byte{
|
||||
opPUSHB000, // [255]
|
||||
255,
|
||||
opPUSHW001, // [255, -2, 253]
|
||||
255,
|
||||
254,
|
||||
0,
|
||||
253,
|
||||
opNPUSHB, // [1, -2, 253, 1, 2]
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
opNPUSHW, // [1, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809]
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
},
|
||||
[]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{
|
||||
opPUSHB001, // [10, 20]
|
||||
10,
|
||||
20,
|
||||
opLT, // [1]
|
||||
opPUSHB001, // [1, 10, 20]
|
||||
10,
|
||||
20,
|
||||
opLTEQ, // [1, 1]
|
||||
opPUSHB001, // [1, 1, 10, 20]
|
||||
10,
|
||||
20,
|
||||
opGT, // [1, 1, 0]
|
||||
opPUSHB001, // [1, 1, 0, 10, 20]
|
||||
10,
|
||||
20,
|
||||
opGTEQ, // [1, 1, 0, 0]
|
||||
opEQ, // [1, 1, 1]
|
||||
opNEQ, // [1, 0]
|
||||
},
|
||||
[]int32{1, 0},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"odd/even",
|
||||
// Calculate odd(2+31/64), odd(2+32/64), even(2), even(1).
|
||||
[]byte{
|
||||
opPUSHB000, // [159]
|
||||
159,
|
||||
opODD, // [0]
|
||||
opPUSHB000, // [0, 160]
|
||||
160,
|
||||
opODD, // [0, 1]
|
||||
opPUSHB000, // [0, 1, 128]
|
||||
128,
|
||||
opEVEN, // [0, 1, 1]
|
||||
opPUSHB000, // [0, 1, 1, 64]
|
||||
64,
|
||||
opEVEN, // [0, 1, 1, 0]
|
||||
},
|
||||
[]int32{0, 1, 1, 0},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if true",
|
||||
[]byte{
|
||||
opPUSHB001, // [255, 1]
|
||||
255,
|
||||
1,
|
||||
opIF,
|
||||
opPUSHB000, // [255, 2]
|
||||
2,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 2, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 2, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if false",
|
||||
[]byte{
|
||||
opPUSHB001, // [255, 0]
|
||||
255,
|
||||
0,
|
||||
opIF,
|
||||
opPUSHB000, // [255]
|
||||
2,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else true",
|
||||
[]byte{
|
||||
opPUSHB000, // [1]
|
||||
1,
|
||||
opIF,
|
||||
opPUSHB000, // [2]
|
||||
2,
|
||||
opELSE,
|
||||
opPUSHB000, // not executed
|
||||
3,
|
||||
opEIF,
|
||||
},
|
||||
[]int32{2},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else false",
|
||||
[]byte{
|
||||
opPUSHB000, // [0]
|
||||
0,
|
||||
opIF,
|
||||
opPUSHB000, // not executed
|
||||
2,
|
||||
opELSE,
|
||||
opPUSHB000, // [3]
|
||||
3,
|
||||
opEIF,
|
||||
},
|
||||
[]int32{3},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else true if/else false",
|
||||
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
|
||||
[]byte{
|
||||
opPUSHB010, // [255, 0, 1]
|
||||
255,
|
||||
0,
|
||||
1,
|
||||
opIF,
|
||||
opIF,
|
||||
opPUSHB001, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opPUSHW000, // [255, 0x5858]
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opELSE,
|
||||
opIF,
|
||||
opNPUSHB, // not executed
|
||||
3,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opNPUSHW, // not executed
|
||||
2,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 0x5858, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 0x5858, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else false if/else true",
|
||||
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
|
||||
[]byte{
|
||||
opPUSHB010, // [255, 1, 0]
|
||||
255,
|
||||
1,
|
||||
0,
|
||||
opIF,
|
||||
opIF,
|
||||
opPUSHB001, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opPUSHW000, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opELSE,
|
||||
opIF,
|
||||
opNPUSHB, // [255, 0x58, 0x58, 0x58]
|
||||
3,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opNPUSHW, // not executed
|
||||
2,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 0x58, 0x58, 0x58, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"logical ops",
|
||||
[]byte{
|
||||
opPUSHB010, // [0, 10, 20]
|
||||
0,
|
||||
10,
|
||||
20,
|
||||
opAND, // [0, 1]
|
||||
opOR, // [1]
|
||||
opNOT, // [0]
|
||||
},
|
||||
[]int32{0},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"arithmetic ops",
|
||||
// Calculate abs((-(1 - (2*3)))/2 + 1/64).
|
||||
// The answer is 5/2 + 1/64 in ideal numbers, or 161 in 26.6 fixed point math.
|
||||
[]byte{
|
||||
opPUSHB010, // [64, 128, 192]
|
||||
1 << 6,
|
||||
2 << 6,
|
||||
3 << 6,
|
||||
opMUL, // [64, 384]
|
||||
opSUB, // [-320]
|
||||
opNEG, // [320]
|
||||
opPUSHB000, // [320, 128]
|
||||
2 << 6,
|
||||
opDIV, // [160]
|
||||
opPUSHB000, // [160, 1]
|
||||
1,
|
||||
opADD, // [161]
|
||||
opABS, // [161]
|
||||
},
|
||||
[]int32{161},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"floor, ceiling",
|
||||
[]byte{
|
||||
opPUSHB000, // [96]
|
||||
96,
|
||||
opFLOOR, // [64]
|
||||
opPUSHB000, // [64, 96]
|
||||
96,
|
||||
opCEILING, // [64, 128]
|
||||
},
|
||||
[]int32{64, 128},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rounding",
|
||||
// Round 1.40625 (which is 90/64) under various rounding policies.
|
||||
// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
|
||||
[]byte{
|
||||
opROFF, // []
|
||||
opPUSHB000, // [90]
|
||||
90,
|
||||
opROUND00, // [90]
|
||||
opRTG, // [90]
|
||||
opPUSHB000, // [90, 90]
|
||||
90,
|
||||
opROUND00, // [90, 64]
|
||||
opRTHG, // [90, 64]
|
||||
opPUSHB000, // [90, 64, 90]
|
||||
90,
|
||||
opROUND00, // [90, 64, 96]
|
||||
opRDTG, // [90, 64, 96]
|
||||
opPUSHB000, // [90, 64, 96, 90]
|
||||
90,
|
||||
opROUND00, // [90, 64, 96, 64]
|
||||
opRUTG, // [90, 64, 96, 64]
|
||||
opPUSHB000, // [90, 64, 96, 64, 90]
|
||||
90,
|
||||
opROUND00, // [90, 64, 96, 64, 128]
|
||||
opRTDG, // [90, 64, 96, 64, 128]
|
||||
opPUSHB000, // [90, 64, 96, 64, 128, 90]
|
||||
90,
|
||||
opROUND00, // [90, 64, 96, 64, 128, 96]
|
||||
},
|
||||
[]int32{90, 64, 96, 64, 128, 96},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"super-rounding",
|
||||
// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
|
||||
// and the sign preservation steps of the "Order of rounding operations" section.
|
||||
[]byte{
|
||||
opPUSHB000, // [0x58]
|
||||
0x58,
|
||||
opSROUND, // []
|
||||
opPUSHW000, // [-81]
|
||||
0xff,
|
||||
0xaf,
|
||||
opROUND00, // [-80]
|
||||
opPUSHW000, // [-80, -80]
|
||||
0xff,
|
||||
0xb0,
|
||||
opROUND00, // [-80, -80]
|
||||
opPUSHW000, // [-80, -80, -17]
|
||||
0xff,
|
||||
0xef,
|
||||
opROUND00, // [-80, -80, -16]
|
||||
opPUSHW000, // [-80, -80, -16, -16]
|
||||
0xff,
|
||||
0xf0,
|
||||
opROUND00, // [-80, -80, -16, -16]
|
||||
opPUSHB000, // [-80, -80, -16, -16, 0]
|
||||
0,
|
||||
opROUND00, // [-80, -80, -16, -16, 16]
|
||||
opPUSHB000, // [-80, -80, -16, -16, 16, 16]
|
||||
16,
|
||||
opROUND00, // [-80, -80, -16, -16, 16, 16]
|
||||
opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47]
|
||||
47,
|
||||
opROUND00, // [-80, -80, -16, -16, 16, 16, 16]
|
||||
opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48]
|
||||
48,
|
||||
opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80]
|
||||
},
|
||||
[]int32{-80, -80, -16, -16, 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},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"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 {
|
||||
h := &hinter{}
|
||||
h.init(&Font{
|
||||
maxStorage: 32,
|
||||
maxStackElements: 100,
|
||||
}, 768)
|
||||
err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
|
||||
if err != nil {
|
||||
errStr = err.Error()
|
||||
}
|
||||
if tc.errStr != "" {
|
||||
if errStr == "" {
|
||||
t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
|
||||
} else if !strings.Contains(errStr, tc.errStr) {
|
||||
t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if errStr != "" {
|
||||
t.Errorf("%s: got error %q, want none", tc.desc, errStr)
|
||||
continue
|
||||
}
|
||||
got := h.stack[:len(tc.want)]
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMove tests that the hinter.move method matches the output of the C
|
||||
// Freetype implementation.
|
||||
func TestMove(t *testing.T) {
|
||||
h, p := hinter{}, Point{}
|
||||
testCases := []struct {
|
||||
pvX, pvY, fvX, fvY f2dot14
|
||||
wantX, wantY int32
|
||||
}{
|
||||
{+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
|
||||
{+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
|
||||
{-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
|
||||
{-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
|
||||
{+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
|
||||
{+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
|
||||
{+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
|
||||
{+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
|
||||
{+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
|
||||
{+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
|
||||
{-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
|
||||
{-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
|
||||
{-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
|
||||
{-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
|
||||
{+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
|
||||
{-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
|
||||
{+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
|
||||
{-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
|
||||
{-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
|
||||
{+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
|
||||
{+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
p = Point{}
|
||||
h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
|
||||
h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
|
||||
h.move(&p, 1000, true)
|
||||
tx := p.Flags&flagTouchedX != 0
|
||||
ty := p.Flags&flagTouchedY != 0
|
||||
wantTX := tc.fvX != 0
|
||||
wantTY := tc.fvY != 0
|
||||
if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
|
||||
t.Errorf("pv=%v, fv=%v\ngot %d, %d, %t, %t\nwant %d, %d, %t, %t",
|
||||
h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check that p is aligned with the freedom vector.
|
||||
a := int64(p.X) * int64(tc.fvY)
|
||||
b := int64(p.Y) * int64(tc.fvX)
|
||||
if a != b {
|
||||
t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check that the projected p is 1000 away from the origin.
|
||||
dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
|
||||
if dotProd != 1000 {
|
||||
t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestNormalize tests that the normalize function matches the output of the C
|
||||
// Freetype implementation.
|
||||
func TestNormalize(t *testing.T) {
|
||||
testCases := [][2]f2dot14{
|
||||
{-15895, 3974},
|
||||
{-15543, 5181},
|
||||
{-14654, 7327},
|
||||
{-11585, 11585},
|
||||
{0, 16384},
|
||||
{11585, 11585},
|
||||
{14654, 7327},
|
||||
{15543, 5181},
|
||||
{15895, 3974},
|
||||
{16066, 3213},
|
||||
{16161, 2694},
|
||||
{16219, 2317},
|
||||
{16257, 2032},
|
||||
{16284, 1809},
|
||||
}
|
||||
for i, want := range testCases {
|
||||
got := normalize(f2dot14(i)-4, 1)
|
||||
if got != want {
|
||||
t.Errorf("i=%d: got %v, want %v", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
289
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go
generated
vendored
289
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go
generated
vendored
@@ -1,289 +0,0 @@
|
||||
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package truetype
|
||||
|
||||
// The Truetype opcodes are summarized at
|
||||
// https://developer.apple.com/fonts/TTRefMan/RM07/appendixA.html
|
||||
|
||||
const (
|
||||
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 // Set Projection Vector To Line
|
||||
opSPVTL1 = 0x07 // .
|
||||
opSFVTL0 = 0x08 // Set Freedom Vector To Line
|
||||
opSFVTL1 = 0x09 // .
|
||||
opSPVFS = 0x0a // Set Projection Vector From Stack
|
||||
opSFVFS = 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 // moves point p to the InterSECTion of two lines
|
||||
opSRP0 = 0x10 // Set Reference Point 0
|
||||
opSRP1 = 0x11 // Set Reference Point 1
|
||||
opSRP2 = 0x12 // Set Reference Point 2
|
||||
opSZP0 = 0x13 // Set Zone Pointer 0
|
||||
opSZP1 = 0x14 // Set Zone Pointer 1
|
||||
opSZP2 = 0x15 // Set Zone Pointer 2
|
||||
opSZPS = 0x16 // Set Zone PointerS
|
||||
opSLOOP = 0x17 // Set LOOP variable
|
||||
opRTG = 0x18 // Round To Grid
|
||||
opRTHG = 0x19 // Round To Half Grid
|
||||
opSMD = 0x1a // Set Minimum Distance
|
||||
opELSE = 0x1b // ELSE clause
|
||||
opJMPR = 0x1c // JuMP Relative
|
||||
opSCVTCI = 0x1d // Set Control Value Table Cut-In
|
||||
opSSWCI = 0x1e // Set Single Width Cut-In
|
||||
opSSW = 0x1f // Set Single Width
|
||||
opDUP = 0x20 // DUPlicate top stack element
|
||||
opPOP = 0x21 // POP top stack element
|
||||
opCLEAR = 0x22 // CLEAR the stack
|
||||
opSWAP = 0x23 // SWAP the top two elements on the stack
|
||||
opDEPTH = 0x24 // DEPTH of the stack
|
||||
opCINDEX = 0x25 // Copy the INDEXed element to the top of the stack
|
||||
opMINDEX = 0x26 // Move the INDEXed element to the top of the stack
|
||||
opALIGNPTS = 0x27 // ALIGN PoinTS
|
||||
op_0x28 = 0x28 // deprecated
|
||||
opUTP = 0x29 // UnTouch Point
|
||||
opLOOPCALL = 0x2a // LOOP and CALL function
|
||||
opCALL = 0x2b // CALL function
|
||||
opFDEF = 0x2c // Function DEFinition
|
||||
opENDF = 0x2d // END Function definition
|
||||
opMDAP0 = 0x2e // Move Direct Absolute Point
|
||||
opMDAP1 = 0x2f // .
|
||||
opIUP0 = 0x30 // Interpolate Untouched Points through the outline
|
||||
opIUP1 = 0x31 // .
|
||||
opSHP0 = 0x32 // SHift Point using reference point
|
||||
opSHP1 = 0x33 // .
|
||||
opSHC0 = 0x34 // SHift Contour using reference point
|
||||
opSHC1 = 0x35 // .
|
||||
opSHZ0 = 0x36 // SHift Zone using reference point
|
||||
opSHZ1 = 0x37 // .
|
||||
opSHPIX = 0x38 // SHift point by a PIXel amount
|
||||
opIP = 0x39 // Interpolate Point
|
||||
opMSIRP0 = 0x3a // Move Stack Indirect Relative Point
|
||||
opMSIRP1 = 0x3b // .
|
||||
opALIGNRP = 0x3c // ALIGN to Reference Point
|
||||
opRTDG = 0x3d // Round To Double Grid
|
||||
opMIAP0 = 0x3e // Move Indirect Absolute Point
|
||||
opMIAP1 = 0x3f // .
|
||||
opNPUSHB = 0x40 // PUSH N Bytes
|
||||
opNPUSHW = 0x41 // PUSH N Words
|
||||
opWS = 0x42 // Write Store
|
||||
opRS = 0x43 // Read Store
|
||||
opWCVTP = 0x44 // Write Control Value Table in Pixel units
|
||||
opRCVT = 0x45 // Read Control Value Table entry
|
||||
opGC0 = 0x46 // Get Coordinate projected onto the projection vector
|
||||
opGC1 = 0x47 // .
|
||||
opSCFS = 0x48 // Sets Coordinate From the Stack using projection vector and freedom vector
|
||||
opMD0 = 0x49 // Measure Distance
|
||||
opMD1 = 0x4a // .
|
||||
opMPPEM = 0x4b // Measure Pixels Per EM
|
||||
opMPS = 0x4c // Measure Point Size
|
||||
opFLIPON = 0x4d // set the auto FLIP Boolean to ON
|
||||
opFLIPOFF = 0x4e // set the auto FLIP Boolean to OFF
|
||||
opDEBUG = 0x4f // DEBUG call
|
||||
opLT = 0x50 // Less Than
|
||||
opLTEQ = 0x51 // Less Than or EQual
|
||||
opGT = 0x52 // Greater Than
|
||||
opGTEQ = 0x53 // Greater Than or EQual
|
||||
opEQ = 0x54 // EQual
|
||||
opNEQ = 0x55 // Not EQual
|
||||
opODD = 0x56 // ODD
|
||||
opEVEN = 0x57 // EVEN
|
||||
opIF = 0x58 // IF test
|
||||
opEIF = 0x59 // End IF
|
||||
opAND = 0x5a // logical AND
|
||||
opOR = 0x5b // logical OR
|
||||
opNOT = 0x5c // logical NOT
|
||||
opDELTAP1 = 0x5d // DELTA exception P1
|
||||
opSDB = 0x5e // Set Delta Base in the graphics state
|
||||
opSDS = 0x5f // Set Delta Shift in the graphics state
|
||||
opADD = 0x60 // ADD
|
||||
opSUB = 0x61 // SUBtract
|
||||
opDIV = 0x62 // DIVide
|
||||
opMUL = 0x63 // MULtiply
|
||||
opABS = 0x64 // ABSolute value
|
||||
opNEG = 0x65 // NEGate
|
||||
opFLOOR = 0x66 // FLOOR
|
||||
opCEILING = 0x67 // CEILING
|
||||
opROUND00 = 0x68 // ROUND value
|
||||
opROUND01 = 0x69 // .
|
||||
opROUND10 = 0x6a // .
|
||||
opROUND11 = 0x6b // .
|
||||
opNROUND00 = 0x6c // No ROUNDing of value
|
||||
opNROUND01 = 0x6d // .
|
||||
opNROUND10 = 0x6e // .
|
||||
opNROUND11 = 0x6f // .
|
||||
opWCVTF = 0x70 // Write Control Value Table in Funits
|
||||
opDELTAP2 = 0x71 // DELTA exception P2
|
||||
opDELTAP3 = 0x72 // DELTA exception P3
|
||||
opDELTAC1 = 0x73 // DELTA exception C1
|
||||
opDELTAC2 = 0x74 // DELTA exception C2
|
||||
opDELTAC3 = 0x75 // DELTA exception C3
|
||||
opSROUND = 0x76 // Super ROUND
|
||||
opS45ROUND = 0x77 // Super ROUND 45 degrees
|
||||
opJROT = 0x78 // Jump Relative On True
|
||||
opJROF = 0x79 // Jump Relative On False
|
||||
opROFF = 0x7a // Round OFF
|
||||
op_0x7b = 0x7b // deprecated
|
||||
opRUTG = 0x7c // Round Up To Grid
|
||||
opRDTG = 0x7d // Round Down To Grid
|
||||
opSANGW = 0x7e // Set ANGle Weight
|
||||
opAA = 0x7f // Adjust Angle
|
||||
opFLIPPT = 0x80 // FLIP PoinT
|
||||
opFLIPRGON = 0x81 // FLIP RanGe ON
|
||||
opFLIPRGOFF = 0x82 // FLIP RanGe OFF
|
||||
op_0x83 = 0x83 // deprecated
|
||||
op_0x84 = 0x84 // deprecated
|
||||
opSCANCTRL = 0x85 // SCAN conversion ConTRoL
|
||||
opSDPVTL0 = 0x86 // Set Dual Projection Vector To Line
|
||||
opSDPVTL1 = 0x87 // .
|
||||
opGETINFO = 0x88 // GET INFOrmation
|
||||
opIDEF = 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 // SCANTYPE
|
||||
opINSTCTRL = 0x8e // INSTRuction execution ConTRoL
|
||||
op_0x8f = 0x8f
|
||||
op_0x90 = 0x90
|
||||
op_0x91 = 0x91
|
||||
op_0x92 = 0x92
|
||||
op_0x93 = 0x93
|
||||
op_0x94 = 0x94
|
||||
op_0x95 = 0x95
|
||||
op_0x96 = 0x96
|
||||
op_0x97 = 0x97
|
||||
op_0x98 = 0x98
|
||||
op_0x99 = 0x99
|
||||
op_0x9a = 0x9a
|
||||
op_0x9b = 0x9b
|
||||
op_0x9c = 0x9c
|
||||
op_0x9d = 0x9d
|
||||
op_0x9e = 0x9e
|
||||
op_0x9f = 0x9f
|
||||
op_0xa0 = 0xa0
|
||||
op_0xa1 = 0xa1
|
||||
op_0xa2 = 0xa2
|
||||
op_0xa3 = 0xa3
|
||||
op_0xa4 = 0xa4
|
||||
op_0xa5 = 0xa5
|
||||
op_0xa6 = 0xa6
|
||||
op_0xa7 = 0xa7
|
||||
op_0xa8 = 0xa8
|
||||
op_0xa9 = 0xa9
|
||||
op_0xaa = 0xaa
|
||||
op_0xab = 0xab
|
||||
op_0xac = 0xac
|
||||
op_0xad = 0xad
|
||||
op_0xae = 0xae
|
||||
op_0xaf = 0xaf
|
||||
opPUSHB000 = 0xb0 // PUSH Bytes
|
||||
opPUSHB001 = 0xb1 // .
|
||||
opPUSHB010 = 0xb2 // .
|
||||
opPUSHB011 = 0xb3 // .
|
||||
opPUSHB100 = 0xb4 // .
|
||||
opPUSHB101 = 0xb5 // .
|
||||
opPUSHB110 = 0xb6 // .
|
||||
opPUSHB111 = 0xb7 // .
|
||||
opPUSHW000 = 0xb8 // PUSH Words
|
||||
opPUSHW001 = 0xb9 // .
|
||||
opPUSHW010 = 0xba // .
|
||||
opPUSHW011 = 0xbb // .
|
||||
opPUSHW100 = 0xbc // .
|
||||
opPUSHW101 = 0xbd // .
|
||||
opPUSHW110 = 0xbe // .
|
||||
opPUSHW111 = 0xbf // .
|
||||
opMDRP00000 = 0xc0 // Move Direct Relative Point
|
||||
opMDRP00001 = 0xc1 // .
|
||||
opMDRP00010 = 0xc2 // .
|
||||
opMDRP00011 = 0xc3 // .
|
||||
opMDRP00100 = 0xc4 // .
|
||||
opMDRP00101 = 0xc5 // .
|
||||
opMDRP00110 = 0xc6 // .
|
||||
opMDRP00111 = 0xc7 // .
|
||||
opMDRP01000 = 0xc8 // .
|
||||
opMDRP01001 = 0xc9 // .
|
||||
opMDRP01010 = 0xca // .
|
||||
opMDRP01011 = 0xcb // .
|
||||
opMDRP01100 = 0xcc // .
|
||||
opMDRP01101 = 0xcd // .
|
||||
opMDRP01110 = 0xce // .
|
||||
opMDRP01111 = 0xcf // .
|
||||
opMDRP10000 = 0xd0 // .
|
||||
opMDRP10001 = 0xd1 // .
|
||||
opMDRP10010 = 0xd2 // .
|
||||
opMDRP10011 = 0xd3 // .
|
||||
opMDRP10100 = 0xd4 // .
|
||||
opMDRP10101 = 0xd5 // .
|
||||
opMDRP10110 = 0xd6 // .
|
||||
opMDRP10111 = 0xd7 // .
|
||||
opMDRP11000 = 0xd8 // .
|
||||
opMDRP11001 = 0xd9 // .
|
||||
opMDRP11010 = 0xda // .
|
||||
opMDRP11011 = 0xdb // .
|
||||
opMDRP11100 = 0xdc // .
|
||||
opMDRP11101 = 0xdd // .
|
||||
opMDRP11110 = 0xde // .
|
||||
opMDRP11111 = 0xdf // .
|
||||
opMIRP00000 = 0xe0 // Move Indirect Relative Point
|
||||
opMIRP00001 = 0xe1 // .
|
||||
opMIRP00010 = 0xe2 // .
|
||||
opMIRP00011 = 0xe3 // .
|
||||
opMIRP00100 = 0xe4 // .
|
||||
opMIRP00101 = 0xe5 // .
|
||||
opMIRP00110 = 0xe6 // .
|
||||
opMIRP00111 = 0xe7 // .
|
||||
opMIRP01000 = 0xe8 // .
|
||||
opMIRP01001 = 0xe9 // .
|
||||
opMIRP01010 = 0xea // .
|
||||
opMIRP01011 = 0xeb // .
|
||||
opMIRP01100 = 0xec // .
|
||||
opMIRP01101 = 0xed // .
|
||||
opMIRP01110 = 0xee // .
|
||||
opMIRP01111 = 0xef // .
|
||||
opMIRP10000 = 0xf0 // .
|
||||
opMIRP10001 = 0xf1 // .
|
||||
opMIRP10010 = 0xf2 // .
|
||||
opMIRP10011 = 0xf3 // .
|
||||
opMIRP10100 = 0xf4 // .
|
||||
opMIRP10101 = 0xf5 // .
|
||||
opMIRP10110 = 0xf6 // .
|
||||
opMIRP10111 = 0xf7 // .
|
||||
opMIRP11000 = 0xf8 // .
|
||||
opMIRP11001 = 0xf9 // .
|
||||
opMIRP11010 = 0xfa // .
|
||||
opMIRP11011 = 0xfb // .
|
||||
opMIRP11100 = 0xfc // .
|
||||
opMIRP11101 = 0xfd // .
|
||||
opMIRP11110 = 0xfe // .
|
||||
opMIRP11111 = 0xff // .
|
||||
)
|
||||
|
||||
// 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
|
||||
0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, // 0x00 - 0x0f
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1f
|
||||
1, 1, 0, 2, 0, 1, 1, 2, 0, 1, 2, 1, 1, 0, 1, 1, // 0x20 - 0x2f
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f
|
||||
0, 0, 2, 1, 2, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, // 0x40 - 0x4f
|
||||
2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, // 0x50 - 0x5f
|
||||
2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6f
|
||||
2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 1, // 0x70 - 0x7f
|
||||
0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, 0, // 0x80 - 0x8f
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xf0 - 0xff
|
||||
}
|
||||
554
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go
generated
vendored
554
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go
generated
vendored
@@ -1,554 +0,0 @@
|
||||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
// Package truetype provides a parser for the TTF and TTC file formats.
|
||||
// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/
|
||||
// and http://www.microsoft.com/typography/otspec/
|
||||
//
|
||||
// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font
|
||||
// metrics and control points. All these methods take a scale parameter, which
|
||||
// is the number of device units in 1 em. For example, if 1 em is 10 pixels and
|
||||
// 1 pixel is 64 units, then scale is 640. If the device space involves pixels,
|
||||
// 64 units per pixel is recommended, since that is what the bytecode hinter
|
||||
// uses when snapping point co-ordinates to the pixel grid.
|
||||
//
|
||||
// To measure a TrueType font in ideal FUnit space, use scale equal to
|
||||
// font.FUnitsPerEm().
|
||||
package truetype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// An Index is a Font's index of a rune.
|
||||
type Index uint16
|
||||
|
||||
// A Bounds holds the co-ordinate range of one or more glyphs.
|
||||
// The endpoints are inclusive.
|
||||
type Bounds struct {
|
||||
XMin, YMin, XMax, YMax int32
|
||||
}
|
||||
|
||||
// An HMetric holds the horizontal metrics of a single glyph.
|
||||
type HMetric struct {
|
||||
AdvanceWidth, LeftSideBearing int32
|
||||
}
|
||||
|
||||
// A VMetric holds the vertical metrics of a single glyph.
|
||||
type VMetric struct {
|
||||
AdvanceHeight, TopSideBearing int32
|
||||
}
|
||||
|
||||
// A FormatError reports that the input is not a valid TrueType font.
|
||||
type FormatError string
|
||||
|
||||
func (e FormatError) Error() string {
|
||||
return "freetype: invalid TrueType format: " + string(e)
|
||||
}
|
||||
|
||||
// An UnsupportedError reports that the input uses a valid but unimplemented
|
||||
// TrueType feature.
|
||||
type UnsupportedError string
|
||||
|
||||
func (e UnsupportedError) Error() string {
|
||||
return "freetype: unsupported TrueType feature: " + string(e)
|
||||
}
|
||||
|
||||
// u32 returns the big-endian uint32 at b[i:].
|
||||
func u32(b []byte, i int) uint32 {
|
||||
return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
|
||||
}
|
||||
|
||||
// u16 returns the big-endian uint16 at b[i:].
|
||||
func u16(b []byte, i int) uint16 {
|
||||
return uint16(b[i])<<8 | uint16(b[i+1])
|
||||
}
|
||||
|
||||
// readTable returns a slice of the TTF data given by a table's directory entry.
|
||||
func readTable(ttf []byte, offsetLength []byte) ([]byte, error) {
|
||||
offset := int(u32(offsetLength, 0))
|
||||
if offset < 0 {
|
||||
return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset)))
|
||||
}
|
||||
length := int(u32(offsetLength, 4))
|
||||
if length < 0 {
|
||||
return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length)))
|
||||
}
|
||||
end := offset + length
|
||||
if end < 0 || end > len(ttf) {
|
||||
return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length)))
|
||||
}
|
||||
return ttf[offset:end], nil
|
||||
}
|
||||
|
||||
const (
|
||||
locaOffsetFormatUnknown int = iota
|
||||
locaOffsetFormatShort
|
||||
locaOffsetFormatLong
|
||||
)
|
||||
|
||||
// A cm holds a parsed cmap entry.
|
||||
type cm struct {
|
||||
start, end, delta, offset uint32
|
||||
}
|
||||
|
||||
// A Font represents a Truetype font.
|
||||
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, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, os2, prep, vmtx []byte
|
||||
|
||||
cmapIndexes []byte
|
||||
|
||||
// Cached values derived from the raw ttf data.
|
||||
cm []cm
|
||||
locaOffsetFormat int
|
||||
nGlyph, nHMetric, nKern int
|
||||
fUnitsPerEm int32
|
||||
bounds Bounds
|
||||
// Values from the maxp section.
|
||||
maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16
|
||||
}
|
||||
|
||||
func (f *Font) parseCmap() error {
|
||||
const (
|
||||
cmapFormat4 = 4
|
||||
cmapFormat12 = 12
|
||||
languageIndependent = 0
|
||||
|
||||
// A 32-bit encoding consists of a most-significant 16-bit Platform ID and a
|
||||
// least-significant 16-bit Platform Specific ID. The magic numbers are
|
||||
// specified at https://www.microsoft.com/typography/otspec/name.htm
|
||||
unicodeEncoding = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0)
|
||||
microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol)
|
||||
microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2)
|
||||
microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4)
|
||||
)
|
||||
|
||||
if len(f.cmap) < 4 {
|
||||
return FormatError("cmap too short")
|
||||
}
|
||||
nsubtab := int(u16(f.cmap, 2))
|
||||
if len(f.cmap) < 8*nsubtab+4 {
|
||||
return FormatError("cmap too short")
|
||||
}
|
||||
offset, found, x := 0, false, 4
|
||||
for i := 0; i < nsubtab; i++ {
|
||||
// We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32.
|
||||
// All values are big-endian.
|
||||
pidPsid, o := u32(f.cmap, x), u32(f.cmap, x+4)
|
||||
x += 8
|
||||
// We prefer the Unicode cmap encoding. Failing to find that, we fall
|
||||
// back onto the Microsoft cmap encoding.
|
||||
if pidPsid == unicodeEncoding {
|
||||
offset, found = int(o), true
|
||||
break
|
||||
|
||||
} else if pidPsid == microsoftSymbolEncoding ||
|
||||
pidPsid == microsoftUCS2Encoding ||
|
||||
pidPsid == microsoftUCS4Encoding {
|
||||
|
||||
offset, found = int(o), true
|
||||
// We don't break out of the for loop, so that Unicode can override Microsoft.
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return UnsupportedError("cmap encoding")
|
||||
}
|
||||
if offset <= 0 || offset > len(f.cmap) {
|
||||
return FormatError("bad cmap offset")
|
||||
}
|
||||
|
||||
cmapFormat := u16(f.cmap, offset)
|
||||
switch cmapFormat {
|
||||
case cmapFormat4:
|
||||
language := u16(f.cmap, offset+4)
|
||||
if language != languageIndependent {
|
||||
return UnsupportedError(fmt.Sprintf("language: %d", language))
|
||||
}
|
||||
segCountX2 := int(u16(f.cmap, offset+6))
|
||||
if segCountX2%2 == 1 {
|
||||
return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2))
|
||||
}
|
||||
segCount := segCountX2 / 2
|
||||
offset += 14
|
||||
f.cm = make([]cm, segCount)
|
||||
for i := 0; i < segCount; i++ {
|
||||
f.cm[i].end = uint32(u16(f.cmap, offset))
|
||||
offset += 2
|
||||
}
|
||||
offset += 2
|
||||
for i := 0; i < segCount; i++ {
|
||||
f.cm[i].start = uint32(u16(f.cmap, offset))
|
||||
offset += 2
|
||||
}
|
||||
for i := 0; i < segCount; i++ {
|
||||
f.cm[i].delta = uint32(u16(f.cmap, offset))
|
||||
offset += 2
|
||||
}
|
||||
for i := 0; i < segCount; i++ {
|
||||
f.cm[i].offset = uint32(u16(f.cmap, offset))
|
||||
offset += 2
|
||||
}
|
||||
f.cmapIndexes = f.cmap[offset:]
|
||||
return nil
|
||||
|
||||
case cmapFormat12:
|
||||
if u16(f.cmap, offset+2) != 0 {
|
||||
return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4]))
|
||||
}
|
||||
length := u32(f.cmap, offset+4)
|
||||
language := u32(f.cmap, offset+8)
|
||||
if language != languageIndependent {
|
||||
return UnsupportedError(fmt.Sprintf("language: %d", language))
|
||||
}
|
||||
nGroups := u32(f.cmap, offset+12)
|
||||
if length != 12*nGroups+16 {
|
||||
return FormatError("inconsistent cmap length")
|
||||
}
|
||||
offset += 16
|
||||
f.cm = make([]cm, nGroups)
|
||||
for i := uint32(0); i < nGroups; i++ {
|
||||
f.cm[i].start = u32(f.cmap, offset+0)
|
||||
f.cm[i].end = u32(f.cmap, offset+4)
|
||||
f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start
|
||||
offset += 12
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat))
|
||||
}
|
||||
|
||||
func (f *Font) parseHead() error {
|
||||
if len(f.head) != 54 {
|
||||
return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
|
||||
}
|
||||
f.fUnitsPerEm = int32(u16(f.head, 18))
|
||||
f.bounds.XMin = int32(int16(u16(f.head, 36)))
|
||||
f.bounds.YMin = int32(int16(u16(f.head, 38)))
|
||||
f.bounds.XMax = int32(int16(u16(f.head, 40)))
|
||||
f.bounds.YMax = int32(int16(u16(f.head, 42)))
|
||||
switch i := u16(f.head, 50); i {
|
||||
case 0:
|
||||
f.locaOffsetFormat = locaOffsetFormatShort
|
||||
case 1:
|
||||
f.locaOffsetFormat = locaOffsetFormatLong
|
||||
default:
|
||||
return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Font) parseHhea() error {
|
||||
if len(f.hhea) != 36 {
|
||||
return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea)))
|
||||
}
|
||||
f.nHMetric = int(u16(f.hhea, 34))
|
||||
if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) {
|
||||
return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Font) parseKern() error {
|
||||
// Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says:
|
||||
// "Previous versions of the 'kern' table defined both the version and nTables fields in the header
|
||||
// as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged
|
||||
// (although AAT can sense an old kerning table and still make correct use of it). Microsoft
|
||||
// Windows still uses the older format for the 'kern' table and will not recognize the newer one.
|
||||
// Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS
|
||||
// and Windows should use the old format."
|
||||
// Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format,
|
||||
// just like the C Freetype implementation.
|
||||
if len(f.kern) == 0 {
|
||||
if f.nKern != 0 {
|
||||
return FormatError("bad kern table length")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(f.kern) < 18 {
|
||||
return FormatError("kern data too short")
|
||||
}
|
||||
version, offset := u16(f.kern, 0), 2
|
||||
if version != 0 {
|
||||
return UnsupportedError(fmt.Sprintf("kern version: %d", version))
|
||||
}
|
||||
n, offset := u16(f.kern, offset), offset+2
|
||||
if n != 1 {
|
||||
return UnsupportedError(fmt.Sprintf("kern nTables: %d", n))
|
||||
}
|
||||
offset += 2
|
||||
length, offset := int(u16(f.kern, offset)), offset+2
|
||||
coverage, offset := u16(f.kern, offset), offset+2
|
||||
if coverage != 0x0001 {
|
||||
// We only support horizontal kerning.
|
||||
return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage))
|
||||
}
|
||||
f.nKern, offset = int(u16(f.kern, offset)), offset+2
|
||||
if 6*f.nKern != length-14 {
|
||||
return FormatError("bad kern table length")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Font) parseMaxp() error {
|
||||
if len(f.maxp) != 32 {
|
||||
return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp)))
|
||||
}
|
||||
f.nGlyph = int(u16(f.maxp, 4))
|
||||
f.maxTwilightPoints = u16(f.maxp, 16)
|
||||
f.maxStorage = u16(f.maxp, 18)
|
||||
f.maxFunctionDefs = u16(f.maxp, 20)
|
||||
f.maxStackElements = u16(f.maxp, 24)
|
||||
return nil
|
||||
}
|
||||
|
||||
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
|
||||
func (f *Font) scale(x int32) int32 {
|
||||
if x >= 0 {
|
||||
x += f.fUnitsPerEm / 2
|
||||
} else {
|
||||
x -= f.fUnitsPerEm / 2
|
||||
}
|
||||
return x / f.fUnitsPerEm
|
||||
}
|
||||
|
||||
// Bounds returns the union of a Font's glyphs' bounds.
|
||||
func (f *Font) Bounds(scale int32) Bounds {
|
||||
b := f.bounds
|
||||
b.XMin = f.scale(scale * b.XMin)
|
||||
b.YMin = f.scale(scale * b.YMin)
|
||||
b.XMax = f.scale(scale * b.XMax)
|
||||
b.YMax = f.scale(scale * b.YMax)
|
||||
return b
|
||||
}
|
||||
|
||||
// FUnitsPerEm returns the number of FUnits in a Font's em-square's side.
|
||||
func (f *Font) FUnitsPerEm() int32 {
|
||||
return f.fUnitsPerEm
|
||||
}
|
||||
|
||||
// Index returns a Font's index for the given rune.
|
||||
func (f *Font) Index(x rune) Index {
|
||||
c := uint32(x)
|
||||
for i, j := 0, len(f.cm); i < j; {
|
||||
h := i + (j-i)/2
|
||||
cm := &f.cm[h]
|
||||
if c < cm.start {
|
||||
j = h
|
||||
} else if cm.end < c {
|
||||
i = h + 1
|
||||
} else if cm.offset == 0 {
|
||||
return Index(c + cm.delta)
|
||||
} else {
|
||||
offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start))
|
||||
return Index(u16(f.cmapIndexes, offset))
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// unscaledHMetric returns the unscaled horizontal metrics for the glyph with
|
||||
// the given index.
|
||||
func (f *Font) unscaledHMetric(i Index) (h HMetric) {
|
||||
j := int(i)
|
||||
if j < 0 || f.nGlyph <= j {
|
||||
return HMetric{}
|
||||
}
|
||||
if j >= f.nHMetric {
|
||||
p := 4 * (f.nHMetric - 1)
|
||||
return HMetric{
|
||||
AdvanceWidth: int32(u16(f.hmtx, p)),
|
||||
LeftSideBearing: int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
|
||||
}
|
||||
}
|
||||
return HMetric{
|
||||
AdvanceWidth: int32(u16(f.hmtx, 4*j)),
|
||||
LeftSideBearing: int32(int16(u16(f.hmtx, 4*j+2))),
|
||||
}
|
||||
}
|
||||
|
||||
// HMetric returns the horizontal metrics for the glyph with the given index.
|
||||
func (f *Font) HMetric(scale int32, i Index) HMetric {
|
||||
h := f.unscaledHMetric(i)
|
||||
h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
|
||||
h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
|
||||
return h
|
||||
}
|
||||
|
||||
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
|
||||
// the given index. yMax is the top of the glyph's bounding box.
|
||||
func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
|
||||
j := int(i)
|
||||
if j < 0 || f.nGlyph <= j {
|
||||
return VMetric{}
|
||||
}
|
||||
if 4*j+4 <= len(f.vmtx) {
|
||||
return VMetric{
|
||||
AdvanceHeight: int32(u16(f.vmtx, 4*j)),
|
||||
TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))),
|
||||
}
|
||||
}
|
||||
// The OS/2 table has grown over time.
|
||||
// https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html
|
||||
// says that it was originally 68 bytes. Optional fields, including
|
||||
// the ascender and descender, are described at
|
||||
// http://www.microsoft.com/typography/otspec/os2.htm
|
||||
if len(f.os2) >= 72 {
|
||||
sTypoAscender := int32(int16(u16(f.os2, 68)))
|
||||
sTypoDescender := int32(int16(u16(f.os2, 70)))
|
||||
return VMetric{
|
||||
AdvanceHeight: sTypoAscender - sTypoDescender,
|
||||
TopSideBearing: sTypoAscender - yMax,
|
||||
}
|
||||
}
|
||||
return VMetric{
|
||||
AdvanceHeight: f.fUnitsPerEm,
|
||||
TopSideBearing: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// VMetric returns the vertical metrics for the glyph with the given index.
|
||||
func (f *Font) VMetric(scale int32, i Index) VMetric {
|
||||
// TODO: should 0 be bounds.YMax?
|
||||
v := f.unscaledVMetric(i, 0)
|
||||
v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
|
||||
v.TopSideBearing = f.scale(scale * v.TopSideBearing)
|
||||
return v
|
||||
}
|
||||
|
||||
// Kerning returns the kerning for the given glyph pair.
|
||||
func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
|
||||
if f.nKern == 0 {
|
||||
return 0
|
||||
}
|
||||
g := uint32(i0)<<16 | uint32(i1)
|
||||
lo, hi := 0, f.nKern
|
||||
for lo < hi {
|
||||
i := (lo + hi) / 2
|
||||
ig := u32(f.kern, 18+6*i)
|
||||
if ig < g {
|
||||
lo = i + 1
|
||||
} else if ig > g {
|
||||
hi = i
|
||||
} else {
|
||||
return f.scale(scale * int32(int16(u16(f.kern, 22+6*i))))
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Parse returns a new Font for the given TTF or TTC data.
|
||||
//
|
||||
// For TrueType Collections, the first font in the collection is parsed.
|
||||
func Parse(ttf []byte) (font *Font, err error) {
|
||||
return parse(ttf, 0)
|
||||
}
|
||||
|
||||
func parse(ttf []byte, offset int) (font *Font, err error) {
|
||||
if len(ttf)-offset < 12 {
|
||||
err = FormatError("TTF data is too short")
|
||||
return
|
||||
}
|
||||
originalOffset := offset
|
||||
magic, offset := u32(ttf, offset), offset+4
|
||||
switch magic {
|
||||
case 0x00010000:
|
||||
// No-op.
|
||||
case 0x74746366: // "ttcf" as a big-endian uint32.
|
||||
if originalOffset != 0 {
|
||||
err = FormatError("recursive TTC")
|
||||
return
|
||||
}
|
||||
ttcVersion, offset := u32(ttf, offset), offset+4
|
||||
if ttcVersion != 0x00010000 {
|
||||
// TODO: support TTC version 2.0, once I have such a .ttc file to test with.
|
||||
err = FormatError("bad TTC version")
|
||||
return
|
||||
}
|
||||
numFonts, offset := int(u32(ttf, offset)), offset+4
|
||||
if numFonts <= 0 {
|
||||
err = FormatError("bad number of TTC fonts")
|
||||
return
|
||||
}
|
||||
if len(ttf[offset:])/4 < numFonts {
|
||||
err = FormatError("TTC offset table is too short")
|
||||
return
|
||||
}
|
||||
// TODO: provide an API to select which font in a TrueType collection to return,
|
||||
// not just the first one. This may require an API to parse a TTC's name tables,
|
||||
// so users of this package can select the font in a TTC by name.
|
||||
offset = int(u32(ttf, offset))
|
||||
if offset <= 0 || offset > len(ttf) {
|
||||
err = FormatError("bad TTC offset")
|
||||
return
|
||||
}
|
||||
return parse(ttf, offset)
|
||||
default:
|
||||
err = FormatError("bad TTF version")
|
||||
return
|
||||
}
|
||||
n, offset := int(u16(ttf, offset)), offset+2
|
||||
if len(ttf) < 16*n+12 {
|
||||
err = FormatError("TTF data is too short")
|
||||
return
|
||||
}
|
||||
f := new(Font)
|
||||
// Assign the table slices.
|
||||
for i := 0; i < n; i++ {
|
||||
x := 16*i + 12
|
||||
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 "hdmx":
|
||||
f.hdmx, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "head":
|
||||
f.head, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "hhea":
|
||||
f.hhea, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "hmtx":
|
||||
f.hmtx, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "kern":
|
||||
f.kern, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "loca":
|
||||
f.loca, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "maxp":
|
||||
f.maxp, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "OS/2":
|
||||
f.os2, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "prep":
|
||||
f.prep, err = readTable(ttf, ttf[x+8:x+16])
|
||||
case "vmtx":
|
||||
f.vmtx, err = readTable(ttf, ttf[x+8:x+16])
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Parse and sanity-check the TTF data.
|
||||
if err = f.parseHead(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = f.parseMaxp(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = f.parseCmap(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = f.parseKern(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = f.parseHhea(); err != nil {
|
||||
return
|
||||
}
|
||||
font = f
|
||||
return
|
||||
}
|
||||
366
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go
generated
vendored
366
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go
generated
vendored
@@ -1,366 +0,0 @@
|
||||
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
package truetype
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func parseTestdataFont(name string) (font *Font, testdataIsOptional bool, err error) {
|
||||
b, err := ioutil.ReadFile(fmt.Sprintf("../../testdata/%s.ttf", name))
|
||||
if err != nil {
|
||||
// The "x-foo" fonts are optional tests, as they are not checked
|
||||
// in for copyright or file size reasons.
|
||||
return nil, strings.HasPrefix(name, "x-"), fmt.Errorf("%s: ReadFile: %v", name, err)
|
||||
}
|
||||
font, err = Parse(b)
|
||||
if err != nil {
|
||||
return nil, true, fmt.Errorf("%s: Parse: %v", name, err)
|
||||
}
|
||||
return font, false, nil
|
||||
}
|
||||
|
||||
// TestParse tests that the luxisr.ttf metrics and glyphs are parsed correctly.
|
||||
// The numerical values can be manually verified by examining luxisr.ttx.
|
||||
func TestParse(t *testing.T) {
|
||||
font, _, err := parseTestdataFont("luxisr")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := font.FUnitsPerEm(), int32(2048); got != want {
|
||||
t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
|
||||
}
|
||||
fupe := font.FUnitsPerEm()
|
||||
if got, want := font.Bounds(fupe), (Bounds{-441, -432, 2024, 2033}); got != want {
|
||||
t.Errorf("Bounds: got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
i0 := font.Index('A')
|
||||
i1 := font.Index('V')
|
||||
if i0 != 36 || i1 != 57 {
|
||||
t.Fatalf("Index: i0, i1 = %d, %d, want 36, 57", i0, i1)
|
||||
}
|
||||
if got, want := font.HMetric(fupe, i0), (HMetric{1366, 19}); got != want {
|
||||
t.Errorf("HMetric: got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := font.VMetric(fupe, i0), (VMetric{2465, 553}); got != want {
|
||||
t.Errorf("VMetric: got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := font.Kerning(fupe, i0, i1), int32(-144); got != want {
|
||||
t.Errorf("Kerning: got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
g := NewGlyphBuf()
|
||||
err = g.Load(font, fupe, i0, NoHinting)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
g0 := &GlyphBuf{
|
||||
B: g.B,
|
||||
Point: g.Point,
|
||||
End: g.End,
|
||||
}
|
||||
g1 := &GlyphBuf{
|
||||
B: Bounds{19, 0, 1342, 1480},
|
||||
Point: []Point{
|
||||
{19, 0, 51},
|
||||
{581, 1480, 1},
|
||||
{789, 1480, 51},
|
||||
{1342, 0, 1},
|
||||
{1116, 0, 35},
|
||||
{962, 410, 3},
|
||||
{368, 410, 33},
|
||||
{214, 0, 3},
|
||||
{428, 566, 19},
|
||||
{904, 566, 33},
|
||||
{667, 1200, 3},
|
||||
},
|
||||
End: []int{8, 11},
|
||||
}
|
||||
if got, want := fmt.Sprint(g0), fmt.Sprint(g1); got != want {
|
||||
t.Errorf("GlyphBuf:\ngot %v\nwant %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndex(t *testing.T) {
|
||||
testCases := map[string]map[rune]Index{
|
||||
"luxisr": {
|
||||
' ': 3,
|
||||
'!': 4,
|
||||
'A': 36,
|
||||
'V': 57,
|
||||
'É': 101,
|
||||
'fl': 193,
|
||||
'\u22c5': 385,
|
||||
'中': 0,
|
||||
},
|
||||
|
||||
// The x-etc test cases use those versions of the .ttf files provided
|
||||
// by Ubuntu 14.04. See testdata/make-other-hinting-txts.sh for details.
|
||||
|
||||
"x-arial-bold": {
|
||||
' ': 3,
|
||||
'+': 14,
|
||||
'0': 19,
|
||||
'_': 66,
|
||||
'w': 90,
|
||||
'~': 97,
|
||||
'Ä': 98,
|
||||
'fl': 192,
|
||||
'½': 242,
|
||||
'σ': 305,
|
||||
'λ': 540,
|
||||
'ỹ': 1275,
|
||||
'\u04e9': 1319,
|
||||
'中': 0,
|
||||
},
|
||||
"x-deja-vu-sans-oblique": {
|
||||
' ': 3,
|
||||
'*': 13,
|
||||
'Œ': 276,
|
||||
'ω': 861,
|
||||
'‡': 2571,
|
||||
'⊕': 3110,
|
||||
'fl': 4728,
|
||||
'\ufb03': 4729,
|
||||
'\ufffd': 4813,
|
||||
// TODO: '\U0001f640': ???,
|
||||
'中': 0,
|
||||
},
|
||||
"x-droid-sans-japanese": {
|
||||
' ': 0,
|
||||
'\u3000': 3,
|
||||
'\u3041': 25,
|
||||
'\u30fe': 201,
|
||||
'\uff61': 202,
|
||||
'\uff67': 208,
|
||||
'\uff9e': 263,
|
||||
'\uff9f': 264,
|
||||
'\u4e00': 265,
|
||||
'\u557e': 1000,
|
||||
'\u61b6': 2024,
|
||||
'\u6ede': 3177,
|
||||
'\u7505': 3555,
|
||||
'\u81e3': 4602,
|
||||
'\u81e5': 4603,
|
||||
'\u81e7': 4604,
|
||||
'\u81e8': 4605,
|
||||
'\u81ea': 4606,
|
||||
'\u81ed': 4607,
|
||||
'\u81f3': 4608,
|
||||
'\u81f4': 4609,
|
||||
'\u91c7': 5796,
|
||||
'\u9fa0': 6620,
|
||||
'\u203e': 12584,
|
||||
},
|
||||
"x-times-new-roman": {
|
||||
' ': 3,
|
||||
':': 29,
|
||||
'fl': 192,
|
||||
'Ŀ': 273,
|
||||
'♠': 388,
|
||||
'Ŗ': 451,
|
||||
'Σ': 520,
|
||||
'\u200D': 745,
|
||||
'Ẽ': 1216,
|
||||
'\u04e9': 1319,
|
||||
'中': 0,
|
||||
},
|
||||
}
|
||||
for name, wants := range testCases {
|
||||
font, testdataIsOptional, err := parseTestdataFont(name)
|
||||
if err != nil {
|
||||
if testdataIsOptional {
|
||||
t.Log(err)
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
for r, want := range wants {
|
||||
if got := font.Index(r); got != want {
|
||||
t.Errorf("%s: Index of %q, aka %U: got %d, want %d", name, r, r, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type scalingTestData struct {
|
||||
advanceWidth int32
|
||||
bounds Bounds
|
||||
points []Point
|
||||
}
|
||||
|
||||
// scalingTestParse parses a line of points like
|
||||
// 213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1
|
||||
// The line will not have a trailing "\n".
|
||||
func scalingTestParse(line string) (ret scalingTestData) {
|
||||
next := func(s string) (string, int32) {
|
||||
t, i := "", strings.Index(s, " ")
|
||||
if i != -1 {
|
||||
s, t = s[:i], s[i+1:]
|
||||
}
|
||||
x, _ := strconv.Atoi(s)
|
||||
return t, int32(x)
|
||||
}
|
||||
|
||||
i := strings.Index(line, ";")
|
||||
prefix, line := line[:i], line[i+1:]
|
||||
|
||||
prefix, ret.advanceWidth = next(prefix)
|
||||
prefix, ret.bounds.XMin = next(prefix)
|
||||
prefix, ret.bounds.YMin = next(prefix)
|
||||
prefix, ret.bounds.XMax = next(prefix)
|
||||
prefix, ret.bounds.YMax = next(prefix)
|
||||
|
||||
ret.points = make([]Point, 0, 1+strings.Count(line, ","))
|
||||
for len(line) > 0 {
|
||||
s := line
|
||||
if i := strings.Index(line, ","); i != -1 {
|
||||
s, line = line[:i], line[i+1:]
|
||||
for len(line) > 0 && line[0] == ' ' {
|
||||
line = line[1:]
|
||||
}
|
||||
} else {
|
||||
line = ""
|
||||
}
|
||||
s, x := next(s)
|
||||
s, y := next(s)
|
||||
s, f := next(s)
|
||||
ret.points = append(ret.points, Point{X: x, Y: y, Flags: uint32(f)})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// scalingTestEquals is equivalent to, but faster than, calling
|
||||
// reflect.DeepEquals(a, b), and also returns the index of the first non-equal
|
||||
// element. It also treats a nil []Point and an empty non-nil []Point as equal.
|
||||
// a and b must have equal length.
|
||||
func scalingTestEquals(a, b []Point) (index int, equals bool) {
|
||||
for i, p := range a {
|
||||
if p != b[i] {
|
||||
return i, false
|
||||
}
|
||||
}
|
||||
return 0, true
|
||||
}
|
||||
|
||||
var scalingTestCases = []struct {
|
||||
name string
|
||||
size int32
|
||||
}{
|
||||
{"luxisr", 12},
|
||||
{"x-arial-bold", 11},
|
||||
{"x-deja-vu-sans-oblique", 17},
|
||||
{"x-droid-sans-japanese", 9},
|
||||
{"x-times-new-roman", 13},
|
||||
}
|
||||
|
||||
func testScaling(t *testing.T, h Hinting) {
|
||||
for _, tc := range scalingTestCases {
|
||||
font, testdataIsOptional, err := parseTestdataFont(tc.name)
|
||||
if err != nil {
|
||||
if testdataIsOptional {
|
||||
t.Log(err)
|
||||
} else {
|
||||
t.Error(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
hintingStr := "sans"
|
||||
if h != NoHinting {
|
||||
hintingStr = "with"
|
||||
}
|
||||
f, err := os.Open(fmt.Sprintf(
|
||||
"../../testdata/%s-%dpt-%s-hinting.txt", tc.name, tc.size, hintingStr))
|
||||
if err != nil {
|
||||
t.Errorf("%s: Open: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
wants := []scalingTestData{}
|
||||
scanner := bufio.NewScanner(f)
|
||||
if scanner.Scan() {
|
||||
major, minor, patch := 0, 0, 0
|
||||
_, err := fmt.Sscanf(scanner.Text(), "freetype version %d.%d.%d", &major, &minor, &patch)
|
||||
if err != nil {
|
||||
t.Errorf("%s: version information: %v", tc.name, err)
|
||||
}
|
||||
if (major < 2) || (major == 2 && minor < 5) || (major == 2 && minor == 5 && patch < 1) {
|
||||
t.Errorf("%s: need freetype version >= 2.5.1.\n"+
|
||||
"Try setting LD_LIBRARY_PATH=/path/to/freetype_built_from_src/objs/.libs/\n"+
|
||||
"and re-running testdata/make-other-hinting-txts.sh",
|
||||
tc.name)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%s: no version information", tc.name)
|
||||
continue
|
||||
}
|
||||
for scanner.Scan() {
|
||||
wants = append(wants, scalingTestParse(scanner.Text()))
|
||||
}
|
||||
if err := scanner.Err(); err != nil && err != io.EOF {
|
||||
t.Errorf("%s: Scanner: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
glyphBuf := NewGlyphBuf()
|
||||
for i, want := range wants {
|
||||
if err = glyphBuf.Load(font, tc.size*64, Index(i), h); err != nil {
|
||||
t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
|
||||
continue
|
||||
}
|
||||
got := scalingTestData{
|
||||
advanceWidth: glyphBuf.AdvanceWidth,
|
||||
bounds: glyphBuf.B,
|
||||
points: glyphBuf.Point,
|
||||
}
|
||||
|
||||
if got.advanceWidth != want.advanceWidth {
|
||||
t.Errorf("%s: glyph #%d advance width:\ngot %v\nwant %v",
|
||||
tc.name, i, got.advanceWidth, want.advanceWidth)
|
||||
continue
|
||||
}
|
||||
|
||||
if got.bounds != want.bounds {
|
||||
t.Errorf("%s: glyph #%d bounds:\ngot %v\nwant %v",
|
||||
tc.name, i, got.bounds, want.bounds)
|
||||
continue
|
||||
}
|
||||
|
||||
for i := range got.points {
|
||||
got.points[i].Flags &= 0x01
|
||||
}
|
||||
if len(got.points) != len(want.points) {
|
||||
t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\ndifferent slice lengths: %d versus %d",
|
||||
tc.name, i, got.points, want.points, len(got.points), len(want.points))
|
||||
continue
|
||||
}
|
||||
if j, equals := scalingTestEquals(got.points, want.points); !equals {
|
||||
t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\nat index %d: %v versus %v",
|
||||
tc.name, i, got.points, want.points, j, got.points[j], want.points[j])
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalingSansHinting(t *testing.T) {
|
||||
testScaling(t, NoHinting)
|
||||
}
|
||||
|
||||
func TestScalingWithHinting(t *testing.T) {
|
||||
testScaling(t, FullHinting)
|
||||
}
|
||||
1
Godeps/_workspace/src/code.google.com/p/freetype-go/lib/codereview/codereview.cfg
generated
vendored
1
Godeps/_workspace/src/code.google.com/p/freetype-go/lib/codereview/codereview.cfg
generated
vendored
@@ -1 +0,0 @@
|
||||
defaultcc: golang-codereviews@googlegroups.com
|
||||
169
Godeps/_workspace/src/code.google.com/p/freetype-go/licenses/ftl.txt
generated
vendored
169
Godeps/_workspace/src/code.google.com/p/freetype-go/licenses/ftl.txt
generated
vendored
@@ -1,169 +0,0 @@
|
||||
The FreeType Project LICENSE
|
||||
----------------------------
|
||||
|
||||
2006-Jan-27
|
||||
|
||||
Copyright 1996-2002, 2006 by
|
||||
David Turner, Robert Wilhelm, and Werner Lemberg
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The FreeType Project is distributed in several archive packages;
|
||||
some of them may contain, in addition to the FreeType font engine,
|
||||
various tools and contributions which rely on, or relate to, the
|
||||
FreeType Project.
|
||||
|
||||
This license applies to all files found in such packages, and
|
||||
which do not fall under their own explicit license. The license
|
||||
affects thus the FreeType font engine, the test programs,
|
||||
documentation and makefiles, at the very least.
|
||||
|
||||
This license was inspired by the BSD, Artistic, and IJG
|
||||
(Independent JPEG Group) licenses, which all encourage inclusion
|
||||
and use of free software in commercial and freeware products
|
||||
alike. As a consequence, its main points are that:
|
||||
|
||||
o We don't promise that this software works. However, we will be
|
||||
interested in any kind of bug reports. (`as is' distribution)
|
||||
|
||||
o You can use this software for whatever you want, in parts or
|
||||
full form, without having to pay us. (`royalty-free' usage)
|
||||
|
||||
o You may not pretend that you wrote this software. If you use
|
||||
it, or only parts of it, in a program, you must acknowledge
|
||||
somewhere in your documentation that you have used the
|
||||
FreeType code. (`credits')
|
||||
|
||||
We specifically permit and encourage the inclusion of this
|
||||
software, with or without modifications, in commercial products.
|
||||
We disclaim all warranties covering The FreeType Project and
|
||||
assume no liability related to The FreeType Project.
|
||||
|
||||
|
||||
Finally, many people asked us for a preferred form for a
|
||||
credit/disclaimer to use in compliance with this license. We thus
|
||||
encourage you to use the following text:
|
||||
|
||||
"""
|
||||
Portions of this software are copyright <20> <year> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
"""
|
||||
|
||||
Please replace <year> with the value from the FreeType version you
|
||||
actually use.
|
||||
|
||||
|
||||
Legal Terms
|
||||
===========
|
||||
|
||||
0. Definitions
|
||||
--------------
|
||||
|
||||
Throughout this license, the terms `package', `FreeType Project',
|
||||
and `FreeType archive' refer to the set of files originally
|
||||
distributed by the authors (David Turner, Robert Wilhelm, and
|
||||
Werner Lemberg) as the `FreeType Project', be they named as alpha,
|
||||
beta or final release.
|
||||
|
||||
`You' refers to the licensee, or person using the project, where
|
||||
`using' is a generic term including compiling the project's source
|
||||
code as well as linking it to form a `program' or `executable'.
|
||||
This program is referred to as `a program using the FreeType
|
||||
engine'.
|
||||
|
||||
This license applies to all files distributed in the original
|
||||
FreeType Project, including all source code, binaries and
|
||||
documentation, unless otherwise stated in the file in its
|
||||
original, unmodified form as distributed in the original archive.
|
||||
If you are unsure whether or not a particular file is covered by
|
||||
this license, you must contact us to verify this.
|
||||
|
||||
The FreeType Project is copyright (C) 1996-2000 by David Turner,
|
||||
Robert Wilhelm, and Werner Lemberg. All rights reserved except as
|
||||
specified below.
|
||||
|
||||
1. No Warranty
|
||||
--------------
|
||||
|
||||
THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
|
||||
USE, OF THE FREETYPE PROJECT.
|
||||
|
||||
2. Redistribution
|
||||
-----------------
|
||||
|
||||
This license grants a worldwide, royalty-free, perpetual and
|
||||
irrevocable right and license to use, execute, perform, compile,
|
||||
display, copy, create derivative works of, distribute and
|
||||
sublicense the FreeType Project (in both source and object code
|
||||
forms) and derivative works thereof for any purpose; and to
|
||||
authorize others to exercise some or all of the rights granted
|
||||
herein, subject to the following conditions:
|
||||
|
||||
o Redistribution of source code must retain this license file
|
||||
(`FTL.TXT') unaltered; any additions, deletions or changes to
|
||||
the original files must be clearly indicated in accompanying
|
||||
documentation. The copyright notices of the unaltered,
|
||||
original files must be preserved in all copies of source
|
||||
files.
|
||||
|
||||
o Redistribution in binary form must provide a disclaimer that
|
||||
states that the software is based in part of the work of the
|
||||
FreeType Team, in the distribution documentation. We also
|
||||
encourage you to put an URL to the FreeType web page in your
|
||||
documentation, though this isn't mandatory.
|
||||
|
||||
These conditions apply to any software derived from or based on
|
||||
the FreeType Project, not just the unmodified files. If you use
|
||||
our work, you must acknowledge us. However, no fee need be paid
|
||||
to us.
|
||||
|
||||
3. Advertising
|
||||
--------------
|
||||
|
||||
Neither the FreeType authors and contributors nor you shall use
|
||||
the name of the other for commercial, advertising, or promotional
|
||||
purposes without specific prior written permission.
|
||||
|
||||
We suggest, but do not require, that you use one or more of the
|
||||
following phrases to refer to this software in your documentation
|
||||
or advertising materials: `FreeType Project', `FreeType Engine',
|
||||
`FreeType library', or `FreeType Distribution'.
|
||||
|
||||
As you have not signed this license, you are not required to
|
||||
accept it. However, as the FreeType Project is copyrighted
|
||||
material, only this license, or another one contracted with the
|
||||
authors, grants you the right to use, distribute, and modify it.
|
||||
Therefore, by using, distributing, or modifying the FreeType
|
||||
Project, you indicate that you understand and accept all the terms
|
||||
of this license.
|
||||
|
||||
4. Contacts
|
||||
-----------
|
||||
|
||||
There are two mailing lists related to FreeType:
|
||||
|
||||
o freetype@nongnu.org
|
||||
|
||||
Discusses general use and applications of FreeType, as well as
|
||||
future and wanted additions to the library and distribution.
|
||||
If you are looking for support, start in this list if you
|
||||
haven't found anything to help you in the documentation.
|
||||
|
||||
o freetype-devel@nongnu.org
|
||||
|
||||
Discusses bugs, as well as engine internals, design issues,
|
||||
specific licenses, porting, etc.
|
||||
|
||||
Our home page can be found at
|
||||
|
||||
http://www.freetype.org
|
||||
|
||||
|
||||
--- end of FTL.TXT ---
|
||||
340
Godeps/_workspace/src/code.google.com/p/freetype-go/licenses/gpl.txt
generated
vendored
340
Godeps/_workspace/src/code.google.com/p/freetype-go/licenses/gpl.txt
generated
vendored
@@ -1,340 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
42
Godeps/_workspace/src/code.google.com/p/freetype-go/testdata/COPYING
generated
vendored
42
Godeps/_workspace/src/code.google.com/p/freetype-go/testdata/COPYING
generated
vendored
@@ -1,42 +0,0 @@
|
||||
Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font
|
||||
instruction code copyright (c) 2001 by URW++ GmbH. All Rights
|
||||
Reserved. Luxi is a registered trademark of Bigelow & Holmes Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of these Fonts and associated documentation files (the "Font
|
||||
Software"), to deal in the Font Software, including without
|
||||
limitation the rights to use, copy, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software.
|
||||
|
||||
The Font Software may not be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may not
|
||||
be modified nor may additional glyphs or characters be added to the
|
||||
Fonts. This License becomes null and void when the Fonts or Font
|
||||
Software have been modified.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
BIGELOW & HOLMES INC. OR URW++ GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
|
||||
INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
|
||||
SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Bigelow & Holmes
|
||||
Inc. and URW++ GmbH. shall not be used in advertising or otherwise to
|
||||
promote the sale, use or other dealings in this Font Software without
|
||||
prior written authorization from Bigelow & Holmes Inc. and URW++ GmbH.
|
||||
|
||||
For further information, contact:
|
||||
|
||||
info@urwpp.de
|
||||
or
|
||||
design@bigelowandholmes.com
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user