From 84d2482ddbff9564c9ad75b2d30af66e3ddfd44d Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 12 May 2016 15:08:58 -0400 Subject: Updating go depencancies. Switching to go1.6 vendoring (#2949) --- .../src/github.com/golang/freetype/AUTHORS | 18 - .../src/github.com/golang/freetype/CONTRIBUTORS | 36 - .../src/github.com/golang/freetype/LICENSE | 12 - .../src/github.com/golang/freetype/README | 21 - .../golang/freetype/cmd/print-glyph-points/main.c | 87 - .../golang/freetype/example/drawer/main.go | 157 -- .../golang/freetype/example/freetype/main.go | 149 -- .../golang/freetype/example/gamma/main.go | 85 - .../golang/freetype/example/raster/main.go | 184 -- .../golang/freetype/example/round/main.go | 109 -- .../golang/freetype/example/truetype/main.go | 80 - .../src/github.com/golang/freetype/freetype.go | 341 ---- .../github.com/golang/freetype/licenses/ftl.txt | 169 -- .../github.com/golang/freetype/licenses/gpl.txt | 340 ---- .../src/github.com/golang/freetype/raster/geom.go | 245 --- .../src/github.com/golang/freetype/raster/paint.go | 287 ---- .../github.com/golang/freetype/raster/raster.go | 601 ------- .../github.com/golang/freetype/raster/stroke.go | 483 ------ .../github.com/golang/freetype/truetype/face.go | 495 ------ .../github.com/golang/freetype/truetype/glyph.go | 517 ------ .../github.com/golang/freetype/truetype/hint.go | 1763 -------------------- .../github.com/golang/freetype/truetype/opcodes.go | 289 ---- .../golang/freetype/truetype/truetype.go | 639 ------- 23 files changed, 7107 deletions(-) delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/AUTHORS delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/CONTRIBUTORS delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/LICENSE delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/README delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/cmd/print-glyph-points/main.c delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/drawer/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/freetype/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/gamma/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/raster/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/round/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/example/truetype/main.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/freetype.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/licenses/ftl.txt delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/licenses/gpl.txt delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/raster/geom.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/raster/paint.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/raster/raster.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/raster/stroke.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go delete mode 100644 Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go (limited to 'Godeps/_workspace/src/github.com/golang/freetype') diff --git a/Godeps/_workspace/src/github.com/golang/freetype/AUTHORS b/Godeps/_workspace/src/github.com/golang/freetype/AUTHORS deleted file mode 100644 index 7b70f7768..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/AUTHORS +++ /dev/null @@ -1,18 +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 -# The email address is not required for organizations. - -# Please keep the list sorted. - -Google Inc. -Jeff R. Allen -Rémy Oudompheng -Roger Peppe -Steven Edwards diff --git a/Godeps/_workspace/src/github.com/golang/freetype/CONTRIBUTORS b/Godeps/_workspace/src/github.com/golang/freetype/CONTRIBUTORS deleted file mode 100644 index 7494b12c3..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/CONTRIBUTORS +++ /dev/null @@ -1,36 +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 - -# Please keep the list sorted. - -Andrew Gerrand -Jeff R. Allen -Nigel Tao -Rémy Oudompheng -Rob Pike -Roger Peppe -Russ Cox -Steven Edwards diff --git a/Godeps/_workspace/src/github.com/golang/freetype/LICENSE b/Godeps/_workspace/src/github.com/golang/freetype/LICENSE deleted file mode 100644 index e854ba5db..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/LICENSE +++ /dev/null @@ -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. diff --git a/Godeps/_workspace/src/github.com/golang/freetype/README b/Godeps/_workspace/src/github.com/golang/freetype/README deleted file mode 100644 index 39b3d8250..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/README +++ /dev/null @@ -1,21 +0,0 @@ -The Freetype font rasterizer in the Go programming language. - -To download and install from source: -$ go get github.com/golang/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 26.6 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. - -Unless otherwise noted, the Freetype-Go source files are distributed -under the BSD-style license found in the LICENSE file. diff --git a/Godeps/_workspace/src/github.com/golang/freetype/cmd/print-glyph-points/main.c b/Godeps/_workspace/src/github.com/golang/freetype/cmd/print-glyph-points/main.c deleted file mode 100644 index 6e821e892..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/cmd/print-glyph-points/main.c +++ /dev/null @@ -1,87 +0,0 @@ -/* -gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxisr.ttf with_hinting -*/ - -#include -#include -#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; -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/drawer/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/drawer/main.go deleted file mode 100644 index 4af981f9f..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/drawer/main.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2015 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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -package main - -import ( - "bufio" - "flag" - "fmt" - "image" - "image/color" - "image/draw" - "image/png" - "io/ioutil" - "log" - "math" - "os" - - "github.com/golang/freetype/truetype" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -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") -) - -const title = "Jabberwocky" - -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 - } - f, err := truetype.Parse(fontBytes) - if err != nil { - log.Println(err) - return - } - - // Draw the background and the guidelines. - 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} - } - const imgW, imgH = 640, 480 - rgba := image.NewRGBA(image.Rect(0, 0, imgW, imgH)) - draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) - for i := 0; i < 200; i++ { - rgba.Set(10, 10+i, ruler) - rgba.Set(10+i, 10, ruler) - } - - // Draw the text. - h := font.HintingNone - switch *hinting { - case "full": - h = font.HintingFull - } - d := &font.Drawer{ - Dst: rgba, - Src: fg, - Face: truetype.NewFace(f, &truetype.Options{ - Size: *size, - DPI: *dpi, - Hinting: h, - }), - } - y := 10 + int(math.Ceil(*size**dpi/72)) - dy := int(math.Ceil(*size * *spacing * *dpi / 72)) - d.Dot = fixed.Point26_6{ - X: (fixed.I(imgW) - d.MeasureString(title)) / 2, - Y: fixed.I(y), - } - d.DrawString(title) - y += dy - for _, s := range text { - d.Dot = fixed.P(10, y) - d.DrawString(s) - y += dy - } - - // Save that RGBA image to disk. - outFile, err := os.Create("out.png") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer outFile.Close() - b := bufio.NewWriter(outFile) - 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.") -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/freetype/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/freetype/main.go deleted file mode 100644 index 21657a381..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/freetype/main.go +++ /dev/null @@ -1,149 +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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -package main - -import ( - "bufio" - "flag" - "fmt" - "image" - "image/color" - "image/draw" - "image/png" - "io/ioutil" - "log" - "os" - - "github.com/golang/freetype" - "golang.org/x/image/font" -) - -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 - } - f, 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(f) - c.SetFontSize(*size) - c.SetClip(rgba.Bounds()) - c.SetDst(rgba) - c.SetSrc(fg) - switch *hinting { - default: - c.SetHinting(font.HintingNone) - case "full": - c.SetHinting(font.HintingFull) - } - - // 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.PointToFixed(*size)>>6)) - for _, s := range text { - _, err = c.DrawString(s, pt) - if err != nil { - log.Println(err) - return - } - pt.Y += c.PointToFixed(*size * *spacing) - } - - // Save that RGBA image to disk. - outFile, err := os.Create("out.png") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer outFile.Close() - b := bufio.NewWriter(outFile) - 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.") -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/gamma/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/gamma/main.go deleted file mode 100644 index 778697f4f..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/gamma/main.go +++ /dev/null @@ -1,85 +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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -package main - -import ( - "bufio" - "fmt" - "image" - "image/draw" - "image/png" - "log" - "os" - - "github.com/golang/freetype/raster" - "golang.org/x/image/math/fixed" -) - -func p(x, y int) fixed.Point26_6 { - return fixed.Point26_6{ - X: fixed.Int26_6(x * 64), - Y: fixed.Int26_6(y * 64), - } -} - -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. - outFile, err := os.Create("out.png") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer outFile.Close() - b := bufio.NewWriter(outFile) - 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.") -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/raster/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/raster/main.go deleted file mode 100644 index ae9c57f97..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/raster/main.go +++ /dev/null @@ -1,184 +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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -package main - -import ( - "bufio" - "fmt" - "image" - "image/color" - "image/draw" - "image/png" - "log" - "os" - - "github.com/golang/freetype/raster" - "golang.org/x/image/math/fixed" -) - -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) fixed.Point26_6 { - x, y := 20+n.x/4, 380-n.y/4 - return fixed.Point26_6{ - X: fixed.Int26_6(x << 6), - Y: fixed.Int26_6(y << 6), - } -} - -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)/64, int(p.Y)/64 - 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. - outFile, err := os.Create("out.png") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer outFile.Close() - b := bufio.NewWriter(outFile) - 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.") -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/round/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/round/main.go deleted file mode 100644 index 6c3012e62..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/round/main.go +++ /dev/null @@ -1,109 +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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -// 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" - - "github.com/golang/freetype/raster" - "golang.org/x/image/math/fixed" -) - -// pDot returns the dot product p·q. -func pDot(p, q fixed.Point26_6) fixed.Int52_12 { - px, py := int64(p.X), int64(p.Y) - qx, qy := int64(q.X), int64(q.Y) - return fixed.Int52_12(px*qx + py*qy) -} - -func main() { - const ( - n = 17 - r = 64 * 80 - ) - s := fixed.Int26_6(r * math.Sqrt(2) / 2) - t := fixed.Int26_6(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 := fixed.Int26_6(6400 + 12800*(i%4)) - cy := fixed.Int26_6(640 + 8000*(i/4)) - c := fixed.Point26_6{X: cx, Y: cy} - theta := math.Pi * (0.5 + 0.5*float64(i)/(n-1)) - dx := fixed.Int26_6(r * math.Cos(theta)) - dy := fixed.Int26_6(r * math.Sin(theta)) - d := fixed.Point26_6{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(fixed.Point26_6{X: r, Y: 0})) - z.Add2(c.Add(fixed.Point26_6{X: r, Y: t}), c.Add(fixed.Point26_6{X: s, Y: s})) - z.Add2(c.Add(fixed.Point26_6{X: t, Y: r}), c.Add(fixed.Point26_6{X: 0, Y: r})) - // Add another quadratic segment whose angle ranges between 0 and 90 - // degrees. For an explanation of the magic constants 128, 150, 181 and - // 256, read the comments in the freetype/raster package. - dot := 256 * pDot(d, fixed.Point26_6{X: 0, Y: r}) / (r * r) - multiple := fixed.Int26_6(150-(150-128)*(dot-181)/(256-181)) >> 2 - z.Add2(c.Add(fixed.Point26_6{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 := fixed.Int26_6(6400 + 12800*(i%4)) - cy := fixed.Int26_6(640 + 8000*(i/4)) - for j := 0; j < n; j++ { - theta := math.Pi * float64(j) / (n - 1) - dx := fixed.Int26_6(r * math.Cos(theta)) - dy := fixed.Int26_6(r * math.Sin(theta)) - m.Set(int((cx+dx)/64), int((cy+dy)/64), color.RGBA{255, 255, 0, 255}) - } - } - - // Save that RGBA image to disk. - outFile, err := os.Create("out.png") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer outFile.Close() - b := bufio.NewWriter(outFile) - 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.") -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/example/truetype/main.go b/Godeps/_workspace/src/github.com/golang/freetype/example/truetype/main.go deleted file mode 100644 index 5fc72f771..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/example/truetype/main.go +++ /dev/null @@ -1,80 +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. - -// +build ignore -// -// This build tag means that "go install github.com/golang/freetype/..." -// doesn't install this example program. Use "go run main.go" to run it. - -package main - -import ( - "flag" - "fmt" - "io/ioutil" - "log" - - "github.com/golang/freetype/truetype" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font") - -func printBounds(b fixed.Rectangle26_6) { - fmt.Printf("Min.X:%d Min.Y:%d Max.X:%d Max.Y:%d\n", b.Min.X, b.Min.Y, b.Max.X, b.Max.Y) -} - -func printGlyph(g *truetype.GlyphBuf) { - printBounds(g.Bounds) - fmt.Print("Points:\n---\n") - e := 0 - for i, p := range g.Points { - 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.Ends[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 - } - f, err := truetype.Parse(b) - if err != nil { - log.Println(err) - return - } - fupe := fixed.Int26_6(f.FUnitsPerEm()) - printBounds(f.Bounds(fupe)) - fmt.Printf("FUnitsPerEm:%d\n\n", fupe) - - c0, c1 := 'A', 'V' - - i0 := f.Index(c0) - hm := f.HMetric(fupe, i0) - g := &truetype.GlyphBuf{} - err = g.Load(f, fupe, i0, font.HintingNone) - 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 := f.Index(c1) - fmt.Printf("\n'%c', '%c' Kern:%d\n", c0, c1, f.Kern(fupe, i0, i1)) -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/freetype.go b/Godeps/_workspace/src/github.com/golang/freetype/freetype.go deleted file mode 100644 index bec01f6b7..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/freetype.go +++ /dev/null @@ -1,341 +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" - - "github.com/golang/freetype/raster" - "github.com/golang/freetype/truetype" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -// 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 fixed.Int26_6 - 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 fixed.Point26_6 -// co-ordinate pair measured in fixed.Int26_6 units. -func Pt(x, y int) fixed.Point26_6 { - return fixed.Point26_6{ - X: fixed.Int26_6(x << 6), - Y: fixed.Int26_6(y << 6), - } -} - -// A Context holds the state for drawing text in a given font and size. -type Context struct { - r *raster.Rasterizer - f *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 fixed.Int26_6 - hinting font.Hinting - // cache is the glyph cache. - cache [nGlyphs * nXFractions * nYFractions]cacheEntry -} - -// PointToFixed converts the given number of points (as in "a 12 point font") -// into a 26.6 fixed point number of pixels. -func (c *Context) PointToFixed(x float64) fixed.Int26_6 { - return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0)) -} - -// drawContour draws the given closed contour with the given offset. -func (c *Context) drawContour(ps []truetype.Point, dx, dy fixed.Int26_6) { - 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 := fixed.Point26_6{ - X: dx + ps[0].X, - Y: dy - ps[0].Y, - } - others := []truetype.Point(nil) - if ps[0].Flags&0x01 != 0 { - others = ps[1:] - } else { - last := fixed.Point26_6{ - X: dx + ps[len(ps)-1].X, - Y: dy - ps[len(ps)-1].Y, - } - if ps[len(ps)-1].Flags&0x01 != 0 { - start = last - others = ps[:len(ps)-1] - } else { - start = fixed.Point26_6{ - 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 := fixed.Point26_6{ - X: dx + p.X, - Y: dy - p.Y, - } - 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 := fixed.Point26_6{ - 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 26.6 fixed point arguments fx and fy must be in the range [0, 1). -func (c *Context) rasterize(glyph truetype.Index, fx, fy fixed.Int26_6) ( - fixed.Int26_6, *image.Alpha, image.Point, error) { - - if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil { - return 0, nil, image.Point{}, err - } - // Calculate the integer-pixel bounds for the glyph. - xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6 - ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6 - xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6 - ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6 - 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 -= fixed.Int26_6(xmin << 6) - fy -= fixed.Int26_6(ymin << 6) - // Rasterize the glyph's vectors. - c.r.Clear() - e0 := 0 - for _, e1 := range c.glyphBuf.Ends { - c.drawContour(c.glyphBuf.Points[e0:e1], fx, fy) - e0 = e1 - } - a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) - c.r.Rasterize(raster.NewAlphaSrcPainter(a)) - return c.glyphBuf.AdvanceWidth, 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 fixed.Point26_6) ( - fixed.Int26_6, *image.Alpha, image.Point, error) { - - // Split p.X and p.Y into their integer and fractional parts. - ix, fx := int(p.X>>6), p.X&0x3f - iy, fy := int(p.Y>>6), p.Y&0x3f - // Calculate the index t into the cache array. - tg := int(glyph) % nGlyphs - tx := int(fx) / (64 / nXFractions) - ty := int(fy) / (64 / 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 fixed.Point26_6 and can therefore represent sub-pixel positions. -func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, error) { - if c.f == nil { - return fixed.Point26_6{}, errors.New("freetype: DrawText called with a nil font") - } - prev, hasPrev := truetype.Index(0), false - for _, rune := range s { - index := c.f.Index(rune) - if hasPrev { - kern := c.f.Kern(c.scale, prev, index) - if c.hinting != font.HintingNone { - kern = (kern + 32) &^ 63 - } - p.X += kern - } - advanceWidth, mask, offset, err := c.glyph(index, p) - if err != nil { - return fixed.Point26_6{}, 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 = fixed.Int26_6(c.fontSize * c.dpi * (64.0 / 72.0)) - if c.f == nil { - c.r.SetBounds(0, 0) - } else { - // Set the rasterizer's bounds to be big enough to handle the largest glyph. - b := c.f.Bounds(c.scale) - xmin := +int(b.Min.X) >> 6 - ymin := -int(b.Max.Y) >> 6 - xmax := +int(b.Max.X+63) >> 6 - ymax := -int(b.Min.Y-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(f *truetype.Font) { - if c.f == f { - return - } - c.f = f - 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 font.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), - fontSize: 12, - dpi: 72, - scale: 12 << 6, - } -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/licenses/ftl.txt b/Godeps/_workspace/src/github.com/golang/freetype/licenses/ftl.txt deleted file mode 100644 index bbaba33f4..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/licenses/ftl.txt +++ /dev/null @@ -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 The FreeType - Project (www.freetype.org). All rights reserved. - """ - - Please replace 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 --- diff --git a/Godeps/_workspace/src/github.com/golang/freetype/licenses/gpl.txt b/Godeps/_workspace/src/github.com/golang/freetype/licenses/gpl.txt deleted file mode 100644 index b2fe7b6af..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/licenses/gpl.txt +++ /dev/null @@ -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. - - - Copyright (C) - - 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. - - , 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. diff --git a/Godeps/_workspace/src/github.com/golang/freetype/raster/geom.go b/Godeps/_workspace/src/github.com/golang/freetype/raster/geom.go deleted file mode 100644 index f3696ea98..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/raster/geom.go +++ /dev/null @@ -1,245 +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" - - "golang.org/x/image/math/fixed" -) - -// maxAbs returns the maximum of abs(a) and abs(b). -func maxAbs(a, b fixed.Int26_6) fixed.Int26_6 { - if a < 0 { - a = -a - } - if b < 0 { - b = -b - } - if a < b { - return b - } - return a -} - -// pNeg returns the vector -p, or equivalently p rotated by 180 degrees. -func pNeg(p fixed.Point26_6) fixed.Point26_6 { - return fixed.Point26_6{-p.X, -p.Y} -} - -// pDot returns the dot product p·q. -func pDot(p fixed.Point26_6, q fixed.Point26_6) fixed.Int52_12 { - px, py := int64(p.X), int64(p.Y) - qx, qy := int64(q.X), int64(q.Y) - return fixed.Int52_12(px*qx + py*qy) -} - -// pLen returns the length of the vector p. -func pLen(p fixed.Point26_6) fixed.Int26_6 { - // TODO(nigeltao): use fixed point math. - x := float64(p.X) - y := float64(p.Y) - return fixed.Int26_6(math.Sqrt(x*x + y*y)) -} - -// pNorm returns the vector p normalized to the given length, or zero if p is -// degenerate. -func pNorm(p fixed.Point26_6, length fixed.Int26_6) fixed.Point26_6 { - d := pLen(p) - if d == 0 { - return fixed.Point26_6{} - } - s, t := int64(length), int64(d) - x := int64(p.X) * s / t - y := int64(p.Y) * s / t - return fixed.Point26_6{fixed.Int26_6(x), fixed.Int26_6(y)} -} - -// pRot45CW 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 pRot45CW(p fixed.Point26_6) fixed.Point26_6 { - // 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 fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} -} - -// pRot90CW returns the vector p rotated clockwise by 90 degrees. -// -// Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}. -func pRot90CW(p fixed.Point26_6) fixed.Point26_6 { - return fixed.Point26_6{-p.Y, p.X} -} - -// pRot135CW 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 pRot135CW(p fixed.Point26_6) fixed.Point26_6 { - // 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 fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} -} - -// pRot45CCW 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 pRot45CCW(p fixed.Point26_6) fixed.Point26_6 { - // 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 fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} -} - -// pRot90CCW 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 pRot90CCW(p fixed.Point26_6) fixed.Point26_6 { - return fixed.Point26_6{p.Y, -p.X} -} - -// pRot135CCW 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 pRot135CCW(p fixed.Point26_6) fixed.Point26_6 { - // 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 fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} -} - -// An Adder accumulates points on a curve. -type Adder interface { - // Start starts a new curve at the given point. - Start(a fixed.Point26_6) - // Add1 adds a linear segment to the current curve. - Add1(b fixed.Point26_6) - // Add2 adds a quadratic segment to the current curve. - Add2(b, c fixed.Point26_6) - // Add3 adds a cubic segment to the current curve. - Add3(b, c, d fixed.Point26_6) -} - -// 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 []fixed.Int26_6 - -// 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([]fixed.Int26_6(p[i+1:i+3])) - i += 4 - case 1: - s += "A1" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+3])) - i += 4 - case 2: - s += "A2" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+5])) - i += 6 - case 3: - s += "A3" + fmt.Sprint([]fixed.Int26_6(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 fixed.Point26_6) { - *p = append(*p, 0, a.X, a.Y, 0) -} - -// Add1 adds a linear segment to the current curve. -func (p *Path) Add1(b fixed.Point26_6) { - *p = append(*p, 1, b.X, b.Y, 1) -} - -// Add2 adds a quadratic segment to the current curve. -func (p *Path) Add2(b, c fixed.Point26_6) { - *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 fixed.Point26_6) { - *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 fixed.Int26_6, cr Capper, jr Joiner) { - Stroke(p, q, width, cr, jr) -} - -// firstPoint returns the first point in a non-empty Path. -func (p Path) firstPoint() fixed.Point26_6 { - return fixed.Point26_6{p[1], p[2]} -} - -// lastPoint returns the last point in a non-empty Path. -func (p Path) lastPoint() fixed.Point26_6 { - return fixed.Point26_6{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( - fixed.Point26_6{q[i-2], q[i-1]}, - ) - case 2: - i -= 6 - p.Add2( - fixed.Point26_6{q[i+2], q[i+3]}, - fixed.Point26_6{q[i-2], q[i-1]}, - ) - case 3: - i -= 8 - p.Add3( - fixed.Point26_6{q[i+4], q[i+5]}, - fixed.Point26_6{q[i+2], q[i+3]}, - fixed.Point26_6{q[i-2], q[i-1]}, - ) - default: - panic("freetype/raster: bad path") - } - } -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/raster/paint.go b/Godeps/_workspace/src/github.com/golang/freetype/raster/paint.go deleted file mode 100644 index 185d36a8e..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/raster/paint.go +++ /dev/null @@ -1,287 +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 Alpha == 0xffff. -type Span struct { - Y, X0, X1 int - Alpha 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 a *image.Alpha using -// the Over Porter-Duff composition operator. -type AlphaOverPainter struct { - Image *image.Alpha -} - -// Paint satisfies the Painter interface. -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.Alpha >> 8) - 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 a *image.Alpha using -// the Src Porter-Duff composition operator. -type AlphaSrcPainter struct { - Image *image.Alpha -} - -// Paint satisfies the Painter interface. -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.Alpha >> 8) - 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} -} - -// An RGBAPainter is a Painter that paints Spans onto a *image.RGBA. -type RGBAPainter struct { - // Image is the image to compose onto. - Image *image.RGBA - // Op is the Porter-Duff composition operator. - Op draw.Op - // cr, cg, cb and ca are the 16-bit color to paint the spans. - cr, cg, cb, ca uint32 -} - -// Paint satisfies the Painter interface. -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 mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go. - ma := s.Alpha - 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.Alpha >= 0x8000 { - 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 { - // Painter is the wrapped Painter. - Painter Painter - // a is the precomputed alpha values for linear interpolation, with fully - // opaque == 0xffff. - a [256]uint16 - // gammaIsOne is 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 n = 0x101 - for i, s := range ss { - if s.Alpha == 0 || s.Alpha == 0xffff { - continue - } - p, q := s.Alpha/n, s.Alpha%n - // 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 - ss[i].Alpha = (a + n/2) / n - } - } - g.Painter.Paint(ss, done) -} - -// SetGamma sets the gamma value. -func (g *GammaCorrectionPainter) SetGamma(gamma float64) { - g.gammaIsOne = gamma == 1 - if g.gammaIsOne { - return - } - 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 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/raster/raster.go b/Godeps/_workspace/src/github.com/golang/freetype/raster/raster.go deleted file mode 100644 index 995925e2a..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/raster/raster.go +++ /dev/null @@ -1,601 +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 provides an anti-aliasing 2-D rasterizer. -// -// It is part of the larger Freetype suite of font-related packages, but the -// raster package is not specific to font rasterization, and can be used -// standalone without any other Freetype 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" - - "golang.org/x/image/math/fixed" -) - -// 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 fixed.Point26_6 - // 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 26.6 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 fixed.Int26_6) { - // Break the 26.6 fixed point X co-ordinates into integral and fractional parts. - x0i := int(x0) / 64 - x0f := x0 - fixed.Int26_6(64*x0i) - x1i := int(x1) / 64 - x1f := x1 - fixed.Int26_6(64*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 64 units in 26.6 fixed point format. - var ( - p, q, edge0, edge1 fixed.Int26_6 - xiDelta int - ) - if dx > 0 { - p, q = (64-x0f)*dy, dx - edge0, edge1, xiDelta = 0, 64, 1 - } else { - p, q = x0f*dy, -dx - edge0, edge1, xiDelta = 64, 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 = 64 * (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(64 * 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 fixed.Point26_6) { - r.setCell(int(a.X/64), int(a.Y/64)) - r.a = a -} - -// Add1 adds a linear segment to the current curve. -func (r *Rasterizer) Add1(b fixed.Point26_6) { - x0, y0 := r.a.X, r.a.Y - x1, y1 := b.X, b.Y - dx, dy := x1-x0, y1-y0 - // Break the 26.6 fixed point Y co-ordinates into integral and fractional - // parts. - y0i := int(y0) / 64 - y0f := y0 - fixed.Int26_6(64*y0i) - y1i := int(y1) / 64 - y1f := y1 - fixed.Int26_6(64*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 fixed.Int26_6 - yiDelta int - ) - if dy > 0 { - edge0, edge1, yiDelta = 0, 64, 1 - } else { - edge0, edge1, yiDelta = 64, 0, -1 - } - x0i, yi := int(x0)/64, y0i - x0fTimes2 := (int(x0) - (64 * 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 64 units in 26.6 fixed point format. - var ( - p, q, edge0, edge1 fixed.Int26_6 - yiDelta int - ) - if dy > 0 { - p, q = (64-y0f)*dx, dy - edge0, edge1, yiDelta = 0, 64, 1 - } else { - p, q = y0f*dx, -dy - edge0, edge1, yiDelta = 64, 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)/64, yi) - if yi != y1i { - // Do all the intermediate scanlines. - p = 64 * 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)/64, 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 fixed.Point26_6) { - // 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) / fixed.Int26_6(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]fixed.Point26_6 - 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(fixed.Point26_6{midx, midy}) - r.Add1(p[0]) - i-- - } - } -} - -// Add3 adds a cubic segment to the current curve. -func (r *Rasterizer) Add3(b, c, d fixed.Point26_6) { - // 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) / fixed.Int26_6(r.splitScale2) - dev3 := maxAbs(r.a.X-2*b.X+d.X, r.a.Y-2*b.Y+d.Y) / fixed.Int26_6(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]fixed.Point26_6 - 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(fixed.Point26_6{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( - fixed.Point26_6{p[i+1], p[i+2]}, - ) - i += 4 - case 1: - r.Add1( - fixed.Point26_6{p[i+1], p[i+2]}, - ) - i += 4 - case 2: - r.Add2( - fixed.Point26_6{p[i+1], p[i+2]}, - fixed.Point26_6{p[i+3], p[i+4]}, - ) - i += 6 - case 3: - r.Add3( - fixed.Point26_6{p[i+1], p[i+2]}, - fixed.Point26_6{p[i+3], p[i+4]}, - fixed.Point26_6{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 fixed.Int26_6, cr Capper, jr Joiner) { - Stroke(r, q, width, cr, jr) -} - -// areaToAlpha converts an area value to a uint32 alpha value. A completely -// filled pixel corresponds to an area of 64*64*2, and an alpha of 0xffff. 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 16-bit - // alpha. - a := (area + 1) >> 1 - if a < 0 { - a = -a - } - alpha := uint32(a) - if r.UseNonZeroWinding { - if alpha > 0x0fff { - alpha = 0x0fff - } - } else { - alpha &= 0x1fff - if alpha > 0x1000 { - alpha = 0x2000 - alpha - } else if alpha == 0x1000 { - alpha = 0x0fff - } - } - // alpha is now in the range [0x0000, 0x0fff]. Convert that 12-bit alpha to - // 16-bit alpha. - return alpha<<4 | alpha>>8 -} - -// 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 * 64 * 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*64*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 = fixed.Point26_6{} - 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 fixed.Int26_6 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 (version 2.4.0) - // implementation. - ss2, ss3 := 32, 16 - 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 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/raster/stroke.go b/Godeps/_workspace/src/github.com/golang/freetype/raster/stroke.go deleted file mode 100644 index 8d4379757..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/raster/stroke.go +++ /dev/null @@ -1,483 +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 ( - "golang.org/x/image/math/fixed" -) - -// Two points are considered practically equal if the square of the distance -// between them is less than one quarter (i.e. 1024 / 4096). -const epsilon = fixed.Int52_12(1024) - -// 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 fixed.Int26_6, pivot, n1 fixed.Point26_6) -} - -// The CapperFunc type adapts an ordinary function to be a Capper. -type CapperFunc func(Adder, fixed.Int26_6, fixed.Point26_6, fixed.Point26_6) - -func (f CapperFunc) Cap(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { - 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 fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) -} - -// The JoinerFunc type adapts an ordinary function to be a Joiner. -type JoinerFunc func(lhs, rhs Adder, halfWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) - -func (f JoinerFunc) Join(lhs, rhs Adder, halfWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { - 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 fixed.Int26_6, pivot, n1 fixed.Point26_6) { - // 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 := pRot90CCW(n1) - 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 fixed.Int26_6, pivot, n1 fixed.Point26_6) { - p.Add1(pivot.Add(n1)) -} - -// SquareCapper adds square caps to a stroked path. -var SquareCapper Capper = CapperFunc(squareCapper) - -func squareCapper(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { - e := pRot90CCW(n1) - 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 fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { - dot := pDot(pRot90CW(n0), n1) - if dot >= 0 { - addArc(lhs, pivot, n0, n1) - rhs.Add1(pivot.Sub(n1)) - } else { - lhs.Add1(pivot.Add(n1)) - addArc(rhs, pivot, pNeg(n0), pNeg(n1)) - } -} - -// BevelJoiner adds bevel joins to a stroked path. -var BevelJoiner Joiner = JoinerFunc(bevelJoiner) - -func bevelJoiner(lhs, rhs Adder, haflWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { - 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 fixed.Point26_6) { - // r2 is the square of the length of n0. - r2 := pDot(n0, 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 fixed.Point26_6 - // 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 := pRot45CW(n0) - m1 := pRot90CW(n0) - m2 := pRot90CW(m0) - if pDot(m1, n1) >= 0 { - if pDot(n0, n1) >= 0 { - if pDot(m2, 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 pDot(m0, 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 pDot(n0, n1) >= 0 { - if pDot(m0, 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 = pNeg(m2) - } - } 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 pDot(m2, n1) <= 0 { - // n1 is between 90 and 135 degrees counter-clockwise of n0. - s = pNeg(m1) - } else { - // n1 is between 135 and 180 degrees counter-clockwise of n0. - p.Add2(pm1.Sub(n0t), pivot.Sub(m0)) - s = pNeg(m0) - } - } - } - // 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 * pDot(s, n1) / r2 - multiple := fixed.Int26_6(150-(150-128)*(d-181)/(256-181)) >> 2 - p.Add2(pivot.Add(s.Add(n1).Mul(multiple)), pivot.Add(n1)) -} - -// midpoint returns the midpoint of two Points. -func midpoint(a, b fixed.Point26_6) fixed.Point26_6 { - return fixed.Point26_6{(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 fixed.Point26_6) bool { - v := pRot45CCW(v0) - return pDot(v, v1) < 0 || pDot(pRot90CW(v), v1) < 0 -} - -// interpolate returns the point (1-t)*a + t*b. -func interpolate(a, b fixed.Point26_6, t fixed.Int52_12) fixed.Point26_6 { - s := 1<<12 - t - x := s*fixed.Int52_12(a.X) + t*fixed.Int52_12(b.X) - y := s*fixed.Int52_12(a.Y) + t*fixed.Int52_12(b.Y) - return fixed.Point26_6{fixed.Int26_6(x >> 12), fixed.Int26_6(y >> 12)} -} - -// 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 fixed.Point26_6) fixed.Int52_12 { - 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 2048 - } - return fixed.Int52_12(-4096 * (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 fixed.Int26_6 - // 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 fixed.Point26_6 -} - -// 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 fixed.Point26_6) { - // 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]fixed.Point26_6 - 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 fixed.Point26_6 - - 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 := pDot(ab, ab) < fixed.Int52_12(1<<12) - bcIsSmall := pDot(bc, bc) < fixed.Int52_12(1<<12) - if abIsSmall && bcIsSmall { - // Approximate the segment by a circular arc. - cnorm = pRot90CCW(pNorm(bc, k.u)) - mac := midpoint(a, c) - addArc(k.p, mac, anorm, cnorm) - addArc(&k.r, mac, pNeg(anorm), pNeg(cnorm)) - } 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 := pRot90CCW(pNorm(c.Sub(a), k.u)) - cnorm = pRot90CCW(pNorm(bc, k.u)) - 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 fixed.Point26_6) { - bnorm := pRot90CCW(pNorm(b.Sub(k.a), k.u)) - 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 fixed.Point26_6) { - ab := b.Sub(k.a) - bc := c.Sub(b) - abnorm := pRot90CCW(pNorm(ab, k.u)) - 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 := pDot(ab, ab) < epsilon - bcIsSmall := pDot(bc, bc) < epsilon - if abIsSmall || bcIsSmall { - acnorm := pRot90CCW(pNorm(c.Sub(k.a), k.u)) - 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 || 4096 <= t { - 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 := pRot90CCW(pNorm(bc, k.u)) - if pDot(abnorm, bcnorm) < -fixed.Int52_12(k.u)*fixed.Int52_12(k.u)*2047/2048 { - pArc := pDot(abnorm, bc) < 0 - - k.p.Add1(mabc.Add(abnorm)) - if pArc { - z := pRot90CW(abnorm) - 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 := pRot90CW(abnorm) - addArc(&k.r, mabc, pNeg(abnorm), z) - addArc(&k.r, mabc, z, pNeg(bcnorm)) - } - 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 fixed.Point26_6) { - 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 = fixed.Point26_6{q[1], q[2]} - for i := 4; i < len(q); { - switch q[i] { - case 1: - k.Add1( - fixed.Point26_6{q[i+1], q[i+2]}, - ) - i += 4 - case 2: - k.Add2( - fixed.Point26_6{q[i+1], q[i+2]}, - fixed.Point26_6{q[i+3], q[i+4]}, - ) - i += 6 - case 3: - k.Add3( - fixed.Point26_6{q[i+1], q[i+2]}, - fixed.Point26_6{q[i+3], q[i+4]}, - fixed.Point26_6{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(), pNeg(k.anorm)) - addPathReversed(k.p, k.r) - pivot := q.firstPoint() - k.cr.Cap(k.p, k.u, pivot, pivot.Sub(fixed.Point26_6{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 fixed.Int26_6, 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:]) -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go deleted file mode 100644 index d64a014c3..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright 2015 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 ( - "image" - - "github.com/golang/freetype/raster" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -func powerOf2(i int) bool { - return i != 0 && (i&(i-1)) == 0 -} - -// Options are optional arguments to NewFace. -type Options struct { - // Size is the font size in points, as in "a 10 point font size". - // - // A zero value means to use a 12 point font size. - Size float64 - - // DPI is the dots-per-inch resolution. - // - // A zero value means to use 72 DPI. - DPI float64 - - // Hinting is how to quantize the glyph nodes. - // - // A zero value means to use no hinting. - Hinting font.Hinting - - // GlyphCacheEntries is the number of entries in the glyph mask image - // cache. - // - // If non-zero, it must be a power of 2. - // - // A zero value means to use 512 entries. - GlyphCacheEntries int - - // SubPixelsX is the number of sub-pixel locations a glyph's dot is - // quantized to, in the horizontal direction. For example, a value of 8 - // means that the dot is quantized to 1/8th of a pixel. This quantization - // only affects the glyph mask image, not its bounding box or advance - // width. A higher value gives a more faithful glyph image, but reduces the - // effectiveness of the glyph cache. - // - // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. - // - // A zero value means to use 4 sub-pixel locations. - SubPixelsX int - - // SubPixelsY is the number of sub-pixel locations a glyph's dot is - // quantized to, in the vertical direction. For example, a value of 8 - // means that the dot is quantized to 1/8th of a pixel. This quantization - // only affects the glyph mask image, not its bounding box or advance - // width. A higher value gives a more faithful glyph image, but reduces the - // effectiveness of the glyph cache. - // - // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. - // - // A zero value means to use 1 sub-pixel location. - SubPixelsY int -} - -func (o *Options) size() float64 { - if o != nil && o.Size > 0 { - return o.Size - } - return 12 -} - -func (o *Options) dpi() float64 { - if o != nil && o.DPI > 0 { - return o.DPI - } - return 72 -} - -func (o *Options) hinting() font.Hinting { - if o != nil { - switch o.Hinting { - case font.HintingVertical, font.HintingFull: - // TODO: support vertical hinting. - return font.HintingFull - } - } - return font.HintingNone -} - -func (o *Options) glyphCacheEntries() int { - if o != nil && powerOf2(o.GlyphCacheEntries) { - return o.GlyphCacheEntries - } - // 512 is 128 * 4 * 1, which lets us cache 128 glyphs at 4 * 1 subpixel - // locations in the X and Y direction. - return 512 -} - -func (o *Options) subPixelsX() (value uint32, halfQuantum, mask fixed.Int26_6) { - if o != nil { - switch o.SubPixelsX { - case 1, 2, 4, 8, 16, 32, 64: - return subPixels(o.SubPixelsX) - } - } - // This default value of 4 isn't based on anything scientific, merely as - // small a number as possible that looks almost as good as no quantization, - // or returning subPixels(64). - return subPixels(4) -} - -func (o *Options) subPixelsY() (value uint32, halfQuantum, mask fixed.Int26_6) { - if o != nil { - switch o.SubPixelsX { - case 1, 2, 4, 8, 16, 32, 64: - return subPixels(o.SubPixelsX) - } - } - // This default value of 1 isn't based on anything scientific, merely that - // vertical sub-pixel glyph rendering is pretty rare. Baseline locations - // can usually afford to snap to the pixel grid, so the vertical direction - // doesn't have the deal with the horizontal's fractional advance widths. - return subPixels(1) -} - -// subPixels returns q and the bias and mask that leads to q quantized -// sub-pixel locations per full pixel. -// -// For example, q == 4 leads to a bias of 8 and a mask of 0xfffffff0, or -16, -// because we want to round fractions of fixed.Int26_6 as: -// - 0 to 7 rounds to 0. -// - 8 to 23 rounds to 16. -// - 24 to 39 rounds to 32. -// - 40 to 55 rounds to 48. -// - 56 to 63 rounds to 64. -// which means to add 8 and then bitwise-and with -16, in two's complement -// representation. -// -// When q == 1, we want bias == 32 and mask == -64. -// When q == 2, we want bias == 16 and mask == -32. -// When q == 4, we want bias == 8 and mask == -16. -// ... -// When q == 64, we want bias == 0 and mask == -1. (The no-op case). -// The pattern is clear. -func subPixels(q int) (value uint32, bias, mask fixed.Int26_6) { - return uint32(q), 32 / fixed.Int26_6(q), -64 / fixed.Int26_6(q) -} - -// glyphCacheEntry caches the arguments and return values of rasterize. -type glyphCacheEntry struct { - key glyphCacheKey - val glyphCacheVal -} - -type glyphCacheKey struct { - index Index - fx, fy uint8 -} - -type glyphCacheVal struct { - advanceWidth fixed.Int26_6 - offset image.Point - gw int - gh int -} - -type indexCacheEntry struct { - rune rune - index Index -} - -// NewFace returns a new font.Face for the given Font. -func NewFace(f *Font, opts *Options) font.Face { - a := &face{ - f: f, - hinting: opts.hinting(), - scale: fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)), - glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()), - } - a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX() - a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY() - - // Fill the cache with invalid entries. Valid glyph cache entries have fx - // and fy in the range [0, 64). Valid index cache entries have rune >= 0. - for i := range a.glyphCache { - a.glyphCache[i].key.fy = 0xff - } - for i := range a.indexCache { - a.indexCache[i].rune = -1 - } - - // Set the rasterizer's bounds to be big enough to handle the largest glyph. - b := f.Bounds(a.scale) - xmin := +int(b.Min.X) >> 6 - ymin := -int(b.Max.Y) >> 6 - xmax := +int(b.Max.X+63) >> 6 - ymax := -int(b.Min.Y-63) >> 6 - a.maxw = xmax - xmin - a.maxh = ymax - ymin - a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache))) - a.r.SetBounds(a.maxw, a.maxh) - a.p = facePainter{a} - - return a -} - -type face struct { - f *Font - hinting font.Hinting - scale fixed.Int26_6 - subPixelX uint32 - subPixelBiasX fixed.Int26_6 - subPixelMaskX fixed.Int26_6 - subPixelY uint32 - subPixelBiasY fixed.Int26_6 - subPixelMaskY fixed.Int26_6 - masks *image.Alpha - glyphCache []glyphCacheEntry - r raster.Rasterizer - p raster.Painter - paintOffset int - maxw int - maxh int - glyphBuf GlyphBuf - indexCache [indexCacheLen]indexCacheEntry - - // TODO: clip rectangle? -} - -const indexCacheLen = 256 - -func (a *face) index(r rune) Index { - const mask = indexCacheLen - 1 - c := &a.indexCache[r&mask] - if c.rune == r { - return c.index - } - i := a.f.Index(r) - c.rune = r - c.index = i - return i -} - -// Close satisfies the font.Face interface. -func (a *face) Close() error { return nil } - -// Kern satisfies the font.Face interface. -func (a *face) Kern(r0, r1 rune) fixed.Int26_6 { - i0 := a.index(r0) - i1 := a.index(r1) - kern := a.f.Kern(a.scale, i0, i1) - if a.hinting != font.HintingNone { - kern = (kern + 32) &^ 63 - } - return kern -} - -// Glyph satisfies the font.Face interface. -func (a *face) Glyph(dot fixed.Point26_6, r rune) ( - dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { - - // Quantize to the sub-pixel granularity. - dotX := (dot.X + a.subPixelBiasX) & a.subPixelMaskX - dotY := (dot.Y + a.subPixelBiasY) & a.subPixelMaskY - - // Split the coordinates into their integer and fractional parts. - ix, fx := int(dotX>>6), dotX&0x3f - iy, fy := int(dotY>>6), dotY&0x3f - - index := a.index(r) - cIndex := uint32(index) - cIndex = cIndex*a.subPixelX - uint32(fx/a.subPixelMaskX) - cIndex = cIndex*a.subPixelY - uint32(fy/a.subPixelMaskY) - cIndex &= uint32(len(a.glyphCache) - 1) - a.paintOffset = a.maxh * int(cIndex) - k := glyphCacheKey{ - index: index, - fx: uint8(fx), - fy: uint8(fy), - } - var v glyphCacheVal - if a.glyphCache[cIndex].key != k { - var ok bool - v, ok = a.rasterize(index, fx, fy) - if !ok { - return image.Rectangle{}, nil, image.Point{}, 0, false - } - a.glyphCache[cIndex] = glyphCacheEntry{k, v} - } else { - v = a.glyphCache[cIndex].val - } - - dr.Min = image.Point{ - X: ix + v.offset.X, - Y: iy + v.offset.Y, - } - dr.Max = image.Point{ - X: dr.Min.X + v.gw, - Y: dr.Min.Y + v.gh, - } - return dr, a.masks, image.Point{Y: a.paintOffset}, v.advanceWidth, true -} - -func (a *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { - return fixed.Rectangle26_6{}, 0, false - } - xmin := +a.glyphBuf.Bounds.Min.X - ymin := -a.glyphBuf.Bounds.Max.Y - xmax := +a.glyphBuf.Bounds.Max.X - ymax := -a.glyphBuf.Bounds.Min.Y - if xmin > xmax || ymin > ymax { - return fixed.Rectangle26_6{}, 0, false - } - return fixed.Rectangle26_6{ - Min: fixed.Point26_6{ - X: xmin, - Y: ymin, - }, - Max: fixed.Point26_6{ - X: xmax, - Y: ymax, - }, - }, a.glyphBuf.AdvanceWidth, true -} - -func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { - return 0, false - } - return a.glyphBuf.AdvanceWidth, true -} - -// rasterize returns the advance width, integer-pixel offset to render at, and -// the width and height of the given glyph at the given sub-pixel offsets. -// -// The 26.6 fixed point arguments fx and fy must be in the range [0, 1). -func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) (v glyphCacheVal, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, index, a.hinting); err != nil { - return glyphCacheVal{}, false - } - // Calculate the integer-pixel bounds for the glyph. - xmin := int(fx+a.glyphBuf.Bounds.Min.X) >> 6 - ymin := int(fy-a.glyphBuf.Bounds.Max.Y) >> 6 - xmax := int(fx+a.glyphBuf.Bounds.Max.X+0x3f) >> 6 - ymax := int(fy-a.glyphBuf.Bounds.Min.Y+0x3f) >> 6 - if xmin > xmax || ymin > ymax { - return glyphCacheVal{}, false - } - // 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 -= fixed.Int26_6(xmin << 6) - fy -= fixed.Int26_6(ymin << 6) - // Rasterize the glyph's vectors. - a.r.Clear() - pixOffset := a.paintOffset * a.maxw - clear(a.masks.Pix[pixOffset : pixOffset+a.maxw*a.maxh]) - e0 := 0 - for _, e1 := range a.glyphBuf.Ends { - a.drawContour(a.glyphBuf.Points[e0:e1], fx, fy) - e0 = e1 - } - a.r.Rasterize(a.p) - return glyphCacheVal{ - a.glyphBuf.AdvanceWidth, - image.Point{xmin, ymin}, - xmax - xmin, - ymax - ymin, - }, true -} - -func clear(pix []byte) { - for i := range pix { - pix[i] = 0 - } -} - -// drawContour draws the given closed contour with the given offset. -func (a *face) drawContour(ps []Point, dx, dy fixed.Int26_6) { - 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 := fixed.Point26_6{ - X: dx + ps[0].X, - Y: dy - ps[0].Y, - } - var others []Point - if ps[0].Flags&0x01 != 0 { - others = ps[1:] - } else { - last := fixed.Point26_6{ - X: dx + ps[len(ps)-1].X, - Y: dy - ps[len(ps)-1].Y, - } - if ps[len(ps)-1].Flags&0x01 != 0 { - start = last - others = ps[:len(ps)-1] - } else { - start = fixed.Point26_6{ - X: (start.X + last.X) / 2, - Y: (start.Y + last.Y) / 2, - } - others = ps - } - } - a.r.Start(start) - q0, on0 := start, true - for _, p := range others { - q := fixed.Point26_6{ - X: dx + p.X, - Y: dy - p.Y, - } - on := p.Flags&0x01 != 0 - if on { - if on0 { - a.r.Add1(q) - } else { - a.r.Add2(q0, q) - } - } else { - if on0 { - // No-op. - } else { - mid := fixed.Point26_6{ - X: (q0.X + q.X) / 2, - Y: (q0.Y + q.Y) / 2, - } - a.r.Add2(q0, mid) - } - } - q0, on0 = q, on - } - // Close the curve. - if on0 { - a.r.Add1(start) - } else { - a.r.Add2(q0, start) - } -} - -// facePainter is like a raster.AlphaSrcPainter, with an additional Y offset -// (face.paintOffset) to the painted spans. -type facePainter struct { - a *face -} - -func (p facePainter) Paint(ss []raster.Span, done bool) { - m := p.a.masks - b := m.Bounds() - b.Min.Y = p.a.paintOffset - b.Max.Y = p.a.paintOffset + p.a.maxh - for _, s := range ss { - s.Y += p.a.paintOffset - 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-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X - p := m.Pix[base+s.X0 : base+s.X1] - color := uint8(s.Alpha >> 8) - for i := range p { - p[i] = color - } - } -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go deleted file mode 100644 index c2935a58e..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go +++ /dev/null @@ -1,517 +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 - -import ( - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -// 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 fixed.Int26_6 - // 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 fixed.Int26_6 - // Bounds is the glyph's bounding box. - Bounds fixed.Rectangle26_6 - // Points 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. - Points, Unhinted, InFontUnits []Point - // Ends is the point indexes of the end point of each contour. The length - // of Ends is the number of contours in the glyph. The i'th contour - // consists of points Points[Ends[i-1]:Ends[i]], where Ends[-1] is - // interpreted to mean zero. - Ends []int - - font *Font - scale fixed.Int26_6 - hinting font.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 fixed.Int26_6 - // 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 fixed.Int26_6, i Index, h font.Hinting) error { - g.Points = g.Points[:0] - g.Unhinted = g.Unhinted[:0] - g.InFontUnits = g.InFontUnits[:0] - g.Ends = g.Ends[:0] - g.font = f - g.hinting = h - g.scale = scale - g.pp1x = 0 - g.phantomPoints = [4]Point{} - g.metricsSet = false - - if h != font.HintingNone { - 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 != font.HintingNone { - pp1x = g.phantomPoints[0].X - } - if pp1x != 0 { - for i := range g.Points { - g.Points[i].X -= pp1x - } - } - - advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X - if h != font.HintingNone { - 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 fixed.Int26_6(hdmx[0]) == scale>>6 { - advanceWidth = fixed.Int26_6(hdmx[2+i]) << 6 - break - } - } - } - } - advanceWidth = (advanceWidth + 32) &^ 63 - } - g.AdvanceWidth = advanceWidth - - // Set g.Bounds 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.Points) == 0 { - g.Bounds = fixed.Rectangle26_6{} - } else { - p := g.Points[0] - g.Bounds.Min.X = p.X - g.Bounds.Max.X = p.X - g.Bounds.Min.Y = p.Y - g.Bounds.Max.Y = p.Y - for _, p := range g.Points[1:] { - if g.Bounds.Min.X > p.X { - g.Bounds.Min.X = p.X - } else if g.Bounds.Max.X < p.X { - g.Bounds.Max.X = p.X - } - if g.Bounds.Min.Y > p.Y { - g.Bounds.Min.Y = p.Y - } else if g.Bounds.Max.Y < p.Y { - g.Bounds.Max.Y = p.Y - } - } - // Snap the box to the grid, if hinting is on. - if h != font.HintingNone { - g.Bounds.Min.X &^= 63 - g.Bounds.Min.Y &^= 63 - g.Bounds.Max.X += 63 - g.Bounds.Max.X &^= 63 - g.Bounds.Max.Y += 63 - g.Bounds.Max.Y &^= 63 - } - } - return nil -} - -func (g *GlyphBuf) load(recursion uint32, 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, fixed.Int26_6(0), fixed.Int26_6(0) - if g0+10 <= g1 { - glyf = g.font.glyf[g0:g1] - ne = int(int16(u16(glyf, 0))) - boundsXMin = fixed.Int26_6(int16(u16(glyf, 2))) - boundsYMax = fixed.Int26_6(int16(u16(glyf, 8))) - } - - // Create the phantom points. - uhm, pp1x := g.font.unscaledHMetric(i), fixed.Int26_6(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.Points), len(g.Points), true, true) - copy(g.phantomPoints[:], g.Points[len(g.Points)-4:]) - g.Points = g.Points[:len(g.Points)-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.Points), len(g.Ends) - program := g.loadSimple(glyf, ne) - g.addPhantomsAndScale(np0, np0, true, true) - pp1x = g.Points[len(g.Points)-4].X - if g.hinting != font.HintingNone { - if len(program) != 0 { - err := g.hinter.run( - program, - g.Points[np0:], - g.Unhinted[np0:], - g.InFontUnits[np0:], - g.Ends[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.Points[len(g.Points)-4:]) - } - g.Points = g.Points[:len(g.Points)-4] - if np0 != 0 { - // The hinting program expects the []Ends 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.Ends); i++ { - g.Ends[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.Ends = append(g.Ends, 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.Points) - np1 := np0 + int(g.Ends[len(g.Ends)-1]) - - // Decode the flags. - for i := np0; i < np1; { - c := uint32(glyf[offset]) - offset++ - g.Points = append(g.Points, Point{Flags: c}) - i++ - if c&flagRepeat != 0 { - count := glyf[offset] - offset++ - for ; count > 0; count-- { - g.Points = append(g.Points, Point{Flags: c}) - i++ - } - } - } - - // Decode the co-ordinates. - var x int16 - for i := np0; i < np1; i++ { - f := g.Points[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.Points[i].X = fixed.Int26_6(x) - } - var y int16 - for i := np0; i < np1; i++ { - f := g.Points[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.Points[i].Y = fixed.Int26_6(y) - } - - return program -} - -func (g *GlyphBuf) loadCompound(recursion uint32, 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.Points), len(g.Ends) - offset := loadOffset - for { - flags := u16(glyf, offset) - component := Index(u16(glyf, offset+2)) - dx, dy, transform, hasTransform := fixed.Int26_6(0), fixed.Int26_6(0), [4]int16{}, false - if flags&flagArg1And2AreWords != 0 { - dx = fixed.Int26_6(int16(u16(glyf, offset+4))) - dy = fixed.Int26_6(int16(u16(glyf, offset+6))) - offset += 8 - } else { - dx = fixed.Int26_6(int16(int8(glyf[offset+4]))) - dy = fixed.Int26_6(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] = int16(u16(glyf, offset+0)) - transform[3] = transform[0] - offset += 2 - case flags&flagWeHaveAnXAndYScale != 0: - transform[0] = int16(u16(glyf, offset+0)) - transform[3] = int16(u16(glyf, offset+2)) - offset += 4 - case flags&flagWeHaveATwoByTwo != 0: - transform[0] = int16(u16(glyf, offset+0)) - transform[1] = int16(u16(glyf, offset+2)) - transform[2] = int16(u16(glyf, offset+4)) - transform[3] = int16(u16(glyf, offset+6)) - offset += 8 - } - } - savedPP := g.phantomPoints - np0 := len(g.Points) - 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.Points); j++ { - p := &g.Points[j] - newX := 0 + - fixed.Int26_6((int64(p.X)*int64(transform[0])+1<<13)>>14) + - fixed.Int26_6((int64(p.Y)*int64(transform[2])+1<<13)>>14) - newY := 0 + - fixed.Int26_6((int64(p.X)*int64(transform[1])+1<<13)>>14) + - fixed.Int26_6((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.Points); j++ { - p := &g.Points[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 != font.HintingNone && offset+2 <= len(glyf) { - instrLen = int(u16(glyf, offset)) - offset += 2 - } - - g.addPhantomsAndScale(np0, len(g.Points), false, instrLen > 0) - points, ends := g.Points[np0:], g.Ends[ne0:] - g.Points = g.Points[:len(g.Points)-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.Points = append(g.Points, g.phantomPoints[:]...) - // Scale the points. - if simple && g.hinting != font.HintingNone { - g.InFontUnits = append(g.InFontUnits, g.Points[np1:]...) - } - for i := np1; i < len(g.Points); i++ { - p := &g.Points[i] - p.X = g.font.scale(g.scale * p.X) - p.Y = g.font.scale(g.scale * p.Y) - } - if g.hinting == font.HintingNone { - 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.Points[len(g.Points)-4].X - if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 { - for i := np0; i < len(g.Points); i++ { - g.Points[i].X += dx - } - } - } - if simple { - g.Unhinted = append(g.Unhinted, g.Points[np1:]...) - } - // Round the 2nd and 4th phantom point to the grid. - p := &g.Points[len(g.Points)-3] - p.X = (p.X + 32) &^ 63 - p = &g.Points[len(g.Points)-1] - p.Y = (p.Y + 32) &^ 63 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go deleted file mode 100644 index 0315de511..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go +++ /dev/null @@ -1,1763 +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 - -// This file implements a Truetype bytecode interpreter. -// The opcodes are described at https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html - -import ( - "errors" - "math" - - "golang.org/x/image/math/fixed" -) - -const ( - twilightZone = 0 - glyphZone = 1 - numZone = 2 -) - -type pointType uint32 - -const ( - current pointType = 0 - unhinted pointType = 1 - inFontUnits pointType = 2 - numPointType = 3 -) - -// callStackEntry is a bytecode call stack entry. -type callStackEntry struct { - program []byte - pc int - loopCount int32 -} - -// hinter implements bytecode hinting. A hinter can be re-used to hint a series -// of glyphs from a Font. -type hinter struct { - stack, store []int32 - - // functions is a map from function number to bytecode. - functions map[int32][]byte - - // font and scale are the font and scale last used for this hinter. - // Changing the font will require running the new font's fpgm bytecode. - // Changing either will require running the font's prep bytecode. - font *Font - scale fixed.Int26_6 - - // gs and defaultGS are the current and default graphics state. The - // default graphics state is the global default graphics state after - // the font's fpgm and prep programs have been run. - gs, defaultGS graphicsState - - // points and ends are the twilight zone's points, glyph's points - // and glyph's contour boundaries. - points [numZone][numPointType][]Point - ends []int - - // scaledCVT is the lazily initialized scaled Control Value Table. - scaledCVTInitialized bool - scaledCVT []fixed.Int26_6 -} - -// graphicsState is described at https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html -type graphicsState struct { - // Projection vector, freedom vector and dual projection vector. - pv, fv, dv [2]f2dot14 - // Reference points and zone pointers. - rp, zp [3]int32 - // Control Value / Single Width Cut-In. - controlValueCutIn, singleWidthCutIn, singleWidth fixed.Int26_6 - // Delta base / shift. - deltaBase, deltaShift int32 - // Minimum distance. - minDist fixed.Int26_6 - // Loop count. - loop int32 - // Rounding policy. - roundPeriod, roundPhase, roundThreshold fixed.Int26_6 - roundSuper45 bool - // Auto-flip. - autoFlip bool -} - -var globalDefaultGS = graphicsState{ - pv: [2]f2dot14{0x4000, 0}, // Unit vector along the X axis. - fv: [2]f2dot14{0x4000, 0}, - dv: [2]f2dot14{0x4000, 0}, - zp: [3]int32{1, 1, 1}, - controlValueCutIn: (17 << 6) / 16, // 17/16 as a fixed.Int26_6. - deltaBase: 9, - deltaShift: 3, - minDist: 1 << 6, // 1 as a fixed.Int26_6. - loop: 1, - roundPeriod: 1 << 6, // 1 as a fixed.Int26_6. - roundThreshold: 1 << 5, // 1/2 as a fixed.Int26_6. - roundSuper45: false, - autoFlip: true, -} - -func resetTwilightPoints(f *Font, p []Point) []Point { - if n := int(f.maxTwilightPoints) + 4; n <= cap(p) { - p = p[:n] - for i := range p { - p[i] = Point{} - } - } else { - p = make([]Point, n) - } - return p -} - -func (h *hinter) init(f *Font, scale fixed.Int26_6) error { - h.points[twilightZone][0] = resetTwilightPoints(f, h.points[twilightZone][0]) - h.points[twilightZone][1] = resetTwilightPoints(f, h.points[twilightZone][1]) - h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2]) - - rescale := h.scale != scale - if h.font != f { - h.font, rescale = f, true - if h.functions == nil { - h.functions = make(map[int32][]byte) - } else { - for k := range h.functions { - delete(h.functions, k) - } - } - - if x := int(f.maxStackElements); x > len(h.stack) { - x += 255 - x &^= 255 - h.stack = make([]int32, x) - } - if x := int(f.maxStorage); x > len(h.store) { - x += 15 - x &^= 15 - h.store = make([]int32, x) - } - if len(f.fpgm) != 0 { - if err := h.run(f.fpgm, nil, nil, nil, nil); err != nil { - return err - } - } - } - - if rescale { - h.scale = scale - h.scaledCVTInitialized = false - - h.defaultGS = globalDefaultGS - - if len(f.prep) != 0 { - if err := h.run(f.prep, nil, nil, nil, nil); err != nil { - return err - } - h.defaultGS = h.gs - // The MS rasterizer doesn't allow the following graphics state - // variables to be modified by the CVT program. - h.defaultGS.pv = globalDefaultGS.pv - h.defaultGS.fv = globalDefaultGS.fv - h.defaultGS.dv = globalDefaultGS.dv - h.defaultGS.rp = globalDefaultGS.rp - h.defaultGS.zp = globalDefaultGS.zp - h.defaultGS.loop = globalDefaultGS.loop - } - } - return nil -} - -func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ends []int) error { - h.gs = h.defaultGS - h.points[glyphZone][current] = pCurrent - h.points[glyphZone][unhinted] = pUnhinted - h.points[glyphZone][inFontUnits] = pInFontUnits - h.ends = ends - - if len(program) > 50000 { - return errors.New("truetype: hinting: too many instructions") - } - var ( - steps, pc, top int - opcode uint8 - - callStack [32]callStackEntry - callStackTop int - ) - - for 0 <= pc && pc < len(program) { - steps++ - if steps == 100000 { - return errors.New("truetype: hinting: too many steps") - } - opcode = program[pc] - if top < int(popCount[opcode]) { - return errors.New("truetype: hinting: stack underflow") - } - switch opcode { - - case opSVTCA0: - h.gs.pv = [2]f2dot14{0, 0x4000} - h.gs.fv = [2]f2dot14{0, 0x4000} - h.gs.dv = [2]f2dot14{0, 0x4000} - - case opSVTCA1: - h.gs.pv = [2]f2dot14{0x4000, 0} - h.gs.fv = [2]f2dot14{0x4000, 0} - h.gs.dv = [2]f2dot14{0x4000, 0} - - case opSPVTCA0: - h.gs.pv = [2]f2dot14{0, 0x4000} - h.gs.dv = [2]f2dot14{0, 0x4000} - - case opSPVTCA1: - h.gs.pv = [2]f2dot14{0x4000, 0} - h.gs.dv = [2]f2dot14{0x4000, 0} - - case opSFVTCA0: - h.gs.fv = [2]f2dot14{0, 0x4000} - - case opSFVTCA1: - h.gs.fv = [2]f2dot14{0x4000, 0} - - case opSPVTL0, opSPVTL1, opSFVTL0, opSFVTL1: - top -= 2 - p1 := h.point(0, current, h.stack[top+0]) - p2 := h.point(0, current, h.stack[top+1]) - if p1 == nil || p2 == nil { - return errors.New("truetype: hinting: point out of range") - } - dx := f2dot14(p1.X - p2.X) - dy := f2dot14(p1.Y - p2.Y) - if dx == 0 && dy == 0 { - dx = 0x4000 - } else if opcode&1 != 0 { - // Counter-clockwise rotation. - dx, dy = -dy, dx - } - v := normalize(dx, dy) - if opcode < opSFVTL0 { - h.gs.pv = v - h.gs.dv = v - } else { - h.gs.fv = v - } - - case opSPVFS: - top -= 2 - h.gs.pv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) - h.gs.dv = h.gs.pv - - case opSFVFS: - top -= 2 - h.gs.fv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) - - case opGPV: - if top+1 >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top+0] = int32(h.gs.pv[0]) - h.stack[top+1] = int32(h.gs.pv[1]) - top += 2 - - case opGFV: - if top+1 >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top+0] = int32(h.gs.fv[0]) - h.stack[top+1] = int32(h.gs.fv[1]) - top += 2 - - case opSFVTPV: - h.gs.fv = h.gs.pv - - case opISECT: - top -= 5 - p := h.point(2, current, h.stack[top+0]) - a0 := h.point(1, current, h.stack[top+1]) - a1 := h.point(1, current, h.stack[top+2]) - b0 := h.point(0, current, h.stack[top+3]) - b1 := h.point(0, current, h.stack[top+4]) - if p == nil || a0 == nil || a1 == nil || b0 == nil || b1 == nil { - return errors.New("truetype: hinting: point out of range") - } - - dbx := b1.X - b0.X - dby := b1.Y - b0.Y - dax := a1.X - a0.X - day := a1.Y - a0.Y - dx := b0.X - a0.X - dy := b0.Y - a0.Y - discriminant := mulDiv(int64(dax), int64(-dby), 0x40) + - mulDiv(int64(day), int64(dbx), 0x40) - dotProduct := mulDiv(int64(dax), int64(dbx), 0x40) + - mulDiv(int64(day), int64(dby), 0x40) - // The discriminant above is actually a cross product of vectors - // da and db. Together with the dot product, they can be used as - // surrogates for sine and cosine of the angle between the vectors. - // Indeed, - // dotproduct = |da||db|cos(angle) - // discriminant = |da||db|sin(angle) - // We use these equations to reject grazing intersections by - // thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. - absDisc, absDotP := discriminant, dotProduct - if absDisc < 0 { - absDisc = -absDisc - } - if absDotP < 0 { - absDotP = -absDotP - } - if 19*absDisc > absDotP { - val := mulDiv(int64(dx), int64(-dby), 0x40) + - mulDiv(int64(dy), int64(dbx), 0x40) - rx := mulDiv(val, int64(dax), discriminant) - ry := mulDiv(val, int64(day), discriminant) - p.X = a0.X + fixed.Int26_6(rx) - p.Y = a0.Y + fixed.Int26_6(ry) - } else { - p.X = (a0.X + a1.X + b0.X + b1.X) / 4 - p.Y = (a0.Y + a1.Y + b0.Y + b1.Y) / 4 - } - p.Flags |= flagTouchedX | flagTouchedY - - case opSRP0, opSRP1, opSRP2: - top-- - h.gs.rp[opcode-opSRP0] = h.stack[top] - - case opSZP0, opSZP1, opSZP2: - top-- - h.gs.zp[opcode-opSZP0] = h.stack[top] - - case opSZPS: - top-- - h.gs.zp[0] = h.stack[top] - h.gs.zp[1] = h.stack[top] - h.gs.zp[2] = h.stack[top] - - case opSLOOP: - top-- - if h.stack[top] <= 0 { - return errors.New("truetype: hinting: invalid data") - } - h.gs.loop = h.stack[top] - - case opRTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1 << 5 - h.gs.roundSuper45 = false - - case opRTHG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 1 << 5 - h.gs.roundThreshold = 1 << 5 - h.gs.roundSuper45 = false - - case opSMD: - top-- - h.gs.minDist = fixed.Int26_6(h.stack[top]) - - case opELSE: - opcode = 1 - goto ifelse - - case opJMPR: - top-- - pc += int(h.stack[top]) - continue - - case opSCVTCI: - top-- - h.gs.controlValueCutIn = fixed.Int26_6(h.stack[top]) - - case opSSWCI: - top-- - h.gs.singleWidthCutIn = fixed.Int26_6(h.stack[top]) - - case opSSW: - top-- - h.gs.singleWidth = h.font.scale(h.scale * fixed.Int26_6(h.stack[top])) - - case opDUP: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top] = h.stack[top-1] - top++ - - case opPOP: - top-- - - case opCLEAR: - top = 0 - - case opSWAP: - h.stack[top-1], h.stack[top-2] = h.stack[top-2], h.stack[top-1] - - case opDEPTH: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top] = int32(top) - top++ - - case opCINDEX, opMINDEX: - x := int(h.stack[top-1]) - if x <= 0 || x >= top { - return errors.New("truetype: hinting: invalid data") - } - h.stack[top-1] = h.stack[top-1-x] - if opcode == opMINDEX { - copy(h.stack[top-1-x:top-1], h.stack[top-x:top]) - top-- - } - - case opALIGNPTS: - top -= 2 - p := h.point(1, current, h.stack[top]) - q := h.point(0, current, h.stack[top+1]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - d := dotProduct(fixed.Int26_6(q.X-p.X), fixed.Int26_6(q.Y-p.Y), h.gs.pv) / 2 - h.move(p, +d, true) - h.move(q, -d, true) - - case opUTP: - top-- - p := h.point(0, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - p.Flags &^= flagTouchedX | flagTouchedY - - case opLOOPCALL, opCALL: - if callStackTop >= len(callStack) { - return errors.New("truetype: hinting: call stack overflow") - } - top-- - f, ok := h.functions[h.stack[top]] - if !ok { - return errors.New("truetype: hinting: undefined function") - } - callStack[callStackTop] = callStackEntry{program, pc, 1} - if opcode == opLOOPCALL { - top-- - if h.stack[top] == 0 { - break - } - callStack[callStackTop].loopCount = h.stack[top] - } - callStackTop++ - program, pc = f, 0 - continue - - case opFDEF: - // Save all bytecode up until the next ENDF. - startPC := pc + 1 - fdefloop: - for { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: unbalanced FDEF") - } - switch program[pc] { - case opFDEF: - return errors.New("truetype: hinting: nested FDEF") - case opENDF: - top-- - h.functions[h.stack[top]] = program[startPC : pc+1] - break fdefloop - default: - var ok bool - pc, ok = skipInstructionPayload(program, pc) - if !ok { - return errors.New("truetype: hinting: unbalanced FDEF") - } - } - } - - case opENDF: - if callStackTop == 0 { - return errors.New("truetype: hinting: call stack underflow") - } - callStackTop-- - callStack[callStackTop].loopCount-- - if callStack[callStackTop].loopCount != 0 { - callStackTop++ - pc = 0 - continue - } - program, pc = callStack[callStackTop].program, callStack[callStackTop].pc - - case opMDAP0, opMDAP1: - top-- - i := h.stack[top] - p := h.point(0, current, i) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - distance := fixed.Int26_6(0) - if opcode == opMDAP1 { - distance = dotProduct(p.X, p.Y, h.gs.pv) - // TODO: metrics compensation. - distance = h.round(distance) - distance - } - h.move(p, distance, true) - h.gs.rp[0] = i - h.gs.rp[1] = i - - case opIUP0, opIUP1: - iupY, mask := opcode == opIUP0, uint32(flagTouchedX) - if iupY { - mask = flagTouchedY - } - prevEnd := 0 - for _, end := range h.ends { - for i := prevEnd; i < end; i++ { - for i < end && h.points[glyphZone][current][i].Flags&mask == 0 { - i++ - } - if i == end { - break - } - firstTouched, curTouched := i, i - i++ - for ; i < end; i++ { - if h.points[glyphZone][current][i].Flags&mask != 0 { - h.iupInterp(iupY, curTouched+1, i-1, curTouched, i) - curTouched = i - } - } - if curTouched == firstTouched { - h.iupShift(iupY, prevEnd, end, curTouched) - } else { - h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched) - if firstTouched > 0 { - h.iupInterp(iupY, prevEnd, firstTouched-1, curTouched, firstTouched) - } - } - } - prevEnd = end - } - - case opSHP0, opSHP1: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - _, _, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(2, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, d, true) - } - h.gs.loop = 1 - - case opSHC0, opSHC1: - top-- - zonePointer, i, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - if h.gs.zp[2] == 0 { - // TODO: implement this when we have a glyph that does this. - return errors.New("hinting: unimplemented SHC instruction") - } - contour := h.stack[top] - if contour < 0 || len(ends) <= int(contour) { - return errors.New("truetype: hinting: contour out of range") - } - j0, j1 := int32(0), int32(h.ends[contour]) - if contour > 0 { - j0 = int32(h.ends[contour-1]) - } - move := h.gs.zp[zonePointer] != h.gs.zp[2] - for j := j0; j < j1; j++ { - if move || j != i { - h.move(h.point(2, current, j), d, true) - } - } - - case opSHZ0, opSHZ1: - top-- - zonePointer, i, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - - // As per C Freetype, SHZ doesn't move the phantom points, or mark - // the points as touched. - limit := int32(len(h.points[h.gs.zp[2]][current])) - if h.gs.zp[2] == glyphZone { - limit -= 4 - } - for j := int32(0); j < limit; j++ { - if i != j || h.gs.zp[zonePointer] != h.gs.zp[2] { - h.move(h.point(2, current, j), d, false) - } - } - - case opSHPIX: - top-- - d := fixed.Int26_6(h.stack[top]) - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(2, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, d, true) - } - h.gs.loop = 1 - - case opIP: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - pointType := inFontUnits - twilight := h.gs.zp[0] == 0 || h.gs.zp[1] == 0 || h.gs.zp[2] == 0 - if twilight { - pointType = unhinted - } - p := h.point(1, pointType, h.gs.rp[2]) - oldP := h.point(0, pointType, h.gs.rp[1]) - oldRange := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) - - p = h.point(1, current, h.gs.rp[2]) - curP := h.point(0, current, h.gs.rp[1]) - curRange := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - i := h.stack[top] - p = h.point(2, pointType, i) - oldDist := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) - p = h.point(2, current, i) - curDist := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) - newDist := fixed.Int26_6(0) - if oldDist != 0 { - if oldRange != 0 { - newDist = fixed.Int26_6(mulDiv(int64(oldDist), int64(curRange), int64(oldRange))) - } else { - newDist = -oldDist - } - } - h.move(p, newDist-curDist, true) - } - h.gs.loop = 1 - - case opMSIRP0, opMSIRP1: - top -= 2 - i := h.stack[top] - distance := fixed.Int26_6(h.stack[top+1]) - - // TODO: special case h.gs.zp[1] == 0 in C Freetype. - ref := h.point(0, current, h.gs.rp[0]) - p := h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - - // Set-RP0 bit. - if opcode == opMSIRP1 { - h.gs.rp[0] = i - } - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - - // Move the point. - h.move(p, distance-curDist, true) - - case opALIGNRP: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - ref := h.point(0, current, h.gs.rp[0]) - if ref == nil { - return errors.New("truetype: hinting: point out of range") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(1, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, -dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv), true) - } - h.gs.loop = 1 - - case opRTDG: - h.gs.roundPeriod = 1 << 5 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1 << 4 - h.gs.roundSuper45 = false - - case opMIAP0, opMIAP1: - top -= 2 - i := h.stack[top] - distance := h.getScaledCVT(h.stack[top+1]) - if h.gs.zp[0] == 0 { - p := h.point(0, unhinted, i) - q := h.point(0, current, i) - p.X = fixed.Int26_6((int64(distance) * int64(h.gs.fv[0])) >> 14) - p.Y = fixed.Int26_6((int64(distance) * int64(h.gs.fv[1])) >> 14) - *q = *p - } - p := h.point(0, current, i) - oldDist := dotProduct(p.X, p.Y, h.gs.pv) - if opcode == opMIAP1 { - if fabs(distance-oldDist) > h.gs.controlValueCutIn { - distance = oldDist - } - // TODO: metrics compensation. - distance = h.round(distance) - } - h.move(p, distance-oldDist, true) - h.gs.rp[0] = i - h.gs.rp[1] = i - - case opNPUSHB: - opcode = 0 - goto push - - case opNPUSHW: - opcode = 0x80 - goto push - - case opWS: - top -= 2 - i := int(h.stack[top]) - if i < 0 || len(h.store) <= i { - return errors.New("truetype: hinting: invalid data") - } - h.store[i] = h.stack[top+1] - - case opRS: - i := int(h.stack[top-1]) - if i < 0 || len(h.store) <= i { - return errors.New("truetype: hinting: invalid data") - } - h.stack[top-1] = h.store[i] - - case opWCVTP: - top -= 2 - h.setScaledCVT(h.stack[top], fixed.Int26_6(h.stack[top+1])) - - case opRCVT: - h.stack[top-1] = int32(h.getScaledCVT(h.stack[top-1])) - - case opGC0, opGC1: - i := h.stack[top-1] - if opcode == opGC0 { - p := h.point(2, current, i) - h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.pv)) - } else { - p := h.point(2, unhinted, i) - // Using dv as per C Freetype. - h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.dv)) - } - - case opSCFS: - top -= 2 - i := h.stack[top] - p := h.point(2, current, i) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - c := dotProduct(p.X, p.Y, h.gs.pv) - h.move(p, fixed.Int26_6(h.stack[top+1])-c, true) - if h.gs.zp[2] != 0 { - break - } - q := h.point(2, unhinted, i) - if q == nil { - return errors.New("truetype: hinting: point out of range") - } - q.X = p.X - q.Y = p.Y - - case opMD0, opMD1: - top-- - pt, v, scale := pointType(0), [2]f2dot14{}, false - if opcode == opMD0 { - pt = current - v = h.gs.pv - } else if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { - pt = unhinted - v = h.gs.dv - } else { - pt = inFontUnits - v = h.gs.dv - scale = true - } - p := h.point(0, pt, h.stack[top-1]) - q := h.point(1, pt, h.stack[top]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - d := int32(dotProduct(p.X-q.X, p.Y-q.Y, v)) - if scale { - d = int32(int64(d*int32(h.scale)) / int64(h.font.fUnitsPerEm)) - } - h.stack[top-1] = d - - case opMPPEM, opMPS: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - // For MPS, point size should be irrelevant; we return the PPEM. - h.stack[top] = int32(h.scale) >> 6 - top++ - - case opFLIPON, opFLIPOFF: - h.gs.autoFlip = opcode == opFLIPON - - case opDEBUG: - // No-op. - - case opLT: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] < h.stack[top]) - - case opLTEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] <= h.stack[top]) - - case opGT: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] > h.stack[top]) - - case opGTEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] >= h.stack[top]) - - case opEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] == h.stack[top]) - - case opNEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] != h.stack[top]) - - case opODD, opEVEN: - i := h.round(fixed.Int26_6(h.stack[top-1])) >> 6 - h.stack[top-1] = int32(i&1) ^ int32(opcode-opODD) - - case opIF: - top-- - if h.stack[top] == 0 { - opcode = 0 - goto ifelse - } - - case opEIF: - // No-op. - - case opAND: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] != 0 && h.stack[top] != 0) - - case opOR: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1]|h.stack[top] != 0) - - case opNOT: - h.stack[top-1] = bool2int32(h.stack[top-1] == 0) - - case opDELTAP1: - goto delta - - case opSDB: - top-- - h.gs.deltaBase = h.stack[top] - - case opSDS: - top-- - h.gs.deltaShift = h.stack[top] - - case opADD: - top-- - h.stack[top-1] += h.stack[top] - - case opSUB: - top-- - h.stack[top-1] -= h.stack[top] - - case opDIV: - top-- - if h.stack[top] == 0 { - return errors.New("truetype: hinting: division by zero") - } - h.stack[top-1] = int32(fdiv(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) - - case opMUL: - top-- - h.stack[top-1] = int32(fmul(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) - - case opABS: - if h.stack[top-1] < 0 { - h.stack[top-1] = -h.stack[top-1] - } - - case opNEG: - h.stack[top-1] = -h.stack[top-1] - - case opFLOOR: - h.stack[top-1] &^= 63 - - case opCEILING: - h.stack[top-1] += 63 - h.stack[top-1] &^= 63 - - case opROUND00, opROUND01, opROUND10, opROUND11: - // The four flavors of opROUND are equivalent. See the comment below on - // opNROUND for the rationale. - h.stack[top-1] = int32(h.round(fixed.Int26_6(h.stack[top-1]))) - - case opNROUND00, opNROUND01, opNROUND10, opNROUND11: - // No-op. The spec says to add one of four "compensations for the engine - // characteristics", to cater for things like "different dot-size printers". - // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#engine_compensation - // This code does not implement engine compensation, as we don't expect to - // be used to output on dot-matrix printers. - - case opWCVTF: - top -= 2 - h.setScaledCVT(h.stack[top], h.font.scale(h.scale*fixed.Int26_6(h.stack[top+1]))) - - case opDELTAP2, opDELTAP3, opDELTAC1, opDELTAC2, opDELTAC3: - goto delta - - case opSROUND, opS45ROUND: - top-- - switch (h.stack[top] >> 6) & 0x03 { - case 0: - h.gs.roundPeriod = 1 << 5 - case 1, 3: - h.gs.roundPeriod = 1 << 6 - case 2: - h.gs.roundPeriod = 1 << 7 - } - h.gs.roundSuper45 = opcode == opS45ROUND - if h.gs.roundSuper45 { - // The spec says to multiply by √2, but the C Freetype code says 1/√2. - // We go with 1/√2. - h.gs.roundPeriod *= 46341 - h.gs.roundPeriod /= 65536 - } - h.gs.roundPhase = h.gs.roundPeriod * fixed.Int26_6((h.stack[top]>>4)&0x03) / 4 - if x := h.stack[top] & 0x0f; x != 0 { - h.gs.roundThreshold = h.gs.roundPeriod * fixed.Int26_6(x-4) / 8 - } else { - h.gs.roundThreshold = h.gs.roundPeriod - 1 - } - - case opJROT: - top -= 2 - if h.stack[top+1] != 0 { - pc += int(h.stack[top]) - continue - } - - case opJROF: - top -= 2 - if h.stack[top+1] == 0 { - pc += int(h.stack[top]) - continue - } - - case opROFF: - h.gs.roundPeriod = 0 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 0 - h.gs.roundSuper45 = false - - case opRUTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1<<6 - 1 - h.gs.roundSuper45 = false - - case opRDTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 0 - h.gs.roundSuper45 = false - - case opSANGW, opAA: - // These ops are "anachronistic" and no longer used. - top-- - - case opFLIPPT: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - points := h.points[glyphZone][current] - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - i := h.stack[top] - if i < 0 || len(points) <= int(i) { - return errors.New("truetype: hinting: point out of range") - } - points[i].Flags ^= flagOnCurve - } - h.gs.loop = 1 - - case opFLIPRGON, opFLIPRGOFF: - top -= 2 - i, j, points := h.stack[top], h.stack[top+1], h.points[glyphZone][current] - if i < 0 || len(points) <= int(i) || j < 0 || len(points) <= int(j) { - return errors.New("truetype: hinting: point out of range") - } - for ; i <= j; i++ { - if opcode == opFLIPRGON { - points[i].Flags |= flagOnCurve - } else { - points[i].Flags &^= flagOnCurve - } - } - - case opSCANCTRL: - // We do not support dropout control, as we always rasterize grayscale glyphs. - top-- - - case opSDPVTL0, opSDPVTL1: - top -= 2 - for i := 0; i < 2; i++ { - pt := unhinted - if i != 0 { - pt = current - } - p := h.point(1, pt, h.stack[top]) - q := h.point(2, pt, h.stack[top+1]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - dx := f2dot14(p.X - q.X) - dy := f2dot14(p.Y - q.Y) - if dx == 0 && dy == 0 { - dx = 0x4000 - } else if opcode&1 != 0 { - // Counter-clockwise rotation. - dx, dy = -dy, dx - } - if i == 0 { - h.gs.dv = normalize(dx, dy) - } else { - h.gs.pv = normalize(dx, dy) - } - } - - case opGETINFO: - res := int32(0) - if h.stack[top-1]&(1<<0) != 0 { - // Set the engine version. We hard-code this to 35, the same as - // the C freetype code, which says that "Version~35 corresponds - // to MS rasterizer v.1.7 as used e.g. in Windows~98". - res |= 35 - } - if h.stack[top-1]&(1<<5) != 0 { - // Set that we support grayscale. - res |= 1 << 12 - } - // We set no other bits, as we do not support rotated or stretched glyphs. - h.stack[top-1] = res - - case opIDEF: - // IDEF is for ancient versions of the bytecode interpreter, and is no longer used. - return errors.New("truetype: hinting: unsupported IDEF instruction") - - case opROLL: - h.stack[top-1], h.stack[top-3], h.stack[top-2] = - h.stack[top-3], h.stack[top-2], h.stack[top-1] - - case opMAX: - top-- - if h.stack[top-1] < h.stack[top] { - h.stack[top-1] = h.stack[top] - } - - case opMIN: - top-- - if h.stack[top-1] > h.stack[top] { - h.stack[top-1] = h.stack[top] - } - - case opSCANTYPE: - // We do not support dropout control, as we always rasterize grayscale glyphs. - top-- - - case opINSTCTRL: - // TODO: support instruction execution control? It seems rare, and even when - // nominally used (e.g. Source Sans Pro), it seems conditional on extreme or - // unusual rasterization conditions. For example, the code snippet at - // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#INSTCTRL - // uses INSTCTRL when grid-fitting a rotated or stretched glyph, but - // freetype-go does not support rotated or stretched glyphs. - top -= 2 - - default: - if opcode < opPUSHB000 { - return errors.New("truetype: hinting: unrecognized instruction") - } - - if opcode < opMDRP00000 { - // PUSHxxxx opcode. - - if opcode < opPUSHW000 { - opcode -= opPUSHB000 - 1 - } else { - opcode -= opPUSHW000 - 1 - 0x80 - } - goto push - } - - if opcode < opMIRP00000 { - // MDRPxxxxx opcode. - - top-- - i := h.stack[top] - ref := h.point(0, current, h.gs.rp[0]) - p := h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - - oldDist := fixed.Int26_6(0) - if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { - p0 := h.point(1, unhinted, i) - p1 := h.point(0, unhinted, h.gs.rp[0]) - oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) - } else { - p0 := h.point(1, inFontUnits, i) - p1 := h.point(0, inFontUnits, h.gs.rp[0]) - oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) - oldDist = h.font.scale(h.scale * oldDist) - } - - // Single-width cut-in test. - if x := fabs(oldDist - h.gs.singleWidth); x < h.gs.singleWidthCutIn { - if oldDist >= 0 { - oldDist = +h.gs.singleWidth - } else { - oldDist = -h.gs.singleWidth - } - } - - // Rounding bit. - // TODO: metrics compensation. - distance := oldDist - if opcode&0x04 != 0 { - distance = h.round(oldDist) - } - - // Minimum distance bit. - if opcode&0x08 != 0 { - if oldDist >= 0 { - if distance < h.gs.minDist { - distance = h.gs.minDist - } - } else { - if distance > -h.gs.minDist { - distance = -h.gs.minDist - } - } - } - - // Set-RP0 bit. - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - if opcode&0x10 != 0 { - h.gs.rp[0] = i - } - - // Move the point. - oldDist = dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - h.move(p, distance-oldDist, true) - - } else { - // MIRPxxxxx opcode. - - top -= 2 - i := h.stack[top] - cvtDist := h.getScaledCVT(h.stack[top+1]) - if fabs(cvtDist-h.gs.singleWidth) < h.gs.singleWidthCutIn { - if cvtDist >= 0 { - cvtDist = +h.gs.singleWidth - } else { - cvtDist = -h.gs.singleWidth - } - } - - if h.gs.zp[1] == 0 { - // TODO: implement once we have a .ttf file that triggers - // this, so that we can step through C's freetype. - return errors.New("truetype: hinting: unimplemented twilight point adjustment") - } - - ref := h.point(0, unhinted, h.gs.rp[0]) - p := h.point(1, unhinted, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - oldDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.dv) - - ref = h.point(0, current, h.gs.rp[0]) - p = h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - - if h.gs.autoFlip && oldDist^cvtDist < 0 { - cvtDist = -cvtDist - } - - // Rounding bit. - // TODO: metrics compensation. - distance := cvtDist - if opcode&0x04 != 0 { - // The CVT value is only used if close enough to oldDist. - if (h.gs.zp[0] == h.gs.zp[1]) && - (fabs(cvtDist-oldDist) > h.gs.controlValueCutIn) { - - distance = oldDist - } - distance = h.round(distance) - } - - // Minimum distance bit. - if opcode&0x08 != 0 { - if oldDist >= 0 { - if distance < h.gs.minDist { - distance = h.gs.minDist - } - } else { - if distance > -h.gs.minDist { - distance = -h.gs.minDist - } - } - } - - // Set-RP0 bit. - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - if opcode&0x10 != 0 { - h.gs.rp[0] = i - } - - // Move the point. - h.move(p, distance-curDist, true) - } - } - pc++ - continue - - ifelse: - // Skip past bytecode until the next ELSE (if opcode == 0) or the - // next EIF (for all opcodes). Opcode == 0 means that we have come - // from an IF. Opcode == 1 means that we have come from an ELSE. - { - ifelseloop: - for depth := 0; ; { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: unbalanced IF or ELSE") - } - switch program[pc] { - case opIF: - depth++ - case opELSE: - if depth == 0 && opcode == 0 { - break ifelseloop - } - case opEIF: - depth-- - if depth < 0 { - break ifelseloop - } - default: - var ok bool - pc, ok = skipInstructionPayload(program, pc) - if !ok { - return errors.New("truetype: hinting: unbalanced IF or ELSE") - } - } - } - pc++ - continue - } - - push: - // Push n elements from the program to the stack, where n is the low 7 bits of - // opcode. If the low 7 bits are zero, then n is the next byte from the program. - // The high bit being 0 means that the elements are zero-extended bytes. - // The high bit being 1 means that the elements are sign-extended words. - { - width := 1 - if opcode&0x80 != 0 { - opcode &^= 0x80 - width = 2 - } - if opcode == 0 { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: insufficient data") - } - opcode = program[pc] - } - pc++ - if top+int(opcode) > len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - if pc+width*int(opcode) > len(program) { - return errors.New("truetype: hinting: insufficient data") - } - for ; opcode > 0; opcode-- { - if width == 1 { - h.stack[top] = int32(program[pc]) - } else { - h.stack[top] = int32(int8(program[pc]))<<8 | int32(program[pc+1]) - } - top++ - pc += width - } - continue - } - - delta: - { - if opcode >= opDELTAC1 && !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - top-- - n := h.stack[top] - if int32(top) < 2*n { - return errors.New("truetype: hinting: stack underflow") - } - for ; n > 0; n-- { - top -= 2 - b := h.stack[top] - c := (b & 0xf0) >> 4 - switch opcode { - case opDELTAP2, opDELTAC2: - c += 16 - case opDELTAP3, opDELTAC3: - c += 32 - } - c += h.gs.deltaBase - if ppem := (int32(h.scale) + 1<<5) >> 6; ppem != c { - continue - } - b = (b & 0x0f) - 8 - if b >= 0 { - b++ - } - b = b * 64 / (1 << uint32(h.gs.deltaShift)) - if opcode >= opDELTAC1 { - a := h.stack[top+1] - if a < 0 || len(h.scaledCVT) <= int(a) { - return errors.New("truetype: hinting: index out of range") - } - h.scaledCVT[a] += fixed.Int26_6(b) - } else { - p := h.point(0, current, h.stack[top+1]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, fixed.Int26_6(b), true) - } - } - pc++ - continue - } - } - return nil -} - -func (h *hinter) initializeScaledCVT() { - h.scaledCVTInitialized = true - if n := len(h.font.cvt) / 2; n <= cap(h.scaledCVT) { - h.scaledCVT = h.scaledCVT[:n] - } else { - if n < 32 { - n = 32 - } - h.scaledCVT = make([]fixed.Int26_6, len(h.font.cvt)/2, n) - } - for i := range h.scaledCVT { - unscaled := uint16(h.font.cvt[2*i])<<8 | uint16(h.font.cvt[2*i+1]) - h.scaledCVT[i] = h.font.scale(h.scale * fixed.Int26_6(int16(unscaled))) - } -} - -// getScaledCVT returns the scaled value from the font's Control Value Table. -func (h *hinter) getScaledCVT(i int32) fixed.Int26_6 { - if !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - if i < 0 || len(h.scaledCVT) <= int(i) { - return 0 - } - return h.scaledCVT[i] -} - -// setScaledCVT overrides the scaled value from the font's Control Value Table. -func (h *hinter) setScaledCVT(i int32, v fixed.Int26_6) { - if !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - if i < 0 || len(h.scaledCVT) <= int(i) { - return - } - h.scaledCVT[i] = v -} - -func (h *hinter) point(zonePointer uint32, pt pointType, i int32) *Point { - points := h.points[h.gs.zp[zonePointer]][pt] - if i < 0 || len(points) <= int(i) { - return nil - } - return &points[i] -} - -func (h *hinter) move(p *Point, distance fixed.Int26_6, touch bool) { - fvx := int64(h.gs.fv[0]) - pvx := int64(h.gs.pv[0]) - if fvx == 0x4000 && pvx == 0x4000 { - p.X += fixed.Int26_6(distance) - if touch { - p.Flags |= flagTouchedX - } - return - } - - fvy := int64(h.gs.fv[1]) - pvy := int64(h.gs.pv[1]) - if fvy == 0x4000 && pvy == 0x4000 { - p.Y += fixed.Int26_6(distance) - if touch { - p.Flags |= flagTouchedY - } - return - } - - fvDotPv := (fvx*pvx + fvy*pvy) >> 14 - - if fvx != 0 { - p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv)) - if touch { - p.Flags |= flagTouchedX - } - } - - if fvy != 0 { - p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv)) - if touch { - p.Flags |= flagTouchedY - } - } -} - -func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { - if p1 > p2 { - return - } - if ref1 >= len(h.points[glyphZone][current]) || - ref2 >= len(h.points[glyphZone][current]) { - return - } - - var ifu1, ifu2 fixed.Int26_6 - if interpY { - ifu1 = h.points[glyphZone][inFontUnits][ref1].Y - ifu2 = h.points[glyphZone][inFontUnits][ref2].Y - } else { - ifu1 = h.points[glyphZone][inFontUnits][ref1].X - ifu2 = h.points[glyphZone][inFontUnits][ref2].X - } - if ifu1 > ifu2 { - ifu1, ifu2 = ifu2, ifu1 - ref1, ref2 = ref2, ref1 - } - - var unh1, unh2, delta1, delta2 fixed.Int26_6 - if interpY { - unh1 = h.points[glyphZone][unhinted][ref1].Y - unh2 = h.points[glyphZone][unhinted][ref2].Y - delta1 = h.points[glyphZone][current][ref1].Y - unh1 - delta2 = h.points[glyphZone][current][ref2].Y - unh2 - } else { - unh1 = h.points[glyphZone][unhinted][ref1].X - unh2 = h.points[glyphZone][unhinted][ref2].X - delta1 = h.points[glyphZone][current][ref1].X - unh1 - delta2 = h.points[glyphZone][current][ref2].X - unh2 - } - - var xy, ifuXY fixed.Int26_6 - if ifu1 == ifu2 { - for i := p1; i <= p2; i++ { - if interpY { - xy = h.points[glyphZone][unhinted][i].Y - } else { - xy = h.points[glyphZone][unhinted][i].X - } - - if xy <= unh1 { - xy += delta1 - } else { - xy += delta2 - } - - if interpY { - h.points[glyphZone][current][i].Y = xy - } else { - h.points[glyphZone][current][i].X = xy - } - } - return - } - - scale, scaleOK := int64(0), false - for i := p1; i <= p2; i++ { - if interpY { - xy = h.points[glyphZone][unhinted][i].Y - ifuXY = h.points[glyphZone][inFontUnits][i].Y - } else { - xy = h.points[glyphZone][unhinted][i].X - ifuXY = h.points[glyphZone][inFontUnits][i].X - } - - if xy <= unh1 { - xy += delta1 - } else if xy >= unh2 { - xy += delta2 - } else { - if !scaleOK { - scaleOK = true - scale = mulDiv(int64(unh2+delta2-unh1-delta1), 0x10000, int64(ifu2-ifu1)) - } - numer := int64(ifuXY-ifu1) * scale - if numer >= 0 { - numer += 0x8000 - } else { - numer -= 0x8000 - } - xy = unh1 + delta1 + fixed.Int26_6(numer/0x10000) - } - - if interpY { - h.points[glyphZone][current][i].Y = xy - } else { - h.points[glyphZone][current][i].X = xy - } - } -} - -func (h *hinter) iupShift(interpY bool, p1, p2, p int) { - var delta fixed.Int26_6 - if interpY { - delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y - } else { - delta = h.points[glyphZone][current][p].X - h.points[glyphZone][unhinted][p].X - } - if delta == 0 { - return - } - for i := p1; i < p2; i++ { - if i == p { - continue - } - if interpY { - h.points[glyphZone][current][i].Y += delta - } else { - h.points[glyphZone][current][i].X += delta - } - } -} - -func (h *hinter) displacement(useZP1 bool) (zonePointer uint32, i int32, d fixed.Int26_6, ok bool) { - zonePointer, i = uint32(0), h.gs.rp[1] - if useZP1 { - zonePointer, i = 1, h.gs.rp[2] - } - p := h.point(zonePointer, current, i) - q := h.point(zonePointer, unhinted, i) - if p == nil || q == nil { - return 0, 0, 0, false - } - d = dotProduct(p.X-q.X, p.Y-q.Y, h.gs.pv) - return zonePointer, i, d, true -} - -// skipInstructionPayload increments pc by the extra data that follows a -// variable length PUSHB or PUSHW instruction. -func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) { - switch program[pc] { - case opNPUSHB: - pc++ - if pc >= len(program) { - return 0, false - } - pc += int(program[pc]) - case opNPUSHW: - pc++ - if pc >= len(program) { - return 0, false - } - pc += 2 * int(program[pc]) - case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, - opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111: - pc += int(program[pc] - (opPUSHB000 - 1)) - case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011, - opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111: - pc += 2 * int(program[pc]-(opPUSHW000-1)) - } - return pc, true -} - -// f2dot14 is a 2.14 fixed point number. -type f2dot14 int16 - -func normalize(x, y f2dot14) [2]f2dot14 { - fx, fy := float64(x), float64(y) - l := 0x4000 / math.Hypot(fx, fy) - fx *= l - if fx >= 0 { - fx += 0.5 - } else { - fx -= 0.5 - } - fy *= l - if fy >= 0 { - fy += 0.5 - } else { - fy -= 0.5 - } - return [2]f2dot14{f2dot14(fx), f2dot14(fy)} -} - -// fabs returns abs(x) in 26.6 fixed point arithmetic. -func fabs(x fixed.Int26_6) fixed.Int26_6 { - if x < 0 { - return -x - } - return x -} - -// fdiv returns x/y in 26.6 fixed point arithmetic. -func fdiv(x, y fixed.Int26_6) fixed.Int26_6 { - return fixed.Int26_6((int64(x) << 6) / int64(y)) -} - -// fmul returns x*y in 26.6 fixed point arithmetic. -func fmul(x, y fixed.Int26_6) fixed.Int26_6 { - return fixed.Int26_6((int64(x)*int64(y) + 1<<5) >> 6) -} - -// dotProduct returns the dot product of [x, y] and q. It is almost the same as -// px := int64(x) -// py := int64(y) -// qx := int64(q[0]) -// qy := int64(q[1]) -// return fixed.Int26_6((px*qx + py*qy + 1<<13) >> 14) -// except that the computation is done with 32-bit integers to produce exactly -// the same rounding behavior as C Freetype. -func dotProduct(x, y fixed.Int26_6, q [2]f2dot14) fixed.Int26_6 { - // Compute x*q[0] as 64-bit value. - l := uint32((int32(x) & 0xFFFF) * int32(q[0])) - m := (int32(x) >> 16) * int32(q[0]) - - lo1 := l + (uint32(m) << 16) - hi1 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo1 < l) - - // Compute y*q[1] as 64-bit value. - l = uint32((int32(y) & 0xFFFF) * int32(q[1])) - m = (int32(y) >> 16) * int32(q[1]) - - lo2 := l + (uint32(m) << 16) - hi2 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo2 < l) - - // Add them. - lo := lo1 + lo2 - hi := hi1 + hi2 + bool2int32(lo < lo1) - - // Divide the result by 2^14 with rounding. - s := hi >> 31 - l = lo + uint32(s) - hi += s + bool2int32(l < lo) - lo = l - - l = lo + 0x2000 - hi += bool2int32(l < lo) - - return fixed.Int26_6((uint32(hi) << 18) | (l >> 14)) -} - -// mulDiv returns x*y/z, rounded to the nearest integer. -func mulDiv(x, y, z int64) int64 { - xy := x * y - if z < 0 { - xy, z = -xy, -z - } - if xy >= 0 { - xy += z / 2 - } else { - xy -= z / 2 - } - return xy / z -} - -// round rounds the given number. The rounding algorithm is described at -// https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding -func (h *hinter) round(x fixed.Int26_6) fixed.Int26_6 { - if h.gs.roundPeriod == 0 { - // Rounding is off. - return x - } - if x >= 0 { - ret := x - h.gs.roundPhase + h.gs.roundThreshold - if h.gs.roundSuper45 { - ret /= h.gs.roundPeriod - ret *= h.gs.roundPeriod - } else { - ret &= -h.gs.roundPeriod - } - if x != 0 && ret < 0 { - ret = 0 - } - return ret + h.gs.roundPhase - } - ret := -x - h.gs.roundPhase + h.gs.roundThreshold - if h.gs.roundSuper45 { - ret /= h.gs.roundPeriod - ret *= h.gs.roundPeriod - } else { - ret &= -h.gs.roundPeriod - } - if ret < 0 { - ret = 0 - } - return -ret - h.gs.roundPhase -} - -func bool2int32(b bool) int32 { - if b { - return 1 - } - return 0 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go deleted file mode 100644 index 1880e1e63..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go deleted file mode 100644 index 692e01526..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go +++ /dev/null @@ -1,639 +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 pixels in 1 em, expressed as a 26.6 fixed point value. For -// example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to -// fixed.Int26_6(10 << 6). -// -// To measure a TrueType font in ideal FUnit space, use scale equal to -// font.FUnitsPerEm(). -package truetype - -import ( - "fmt" - - "golang.org/x/image/math/fixed" -) - -// An Index is a Font's index of a rune. -type Index uint16 - -// A NameID identifies a name table entry. -// -// See https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html -type NameID uint16 - -const ( - NameIDCopyright NameID = 0 - NameIDFontFamily = 1 - NameIDFontSubfamily = 2 - NameIDUniqueSubfamilyID = 3 - NameIDFontFullName = 4 - NameIDNameTableVersion = 5 - NameIDPostscriptName = 6 - NameIDTrademarkNotice = 7 - NameIDManufacturerName = 8 - NameIDDesignerName = 9 - NameIDFontDescription = 10 - NameIDFontVendorURL = 11 - NameIDFontDesignerURL = 12 - NameIDFontLicense = 13 - NameIDFontLicenseURL = 14 - NameIDPreferredFamily = 16 - NameIDPreferredSubfamily = 17 - NameIDCompatibleName = 18 - NameIDSampleText = 19 -) - -const ( - // 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) -) - -// An HMetric holds the horizontal metrics of a single glyph. -type HMetric struct { - AdvanceWidth, LeftSideBearing fixed.Int26_6 -} - -// A VMetric holds the vertical metrics of a single glyph. -type VMetric struct { - AdvanceHeight, TopSideBearing fixed.Int26_6 -} - -// 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 -} - -// parseSubtables returns the offset and platformID of the best subtable in -// table, where best favors a Unicode cmap encoding, and failing that, a -// Microsoft cmap encoding. offset is the offset of the first subtable in -// table, and size is the size of each subtable. -// -// If pred is non-nil, then only subtables that satisfy that predicate will be -// considered. -func parseSubtables(table []byte, name string, offset, size int, pred func([]byte) bool) ( - bestOffset int, bestPID uint32, retErr error) { - - if len(table) < 4 { - return 0, 0, FormatError(name + " too short") - } - nSubtables := int(u16(table, 2)) - if len(table) < size*nSubtables+offset { - return 0, 0, FormatError(name + " too short") - } - ok := false - for i := 0; i < nSubtables; i, offset = i+1, offset+size { - if pred != nil && !pred(table[offset:]) { - continue - } - // We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32. - // All values are big-endian. - pidPsid := u32(table, offset) - // We prefer the Unicode cmap encoding. Failing to find that, we fall - // back onto the Microsoft cmap encoding. - if pidPsid == unicodeEncoding { - bestOffset, bestPID, ok = offset, pidPsid>>16, true - break - - } else if pidPsid == microsoftSymbolEncoding || - pidPsid == microsoftUCS2Encoding || - pidPsid == microsoftUCS4Encoding { - - bestOffset, bestPID, ok = offset, pidPsid>>16, true - // We don't break out of the for loop, so that Unicode can override Microsoft. - } - } - if !ok { - return 0, 0, UnsupportedError(name + " encoding") - } - return bestOffset, bestPID, 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, name, 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 fixed.Rectangle26_6 - // Values from the maxp section. - maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16 -} - -func (f *Font) parseCmap() error { - const ( - cmapFormat4 = 4 - cmapFormat12 = 12 - languageIndependent = 0 - ) - - offset, _, err := parseSubtables(f.cmap, "cmap", 4, 8, nil) - if err != nil { - return err - } - offset = int(u32(f.cmap, offset+4)) - 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.Min.X = fixed.Int26_6(int16(u16(f.head, 36))) - f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38))) - f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40))) - f.bounds.Max.Y = fixed.Int26_6(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 fixed.Int26_6) fixed.Int26_6 { - if x >= 0 { - x += fixed.Int26_6(f.fUnitsPerEm) / 2 - } else { - x -= fixed.Int26_6(f.fUnitsPerEm) / 2 - } - return x / fixed.Int26_6(f.fUnitsPerEm) -} - -// Bounds returns the union of a Font's glyphs' bounds. -func (f *Font) Bounds(scale fixed.Int26_6) fixed.Rectangle26_6 { - b := f.bounds - b.Min.X = f.scale(scale * b.Min.X) - b.Min.Y = f.scale(scale * b.Min.Y) - b.Max.X = f.scale(scale * b.Max.X) - b.Max.Y = f.scale(scale * b.Max.Y) - 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 -} - -// Name returns the Font's name value for the given NameID. It returns "" if -// there was an error, or if that name was not found. -func (f *Font) Name(id NameID) string { - x, platformID, err := parseSubtables(f.name, "name", 6, 12, func(b []byte) bool { - return NameID(u16(b, 6)) == id - }) - if err != nil { - return "" - } - offset, length := u16(f.name, 4)+u16(f.name, x+10), u16(f.name, x+8) - // Return the ASCII value of the encoded string. - // The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1. - src := f.name[offset : offset+length] - var dst []byte - if platformID != 1 { // UTF-16. - if len(src)&1 != 0 { - return "" - } - dst = make([]byte, len(src)/2) - for i := range dst { - dst[i] = printable(u16(src, 2*i)) - } - } else { // ASCII. - dst = make([]byte, len(src)) - for i, c := range src { - dst[i] = printable(uint16(c)) - } - } - return string(dst) -} - -func printable(r uint16) byte { - if 0x20 <= r && r < 0x7f { - return byte(r) - } - return '?' -} - -// 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: fixed.Int26_6(u16(f.hmtx, p)), - LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))), - } - } - return HMetric{ - AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)), - LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))), - } -} - -// HMetric returns the horizontal metrics for the glyph with the given index. -func (f *Font) HMetric(scale fixed.Int26_6, 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 fixed.Int26_6) (v VMetric) { - j := int(i) - if j < 0 || f.nGlyph <= j { - return VMetric{} - } - if 4*j+4 <= len(f.vmtx) { - return VMetric{ - AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)), - TopSideBearing: fixed.Int26_6(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 := fixed.Int26_6(int16(u16(f.os2, 68))) - sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70))) - return VMetric{ - AdvanceHeight: sTypoAscender - sTypoDescender, - TopSideBearing: sTypoAscender - yMax, - } - } - return VMetric{ - AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm), - TopSideBearing: 0, - } -} - -// VMetric returns the vertical metrics for the glyph with the given index. -func (f *Font) VMetric(scale fixed.Int26_6, 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 -} - -// Kern returns the horizontal adjustment for the given glyph pair. A positive -// kern means to move the glyphs further apart. -func (f *Font) Kern(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 { - 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 * fixed.Int26_6(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 "name": - f.name, 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 -} -- cgit v1.2.3-1-g7c22