summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Godeps/Godeps.json15
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/advanced_path.go42
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/arc.go67
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/Makefile11
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/arc.go36
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64.go67
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go696
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/curve_test.go262
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/quad_float64.go51
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curves.go336
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/dasher.go90
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/demux_converter.go23
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/doc.go5
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/font.go97
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/gc.go55
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/image.go359
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/math.go52
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/paint.go92
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path.go27
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_adder.go70
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_converter.go173
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_storage.go190
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/coverage_table.go203
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerAA.go320
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV1/fillerAA.go303
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV2/fillerAA.go320
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fixed_point.go17
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/line.go55
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/polygon.go581
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/raster_test.go200
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/rgba_interpolation.go150
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stack_gc.go208
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stroker.go135
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/transform.go306
-rw-r--r--Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/vertex2d.go19
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go280
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go292
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go579
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go466
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go530
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go1764
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go673
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go289
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go554
-rw-r--r--Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go366
-rw-r--r--api/user.go39
46 files changed, 5 insertions, 11460 deletions
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 87207c5e1..0faccd1ea 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -3,21 +3,6 @@
"GoVersion": "go1.4",
"Deps": [
{
- "ImportPath": "code.google.com/p/draw2d/draw2d",
- "Comment": "release-20",
- "Rev": "eaeb833648eee1b7c20e77ffc8180646c0395298"
- },
- {
- "ImportPath": "code.google.com/p/freetype-go/freetype/raster",
- "Comment": "release-85",
- "Rev": "46c3056cafbb4da11c4087a892c7d2bfa4224a8f"
- },
- {
- "ImportPath": "code.google.com/p/freetype-go/freetype/truetype",
- "Comment": "release-85",
- "Rev": "46c3056cafbb4da11c4087a892c7d2bfa4224a8f"
- },
- {
"ImportPath": "code.google.com/p/go-uuid/uuid",
"Comment": "null-15",
"Rev": "35bc42037350f0078e3c974c6ea690f1926603ab"
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/advanced_path.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/advanced_path.go
deleted file mode 100644
index 68f1d782b..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/advanced_path.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "math"
-)
-
-//high level path creation
-
-func Rect(path Path, x1, y1, x2, y2 float64) {
- path.MoveTo(x1, y1)
- path.LineTo(x2, y1)
- path.LineTo(x2, y2)
- path.LineTo(x1, y2)
- path.Close()
-}
-
-func RoundRect(path Path, x1, y1, x2, y2, arcWidth, arcHeight float64) {
- arcWidth = arcWidth / 2
- arcHeight = arcHeight / 2
- path.MoveTo(x1, y1+arcHeight)
- path.QuadCurveTo(x1, y1, x1+arcWidth, y1)
- path.LineTo(x2-arcWidth, y1)
- path.QuadCurveTo(x2, y1, x2, y1+arcHeight)
- path.LineTo(x2, y2-arcHeight)
- path.QuadCurveTo(x2, y2, x2-arcWidth, y2)
- path.LineTo(x1+arcWidth, y2)
- path.QuadCurveTo(x1, y2, x1, y2-arcHeight)
- path.Close()
-}
-
-func Ellipse(path Path, cx, cy, rx, ry float64) {
- path.ArcTo(cx, cy, rx, ry, 0, -math.Pi*2)
- path.Close()
-}
-
-func Circle(path Path, cx, cy, radius float64) {
- path.ArcTo(cx, cy, radius, radius, 0, -math.Pi*2)
- path.Close()
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/arc.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/arc.go
deleted file mode 100644
index 0698b8da0..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/arc.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/raster"
- "math"
-)
-
-func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
- end := start + angle
- clockWise := true
- if angle < 0 {
- clockWise = false
- }
- ra := (math.Abs(rx) + math.Abs(ry)) / 2
- da := math.Acos(ra/(ra+0.125/scale)) * 2
- //normalize
- if !clockWise {
- da = -da
- }
- angle = start + da
- var curX, curY float64
- for {
- if (angle < end-da/4) != clockWise {
- curX = x + math.Cos(end)*rx
- curY = y + math.Sin(end)*ry
- return curX, curY
- }
- curX = x + math.Cos(angle)*rx
- curY = y + math.Sin(angle)*ry
-
- angle += da
- t.Vertex(curX, curY)
- }
- return curX, curY
-}
-
-func arcAdder(adder raster.Adder, x, y, rx, ry, start, angle, scale float64) raster.Point {
- end := start + angle
- clockWise := true
- if angle < 0 {
- clockWise = false
- }
- ra := (math.Abs(rx) + math.Abs(ry)) / 2
- da := math.Acos(ra/(ra+0.125/scale)) * 2
- //normalize
- if !clockWise {
- da = -da
- }
- angle = start + da
- var curX, curY float64
- for {
- if (angle < end-da/4) != clockWise {
- curX = x + math.Cos(end)*rx
- curY = y + math.Sin(end)*ry
- return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
- }
- curX = x + math.Cos(angle)*rx
- curY = y + math.Sin(angle)*ry
-
- angle += da
- adder.Add1(raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)})
- }
- return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/Makefile b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/Makefile
deleted file mode 100644
index 15ceee070..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-include $(GOROOT)/src/Make.inc
-
-TARG=draw2d.googlecode.com/hg/draw2d/curve
-GOFILES=\
- cubic_float64.go\
- quad_float64.go\
- cubic_float64_others.go\
-
-
-
-include $(GOROOT)/src/Make.pkg
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/arc.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/arc.go
deleted file mode 100644
index 92850e979..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/arc.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-package curve
-
-import (
- "math"
-)
-
-func SegmentArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) {
- end := start + angle
- clockWise := true
- if angle < 0 {
- clockWise = false
- }
- ra := (math.Abs(rx) + math.Abs(ry)) / 2
- da := math.Acos(ra/(ra+0.125/scale)) * 2
- //normalize
- if !clockWise {
- da = -da
- }
- angle = start + da
- var curX, curY float64
- for {
- if (angle < end-da/4) != clockWise {
- curX = x + math.Cos(end)*rx
- curY = y + math.Sin(end)*ry
- break;
- }
- curX = x + math.Cos(angle)*rx
- curY = y + math.Sin(angle)*ry
-
- angle += da
- t.LineTo(curX, curY)
- }
- t.LineTo(curX, curY)
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64.go
deleted file mode 100644
index 64a7ac639..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 17/05/2011 by Laurent Le Goff
-package curve
-
-import (
- "math"
-)
-
-const (
- CurveRecursionLimit = 32
-)
-
-// X1, Y1, X2, Y2, X3, Y3, X4, Y4 float64
-type CubicCurveFloat64 [8]float64
-
-type LineTracer interface {
- LineTo(x, y float64)
-}
-
-func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float64) {
- // Calculate all the mid-points of the line segments
- //----------------------
- c1[0], c1[1] = c[0], c[1]
- c2[6], c2[7] = c[6], c[7]
- c1[2] = (c[0] + c[2]) / 2
- c1[3] = (c[1] + c[3]) / 2
- x23 = (c[2] + c[4]) / 2
- y23 = (c[3] + c[5]) / 2
- c2[4] = (c[4] + c[6]) / 2
- c2[5] = (c[5] + c[7]) / 2
- c1[4] = (c1[2] + x23) / 2
- c1[5] = (c1[3] + y23) / 2
- c2[2] = (x23 + c2[4]) / 2
- c2[3] = (y23 + c2[5]) / 2
- c1[6] = (c1[4] + c2[2]) / 2
- c1[7] = (c1[5] + c2[3]) / 2
- c2[0], c2[1] = c1[6], c1[7]
- return
-}
-
-func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
- var curves [CurveRecursionLimit]CubicCurveFloat64
- curves[0] = *curve
- i := 0
- // current curve
- var c *CubicCurveFloat64
-
- var dx, dy, d2, d3 float64
-
- for i >= 0 {
- c = &curves[i]
- dx = c[6] - c[0]
- dy = c[7] - c[1]
-
- d2 = math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx))
- d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
-
- if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
- t.LineTo(c[6], c[7])
- i--
- } else {
- // second half of bezier go lower onto the stack
- c.Subdivide(&curves[i+1], &curves[i])
- i++
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go
deleted file mode 100644
index a888b22a1..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go
+++ /dev/null
@@ -1,696 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 17/05/2011 by Laurent Le Goff
-package curve
-
-import (
- "math"
-)
-
-const (
- CurveCollinearityEpsilon = 1e-30
- CurveAngleToleranceEpsilon = 0.01
-)
-
-//mu ranges from 0 to 1, start to end of curve
-func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) {
-
- mum1 := 1 - mu
- mum13 := mum1 * mum1 * mum1
- mu3 := mu * mu * mu
-
- x = mum13*c[0] + 3*mu*mum1*mum1*c[2] + 3*mu*mu*mum1*c[4] + mu3*c[6]
- y = mum13*c[1] + 3*mu*mum1*mum1*c[3] + 3*mu*mu*mum1*c[5] + mu3*c[7]
- return
-}
-
-func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) (x23, y23 float64) {
- inv_t := (1 - t)
- c1[0], c1[1] = c[0], c[1]
- c2[6], c2[7] = c[6], c[7]
-
- c1[2] = inv_t*c[0] + t*c[2]
- c1[3] = inv_t*c[1] + t*c[3]
-
- x23 = inv_t*c[2] + t*c[4]
- y23 = inv_t*c[3] + t*c[5]
-
- c2[4] = inv_t*c[4] + t*c[6]
- c2[5] = inv_t*c[5] + t*c[7]
-
- c1[4] = inv_t*c1[2] + t*x23
- c1[5] = inv_t*c1[3] + t*y23
-
- c2[2] = inv_t*x23 + t*c2[4]
- c2[3] = inv_t*y23 + t*c2[5]
-
- c1[6] = inv_t*c1[4] + t*c2[2]
- c1[7] = inv_t*c1[5] + t*c2[3]
-
- c2[0], c2[1] = c1[6], c1[7]
- return
-}
-
-func (c *CubicCurveFloat64) EstimateDistance() float64 {
- dx1 := c[2] - c[0]
- dy1 := c[3] - c[1]
- dx2 := c[4] - c[2]
- dy2 := c[5] - c[3]
- dx3 := c[6] - c[4]
- dy3 := c[7] - c[5]
- return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3)
-}
-
-// subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision
-func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) {
- c.segmentRec(t, flattening_threshold)
- t.LineTo(c[6], c[7])
-}
-
-func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float64) {
- var c1, c2 CubicCurveFloat64
- c.Subdivide(&c1, &c2)
-
- // Try to approximate the full cubic curve by a single straight line
- //------------------
- dx := c[6] - c[0]
- dy := c[7] - c[1]
-
- d2 := math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx))
- d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
-
- if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) {
- t.LineTo(c[6], c[7])
- return
- }
- // Continue subdivision
- //----------------------
- c1.segmentRec(t, flattening_threshold)
- c2.segmentRec(t, flattening_threshold)
-}
-
-/*
- The function has the following parameters:
- approximationScale :
- Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one.
- It always has some scaling coefficient.
- The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels.
- Usually it looks as follows:
- curved.approximationScale(transform.scale());
- where transform is the affine matrix that includes all the transformations, including viewport and zoom.
- angleTolerance :
- You set it in radians.
- The less this value is the more accurate will be the approximation at sharp turns.
- But 0 means that we don't consider angle conditions at all.
- cuspLimit :
- An angle in radians.
- If 0, only the real cusps will have bevel cuts.
- If more than 0, it will restrict the sharpness.
- The more this value is the less sharp turns will be cut.
- Typically it should not exceed 10-15 degrees.
-*/
-func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) {
- cuspLimit = computeCuspLimit(cuspLimit)
- distanceToleranceSquare := 0.5 / approximationScale
- distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
- c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
- t.LineTo(c[6], c[7])
-}
-
-func computeCuspLimit(v float64) (r float64) {
- if v == 0.0 {
- r = 0.0
- } else {
- r = math.Pi - v
- }
- return
-}
-
-func squareDistance(x1, y1, x2, y2 float64) float64 {
- dx := x2 - x1
- dy := y2 - y1
- return dx*dx + dy*dy
-}
-
-/**
- * http://www.antigrain.com/research/adaptive_bezier/index.html
- */
-func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
- if level > CurveRecursionLimit {
- return
- }
- var c1, c2 CubicCurveFloat64
- x23, y23 := c.Subdivide(&c1, &c2)
-
- // Try to approximate the full cubic curve by a single straight line
- //------------------
- dx := c[6] - c[0]
- dy := c[7] - c[1]
-
- d2 := math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx))
- d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
- switch {
- case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // All collinear OR p1==p4
- //----------------------
- k := dx*dx + dy*dy
- if k == 0 {
- d2 = squareDistance(c[0], c[1], c[2], c[3])
- d3 = squareDistance(c[6], c[7], c[4], c[5])
- } else {
- k = 1 / k
- da1 := c[2] - c[0]
- da2 := c[3] - c[1]
- d2 = k * (da1*dx + da2*dy)
- da1 = c[4] - c[0]
- da2 = c[5] - c[1]
- d3 = k * (da1*dx + da2*dy)
- if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
- // Simple collinear case, 1---2---3---4
- // We can leave just two endpoints
- return
- }
- if d2 <= 0 {
- d2 = squareDistance(c[2], c[3], c[0], c[1])
- } else if d2 >= 1 {
- d2 = squareDistance(c[2], c[3], c[6], c[7])
- } else {
- d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy)
- }
-
- if d3 <= 0 {
- d3 = squareDistance(c[4], c[5], c[0], c[1])
- } else if d3 >= 1 {
- d3 = squareDistance(c[4], c[5], c[6], c[7])
- } else {
- d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy)
- }
- }
- if d2 > d3 {
- if d2 < distanceToleranceSquare {
- t.LineTo(c[2], c[3])
- return
- }
- } else {
- if d3 < distanceToleranceSquare {
- t.LineTo(c[4], c[5])
- return
- }
- }
-
- case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // p1,p2,p4 are collinear, p3 is significant
- //----------------------
- if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- return
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2]))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- t.LineTo(c[2], c[3])
- t.LineTo(c[4], c[5])
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[4], c[5])
- return
- }
- }
- }
-
- case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // p1,p3,p4 are collinear, p2 is significant
- //----------------------
- if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- return
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0]))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- t.LineTo(c[2], c[3])
- t.LineTo(c[4], c[5])
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[2], c[3])
- return
- }
- }
- }
-
- case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // Regular case
- //-----------------
- if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
- // If the curvature doesn't exceed the distanceTolerance value
- // we tend to finish subdivisions.
- //----------------------
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- return
- }
-
- // Angle & Cusp Condition
- //----------------------
- k := math.Atan2(c[5]-c[3], c[4]-c[2])
- da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0]))
- da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k)
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
- if da2 >= math.Pi {
- da2 = 2*math.Pi - da2
- }
-
- if da1+da2 < angleTolerance {
- // Finally we can stop the recursion
- //----------------------
- t.LineTo(x23, y23)
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[2], c[3])
- return
- }
-
- if da2 > cuspLimit {
- t.LineTo(c[4], c[5])
- return
- }
- }
- }
- }
-
- // Continue subdivision
- //----------------------
- c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
- c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
-
-}
-
-func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) {
- cuspLimit = computeCuspLimit(cuspLimit)
- distanceToleranceSquare := 0.5 / approximationScale
- distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
-
- var curves [CurveRecursionLimit]CubicCurveFloat64
- curves[0] = *curve
- i := 0
- // current curve
- var c *CubicCurveFloat64
- var c1, c2 CubicCurveFloat64
- var dx, dy, d2, d3, k, x23, y23 float64
- for i >= 0 {
- c = &curves[i]
- x23, y23 = c.Subdivide(&c1, &c2)
-
- // Try to approximate the full cubic curve by a single straight line
- //------------------
- dx = c[6] - c[0]
- dy = c[7] - c[1]
-
- d2 = math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx))
- d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
- switch {
- case i == len(curves)-1:
- t.LineTo(c[6], c[7])
- i--
- continue
- case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // All collinear OR p1==p4
- //----------------------
- k = dx*dx + dy*dy
- if k == 0 {
- d2 = squareDistance(c[0], c[1], c[2], c[3])
- d3 = squareDistance(c[6], c[7], c[4], c[5])
- } else {
- k = 1 / k
- da1 := c[2] - c[0]
- da2 := c[3] - c[1]
- d2 = k * (da1*dx + da2*dy)
- da1 = c[4] - c[0]
- da2 = c[5] - c[1]
- d3 = k * (da1*dx + da2*dy)
- if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
- // Simple collinear case, 1---2---3---4
- // We can leave just two endpoints
- i--
- continue
- }
- if d2 <= 0 {
- d2 = squareDistance(c[2], c[3], c[0], c[1])
- } else if d2 >= 1 {
- d2 = squareDistance(c[2], c[3], c[6], c[7])
- } else {
- d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy)
- }
-
- if d3 <= 0 {
- d3 = squareDistance(c[4], c[5], c[0], c[1])
- } else if d3 >= 1 {
- d3 = squareDistance(c[4], c[5], c[6], c[7])
- } else {
- d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy)
- }
- }
- if d2 > d3 {
- if d2 < distanceToleranceSquare {
- t.LineTo(c[2], c[3])
- i--
- continue
- }
- } else {
- if d3 < distanceToleranceSquare {
- t.LineTo(c[4], c[5])
- i--
- continue
- }
- }
-
- case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // p1,p2,p4 are collinear, p3 is significant
- //----------------------
- if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- i--
- continue
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2]))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- t.LineTo(c[2], c[3])
- t.LineTo(c[4], c[5])
- i--
- continue
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[4], c[5])
- i--
- continue
- }
- }
- }
-
- case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // p1,p3,p4 are collinear, p2 is significant
- //----------------------
- if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- i--
- continue
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0]))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- t.LineTo(c[2], c[3])
- t.LineTo(c[4], c[5])
- i--
- continue
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[2], c[3])
- i--
- continue
- }
- }
- }
-
- case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // Regular case
- //-----------------
- if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
- // If the curvature doesn't exceed the distanceTolerance value
- // we tend to finish subdivisions.
- //----------------------
- if angleTolerance < CurveAngleToleranceEpsilon {
- t.LineTo(x23, y23)
- i--
- continue
- }
-
- // Angle & Cusp Condition
- //----------------------
- k := math.Atan2(c[5]-c[3], c[4]-c[2])
- da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0]))
- da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k)
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
- if da2 >= math.Pi {
- da2 = 2*math.Pi - da2
- }
-
- if da1+da2 < angleTolerance {
- // Finally we can stop the recursion
- //----------------------
- t.LineTo(x23, y23)
- i--
- continue
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- t.LineTo(c[2], c[3])
- i--
- continue
- }
-
- if da2 > cuspLimit {
- t.LineTo(c[4], c[5])
- i--
- continue
- }
- }
- }
- }
-
- // Continue subdivision
- //----------------------
- curves[i+1], curves[i] = c1, c2
- i++
- }
- t.LineTo(curve[6], curve[7])
-}
-
-/********************** Ahmad thesis *******************/
-
-/**************************************************************************************
-* This code is the implementation of the Parabolic Approximation (PA). Although *
-* it uses recursive subdivision as a safe net for the failing cases, this is an *
-* iterative routine and reduces considerably the number of vertices (point) *
-* generation. *
-**************************************************************************************/
-
-func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) {
- estimatedIFP := c.numberOfInflectionPoints()
- if estimatedIFP == 0 {
- // If no inflection points then apply PA on the full Bezier segment.
- c.doParabolicApproximation(t, flattening_threshold)
- return
- }
- // If one or more inflection point then we will have to subdivide the curve
- numOfIfP, t1, t2 := c.findInflectionPoints()
- if numOfIfP == 2 {
- // Case when 2 inflection points then divide at the smallest one first
- var sub1, tmp1, sub2, sub3 CubicCurveFloat64
- c.SubdivideAt(&sub1, &tmp1, t1)
- // Now find the second inflection point in the second curve an subdivide
- numOfIfP, t1, t2 = tmp1.findInflectionPoints()
- if numOfIfP == 2 {
- tmp1.SubdivideAt(&sub2, &sub3, t2)
- } else if numOfIfP == 1 {
- tmp1.SubdivideAt(&sub2, &sub3, t1)
- } else {
- return
- }
- // Use PA for first subsegment
- sub1.doParabolicApproximation(t, flattening_threshold)
- // Use RS for the second (middle) subsegment
- sub2.Segment(t, flattening_threshold)
- // Drop the last point in the array will be added by the PA in third subsegment
- //noOfPoints--;
- // Use PA for the third curve
- sub3.doParabolicApproximation(t, flattening_threshold)
- } else if numOfIfP == 1 {
- // Case where there is one inflection point, subdivide once and use PA on
- // both subsegments
- var sub1, sub2 CubicCurveFloat64
- c.SubdivideAt(&sub1, &sub2, t1)
- sub1.doParabolicApproximation(t, flattening_threshold)
- //noOfPoints--;
- sub2.doParabolicApproximation(t, flattening_threshold)
- } else {
- // Case where there is no inflection USA PA directly
- c.doParabolicApproximation(t, flattening_threshold)
- }
-}
-
-// Find the third control point deviation form the axis
-func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 {
- dx := c[2] - c[0]
- dy := c[3] - c[1]
- l2 := dx*dx + dy*dy
- if l2 == 0 {
- return 0
- }
- l := math.Sqrt(l2)
- r := (c[3] - c[1]) / l
- s := (c[0] - c[2]) / l
- u := (c[2]*c[1] - c[0]*c[3]) / l
- return math.Abs(r*c[4] + s*c[5] + u)
-}
-
-// Find the number of inflection point
-func (c *CubicCurveFloat64) numberOfInflectionPoints() int {
- dx21 := (c[2] - c[0])
- dy21 := (c[3] - c[1])
- dx32 := (c[4] - c[2])
- dy32 := (c[5] - c[3])
- dx43 := (c[6] - c[4])
- dy43 := (c[7] - c[5])
- if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 {
- return 1 // One inflection point
- } else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 {
- return 0 // No inflection point
- } else {
- // Most cases no inflection point
- b1 := (dx21*dx32 + dy21*dy32) > 0
- b2 := (dx32*dx43 + dy32*dy43) > 0
- if b1 || b2 && !(b1 && b2) { // xor!!
- return 0
- }
- }
- return -1 // cases where there in zero or two inflection points
-}
-
-// This is the main function where all the work is done
-func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) {
- var c *CubicCurveFloat64
- c = curve
- var d, t, dx, dy, d2, d3 float64
- for {
- dx = c[6] - c[0]
- dy = c[7] - c[1]
-
- d2 = math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx))
- d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
-
- if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) {
- // If the subsegment deviation satisfy the flatness then store the last
- // point and stop
- tracer.LineTo(c[6], c[7])
- break
- }
- // Find the third control point deviation and the t values for subdivision
- d = c.thirdControlPointDeviation()
- t = 2 * math.Sqrt(flattening_threshold/d/3)
- if t > 1 {
- // Case where the t value calculated is invalid so using RS
- c.Segment(tracer, flattening_threshold)
- break
- }
- // Valid t value to subdivide at that calculated value
- var b1, b2 CubicCurveFloat64
- c.SubdivideAt(&b1, &b2, t)
- // First subsegment should have its deviation equal to flatness
- dx = b1[6] - b1[0]
- dy = b1[7] - b1[1]
-
- d2 = math.Abs(((b1[2]-b1[6])*dy - (b1[3]-b1[7])*dx))
- d3 = math.Abs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx))
-
- if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) {
- // if not then use RS to handle any mathematical errors
- b1.Segment(tracer, flattening_threshold)
- } else {
- tracer.LineTo(b1[6], b1[7])
- }
- // repeat the process for the left over subsegment.
- c = &b2
- }
-}
-
-// Find the actual inflection points and return the number of inflection points found
-// if 2 inflection points found, the first one returned will be with smaller t value.
-func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) {
- // For Cubic Bezier curve with equation P=a*t^3 + b*t^2 + c*t + d
- // slope of the curve dP/dt = 3*a*t^2 + 2*b*t + c
- // a = (float)(-bez.p1 + 3*bez.p2 - 3*bez.p3 + bez.p4);
- // b = (float)(3*bez.p1 - 6*bez.p2 + 3*bez.p3);
- // c = (float)(-3*bez.p1 + 3*bez.p2);
- ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6])
- bx := (3*curve[0] - 6*curve[2] + 3*curve[4])
- cx := (-3*curve[0] + 3*curve[2])
- ay := (-curve[1] + 3*curve[3] - 3*curve[5] + curve[7])
- by := (3*curve[1] - 6*curve[3] + 3*curve[5])
- cy := (-3*curve[1] + 3*curve[3])
- a := (3 * (ay*bx - ax*by))
- b := (3 * (ay*cx - ax*cy))
- c := (by*cx - bx*cy)
- r2 := (b*b - 4*a*c)
- firstIfp = 0.0
- secondIfp = 0.0
- if r2 >= 0.0 && a != 0.0 {
- r := math.Sqrt(r2)
- firstIfp = ((-b + r) / (2 * a))
- secondIfp = ((-b - r) / (2 * a))
- if (firstIfp > 0.0 && firstIfp < 1.0) && (secondIfp > 0.0 && secondIfp < 1.0) {
- if firstIfp > secondIfp {
- tmp := firstIfp
- firstIfp = secondIfp
- secondIfp = tmp
- }
- if secondIfp-firstIfp > 0.00001 {
- return 2, firstIfp, secondIfp
- } else {
- return 1, firstIfp, secondIfp
- }
- } else if firstIfp > 0.0 && firstIfp < 1.0 {
- return 1, firstIfp, secondIfp
- } else if secondIfp > 0.0 && secondIfp < 1.0 {
- firstIfp = secondIfp
- return 1, firstIfp, secondIfp
- }
- return 0, firstIfp, secondIfp
- }
- return 0, firstIfp, secondIfp
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/curve_test.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/curve_test.go
deleted file mode 100644
index 5e9eecac0..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/curve_test.go
+++ /dev/null
@@ -1,262 +0,0 @@
-package curve
-
-import (
- "bufio"
- "code.google.com/p/draw2d/draw2d/raster"
- "fmt"
- "image"
- "image/color"
- "image/draw"
- "image/png"
- "log"
- "os"
- "testing"
-)
-
-var (
- flattening_threshold float64 = 0.5
- testsCubicFloat64 = []CubicCurveFloat64{
- CubicCurveFloat64{100, 100, 200, 100, 100, 200, 200, 200},
- CubicCurveFloat64{100, 100, 300, 200, 200, 200, 300, 100},
- CubicCurveFloat64{100, 100, 0, 300, 200, 0, 300, 300},
- CubicCurveFloat64{150, 290, 10, 10, 290, 10, 150, 290},
- CubicCurveFloat64{10, 290, 10, 10, 290, 10, 290, 290},
- CubicCurveFloat64{100, 290, 290, 10, 10, 10, 200, 290},
- }
- testsQuadFloat64 = []QuadCurveFloat64{
- QuadCurveFloat64{100, 100, 200, 100, 200, 200},
- QuadCurveFloat64{100, 100, 290, 200, 290, 100},
- QuadCurveFloat64{100, 100, 0, 290, 200, 290},
- QuadCurveFloat64{150, 290, 10, 10, 290, 290},
- QuadCurveFloat64{10, 290, 10, 10, 290, 290},
- QuadCurveFloat64{100, 290, 290, 10, 120, 290},
- }
-)
-
-type Path struct {
- points []float64
-}
-
-func (p *Path) LineTo(x, y float64) {
- if len(p.points)+2 > cap(p.points) {
- points := make([]float64, len(p.points)+2, len(p.points)+32)
- copy(points, p.points)
- p.points = points
- } else {
- p.points = p.points[0 : len(p.points)+2]
- }
- p.points[len(p.points)-2] = x
- p.points[len(p.points)-1] = y
-}
-
-func init() {
- f, err := os.Create("_test.html")
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
- defer f.Close()
- log.Printf("Create html viewer")
- f.Write([]byte("<html><body>"))
- for i := 0; i < len(testsCubicFloat64); i++ {
- f.Write([]byte(fmt.Sprintf("<div><img src='_testRec%d.png'/>\n<img src='_test%d.png'/>\n<img src='_testAdaptiveRec%d.png'/>\n<img src='_testAdaptive%d.png'/>\n<img src='_testParabolic%d.png'/>\n</div>\n", i, i, i, i, i)))
- }
- for i := 0; i < len(testsQuadFloat64); i++ {
- f.Write([]byte(fmt.Sprintf("<div><img src='_testQuad%d.png'/>\n</div>\n", i)))
- }
- f.Write([]byte("</body></html>"))
-
-}
-
-func savepng(filePath string, m image.Image) {
- f, err := os.Create(filePath)
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
- defer f.Close()
- b := bufio.NewWriter(f)
- err = png.Encode(b, m)
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
- err = b.Flush()
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
-}
-
-func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image {
- /*for i := 0; i < len(s); i += 2 {
- x, y := int(s[i]+0.5), int(s[i+1]+0.5)
- img.Set(x, y, c)
- img.Set(x, y+1, c)
- img.Set(x, y-1, c)
- img.Set(x+1, y, c)
- img.Set(x+1, y+1, c)
- img.Set(x+1, y-1, c)
- img.Set(x-1, y, c)
- img.Set(x-1, y+1, c)
- img.Set(x-1, y-1, c)
-
- }*/
- return img
-}
-
-func TestCubicCurveRec(t *testing.T) {
- for i, curve := range testsCubicFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.SegmentRec(&p, flattening_threshold)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_testRec%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func TestCubicCurve(t *testing.T) {
- for i, curve := range testsCubicFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.Segment(&p, flattening_threshold)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_test%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func TestCubicCurveAdaptiveRec(t *testing.T) {
- for i, curve := range testsCubicFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.AdaptiveSegmentRec(&p, 1, 0, 0)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_testAdaptiveRec%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func TestCubicCurveAdaptive(t *testing.T) {
- for i, curve := range testsCubicFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.AdaptiveSegment(&p, 1, 0, 0)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_testAdaptive%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func TestCubicCurveParabolic(t *testing.T) {
- for i, curve := range testsCubicFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.ParabolicSegment(&p, flattening_threshold)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_testParabolic%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func TestQuadCurve(t *testing.T) {
- for i, curve := range testsQuadFloat64 {
- var p Path
- p.LineTo(curve[0], curve[1])
- curve.Segment(&p, flattening_threshold)
- img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
- raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
- raster.PolylineBresenham(img, image.Black, p.points...)
- //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
- drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
- savepng(fmt.Sprintf("_testQuad%d.png", i), img)
- log.Printf("Num of points: %d\n", len(p.points))
- }
- fmt.Println()
-}
-
-func BenchmarkCubicCurveRec(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsCubicFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.SegmentRec(&p, flattening_threshold)
- }
- }
-}
-
-func BenchmarkCubicCurve(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsCubicFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.Segment(&p, flattening_threshold)
- }
- }
-}
-
-func BenchmarkCubicCurveAdaptiveRec(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsCubicFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.AdaptiveSegmentRec(&p, 1, 0, 0)
- }
- }
-}
-
-func BenchmarkCubicCurveAdaptive(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsCubicFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.AdaptiveSegment(&p, 1, 0, 0)
- }
- }
-}
-
-func BenchmarkCubicCurveParabolic(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsCubicFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.ParabolicSegment(&p, flattening_threshold)
- }
- }
-}
-
-func BenchmarkQuadCurve(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, curve := range testsQuadFloat64 {
- p := Path{make([]float64, 0, 32)}
- p.LineTo(curve[0], curve[1])
- curve.Segment(&p, flattening_threshold)
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/quad_float64.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/quad_float64.go
deleted file mode 100644
index bd72affbb..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/quad_float64.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 17/05/2011 by Laurent Le Goff
-package curve
-
-import (
- "math"
-)
-
-//X1, Y1, X2, Y2, X3, Y3 float64
-type QuadCurveFloat64 [6]float64
-
-func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) {
- // Calculate all the mid-points of the line segments
- //----------------------
- c1[0], c1[1] = c[0], c[1]
- c2[4], c2[5] = c[4], c[5]
- c1[2] = (c[0] + c[2]) / 2
- c1[3] = (c[1] + c[3]) / 2
- c2[2] = (c[2] + c[4]) / 2
- c2[3] = (c[3] + c[5]) / 2
- c1[4] = (c1[2] + c2[2]) / 2
- c1[5] = (c1[3] + c2[3]) / 2
- c2[0], c2[1] = c1[4], c1[5]
- return
-}
-
-func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
- var curves [CurveRecursionLimit]QuadCurveFloat64
- curves[0] = *curve
- i := 0
- // current curve
- var c *QuadCurveFloat64
- var dx, dy, d float64
-
- for i >= 0 {
- c = &curves[i]
- dx = c[4] - c[0]
- dy = c[5] - c[1]
-
- d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
-
- if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
- t.LineTo(c[4], c[5])
- i--
- } else {
- // second half of bezier go lower onto the stack
- c.Subdivide(&curves[i+1], &curves[i])
- i++
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curves.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curves.go
deleted file mode 100644
index 4623cd4dc..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curves.go
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "math"
-)
-
-var (
- CurveRecursionLimit = 32
- CurveCollinearityEpsilon = 1e-30
- CurveAngleToleranceEpsilon = 0.01
-)
-
-/*
- The function has the following parameters:
- approximationScale :
- Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one.
- It always has some scaling coefficient.
- The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels.
- Usually it looks as follows:
- curved.approximationScale(transform.scale());
- where transform is the affine matrix that includes all the transformations, including viewport and zoom.
- angleTolerance :
- You set it in radians.
- The less this value is the more accurate will be the approximation at sharp turns.
- But 0 means that we don't consider angle conditions at all.
- cuspLimit :
- An angle in radians.
- If 0, only the real cusps will have bevel cuts.
- If more than 0, it will restrict the sharpness.
- The more this value is the less sharp turns will be cut.
- Typically it should not exceed 10-15 degrees.
-*/
-func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) {
- cuspLimit = computeCuspLimit(cuspLimit)
- distanceToleranceSquare := 0.5 / approximationScale
- distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
- recursiveCubicBezier(v, x1, y1, x2, y2, x3, y3, x4, y4, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
-}
-
-/*
- * see cubicBezier comments for approximationScale and angleTolerance definition
- */
-func quadraticBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float64) {
- distanceToleranceSquare := 0.5 / approximationScale
- distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
-
- recursiveQuadraticBezierBezier(v, x1, y1, x2, y2, x3, y3, 0, distanceToleranceSquare, angleTolerance)
-}
-
-func computeCuspLimit(v float64) (r float64) {
- if v == 0.0 {
- r = 0.0
- } else {
- r = math.Pi - v
- }
- return
-}
-
-/**
- * http://www.antigrain.com/research/adaptive_bezier/index.html
- */
-func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 float64, level int, distanceToleranceSquare, angleTolerance float64) {
- if level > CurveRecursionLimit {
- return
- }
-
- // Calculate all the mid-points of the line segments
- //----------------------
- x12 := (x1 + x2) / 2
- y12 := (y1 + y2) / 2
- x23 := (x2 + x3) / 2
- y23 := (y2 + y3) / 2
- x123 := (x12 + x23) / 2
- y123 := (y12 + y23) / 2
-
- dx := x3 - x1
- dy := y3 - y1
- d := math.Abs(((x2-x3)*dy - (y2-y3)*dx))
-
- if d > CurveCollinearityEpsilon {
- // Regular case
- //-----------------
- if d*d <= distanceToleranceSquare*(dx*dx+dy*dy) {
- // If the curvature doesn't exceed the distanceTolerance value
- // we tend to finish subdivisions.
- //----------------------
- if angleTolerance < CurveAngleToleranceEpsilon {
- v.Vertex(x123, y123)
- return
- }
-
- // Angle & Cusp Condition
- //----------------------
- da := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1))
- if da >= math.Pi {
- da = 2*math.Pi - da
- }
-
- if da < angleTolerance {
- // Finally we can stop the recursion
- //----------------------
- v.Vertex(x123, y123)
- return
- }
- }
- } else {
- // Collinear case
- //------------------
- da := dx*dx + dy*dy
- if da == 0 {
- d = squareDistance(x1, y1, x2, y2)
- } else {
- d = ((x2-x1)*dx + (y2-y1)*dy) / da
- if d > 0 && d < 1 {
- // Simple collinear case, 1---2---3
- // We can leave just two endpoints
- return
- }
- if d <= 0 {
- d = squareDistance(x2, y2, x1, y1)
- } else if d >= 1 {
- d = squareDistance(x2, y2, x3, y3)
- } else {
- d = squareDistance(x2, y2, x1+d*dx, y1+d*dy)
- }
- }
- if d < distanceToleranceSquare {
- v.Vertex(x2, y2)
- return
- }
- }
-
- // Continue subdivision
- //----------------------
- recursiveQuadraticBezierBezier(v, x1, y1, x12, y12, x123, y123, level+1, distanceToleranceSquare, angleTolerance)
- recursiveQuadraticBezierBezier(v, x123, y123, x23, y23, x3, y3, level+1, distanceToleranceSquare, angleTolerance)
-}
-
-/**
- * http://www.antigrain.com/research/adaptive_bezier/index.html
- */
-func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 float64, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
- if level > CurveRecursionLimit {
- return
- }
-
- // Calculate all the mid-points of the line segments
- //----------------------
- x12 := (x1 + x2) / 2
- y12 := (y1 + y2) / 2
- x23 := (x2 + x3) / 2
- y23 := (y2 + y3) / 2
- x34 := (x3 + x4) / 2
- y34 := (y3 + y4) / 2
- x123 := (x12 + x23) / 2
- y123 := (y12 + y23) / 2
- x234 := (x23 + x34) / 2
- y234 := (y23 + y34) / 2
- x1234 := (x123 + x234) / 2
- y1234 := (y123 + y234) / 2
-
- // Try to approximate the full cubic curve by a single straight line
- //------------------
- dx := x4 - x1
- dy := y4 - y1
-
- d2 := math.Abs(((x2-x4)*dy - (y2-y4)*dx))
- d3 := math.Abs(((x3-x4)*dy - (y3-y4)*dx))
-
- switch {
- case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // All collinear OR p1==p4
- //----------------------
- k := dx*dx + dy*dy
- if k == 0 {
- d2 = squareDistance(x1, y1, x2, y2)
- d3 = squareDistance(x4, y4, x3, y3)
- } else {
- k = 1 / k
- da1 := x2 - x1
- da2 := y2 - y1
- d2 = k * (da1*dx + da2*dy)
- da1 = x3 - x1
- da2 = y3 - y1
- d3 = k * (da1*dx + da2*dy)
- if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
- // Simple collinear case, 1---2---3---4
- // We can leave just two endpoints
- return
- }
- if d2 <= 0 {
- d2 = squareDistance(x2, y2, x1, y1)
- } else if d2 >= 1 {
- d2 = squareDistance(x2, y2, x4, y4)
- } else {
- d2 = squareDistance(x2, y2, x1+d2*dx, y1+d2*dy)
- }
-
- if d3 <= 0 {
- d3 = squareDistance(x3, y3, x1, y1)
- } else if d3 >= 1 {
- d3 = squareDistance(x3, y3, x4, y4)
- } else {
- d3 = squareDistance(x3, y3, x1+d3*dx, y1+d3*dy)
- }
- }
- if d2 > d3 {
- if d2 < distanceToleranceSquare {
- v.Vertex(x2, y2)
- return
- }
- } else {
- if d3 < distanceToleranceSquare {
- v.Vertex(x3, y3)
- return
- }
- }
- break
-
- case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // p1,p2,p4 are collinear, p3 is significant
- //----------------------
- if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- v.Vertex(x23, y23)
- return
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(y4-y3, x4-x3) - math.Atan2(y3-y2, x3-x2))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- v.Vertex(x2, y2)
- v.Vertex(x3, y3)
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- v.Vertex(x3, y3)
- return
- }
- }
- }
- break
-
- case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
- // p1,p3,p4 are collinear, p2 is significant
- //----------------------
- if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
- if angleTolerance < CurveAngleToleranceEpsilon {
- v.Vertex(x23, y23)
- return
- }
-
- // Angle Condition
- //----------------------
- da1 := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1))
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
-
- if da1 < angleTolerance {
- v.Vertex(x2, y2)
- v.Vertex(x3, y3)
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- v.Vertex(x2, y2)
- return
- }
- }
- }
- break
-
- case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
- // Regular case
- //-----------------
- if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
- // If the curvature doesn't exceed the distanceTolerance value
- // we tend to finish subdivisions.
- //----------------------
- if angleTolerance < CurveAngleToleranceEpsilon {
- v.Vertex(x23, y23)
- return
- }
-
- // Angle & Cusp Condition
- //----------------------
- k := math.Atan2(y3-y2, x3-x2)
- da1 := math.Abs(k - math.Atan2(y2-y1, x2-x1))
- da2 := math.Abs(math.Atan2(y4-y3, x4-x3) - k)
- if da1 >= math.Pi {
- da1 = 2*math.Pi - da1
- }
- if da2 >= math.Pi {
- da2 = 2*math.Pi - da2
- }
-
- if da1+da2 < angleTolerance {
- // Finally we can stop the recursion
- //----------------------
- v.Vertex(x23, y23)
- return
- }
-
- if cuspLimit != 0.0 {
- if da1 > cuspLimit {
- v.Vertex(x2, y2)
- return
- }
-
- if da2 > cuspLimit {
- v.Vertex(x3, y3)
- return
- }
- }
- }
- break
- }
-
- // Continue subdivision
- //----------------------
- recursiveCubicBezier(v, x1, y1, x12, y12, x123, y123, x1234, y1234, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
- recursiveCubicBezier(v, x1234, y1234, x234, y234, x34, y34, x4, y4, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
-
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/dasher.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/dasher.go
deleted file mode 100644
index 521029992..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/dasher.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-type DashVertexConverter struct {
- command VertexCommand
- next VertexConverter
- x, y, distance float64
- dash []float64
- currentDash int
- dashOffset float64
-}
-
-func NewDashConverter(dash []float64, dashOffset float64, converter VertexConverter) *DashVertexConverter {
- var dasher DashVertexConverter
- dasher.dash = dash
- dasher.currentDash = 0
- dasher.dashOffset = dashOffset
- dasher.next = converter
- return &dasher
-}
-
-func (dasher *DashVertexConverter) NextCommand(cmd VertexCommand) {
- dasher.command = cmd
- if dasher.command == VertexStopCommand {
- dasher.next.NextCommand(VertexStopCommand)
- }
-}
-
-func (dasher *DashVertexConverter) Vertex(x, y float64) {
- switch dasher.command {
- case VertexStartCommand:
- dasher.start(x, y)
- default:
- dasher.lineTo(x, y)
- }
- dasher.command = VertexNoCommand
-}
-
-func (dasher *DashVertexConverter) start(x, y float64) {
- dasher.next.NextCommand(VertexStartCommand)
- dasher.next.Vertex(x, y)
- dasher.x, dasher.y = x, y
- dasher.distance = dasher.dashOffset
- dasher.currentDash = 0
-}
-
-func (dasher *DashVertexConverter) lineTo(x, y float64) {
- rest := dasher.dash[dasher.currentDash] - dasher.distance
- for rest < 0 {
- dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
- dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
- rest = dasher.dash[dasher.currentDash] - dasher.distance
- }
- d := distance(dasher.x, dasher.y, x, y)
- for d >= rest {
- k := rest / d
- lx := dasher.x + k*(x-dasher.x)
- ly := dasher.y + k*(y-dasher.y)
- if dasher.currentDash%2 == 0 {
- // line
- dasher.next.Vertex(lx, ly)
- } else {
- // gap
- dasher.next.NextCommand(VertexStopCommand)
- dasher.next.NextCommand(VertexStartCommand)
- dasher.next.Vertex(lx, ly)
- }
- d = d - rest
- dasher.x, dasher.y = lx, ly
- dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
- rest = dasher.dash[dasher.currentDash]
- }
- dasher.distance = d
- if dasher.currentDash%2 == 0 {
- // line
- dasher.next.Vertex(x, y)
- } else {
- // gap
- dasher.next.NextCommand(VertexStopCommand)
- dasher.next.NextCommand(VertexStartCommand)
- dasher.next.Vertex(x, y)
- }
- if dasher.distance >= dasher.dash[dasher.currentDash] {
- dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
- dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
- }
- dasher.x, dasher.y = x, y
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/demux_converter.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/demux_converter.go
deleted file mode 100644
index b5c871d2c..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/demux_converter.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-type DemuxConverter struct {
- converters []VertexConverter
-}
-
-func NewDemuxConverter(converters ...VertexConverter) *DemuxConverter {
- return &DemuxConverter{converters}
-}
-
-func (dc *DemuxConverter) NextCommand(cmd VertexCommand) {
- for _, converter := range dc.converters {
- converter.NextCommand(cmd)
- }
-}
-func (dc *DemuxConverter) Vertex(x, y float64) {
- for _, converter := range dc.converters {
- converter.Vertex(x, y)
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/doc.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/doc.go
deleted file mode 100644
index 3baeffb4d..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/doc.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-// The package draw2d provide a Graphic Context that can draw vectorial figure on surface.
-package draw2d
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/font.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/font.go
deleted file mode 100644
index eb0b5325c..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/font.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/truetype"
- "io/ioutil"
- "log"
- "path"
-)
-
-var (
- fontFolder = "../resource/font/"
- fonts = make(map[string]*truetype.Font)
-)
-
-type FontStyle byte
-
-const (
- FontStyleNormal FontStyle = iota
- FontStyleBold
- FontStyleItalic
-)
-
-type FontFamily byte
-
-const (
- FontFamilySans FontFamily = iota
- FontFamilySerif
- FontFamilyMono
-)
-
-type FontData struct {
- Name string
- Family FontFamily
- Style FontStyle
-}
-
-func fontFileName(fontData FontData) string {
- fontFileName := fontData.Name
- switch fontData.Family {
- case FontFamilySans:
- fontFileName += "s"
- case FontFamilySerif:
- fontFileName += "r"
- case FontFamilyMono:
- fontFileName += "m"
- }
- if fontData.Style&FontStyleBold != 0 {
- fontFileName += "b"
- } else {
- fontFileName += "r"
- }
-
- if fontData.Style&FontStyleItalic != 0 {
- fontFileName += "i"
- }
- fontFileName += ".ttf"
- return fontFileName
-}
-
-func RegisterFont(fontData FontData, font *truetype.Font) {
- fonts[fontFileName(fontData)] = font
-}
-
-func GetFont(fontData FontData) *truetype.Font {
- fontFileName := fontFileName(fontData)
- font := fonts[fontFileName]
- if font != nil {
- return font
- }
- fonts[fontFileName] = loadFont(fontFileName)
- return fonts[fontFileName]
-}
-
-func GetFontFolder() string {
- return fontFolder
-}
-
-func SetFontFolder(folder string) {
- fontFolder = folder
-}
-
-func loadFont(fontFileName string) *truetype.Font {
- fontBytes, err := ioutil.ReadFile(path.Join(fontFolder, fontFileName))
- if err != nil {
- log.Println(err)
- return nil
- }
- font, err := truetype.Parse(fontBytes)
- if err != nil {
- log.Println(err)
- return nil
- }
- return font
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/gc.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/gc.go
deleted file mode 100644
index 66dc5088f..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/gc.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "image"
- "image/color"
-)
-
-type FillRule int
-
-const (
- FillRuleEvenOdd FillRule = iota
- FillRuleWinding
-)
-
-type GraphicContext interface {
- Path
- // Create a new path
- BeginPath()
- GetMatrixTransform() MatrixTransform
- SetMatrixTransform(tr MatrixTransform)
- ComposeMatrixTransform(tr MatrixTransform)
- Rotate(angle float64)
- Translate(tx, ty float64)
- Scale(sx, sy float64)
- SetStrokeColor(c color.Color)
- SetFillColor(c color.Color)
- SetFillRule(f FillRule)
- SetLineWidth(lineWidth float64)
- SetLineCap(cap Cap)
- SetLineJoin(join Join)
- SetLineDash(dash []float64, dashOffset float64)
- SetFontSize(fontSize float64)
- GetFontSize() float64
- SetFontData(fontData FontData)
- GetFontData() FontData
- DrawImage(image image.Image)
- Save()
- Restore()
- Clear()
- ClearRect(x1, y1, x2, y2 int)
- SetDPI(dpi int)
- GetDPI() int
- GetStringBounds(s string) (left, top, right, bottom float64)
- CreateStringPath(text string, x, y float64) (cursor float64)
- FillString(text string) (cursor float64)
- FillStringAt(text string, x, y float64) (cursor float64)
- StrokeString(text string) (cursor float64)
- StrokeStringAt(text string, x, y float64) (cursor float64)
- Stroke(paths ...*PathStorage)
- Fill(paths ...*PathStorage)
- FillStroke(paths ...*PathStorage)
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/image.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/image.go
deleted file mode 100644
index 9f91bc71f..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/image.go
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/raster"
- "code.google.com/p/freetype-go/freetype/truetype"
- "errors"
- "image"
- "image/color"
- "image/draw"
- "log"
- "math"
-)
-
-type Painter interface {
- raster.Painter
- SetColor(color color.Color)
-}
-
-var (
- defaultFontData = FontData{"luxi", FontFamilySans, FontStyleNormal}
-)
-
-type ImageGraphicContext struct {
- *StackGraphicContext
- img draw.Image
- painter Painter
- fillRasterizer *raster.Rasterizer
- strokeRasterizer *raster.Rasterizer
- glyphBuf *truetype.GlyphBuf
- DPI int
-}
-
-/**
- * Create a new Graphic context from an image
- */
-func NewGraphicContext(img draw.Image) *ImageGraphicContext {
- var painter Painter
- switch selectImage := img.(type) {
- case *image.RGBA:
- painter = raster.NewRGBAPainter(selectImage)
- default:
- panic("Image type not supported")
- }
- return NewGraphicContextWithPainter(img, painter)
-}
-
-// Create a new Graphic context from an image and a Painter (see Freetype-go)
-func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphicContext {
- width, height := img.Bounds().Dx(), img.Bounds().Dy()
- dpi := 92
- gc := &ImageGraphicContext{
- NewStackGraphicContext(),
- img,
- painter,
- raster.NewRasterizer(width, height),
- raster.NewRasterizer(width, height),
- truetype.NewGlyphBuf(),
- dpi,
- }
- return gc
-}
-
-func (gc *ImageGraphicContext) GetDPI() int {
- return gc.DPI
-}
-
-func (gc *ImageGraphicContext) Clear() {
- width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy()
- gc.ClearRect(0, 0, width, height)
-}
-
-func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) {
- imageColor := image.NewUniform(gc.Current.FillColor)
- draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP, draw.Over)
-}
-
-func (gc *ImageGraphicContext) DrawImage(img image.Image) {
- DrawImage(img, gc.img, gc.Current.Tr, draw.Over, BilinearFilter)
-}
-
-func (gc *ImageGraphicContext) FillString(text string) (cursor float64) {
- return gc.FillStringAt(text, 0, 0)
-}
-
-func (gc *ImageGraphicContext) FillStringAt(text string, x, y float64) (cursor float64) {
- width := gc.CreateStringPath(text, x, y)
- gc.Fill()
- return width
-}
-
-func (gc *ImageGraphicContext) StrokeString(text string) (cursor float64) {
- return gc.StrokeStringAt(text, 0, 0)
-}
-
-func (gc *ImageGraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64) {
- width := gc.CreateStringPath(text, x, y)
- gc.Stroke()
- return width
-}
-
-func (gc *ImageGraphicContext) loadCurrentFont() (*truetype.Font, error) {
- font := GetFont(gc.Current.FontData)
- if font == nil {
- font = GetFont(defaultFontData)
- }
- if font == nil {
- return nil, errors.New("No font set, and no default font available.")
- }
- gc.SetFont(font)
- gc.SetFontSize(gc.Current.FontSize)
- return font, nil
-}
-
-func fUnitsToFloat64(x int32) float64 {
- scaled := x << 2
- return float64(scaled/256) + float64(scaled%256)/256.0
-}
-
-// p is a truetype.Point measured in FUnits and positive Y going upwards.
-// The returned value is the same thing measured in floating point and positive Y
-// going downwards.
-func pointToF64Point(p truetype.Point) (x, y float64) {
- return fUnitsToFloat64(p.X), -fUnitsToFloat64(p.Y)
-}
-
-// drawContour draws the given closed contour at the given sub-pixel offset.
-func (gc *ImageGraphicContext) drawContour(ps []truetype.Point, dx, dy float64) {
- if len(ps) == 0 {
- return
- }
- startX, startY := pointToF64Point(ps[0])
- gc.MoveTo(startX+dx, startY+dy)
- q0X, q0Y, on0 := startX, startY, true
- for _, p := range ps[1:] {
- qX, qY := pointToF64Point(p)
- on := p.Flags&0x01 != 0
- if on {
- if on0 {
- gc.LineTo(qX+dx, qY+dy)
- } else {
- gc.QuadCurveTo(q0X+dx, q0Y+dy, qX+dx, qY+dy)
- }
- } else {
- if on0 {
- // No-op.
- } else {
- midX := (q0X + qX) / 2
- midY := (q0Y + qY) / 2
- gc.QuadCurveTo(q0X+dx, q0Y+dy, midX+dx, midY+dy)
- }
- }
- q0X, q0Y, on0 = qX, qY, on
- }
- // Close the curve.
- if on0 {
- gc.LineTo(startX+dx, startY+dy)
- } else {
- gc.QuadCurveTo(q0X+dx, q0Y+dy, startX+dx, startY+dy)
- }
-}
-
-func (gc *ImageGraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) error {
- if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, glyph, truetype.NoHinting); err != nil {
- return err
- }
- e0 := 0
- for _, e1 := range gc.glyphBuf.End {
- gc.drawContour(gc.glyphBuf.Point[e0:e1], dx, dy)
- e0 = e1
- }
- return nil
-}
-
-// CreateStringPath creates a path from the string s at x, y, and returns the string width.
-// The text is placed so that the left edge of the em square of the first character of s
-// and the baseline intersect at x, y. 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.
-func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64 {
- font, err := gc.loadCurrentFont()
- if err != nil {
- log.Println(err)
- return 0.0
- }
- startx := x
- prev, hasPrev := truetype.Index(0), false
- for _, rune := range s {
- index := font.Index(rune)
- if hasPrev {
- x += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index))
- }
- err := gc.drawGlyph(index, x, y)
- if err != nil {
- log.Println(err)
- return startx - x
- }
- x += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth)
- prev, hasPrev = index, true
- }
- return x - startx
-}
-
-// GetStringBounds returns the approximate pixel bounds of the string s at x, y.
-// The the left edge of the em square of the first character of s
-// and the baseline intersect at 0, 0 in the returned coordinates.
-// Therefore the top and left coordinates may well be negative.
-func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64) {
- font, err := gc.loadCurrentFont()
- if err != nil {
- log.Println(err)
- return 0, 0, 0, 0
- }
- top, left, bottom, right = 10e6, 10e6, -10e6, -10e6
- cursor := 0.0
- prev, hasPrev := truetype.Index(0), false
- for _, rune := range s {
- index := font.Index(rune)
- if hasPrev {
- cursor += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index))
- }
- if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, index, truetype.NoHinting); err != nil {
- log.Println(err)
- return 0, 0, 0, 0
- }
- e0 := 0
- for _, e1 := range gc.glyphBuf.End {
- ps := gc.glyphBuf.Point[e0:e1]
- for _, p := range ps {
- x, y := pointToF64Point(p)
- top = math.Min(top, y)
- bottom = math.Max(bottom, y)
- left = math.Min(left, x+cursor)
- right = math.Max(right, x+cursor)
- }
- }
- cursor += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth)
- prev, hasPrev = index, true
- }
- return left, top, right, bottom
-}
-
-// recalc recalculates scale and bounds values from the font size, screen
-// resolution and font metrics, and invalidates the glyph cache.
-func (gc *ImageGraphicContext) recalc() {
- gc.Current.scale = int32(gc.Current.FontSize * float64(gc.DPI) * (64.0 / 72.0))
-}
-
-// SetDPI sets the screen resolution in dots per inch.
-func (gc *ImageGraphicContext) SetDPI(dpi int) {
- gc.DPI = dpi
- gc.recalc()
-}
-
-// SetFont sets the font used to draw text.
-func (gc *ImageGraphicContext) SetFont(font *truetype.Font) {
- gc.Current.font = font
-}
-
-// SetFontSize sets the font size in points (as in ``a 12 point font'').
-func (gc *ImageGraphicContext) SetFontSize(fontSize float64) {
- gc.Current.FontSize = fontSize
- gc.recalc()
-}
-
-func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) {
- gc.painter.SetColor(color)
- rasterizer.Rasterize(gc.painter)
- rasterizer.Clear()
- gc.Current.Path.Clear()
-}
-
-/**** second method ****/
-func (gc *ImageGraphicContext) Stroke(paths ...*PathStorage) {
- paths = append(paths, gc.Current.Path)
- gc.strokeRasterizer.UseNonZeroWinding = true
-
- stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
- stroker.HalfLineWidth = gc.Current.LineWidth / 2
- var pathConverter *PathConverter
- if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
- dasher := NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
- pathConverter = NewPathConverter(dasher)
- } else {
- pathConverter = NewPathConverter(stroker)
- }
- pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
- pathConverter.Convert(paths...)
-
- gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
-}
-
-/**** second method ****/
-func (gc *ImageGraphicContext) Fill(paths ...*PathStorage) {
- paths = append(paths, gc.Current.Path)
- gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
-
- /**** first method ****/
- pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer)))
- pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
- pathConverter.Convert(paths...)
-
- gc.paint(gc.fillRasterizer, gc.Current.FillColor)
-}
-
-/* second method */
-func (gc *ImageGraphicContext) FillStroke(paths ...*PathStorage) {
- gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
- gc.strokeRasterizer.UseNonZeroWinding = true
-
- filler := NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer))
-
- stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
- stroker.HalfLineWidth = gc.Current.LineWidth / 2
-
- demux := NewDemuxConverter(filler, stroker)
- paths = append(paths, gc.Current.Path)
- pathConverter := NewPathConverter(demux)
- pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
- pathConverter.Convert(paths...)
-
- gc.paint(gc.fillRasterizer, gc.Current.FillColor)
- gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
-}
-
-func (f FillRule) UseNonZeroWinding() bool {
- switch f {
- case FillRuleEvenOdd:
- return false
- case FillRuleWinding:
- return true
- }
- return false
-}
-
-func (c Cap) Convert() raster.Capper {
- switch c {
- case RoundCap:
- return raster.RoundCapper
- case ButtCap:
- return raster.ButtCapper
- case SquareCap:
- return raster.SquareCapper
- }
- return raster.RoundCapper
-}
-
-func (j Join) Convert() raster.Joiner {
- switch j {
- case RoundJoin:
- return raster.RoundJoiner
- case BevelJoin:
- return raster.BevelJoiner
- }
- return raster.RoundJoiner
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/math.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/math.go
deleted file mode 100644
index c4bb761df..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/math.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "math"
-)
-
-func distance(x1, y1, x2, y2 float64) float64 {
- dx := x2 - x1
- dy := y2 - y1
- return float64(math.Sqrt(dx*dx + dy*dy))
-}
-
-func vectorDistance(dx, dy float64) float64 {
- return float64(math.Sqrt(dx*dx + dy*dy))
-}
-
-func squareDistance(x1, y1, x2, y2 float64) float64 {
- dx := x2 - x1
- dy := y2 - y1
- return dx*dx + dy*dy
-}
-
-func min(x, y float64) float64 {
- if x < y {
- return x
- }
- return y
-}
-
-func max(x, y float64) float64 {
- if x > y {
- return x
- }
- return y
-}
-
-func minMax(x, y float64) (min, max float64) {
- if x > y {
- return y, x
- }
- return x, y
-}
-
-func minUint32(a, b uint32) uint32 {
- if a < b {
- return a
- }
- return b
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/paint.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/paint.go
deleted file mode 100644
index 885d993ae..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/paint.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-/*
-import (
- "image/draw"
- "image"
- "freetype-go.googlecode.com/hg/freetype/raster"
-)*/
-
-const M = 1<<16 - 1
-
-/*
-type NRGBAPainter struct {
- // The image to compose onto.
- Image *image.NRGBA
- // The Porter-Duff composition operator.
- Op draw.Op
- // The 16-bit color to paint the spans.
- cr, cg, cb, ca uint32
-}
-
-// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
-func (r *NRGBAPainter) Paint(ss []raster.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.Stride
- p := r.Image.Pix[base+s.X0 : base+s.X1]
- // This code is duplicated from drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go.
- // TODO(nigeltao): Factor out common code into a utility function, once the compiler
- // can inline such function calls.
- ma := s.A >> 16
- if r.Op == draw.Over {
- for i, nrgba := range p {
- dr, dg, db, da := nrgba.
- a := M - (r.ca*ma)/M
- da = (da*a + r.ca*ma) / M
- if da != 0 {
- dr = minUint32(M, (dr*a+r.cr*ma)/da)
- dg = minUint32(M, (dg*a+r.cg*ma)/da)
- db = minUint32(M, (db*a+r.cb*ma)/da)
- } else {
- dr, dg, db = 0, 0, 0
- }
- p[i] = image.NRGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
- }
- } else {
- for i, nrgba := range p {
- dr, dg, db, da := nrgba.RGBA()
- a := M - ma
- da = (da*a + r.ca*ma) / M
- if da != 0 {
- dr = minUint32(M, (dr*a+r.cr*ma)/da)
- dg = minUint32(M, (dg*a+r.cg*ma)/da)
- db = minUint32(M, (db*a+r.cb*ma)/da)
- } else {
- dr, dg, db = 0, 0, 0
- }
- p[i] = image.NRGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
- }
- }
- }
-
-}
-
-// SetColor sets the color to paint the spans.
-func (r *NRGBAPainter) SetColor(c image.Color) {
- r.cr, r.cg, r.cb, r.ca = c.RGBA()
-}
-
-// NewRGBAPainter creates a new RGBAPainter for the given image.
-func NewNRGBAPainter(m *image.NRGBA) *NRGBAPainter {
- return &NRGBAPainter{Image: m}
-}
-*/
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path.go
deleted file mode 100644
index b82910e24..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-type Path interface {
- // Return the current point of the path
- LastPoint() (x, y float64)
- // Create a new subpath that start at the specified point
- MoveTo(x, y float64)
- // Create a new subpath that start at the specified point
- // relative to the current point
- RMoveTo(dx, dy float64)
- // Add a line to the current subpath
- LineTo(x, y float64)
- // Add a line to the current subpath
- // relative to the current point
- RLineTo(dx, dy float64)
-
- QuadCurveTo(cx, cy, x, y float64)
- RQuadCurveTo(dcx, dcy, dx, dy float64)
- CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64)
- RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64)
- ArcTo(cx, cy, rx, ry, startAngle, angle float64)
- RArcTo(dcx, dcy, rx, ry, startAngle, angle float64)
- Close()
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_adder.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_adder.go
deleted file mode 100644
index c5efd2beb..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_adder.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/raster"
-)
-
-type VertexAdder struct {
- command VertexCommand
- adder raster.Adder
-}
-
-func NewVertexAdder(adder raster.Adder) *VertexAdder {
- return &VertexAdder{VertexNoCommand, adder}
-}
-
-func (vertexAdder *VertexAdder) NextCommand(cmd VertexCommand) {
- vertexAdder.command = cmd
-}
-
-func (vertexAdder *VertexAdder) Vertex(x, y float64) {
- switch vertexAdder.command {
- case VertexStartCommand:
- vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
- default:
- vertexAdder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
- }
- vertexAdder.command = VertexNoCommand
-}
-
-type PathAdder struct {
- adder raster.Adder
- firstPoint raster.Point
- ApproximationScale float64
-}
-
-func NewPathAdder(adder raster.Adder) *PathAdder {
- return &PathAdder{adder, raster.Point{0, 0}, 1}
-}
-
-func (pathAdder *PathAdder) Convert(paths ...*PathStorage) {
- for _, path := range paths {
- j := 0
- for _, cmd := range path.commands {
- switch cmd {
- case MoveTo:
- pathAdder.firstPoint = raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}
- pathAdder.adder.Start(pathAdder.firstPoint)
- j += 2
- case LineTo:
- pathAdder.adder.Add1(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)})
- j += 2
- case QuadCurveTo:
- pathAdder.adder.Add2(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}, raster.Point{raster.Fix32(path.vertices[j+2] * 256), raster.Fix32(path.vertices[j+3] * 256)})
- j += 4
- case CubicCurveTo:
- pathAdder.adder.Add3(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}, raster.Point{raster.Fix32(path.vertices[j+2] * 256), raster.Fix32(path.vertices[j+3] * 256)}, raster.Point{raster.Fix32(path.vertices[j+4] * 256), raster.Fix32(path.vertices[j+5] * 256)})
- j += 6
- case ArcTo:
- lastPoint := arcAdder(pathAdder.adder, path.vertices[j], path.vertices[j+1], path.vertices[j+2], path.vertices[j+3], path.vertices[j+4], path.vertices[j+5], pathAdder.ApproximationScale)
- pathAdder.adder.Add1(lastPoint)
- j += 6
- case Close:
- pathAdder.adder.Add1(pathAdder.firstPoint)
- }
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_converter.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_converter.go
deleted file mode 100644
index 0ef96b84d..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_converter.go
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 06/12/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "math"
-)
-
-type PathConverter struct {
- converter VertexConverter
- ApproximationScale, AngleTolerance, CuspLimit float64
- startX, startY, x, y float64
-}
-
-func NewPathConverter(converter VertexConverter) *PathConverter {
- return &PathConverter{converter, 1, 0, 0, 0, 0, 0, 0}
-}
-
-func (c *PathConverter) Convert(paths ...*PathStorage) {
- for _, path := range paths {
- j := 0
- for _, cmd := range path.commands {
- j = j + c.ConvertCommand(cmd, path.vertices[j:]...)
- }
- c.converter.NextCommand(VertexStopCommand)
- }
-}
-
-func (c *PathConverter) ConvertCommand(cmd PathCmd, vertices ...float64) int {
- switch cmd {
- case MoveTo:
- c.x, c.y = vertices[0], vertices[1]
- c.startX, c.startY = c.x, c.y
- c.converter.NextCommand(VertexStopCommand)
- c.converter.NextCommand(VertexStartCommand)
- c.converter.Vertex(c.x, c.y)
- return 2
- case LineTo:
- c.x, c.y = vertices[0], vertices[1]
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- c.converter.NextCommand(VertexJoinCommand)
- return 2
- case QuadCurveTo:
- quadraticBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], c.ApproximationScale, c.AngleTolerance)
- c.x, c.y = vertices[2], vertices[3]
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return 4
- case CubicCurveTo:
- cubicBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale, c.AngleTolerance, c.CuspLimit)
- c.x, c.y = vertices[4], vertices[5]
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return 6
- case ArcTo:
- c.x, c.y = arc(c.converter, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale)
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return 6
- case Close:
- c.converter.NextCommand(VertexCloseCommand)
- c.converter.Vertex(c.startX, c.startY)
- return 0
- }
- return 0
-}
-
-func (c *PathConverter) MoveTo(x, y float64) *PathConverter {
- c.x, c.y = x, y
- c.startX, c.startY = c.x, c.y
- c.converter.NextCommand(VertexStopCommand)
- c.converter.NextCommand(VertexStartCommand)
- c.converter.Vertex(c.x, c.y)
- return c
-}
-
-func (c *PathConverter) RMoveTo(dx, dy float64) *PathConverter {
- c.MoveTo(c.x+dx, c.y+dy)
- return c
-}
-
-func (c *PathConverter) LineTo(x, y float64) *PathConverter {
- c.x, c.y = x, y
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- c.converter.NextCommand(VertexJoinCommand)
- return c
-}
-
-func (c *PathConverter) RLineTo(dx, dy float64) *PathConverter {
- c.LineTo(c.x+dx, c.y+dy)
- return c
-}
-
-func (c *PathConverter) QuadCurveTo(cx, cy, x, y float64) *PathConverter {
- quadraticBezier(c.converter, c.x, c.y, cx, cy, x, y, c.ApproximationScale, c.AngleTolerance)
- c.x, c.y = x, y
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return c
-}
-
-func (c *PathConverter) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathConverter {
- c.QuadCurveTo(c.x+dcx, c.y+dcy, c.x+dx, c.y+dy)
- return c
-}
-
-func (c *PathConverter) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathConverter {
- cubicBezier(c.converter, c.x, c.y, cx1, cy1, cx2, cy2, x, y, c.ApproximationScale, c.AngleTolerance, c.CuspLimit)
- c.x, c.y = x, y
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return c
-}
-
-func (c *PathConverter) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) *PathConverter {
- c.CubicCurveTo(c.x+dcx1, c.y+dcy1, c.x+dcx2, c.y+dcy2, c.x+dx, c.y+dy)
- return c
-}
-
-func (c *PathConverter) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathConverter {
- endAngle := startAngle + angle
- clockWise := true
- if angle < 0 {
- clockWise = false
- }
- // normalize
- if clockWise {
- for endAngle < startAngle {
- endAngle += math.Pi * 2.0
- }
- } else {
- for startAngle < endAngle {
- startAngle += math.Pi * 2.0
- }
- }
- startX := cx + math.Cos(startAngle)*rx
- startY := cy + math.Sin(startAngle)*ry
- c.MoveTo(startX, startY)
- c.x, c.y = arc(c.converter, cx, cy, rx, ry, startAngle, angle, c.ApproximationScale)
- if c.startX == c.x && c.startY == c.y {
- c.converter.NextCommand(VertexCloseCommand)
- }
- c.converter.Vertex(c.x, c.y)
- return c
-}
-
-func (c *PathConverter) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *PathConverter {
- c.ArcTo(c.x+dcx, c.y+dcy, rx, ry, startAngle, angle)
- return c
-}
-
-func (c *PathConverter) Close() *PathConverter {
- c.converter.NextCommand(VertexCloseCommand)
- c.converter.Vertex(c.startX, c.startY)
- return c
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_storage.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_storage.go
deleted file mode 100644
index c2a887037..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_storage.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "fmt"
- "math"
-)
-
-type PathCmd int
-
-const (
- MoveTo PathCmd = iota
- LineTo
- QuadCurveTo
- CubicCurveTo
- ArcTo
- Close
-)
-
-type PathStorage struct {
- commands []PathCmd
- vertices []float64
- x, y float64
-}
-
-func NewPathStorage() (p *PathStorage) {
- p = new(PathStorage)
- p.commands = make([]PathCmd, 0, 256)
- p.vertices = make([]float64, 0, 256)
- return
-}
-
-func (p *PathStorage) Clear() {
- p.commands = p.commands[0:0]
- p.vertices = p.vertices[0:0]
- return
-}
-
-func (p *PathStorage) appendToPath(cmd PathCmd, vertices ...float64) {
- if cap(p.vertices) <= len(p.vertices)+6 {
- a := make([]PathCmd, len(p.commands), cap(p.commands)+256)
- b := make([]float64, len(p.vertices), cap(p.vertices)+256)
- copy(a, p.commands)
- p.commands = a
- copy(b, p.vertices)
- p.vertices = b
- }
- p.commands = p.commands[0 : len(p.commands)+1]
- p.commands[len(p.commands)-1] = cmd
- copy(p.vertices[len(p.vertices):len(p.vertices)+len(vertices)], vertices)
- p.vertices = p.vertices[0 : len(p.vertices)+len(vertices)]
-}
-
-func (src *PathStorage) Copy() (dest *PathStorage) {
- dest = new(PathStorage)
- dest.commands = make([]PathCmd, len(src.commands))
- copy(dest.commands, src.commands)
- dest.vertices = make([]float64, len(src.vertices))
- copy(dest.vertices, src.vertices)
- return dest
-}
-
-func (p *PathStorage) LastPoint() (x, y float64) {
- return p.x, p.y
-}
-
-func (p *PathStorage) IsEmpty() bool {
- return len(p.commands) == 0
-}
-
-func (p *PathStorage) Close() *PathStorage {
- p.appendToPath(Close)
- return p
-}
-
-func (p *PathStorage) MoveTo(x, y float64) *PathStorage {
- p.appendToPath(MoveTo, x, y)
- p.x = x
- p.y = y
- return p
-}
-
-func (p *PathStorage) RMoveTo(dx, dy float64) *PathStorage {
- x, y := p.LastPoint()
- p.MoveTo(x+dx, y+dy)
- return p
-}
-
-func (p *PathStorage) LineTo(x, y float64) *PathStorage {
- p.appendToPath(LineTo, x, y)
- p.x = x
- p.y = y
- return p
-}
-
-func (p *PathStorage) RLineTo(dx, dy float64) *PathStorage {
- x, y := p.LastPoint()
- p.LineTo(x+dx, y+dy)
- return p
-}
-
-func (p *PathStorage) QuadCurveTo(cx, cy, x, y float64) *PathStorage {
- p.appendToPath(QuadCurveTo, cx, cy, x, y)
- p.x = x
- p.y = y
- return p
-}
-
-func (p *PathStorage) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathStorage {
- x, y := p.LastPoint()
- p.QuadCurveTo(x+dcx, y+dcy, x+dx, y+dy)
- return p
-}
-
-func (p *PathStorage) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathStorage {
- p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y)
- p.x = x
- p.y = y
- return p
-}
-
-func (p *PathStorage) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) *PathStorage {
- x, y := p.LastPoint()
- p.CubicCurveTo(x+dcx1, y+dcy1, x+dcx2, y+dcy2, x+dx, y+dy)
- return p
-}
-
-func (p *PathStorage) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathStorage {
- endAngle := startAngle + angle
- clockWise := true
- if angle < 0 {
- clockWise = false
- }
- // normalize
- if clockWise {
- for endAngle < startAngle {
- endAngle += math.Pi * 2.0
- }
- } else {
- for startAngle < endAngle {
- startAngle += math.Pi * 2.0
- }
- }
- startX := cx + math.Cos(startAngle)*rx
- startY := cy + math.Sin(startAngle)*ry
- if len(p.commands) > 0 {
- p.LineTo(startX, startY)
- } else {
- p.MoveTo(startX, startY)
- }
- p.appendToPath(ArcTo, cx, cy, rx, ry, startAngle, angle)
- p.x = cx + math.Cos(endAngle)*rx
- p.y = cy + math.Sin(endAngle)*ry
- return p
-}
-
-func (p *PathStorage) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *PathStorage {
- x, y := p.LastPoint()
- p.ArcTo(x+dcx, y+dcy, rx, ry, startAngle, angle)
- return p
-}
-
-func (p *PathStorage) String() string {
- s := ""
- j := 0
- for _, cmd := range p.commands {
- switch cmd {
- case MoveTo:
- s += fmt.Sprintf("MoveTo: %f, %f\n", p.vertices[j], p.vertices[j+1])
- j = j + 2
- case LineTo:
- s += fmt.Sprintf("LineTo: %f, %f\n", p.vertices[j], p.vertices[j+1])
- j = j + 2
- case QuadCurveTo:
- s += fmt.Sprintf("QuadCurveTo: %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3])
- j = j + 4
- case CubicCurveTo:
- s += fmt.Sprintf("CubicCurveTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5])
- j = j + 6
- case ArcTo:
- s += fmt.Sprintf("ArcTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5])
- j = j + 6
- case Close:
- s += "Close\n"
- }
- }
- return s
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/coverage_table.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/coverage_table.go
deleted file mode 100644
index 429836f39..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/coverage_table.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-var SUBPIXEL_OFFSETS_SAMPLE_8 = [8]float64{
- 5.0 / 8,
- 0.0 / 8,
- 3.0 / 8,
- 6.0 / 8,
- 1.0 / 8,
- 4.0 / 8,
- 7.0 / 8,
- 2.0 / 8,
-}
-
-var SUBPIXEL_OFFSETS_SAMPLE_8_FIXED = [8]Fix{
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[0] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[1] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[2] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[3] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[4] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[5] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[6] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_8[7] * FIXED_FLOAT_COEF),
-}
-
-var SUBPIXEL_OFFSETS_SAMPLE_16 = [16]float64{
- 1.0 / 16,
- 8.0 / 16,
- 4.0 / 16,
- 15.0 / 16,
- 11.0 / 16,
- 2.0 / 16,
- 6.0 / 16,
- 14.0 / 16,
- 10.0 / 16,
- 3.0 / 16,
- 7.0 / 16,
- 12.0 / 16,
- 0.0 / 16,
- 9.0 / 16,
- 5.0 / 16,
- 13.0 / 16,
-}
-
-var SUBPIXEL_OFFSETS_SAMPLE_16_FIXED = [16]Fix{
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[0] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[1] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[2] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[3] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[4] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[5] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[6] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[7] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[8] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[9] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[10] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[11] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[12] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[13] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[14] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_16[15] * FIXED_FLOAT_COEF),
-}
-
-var SUBPIXEL_OFFSETS_SAMPLE_32 = [32]float64{
- 28.0 / 32,
- 13.0 / 32,
- 6.0 / 32,
- 23.0 / 32,
- 0.0 / 32,
- 17.0 / 32,
- 10.0 / 32,
- 27.0 / 32,
- 4.0 / 32,
- 21.0 / 32,
- 14.0 / 32,
- 31.0 / 32,
- 8.0 / 32,
- 25.0 / 32,
- 18.0 / 32,
- 3.0 / 32,
- 12.0 / 32,
- 29.0 / 32,
- 22.0 / 32,
- 7.0 / 32,
- 16.0 / 32,
- 1.0 / 32,
- 26.0 / 32,
- 11.0 / 32,
- 20.0 / 32,
- 5.0 / 32,
- 30.0 / 32,
- 15.0 / 32,
- 24.0 / 32,
- 9.0 / 32,
- 2.0 / 32,
- 19.0 / 32,
-}
-var SUBPIXEL_OFFSETS_SAMPLE_32_FIXED = [32]Fix{
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[0] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[1] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[2] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[3] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[4] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[5] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[6] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[7] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[8] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[9] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[10] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[11] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[12] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[13] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[14] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[15] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[16] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[17] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[18] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[19] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[20] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[21] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[22] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[23] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[24] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[25] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[26] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[27] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[28] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[29] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[30] * FIXED_FLOAT_COEF),
- Fix(SUBPIXEL_OFFSETS_SAMPLE_32[31] * FIXED_FLOAT_COEF),
-}
-
-var coverageTable = [256]uint8{
- pixelCoverage(0x00), pixelCoverage(0x01), pixelCoverage(0x02), pixelCoverage(0x03),
- pixelCoverage(0x04), pixelCoverage(0x05), pixelCoverage(0x06), pixelCoverage(0x07),
- pixelCoverage(0x08), pixelCoverage(0x09), pixelCoverage(0x0a), pixelCoverage(0x0b),
- pixelCoverage(0x0c), pixelCoverage(0x0d), pixelCoverage(0x0e), pixelCoverage(0x0f),
- pixelCoverage(0x10), pixelCoverage(0x11), pixelCoverage(0x12), pixelCoverage(0x13),
- pixelCoverage(0x14), pixelCoverage(0x15), pixelCoverage(0x16), pixelCoverage(0x17),
- pixelCoverage(0x18), pixelCoverage(0x19), pixelCoverage(0x1a), pixelCoverage(0x1b),
- pixelCoverage(0x1c), pixelCoverage(0x1d), pixelCoverage(0x1e), pixelCoverage(0x1f),
- pixelCoverage(0x20), pixelCoverage(0x21), pixelCoverage(0x22), pixelCoverage(0x23),
- pixelCoverage(0x24), pixelCoverage(0x25), pixelCoverage(0x26), pixelCoverage(0x27),
- pixelCoverage(0x28), pixelCoverage(0x29), pixelCoverage(0x2a), pixelCoverage(0x2b),
- pixelCoverage(0x2c), pixelCoverage(0x2d), pixelCoverage(0x2e), pixelCoverage(0x2f),
- pixelCoverage(0x30), pixelCoverage(0x31), pixelCoverage(0x32), pixelCoverage(0x33),
- pixelCoverage(0x34), pixelCoverage(0x35), pixelCoverage(0x36), pixelCoverage(0x37),
- pixelCoverage(0x38), pixelCoverage(0x39), pixelCoverage(0x3a), pixelCoverage(0x3b),
- pixelCoverage(0x3c), pixelCoverage(0x3d), pixelCoverage(0x3e), pixelCoverage(0x3f),
- pixelCoverage(0x40), pixelCoverage(0x41), pixelCoverage(0x42), pixelCoverage(0x43),
- pixelCoverage(0x44), pixelCoverage(0x45), pixelCoverage(0x46), pixelCoverage(0x47),
- pixelCoverage(0x48), pixelCoverage(0x49), pixelCoverage(0x4a), pixelCoverage(0x4b),
- pixelCoverage(0x4c), pixelCoverage(0x4d), pixelCoverage(0x4e), pixelCoverage(0x4f),
- pixelCoverage(0x50), pixelCoverage(0x51), pixelCoverage(0x52), pixelCoverage(0x53),
- pixelCoverage(0x54), pixelCoverage(0x55), pixelCoverage(0x56), pixelCoverage(0x57),
- pixelCoverage(0x58), pixelCoverage(0x59), pixelCoverage(0x5a), pixelCoverage(0x5b),
- pixelCoverage(0x5c), pixelCoverage(0x5d), pixelCoverage(0x5e), pixelCoverage(0x5f),
- pixelCoverage(0x60), pixelCoverage(0x61), pixelCoverage(0x62), pixelCoverage(0x63),
- pixelCoverage(0x64), pixelCoverage(0x65), pixelCoverage(0x66), pixelCoverage(0x67),
- pixelCoverage(0x68), pixelCoverage(0x69), pixelCoverage(0x6a), pixelCoverage(0x6b),
- pixelCoverage(0x6c), pixelCoverage(0x6d), pixelCoverage(0x6e), pixelCoverage(0x6f),
- pixelCoverage(0x70), pixelCoverage(0x71), pixelCoverage(0x72), pixelCoverage(0x73),
- pixelCoverage(0x74), pixelCoverage(0x75), pixelCoverage(0x76), pixelCoverage(0x77),
- pixelCoverage(0x78), pixelCoverage(0x79), pixelCoverage(0x7a), pixelCoverage(0x7b),
- pixelCoverage(0x7c), pixelCoverage(0x7d), pixelCoverage(0x7e), pixelCoverage(0x7f),
- pixelCoverage(0x80), pixelCoverage(0x81), pixelCoverage(0x82), pixelCoverage(0x83),
- pixelCoverage(0x84), pixelCoverage(0x85), pixelCoverage(0x86), pixelCoverage(0x87),
- pixelCoverage(0x88), pixelCoverage(0x89), pixelCoverage(0x8a), pixelCoverage(0x8b),
- pixelCoverage(0x8c), pixelCoverage(0x8d), pixelCoverage(0x8e), pixelCoverage(0x8f),
- pixelCoverage(0x90), pixelCoverage(0x91), pixelCoverage(0x92), pixelCoverage(0x93),
- pixelCoverage(0x94), pixelCoverage(0x95), pixelCoverage(0x96), pixelCoverage(0x97),
- pixelCoverage(0x98), pixelCoverage(0x99), pixelCoverage(0x9a), pixelCoverage(0x9b),
- pixelCoverage(0x9c), pixelCoverage(0x9d), pixelCoverage(0x9e), pixelCoverage(0x9f),
- pixelCoverage(0xa0), pixelCoverage(0xa1), pixelCoverage(0xa2), pixelCoverage(0xa3),
- pixelCoverage(0xa4), pixelCoverage(0xa5), pixelCoverage(0xa6), pixelCoverage(0xa7),
- pixelCoverage(0xa8), pixelCoverage(0xa9), pixelCoverage(0xaa), pixelCoverage(0xab),
- pixelCoverage(0xac), pixelCoverage(0xad), pixelCoverage(0xae), pixelCoverage(0xaf),
- pixelCoverage(0xb0), pixelCoverage(0xb1), pixelCoverage(0xb2), pixelCoverage(0xb3),
- pixelCoverage(0xb4), pixelCoverage(0xb5), pixelCoverage(0xb6), pixelCoverage(0xb7),
- pixelCoverage(0xb8), pixelCoverage(0xb9), pixelCoverage(0xba), pixelCoverage(0xbb),
- pixelCoverage(0xbc), pixelCoverage(0xbd), pixelCoverage(0xbe), pixelCoverage(0xbf),
- pixelCoverage(0xc0), pixelCoverage(0xc1), pixelCoverage(0xc2), pixelCoverage(0xc3),
- pixelCoverage(0xc4), pixelCoverage(0xc5), pixelCoverage(0xc6), pixelCoverage(0xc7),
- pixelCoverage(0xc8), pixelCoverage(0xc9), pixelCoverage(0xca), pixelCoverage(0xcb),
- pixelCoverage(0xcc), pixelCoverage(0xcd), pixelCoverage(0xce), pixelCoverage(0xcf),
- pixelCoverage(0xd0), pixelCoverage(0xd1), pixelCoverage(0xd2), pixelCoverage(0xd3),
- pixelCoverage(0xd4), pixelCoverage(0xd5), pixelCoverage(0xd6), pixelCoverage(0xd7),
- pixelCoverage(0xd8), pixelCoverage(0xd9), pixelCoverage(0xda), pixelCoverage(0xdb),
- pixelCoverage(0xdc), pixelCoverage(0xdd), pixelCoverage(0xde), pixelCoverage(0xdf),
- pixelCoverage(0xe0), pixelCoverage(0xe1), pixelCoverage(0xe2), pixelCoverage(0xe3),
- pixelCoverage(0xe4), pixelCoverage(0xe5), pixelCoverage(0xe6), pixelCoverage(0xe7),
- pixelCoverage(0xe8), pixelCoverage(0xe9), pixelCoverage(0xea), pixelCoverage(0xeb),
- pixelCoverage(0xec), pixelCoverage(0xed), pixelCoverage(0xee), pixelCoverage(0xef),
- pixelCoverage(0xf0), pixelCoverage(0xf1), pixelCoverage(0xf2), pixelCoverage(0xf3),
- pixelCoverage(0xf4), pixelCoverage(0xf5), pixelCoverage(0xf6), pixelCoverage(0xf7),
- pixelCoverage(0xf8), pixelCoverage(0xf9), pixelCoverage(0xfa), pixelCoverage(0xfb),
- pixelCoverage(0xfc), pixelCoverage(0xfd), pixelCoverage(0xfe), pixelCoverage(0xff),
-}
-
-func pixelCoverage(a uint8) uint8 {
- return a&1 + a>>1&1 + a>>2&1 + a>>3&1 + a>>4&1 + a>>5&1 + a>>6&1 + a>>7&1
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerAA.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerAA.go
deleted file mode 100644
index dbff87f1e..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerAA.go
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-import (
- "image"
- "image/color"
- "unsafe"
-)
-
-const (
- SUBPIXEL_SHIFT = 3
- SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
-)
-
-var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8_FIXED
-
-type SUBPIXEL_DATA uint8
-type NON_ZERO_MASK_DATA_UNIT uint8
-
-type Rasterizer8BitsSample struct {
- MaskBuffer []SUBPIXEL_DATA
- WindingBuffer []NON_ZERO_MASK_DATA_UNIT
-
- Width int
- BufferWidth int
- Height int
- ClipBound [4]float64
- RemappingMatrix [6]float64
-}
-
-/* width and height define the maximum output size for the filler.
- * The filler will output to larger bitmaps as well, but the output will
- * be cropped.
- */
-func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
- var r Rasterizer8BitsSample
- // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
- // The sampling point for the sub-pixel is at the top right corner. This
- // adjustment moves it to the pixel center.
- r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
- r.Width = width
- r.Height = height
- // The buffer used for filling needs to be one pixel wider than the bitmap.
- // This is because the end flag that turns the fill of is the first pixel
- // after the actually drawn edge.
- r.BufferWidth = width + 1
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
- r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
- return &r
-}
-
-func clip(x, y, width, height, scale int) [4]float64 {
- var clipBound [4]float64
-
- offset := 0.99 / float64(scale)
-
- clipBound[0] = float64(x) + offset
- clipBound[2] = float64(x+width) - offset
-
- clipBound[1] = float64(y * scale)
- clipBound[3] = float64((y + height) * scale)
- return clipBound
-}
-
-func intersect(r1, r2 [4]float64) [4]float64 {
- if r1[0] < r2[0] {
- r1[0] = r2[0]
- }
- if r1[2] > r2[2] {
- r1[2] = r2[2]
- }
- if r1[0] > r1[2] {
- r1[0] = r1[2]
- }
-
- if r1[1] < r2[1] {
- r1[1] = r2[1]
- }
- if r1[3] > r2[3] {
- r1[3] = r2[3]
- }
- if r1[1] > r1[3] {
- r1[1] = r1[3]
- }
- return r1
-}
-
-func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
- // memset 0 the mask buffer
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addEvenOddEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillEvenOdd(img, color, clipRect)
-}
-
-//! Adds an edge to be used with even-odd fill.
-func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
- x := Fix(edge.X * FIXED_FLOAT_COEF)
- slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
- slopeFix := Fix(0)
- if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
- slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
- }
-
- var mask SUBPIXEL_DATA
- var ySub uint32
- var xp, yLine int
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = uint32(y & (SUBPIXEL_COUNT - 1))
- xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
- x += slope
- if y&SLOPE_FIX_MASK == 0 {
- x += slopeFix
- }
- }
-}
-
-//! Adds an edge to be used with non-zero winding fill.
-func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
- x := Fix(edge.X * FIXED_FLOAT_COEF)
- slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
- slopeFix := Fix(0)
- if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
- slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
- }
- var mask SUBPIXEL_DATA
- var ySub uint32
- var xp, yLine int
- winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = uint32(y & (SUBPIXEL_COUNT - 1))
- xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
- r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
- x += slope
- if y&SLOPE_FIX_MASK == 0 {
- x += slopeFix
- }
- }
-}
-
-// Renders the mask to the canvas with even-odd fill.
-func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- // 8bits
- alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := SUBPIXEL_COUNT - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
-
-/*
- * Renders the polygon with non-zero winding fill.
- * param aTarget the target bitmap.
- * param aPolygon the polygon to render.
- * param aColor the color to be used for rendering.
- * param aTransformation the transformation matrix.
- */
-func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
-
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addNonZeroEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillNonZero(img, color, clipRect)
-}
-
-//! Renders the mask to the canvas with non-zero winding fill.
-func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
- var n uint32
- var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- values[n] = 0
- }
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- if temp != 0 {
- var bit SUBPIXEL_DATA = 1
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- if temp&bit != 0 {
- t := values[n]
- values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
- if (t == 0 || values[n] == 0) && t != values[n] {
- mask ^= bit
- }
- }
- bit <<= 1
- }
- }
-
- // 8bits
- alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := uint32(SUBPIXEL_COUNT) - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV1/fillerAA.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV1/fillerAA.go
deleted file mode 100644
index a85d34c77..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV1/fillerAA.go
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-import (
- "image"
- "image/color"
- "unsafe"
-)
-
-const (
- SUBPIXEL_SHIFT = 3
- SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
-)
-
-var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8
-
-type SUBPIXEL_DATA uint16
-type NON_ZERO_MASK_DATA_UNIT uint8
-
-type Rasterizer8BitsSample struct {
- MaskBuffer []SUBPIXEL_DATA
- WindingBuffer []NON_ZERO_MASK_DATA_UNIT
-
- Width int
- BufferWidth int
- Height int
- ClipBound [4]float64
- RemappingMatrix [6]float64
-}
-
-/* width and height define the maximum output size for the filler.
- * The filler will output to larger bitmaps as well, but the output will
- * be cropped.
- */
-func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
- var r Rasterizer8BitsSample
- // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
- // The sampling point for the sub-pixel is at the top right corner. This
- // adjustment moves it to the pixel center.
- r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
- r.Width = width
- r.Height = height
- // The buffer used for filling needs to be one pixel wider than the bitmap.
- // This is because the end flag that turns the fill of is the first pixel
- // after the actually drawn edge.
- r.BufferWidth = width + 1
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
- r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
- return &r
-}
-
-func clip(x, y, width, height, scale int) [4]float64 {
- var clipBound [4]float64
-
- offset := 0.99 / float64(scale)
-
- clipBound[0] = float64(x) + offset
- clipBound[2] = float64(x+width) - offset
-
- clipBound[1] = float64(y * scale)
- clipBound[3] = float64((y + height) * scale)
- return clipBound
-}
-
-func intersect(r1, r2 [4]float64) [4]float64 {
- if r1[0] < r2[0] {
- r1[0] = r2[0]
- }
- if r1[2] > r2[2] {
- r1[2] = r2[2]
- }
- if r1[0] > r1[2] {
- r1[0] = r1[2]
- }
-
- if r1[1] < r2[1] {
- r1[1] = r2[1]
- }
- if r1[3] > r2[3] {
- r1[3] = r2[3]
- }
- if r1[1] > r1[3] {
- r1[1] = r1[3]
- }
- return r1
-}
-
-func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
- // memset 0 the mask buffer
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addEvenOddEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillEvenOdd(img, color, clipRect)
-}
-
-//! Adds an edge to be used with even-odd fill.
-func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
- x := edge.X
- slope := edge.Slope
- var ySub, mask SUBPIXEL_DATA
- var xp, yLine int
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
- xp = int(x + SUBPIXEL_OFFSETS[ySub])
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
- x += slope
- }
-}
-
-// Renders the mask to the canvas with even-odd fill.
-func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- // 8bits
- alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := uint32(SUBPIXEL_COUNT) - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
-
-/*
- * Renders the polygon with non-zero winding fill.
- * param aTarget the target bitmap.
- * param aPolygon the polygon to render.
- * param aColor the color to be used for rendering.
- * param aTransformation the transformation matrix.
- */
-func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
-
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addNonZeroEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillNonZero(img, color, clipRect)
-}
-
-//! Adds an edge to be used with non-zero winding fill.
-func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
- x := edge.X
- slope := edge.Slope
- var ySub, mask SUBPIXEL_DATA
- var xp, yLine int
- winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
- xp = int(x + SUBPIXEL_OFFSETS[ySub])
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
- r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
- x += slope
- }
-}
-
-//! Renders the mask to the canvas with non-zero winding fill.
-func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
- var n uint32
- var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- values[n] = 0
- }
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- if temp != 0 {
- var bit SUBPIXEL_DATA = 1
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- if temp&bit != 0 {
- t := values[n]
- values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
- if (t == 0 || values[n] == 0) && t != values[n] {
- mask ^= bit
- }
- }
- bit <<= 1
- }
- }
-
- // 8bits
- alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := uint32(SUBPIXEL_COUNT) - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV2/fillerAA.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV2/fillerAA.go
deleted file mode 100644
index 0bda5a4db..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV2/fillerAA.go
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-import (
- "image"
- "image/color"
- "unsafe"
-)
-
-const (
- SUBPIXEL_SHIFT = 5
- SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
-)
-
-var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_32_FIXED
-
-type SUBPIXEL_DATA uint32
-type NON_ZERO_MASK_DATA_UNIT uint8
-
-type Rasterizer8BitsSample struct {
- MaskBuffer []SUBPIXEL_DATA
- WindingBuffer []NON_ZERO_MASK_DATA_UNIT
-
- Width int
- BufferWidth int
- Height int
- ClipBound [4]float64
- RemappingMatrix [6]float64
-}
-
-/* width and height define the maximum output size for the filler.
- * The filler will output to larger bitmaps as well, but the output will
- * be cropped.
- */
-func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
- var r Rasterizer8BitsSample
- // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
- // The sampling point for the sub-pixel is at the top right corner. This
- // adjustment moves it to the pixel center.
- r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
- r.Width = width
- r.Height = height
- // The buffer used for filling needs to be one pixel wider than the bitmap.
- // This is because the end flag that turns the fill of is the first pixel
- // after the actually drawn edge.
- r.BufferWidth = width + 1
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
- r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
- return &r
-}
-
-func clip(x, y, width, height, scale int) [4]float64 {
- var clipBound [4]float64
-
- offset := 0.99 / float64(scale)
-
- clipBound[0] = float64(x) + offset
- clipBound[2] = float64(x+width) - offset
-
- clipBound[1] = float64(y * scale)
- clipBound[3] = float64((y + height) * scale)
- return clipBound
-}
-
-func intersect(r1, r2 [4]float64) [4]float64 {
- if r1[0] < r2[0] {
- r1[0] = r2[0]
- }
- if r1[2] > r2[2] {
- r1[2] = r2[2]
- }
- if r1[0] > r1[2] {
- r1[0] = r1[2]
- }
-
- if r1[1] < r2[1] {
- r1[1] = r2[1]
- }
- if r1[3] > r2[3] {
- r1[3] = r2[3]
- }
- if r1[1] > r1[3] {
- r1[1] = r1[3]
- }
- return r1
-}
-
-func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
- // memset 0 the mask buffer
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addEvenOddEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillEvenOdd(img, color, clipRect)
-}
-
-//! Adds an edge to be used with even-odd fill.
-func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
- x := Fix(edge.X * FIXED_FLOAT_COEF)
- slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
- slopeFix := Fix(0)
- if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
- slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
- }
-
- var mask SUBPIXEL_DATA
- var ySub uint32
- var xp, yLine int
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = uint32(y & (SUBPIXEL_COUNT - 1))
- xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
- x += slope
- if y&SLOPE_FIX_MASK == 0 {
- x += slopeFix
- }
- }
-}
-
-//! Adds an edge to be used with non-zero winding fill.
-func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
- x := Fix(edge.X * FIXED_FLOAT_COEF)
- slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
- slopeFix := Fix(0)
- if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
- slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
- }
- var mask SUBPIXEL_DATA
- var ySub uint32
- var xp, yLine int
- winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
- for y := edge.FirstLine; y <= edge.LastLine; y++ {
- ySub = uint32(y & (SUBPIXEL_COUNT - 1))
- xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
- mask = SUBPIXEL_DATA(1 << ySub)
- yLine = y >> SUBPIXEL_SHIFT
- r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
- r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
- x += slope
- if y&SLOPE_FIX_MASK == 0 {
- x += slopeFix
- }
- }
-}
-
-// Renders the mask to the canvas with even-odd fill.
-func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- // 8bits
- //alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := uint32(SUBPIXEL_COUNT) - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
-
-/*
- * Renders the polygon with non-zero winding fill.
- * param aTarget the target bitmap.
- * param aPolygon the polygon to render.
- * param aColor the color to be used for rendering.
- * param aTransformation the transformation matrix.
- */
-func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
-
- r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
- r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
-
- // inline matrix multiplication
- transform := [6]float64{
- tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
- tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
- tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
- tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
- tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
- tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
- }
-
- clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
- clipRect = intersect(clipRect, r.ClipBound)
-
- p := 0
- l := len(*polygon) / 2
- var edges [32]PolygonEdge
- for p < l {
- edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
- for k := 0; k < edgeCount; k++ {
- r.addNonZeroEdge(&edges[k])
- }
- p += 16
- }
-
- r.fillNonZero(img, color, clipRect)
-}
-
-//! Renders the mask to the canvas with non-zero winding fill.
-func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
- var x, y uint32
-
- minX := uint32(clipBound[0])
- maxX := uint32(clipBound[2])
-
- minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
- maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
-
- //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
- pixColor := (*uint32)(unsafe.Pointer(color))
- cs1 := *pixColor & 0xff00ff
- cs2 := *pixColor >> 8 & 0xff00ff
-
- stride := uint32(img.Stride)
- var mask SUBPIXEL_DATA
- var n uint32
- var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- values[n] = 0
- }
-
- for y = minY; y < maxY; y++ {
- tp := img.Pix[y*stride:]
-
- mask = 0
- for x = minX; x <= maxX; x++ {
- p := (*uint32)(unsafe.Pointer(&tp[x]))
- temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
- if temp != 0 {
- var bit SUBPIXEL_DATA = 1
- for n = 0; n < SUBPIXEL_COUNT; n++ {
- if temp&bit != 0 {
- t := values[n]
- values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
- if (t == 0 || values[n] == 0) && t != values[n] {
- mask ^= bit
- }
- }
- bit <<= 1
- }
- }
-
- // 8bits
- //alpha := uint32(coverageTable[mask])
- // 16bits
- //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
- // 32bits
- alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff])
-
- // alpha is in range of 0 to SUBPIXEL_COUNT
- invAlpha := uint32(SUBPIXEL_COUNT) - alpha
-
- ct1 := *p & 0xff00ff * invAlpha
- ct2 := *p >> 8 & 0xff00ff * invAlpha
-
- ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
- ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
-
- *p = ct1 + ct2
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fixed_point.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fixed_point.go
deleted file mode 100644
index 14b8419c3..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fixed_point.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package raster
-
-type Fix int32
-
-const (
- FIXED_SHIFT = 16
- FIXED_FLOAT_COEF = 1 << FIXED_SHIFT
-)
-
-/*! Fixed point math inevitably introduces rounding error to the DDA. The error is
- * fixed every now and then by a separate fix value. The defines below set these.
- */
-const (
- SLOPE_FIX_SHIFT = 8
- SLOPE_FIX_STEP = 1 << SLOPE_FIX_SHIFT
- SLOPE_FIX_MASK = SLOPE_FIX_STEP - 1
-)
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/line.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/line.go
deleted file mode 100644
index 6f6d8863f..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/line.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-import (
- "image/color"
- "image/draw"
-)
-
-func abs(i int) int {
- if i < 0 {
- return -i
- }
- return i
-}
-
-func PolylineBresenham(img draw.Image, c color.Color, s ...float64) {
- for i := 2; i < len(s); i += 2 {
- Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5))
- }
-}
-
-func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) {
- dx := abs(x1 - x0)
- dy := abs(y1 - y0)
- var sx, sy int
- if x0 < x1 {
- sx = 1
- } else {
- sx = -1
- }
- if y0 < y1 {
- sy = 1
- } else {
- sy = -1
- }
- err := dx - dy
-
- var e2 int
- for {
- img.Set(x0, y0, color)
- if x0 == x1 && y0 == y1 {
- return
- }
- e2 = 2 * err
- if e2 > -dy {
- err = err - dy
- x0 = x0 + sx
- }
- if e2 < dx {
- err = err + dx
- y0 = y0 + sy
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/polygon.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/polygon.go
deleted file mode 100644
index 2a19e7355..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/polygon.go
+++ /dev/null
@@ -1,581 +0,0 @@
-// Copyright 2011 The draw2d Authors. All rights reserved.
-// created: 27/05/2011 by Laurent Le Goff
-package raster
-
-const (
- POLYGON_CLIP_NONE = iota
- POLYGON_CLIP_LEFT
- POLYGON_CLIP_RIGHT
- POLYGON_CLIP_TOP
- POLYGON_CLIP_BOTTOM
-)
-
-type Polygon []float64
-
-type PolygonEdge struct {
- X, Slope float64
- FirstLine, LastLine int
- Winding int16
-}
-
-//! A more optimized representation of a polygon edge.
-type PolygonScanEdge struct {
- FirstLine, LastLine int
- Winding int16
- X Fix
- Slope Fix
- SlopeFix Fix
- NextEdge *PolygonScanEdge
-}
-
-//! Calculates the edges of the polygon with transformation and clipping to edges array.
-/*! \param startIndex the index for the first vertex.
- * \param vertexCount the amount of vertices to convert.
- * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges.
- * \param tr the transformation matrix for the polygon.
- * \param aClipRectangle the clip rectangle.
- * \return the amount of edges in the result.
- */
-func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int {
- startIndex = startIndex * 2
- endIndex := startIndex + vertexCount*2
- if endIndex > len(p) {
- endIndex = len(p)
- }
-
- x := p[startIndex]
- y := p[startIndex+1]
- // inline transformation
- prevX := x*tr[0] + y*tr[2] + tr[4]
- prevY := x*tr[1] + y*tr[3] + tr[5]
-
- //! Calculates the clip flags for a point.
- prevClipFlags := POLYGON_CLIP_NONE
- if prevX < clipBound[0] {
- prevClipFlags |= POLYGON_CLIP_LEFT
- } else if prevX >= clipBound[2] {
- prevClipFlags |= POLYGON_CLIP_RIGHT
- }
-
- if prevY < clipBound[1] {
- prevClipFlags |= POLYGON_CLIP_TOP
- } else if prevY >= clipBound[3] {
- prevClipFlags |= POLYGON_CLIP_BOTTOM
- }
-
- edgeCount := 0
- var k, clipFlags, clipSum, clipUnion int
- var xleft, yleft, xright, yright, oldY, maxX, minX float64
- var swapWinding int16
- for n := startIndex; n < endIndex; n = n + 2 {
- k = (n + 2) % len(p)
- x = p[k]*tr[0] + p[k+1]*tr[2] + tr[4]
- y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5]
-
- //! Calculates the clip flags for a point.
- clipFlags = POLYGON_CLIP_NONE
- if prevX < clipBound[0] {
- clipFlags |= POLYGON_CLIP_LEFT
- } else if prevX >= clipBound[2] {
- clipFlags |= POLYGON_CLIP_RIGHT
- }
- if prevY < clipBound[1] {
- clipFlags |= POLYGON_CLIP_TOP
- } else if prevY >= clipBound[3] {
- clipFlags |= POLYGON_CLIP_BOTTOM
- }
-
- clipSum = prevClipFlags | clipFlags
- clipUnion = prevClipFlags & clipFlags
-
- // Skip all edges that are either completely outside at the top or at the bottom.
- if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 {
- if clipUnion&POLYGON_CLIP_RIGHT != 0 {
- // Both clip to right, edge is a vertical line on the right side
- if getVerticalEdge(prevY, y, clipBound[2], &edges[edgeCount], clipBound) {
- edgeCount++
- }
- } else if clipUnion&POLYGON_CLIP_LEFT != 0 {
- // Both clip to left, edge is a vertical line on the left side
- if getVerticalEdge(prevY, y, clipBound[0], &edges[edgeCount], clipBound) {
- edgeCount++
- }
- } else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
- // No clipping in the horizontal direction
- if getEdge(prevX, prevY, x, y, &edges[edgeCount], clipBound) {
- edgeCount++
- }
- } else {
- // Clips to left or right or both.
-
- if x < prevX {
- xleft, yleft = x, y
- xright, yright = prevX, prevY
- swapWinding = -1
- } else {
- xleft, yleft = prevX, prevY
- xright, yright = x, y
- swapWinding = 1
- }
-
- slope := (yright - yleft) / (xright - xleft)
-
- if clipSum&POLYGON_CLIP_RIGHT != 0 {
- // calculate new position for the right vertex
- oldY = yright
- maxX = clipBound[2]
-
- yright = yleft + (maxX-xleft)*slope
- xright = maxX
-
- // add vertical edge for the overflowing part
- if getVerticalEdge(yright, oldY, maxX, &edges[edgeCount], clipBound) {
- edges[edgeCount].Winding *= swapWinding
- edgeCount++
- }
- }
-
- if clipSum&POLYGON_CLIP_LEFT != 0 {
- // calculate new position for the left vertex
- oldY = yleft
- minX = clipBound[0]
-
- yleft = yleft + (minX-xleft)*slope
- xleft = minX
-
- // add vertical edge for the overflowing part
- if getVerticalEdge(oldY, yleft, minX, &edges[edgeCount], clipBound) {
- edges[edgeCount].Winding *= swapWinding
- edgeCount++
- }
- }
-
- if getEdge(xleft, yleft, xright, yright, &edges[edgeCount], clipBound) {
- edges[edgeCount].Winding *= swapWinding
- edgeCount++
- }
- }
- }
-
- prevClipFlags = clipFlags
- prevX = x
- prevY = y
- }
-
- return edgeCount
-}
-
-//! Creates a polygon edge between two vectors.
-/*! Clips the edge vertically to the clip rectangle. Returns true for edges that
- * should be rendered, false for others.
- */
-func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bool {
- var startX, startY, endX, endY float64
- var winding int16
-
- if y0 <= y1 {
- startX = x0
- startY = y0
- endX = x1
- endY = y1
- winding = 1
- } else {
- startX = x1
- startY = y1
- endX = x0
- endY = y0
- winding = -1
- }
-
- // Essentially, firstLine is floor(startY + 1) and lastLine is floor(endY).
- // These are refactored to integer casts in order to avoid function
- // calls. The difference with integer cast is that numbers are always
- // rounded towards zero. Since values smaller than zero get clipped away,
- // only coordinates between 0 and -1 require greater attention as they
- // also round to zero. The problems in this range can be avoided by
- // adding one to the values before conversion and subtracting after it.
-
- firstLine := int(startY + 1)
- lastLine := int(endY+1) - 1
-
- minClip := int(clipBound[1])
- maxClip := int(clipBound[3])
-
- // If start and end are on the same line, the edge doesn't cross
- // any lines and thus can be ignored.
- // If the end is smaller than the first line, edge is out.
- // If the start is larger than the last line, edge is out.
- if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
- return false
- }
-
- // Adjust the start based on the target.
- if firstLine < minClip {
- firstLine = minClip
- }
-
- if lastLine >= maxClip {
- lastLine = maxClip - 1
- }
- edge.Slope = (endX - startX) / (endY - startY)
- edge.X = startX + (float64(firstLine)-startY)*edge.Slope
- edge.Winding = winding
- edge.FirstLine = firstLine
- edge.LastLine = lastLine
-
- return true
-}
-
-//! Creates a vertical polygon edge between two y values.
-/*! Clips the edge vertically to the clip rectangle. Returns true for edges that
- * should be rendered, false for others.
- */
-func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]float64) bool {
- var start, end float64
- var winding int16
- if startY < endY {
- start = startY
- end = endY
- winding = 1
- } else {
- start = endY
- end = startY
- winding = -1
- }
-
- firstLine := int(start + 1)
- lastLine := int(end+1) - 1
-
- minClip := int(clipBound[1])
- maxClip := int(clipBound[3])
-
- // If start and end are on the same line, the edge doesn't cross
- // any lines and thus can be ignored.
- // If the end is smaller than the first line, edge is out.
- // If the start is larger than the last line, edge is out.
- if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
- return false
- }
-
- // Adjust the start based on the clip rect.
- if firstLine < minClip {
- firstLine = minClip
- }
- if lastLine >= maxClip {
- lastLine = maxClip - 1
- }
-
- edge.Slope = 0
- edge.X = x
- edge.Winding = winding
- edge.FirstLine = firstLine
- edge.LastLine = lastLine
-
- return true
-}
-
-type VertexData struct {
- X, Y float64
- ClipFlags int
- Line int
-}
-
-//! Calculates the edges of the polygon with transformation and clipping to edges array.
-/*! Note that this may return upto three times the amount of edges that the polygon has vertices,
- * in the unlucky case where both left and right side get clipped for all edges.
- * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges.
- * \param aTransformation the transformation matrix for the polygon.
- * \param aClipRectangle the clip rectangle.
- * \return the amount of edges in the result.
- */
-func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound [4]float64) int {
- var n int
- vertexData := make([]VertexData, len(p)/2+1)
- for n = 0; n < len(vertexData)-1; n = n + 1 {
- k := n * 2
- vertexData[n].X = p[k]*tr[0] + p[k+1]*tr[2] + tr[4]
- vertexData[n].Y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5]
- // Calculate clip flags for all vertices.
- vertexData[n].ClipFlags = POLYGON_CLIP_NONE
- if vertexData[n].X < clipBound[0] {
- vertexData[n].ClipFlags |= POLYGON_CLIP_LEFT
- } else if vertexData[n].X >= clipBound[2] {
- vertexData[n].ClipFlags |= POLYGON_CLIP_RIGHT
- }
- if vertexData[n].Y < clipBound[1] {
- vertexData[n].ClipFlags |= POLYGON_CLIP_TOP
- } else if vertexData[n].Y >= clipBound[3] {
- vertexData[n].ClipFlags |= POLYGON_CLIP_BOTTOM
- }
-
- // Calculate line of the vertex. If the vertex is clipped by top or bottom, the line
- // is determined by the clip rectangle.
- if vertexData[n].ClipFlags&POLYGON_CLIP_TOP != 0 {
- vertexData[n].Line = int(clipBound[1])
- } else if vertexData[n].ClipFlags&POLYGON_CLIP_BOTTOM != 0 {
- vertexData[n].Line = int(clipBound[3] - 1)
- } else {
- vertexData[n].Line = int(vertexData[n].Y+1) - 1
- }
- }
-
- // Copy the data from 0 to the last entry to make the data to loop.
- vertexData[len(vertexData)-1] = vertexData[0]
-
- // Transform the first vertex; store.
- // Process mVertexCount - 1 times, next is n+1
- // copy the first vertex to
- // Process 1 time, next is n
-
- edgeCount := 0
- for n = 0; n < len(vertexData)-1; n++ {
- clipSum := vertexData[n].ClipFlags | vertexData[n+1].ClipFlags
- clipUnion := vertexData[n].ClipFlags & vertexData[n+1].ClipFlags
-
- if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 &&
- vertexData[n].Line != vertexData[n+1].Line {
- var startIndex, endIndex int
- var winding int16
- if vertexData[n].Y < vertexData[n+1].Y {
- startIndex = n
- endIndex = n + 1
- winding = 1
- } else {
- startIndex = n + 1
- endIndex = n
- winding = -1
- }
-
- firstLine := vertexData[startIndex].Line + 1
- lastLine := vertexData[endIndex].Line
-
- if clipUnion&POLYGON_CLIP_RIGHT != 0 {
- // Both clip to right, edge is a vertical line on the right side
- edges[edgeCount].FirstLine = firstLine
- edges[edgeCount].LastLine = lastLine
- edges[edgeCount].Winding = winding
- edges[edgeCount].X = Fix(clipBound[2] * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = 0
- edges[edgeCount].SlopeFix = 0
-
- edgeCount++
- } else if clipUnion&POLYGON_CLIP_LEFT != 0 {
- // Both clip to left, edge is a vertical line on the left side
- edges[edgeCount].FirstLine = firstLine
- edges[edgeCount].LastLine = lastLine
- edges[edgeCount].Winding = winding
- edges[edgeCount].X = Fix(clipBound[0] * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = 0
- edges[edgeCount].SlopeFix = 0
-
- edgeCount++
- } else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
- // No clipping in the horizontal direction
- slope := (vertexData[endIndex].X -
- vertexData[startIndex].X) /
- (vertexData[endIndex].Y -
- vertexData[startIndex].Y)
-
- // If there is vertical clip (for the top) it will be processed here. The calculation
- // should be done for all non-clipping edges as well to determine the accurate position
- // where the edge crosses the first scanline.
- startx := vertexData[startIndex].X +
- (float64(firstLine)-vertexData[startIndex].Y)*slope
-
- edges[edgeCount].FirstLine = firstLine
- edges[edgeCount].LastLine = lastLine
- edges[edgeCount].Winding = winding
- edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
-
- if lastLine-firstLine >= SLOPE_FIX_STEP {
- edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
- edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
- } else {
- edges[edgeCount].SlopeFix = 0
- }
-
- edgeCount++
- } else {
- // Clips to left or right or both.
- slope := (vertexData[endIndex].X -
- vertexData[startIndex].X) /
- (vertexData[endIndex].Y -
- vertexData[startIndex].Y)
-
- // The edge may clip to both left and right.
- // The clip results in one or two new vertices, and one to three segments.
- // The rounding for scanlines may produce a result where any of the segments is
- // ignored.
-
- // The start is always above the end. Calculate the clip positions to clipVertices.
- // It is possible that only one of the vertices exist. This will be detected from the
- // clip flags of the vertex later, so they are initialized here.
- var clipVertices [2]VertexData
-
- if vertexData[startIndex].X <
- vertexData[endIndex].X {
- clipVertices[0].X = clipBound[0]
- clipVertices[1].X = clipBound[2]
- clipVertices[0].ClipFlags = POLYGON_CLIP_LEFT
- clipVertices[1].ClipFlags = POLYGON_CLIP_RIGHT
- } else {
- clipVertices[0].X = clipBound[2]
- clipVertices[1].X = clipBound[0]
- clipVertices[0].ClipFlags = POLYGON_CLIP_RIGHT
- clipVertices[1].ClipFlags = POLYGON_CLIP_LEFT
- }
-
- var p int
- for p = 0; p < 2; p++ {
- // Check if either of the vertices crosses the edge marked for the clip vertex
- if clipSum&clipVertices[p].ClipFlags != 0 {
- // The the vertex is required, calculate it.
- clipVertices[p].Y = vertexData[startIndex].Y +
- (clipVertices[p].X-
- vertexData[startIndex].X)/slope
-
- // If there is clipping in the vertical direction, the new vertex may be clipped.
- if clipSum&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) != 0 {
- if clipVertices[p].Y < clipBound[1] {
- clipVertices[p].ClipFlags = POLYGON_CLIP_TOP
- clipVertices[p].Line = int(clipBound[1])
- } else if clipVertices[p].Y > clipBound[3] {
- clipVertices[p].ClipFlags = POLYGON_CLIP_BOTTOM
- clipVertices[p].Line = int(clipBound[3] - 1)
- } else {
- clipVertices[p].ClipFlags = 0
- clipVertices[p].Line = int(clipVertices[p].Y+1) - 1
- }
- } else {
- clipVertices[p].ClipFlags = 0
- clipVertices[p].Line = int(clipVertices[p].Y+1) - 1
- }
- }
- }
-
- // Now there are three or four vertices, in the top-to-bottom order of start, clip0, clip1,
- // end. What kind of edges are required for connecting these can be determined from the
- // clip flags.
- // -if clip vertex has horizontal clip flags, it doesn't exist. No edge is generated.
- // -if start vertex or end vertex has horizontal clip flag, the edge to/from the clip vertex is vertical
- // -if the line of two vertices is the same, the edge is not generated, since the edge doesn't
- // cross any scanlines.
-
- // The alternative patterns are:
- // start - clip0 - clip1 - end
- // start - clip0 - end
- // start - clip1 - end
-
- var topClipIndex, bottomClipIndex int
- if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)&
- (POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 {
- // Both sides are clipped, the order is start-clip0-clip1-end
- topClipIndex = 0
- bottomClipIndex = 1
-
- // Add the edge from clip0 to clip1
- // Check that the line is different for the vertices.
- if clipVertices[0].Line != clipVertices[1].Line {
- firstClipLine := clipVertices[0].Line + 1
-
- startx := vertexData[startIndex].X +
- (float64(firstClipLine)-vertexData[startIndex].Y)*slope
-
- edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
- edges[edgeCount].FirstLine = firstClipLine
- edges[edgeCount].LastLine = clipVertices[1].Line
- edges[edgeCount].Winding = winding
-
- if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
- edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
- edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
- } else {
- edges[edgeCount].SlopeFix = 0
- }
-
- edgeCount++
- }
- } else {
- // Clip at either side, check which side. The clip flag is on for the vertex
- // that doesn't exist, i.e. has not been clipped to be inside the rect.
- if clipVertices[0].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
- topClipIndex = 1
- bottomClipIndex = 1
- } else {
- topClipIndex = 0
- bottomClipIndex = 0
- }
- }
-
- // Generate the edges from start - clip top and clip bottom - end
- // Clip top and clip bottom may be the same vertex if there is only one
- // clipped vertex.
-
- // Check that the line is different for the vertices.
- if vertexData[startIndex].Line != clipVertices[topClipIndex].Line {
- edges[edgeCount].FirstLine = firstLine
- edges[edgeCount].LastLine = clipVertices[topClipIndex].Line
- edges[edgeCount].Winding = winding
-
- // If startIndex is clipped, the edge is a vertical one.
- if vertexData[startIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
- edges[edgeCount].X = Fix(clipVertices[topClipIndex].X * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = 0
- edges[edgeCount].SlopeFix = 0
- } else {
- startx := vertexData[startIndex].X +
- (float64(firstLine)-vertexData[startIndex].Y)*slope
-
- edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
-
- if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
- edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
- edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
- } else {
- edges[edgeCount].SlopeFix = 0
- }
- }
-
- edgeCount++
- }
-
- // Check that the line is different for the vertices.
- if clipVertices[bottomClipIndex].Line != vertexData[endIndex].Line {
- firstClipLine := clipVertices[bottomClipIndex].Line + 1
-
- edges[edgeCount].FirstLine = firstClipLine
- edges[edgeCount].LastLine = lastLine
- edges[edgeCount].Winding = winding
-
- // If endIndex is clipped, the edge is a vertical one.
- if vertexData[endIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
- edges[edgeCount].X = Fix(clipVertices[bottomClipIndex].X * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = 0
- edges[edgeCount].SlopeFix = 0
- } else {
- startx := vertexData[startIndex].X +
- (float64(firstClipLine)-vertexData[startIndex].Y)*slope
-
- edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
- edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
-
- if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
- edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
- edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
- } else {
- edges[edgeCount].SlopeFix = 0
- }
- }
-
- edgeCount++
- }
-
- }
- }
- }
-
- return edgeCount
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/raster_test.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/raster_test.go
deleted file mode 100644
index 7872d8d03..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/raster_test.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package raster
-
-import (
- "bufio"
- "code.google.com/p/draw2d/draw2d/curve"
- "code.google.com/p/freetype-go/freetype/raster"
- "image"
- "image/color"
- "image/png"
- "log"
- "os"
- "testing"
-)
-
-var flattening_threshold float64 = 0.5
-
-func savepng(filePath string, m image.Image) {
- f, err := os.Create(filePath)
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
- defer f.Close()
- b := bufio.NewWriter(f)
- err = png.Encode(b, m)
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
- err = b.Flush()
- if err != nil {
- log.Println(err)
- os.Exit(1)
- }
-}
-
-type Path struct {
- points []float64
-}
-
-func (p *Path) LineTo(x, y float64) {
- if len(p.points)+2 > cap(p.points) {
- points := make([]float64, len(p.points)+2, len(p.points)+32)
- copy(points, p.points)
- p.points = points
- } else {
- p.points = p.points[0 : len(p.points)+2]
- }
- p.points[len(p.points)-2] = x
- p.points[len(p.points)-1] = y
-}
-
-func TestFreetype(t *testing.T) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
-
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := raster.NewRasterizer(200, 200)
- rasterizer.UseNonZeroWinding = false
- rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
- for j := 0; j < len(poly); j = j + 2 {
- rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
- }
- painter := raster.NewRGBAPainter(img)
- painter.SetColor(color)
- rasterizer.Rasterize(painter)
-
- savepng("_testFreetype.png", img)
-}
-
-func TestFreetypeNonZeroWinding(t *testing.T) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
-
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := raster.NewRasterizer(200, 200)
- rasterizer.UseNonZeroWinding = true
- rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
- for j := 0; j < len(poly); j = j + 2 {
- rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
- }
- painter := raster.NewRGBAPainter(img)
- painter.SetColor(color)
- rasterizer.Rasterize(painter)
-
- savepng("_testFreetypeNonZeroWinding.png", img)
-}
-
-func TestRasterizer(t *testing.T) {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
- tr := [6]float64{1, 0, 0, 1, 0, 0}
- r := NewRasterizer8BitsSample(200, 200)
- //PolylineBresenham(img, image.Black, poly...)
-
- r.RenderEvenOdd(img, &color, &poly, tr)
- savepng("_testRasterizer.png", img)
-}
-
-func TestRasterizerNonZeroWinding(t *testing.T) {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
- tr := [6]float64{1, 0, 0, 1, 0, 0}
- r := NewRasterizer8BitsSample(200, 200)
- //PolylineBresenham(img, image.Black, poly...)
-
- r.RenderNonZeroWinding(img, &color, &poly, tr)
- savepng("_testRasterizerNonZeroWinding.png", img)
-}
-
-func BenchmarkFreetype(b *testing.B) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
-
- for i := 0; i < b.N; i++ {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := raster.NewRasterizer(200, 200)
- rasterizer.UseNonZeroWinding = false
- rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
- for j := 0; j < len(poly); j = j + 2 {
- rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
- }
- painter := raster.NewRGBAPainter(img)
- painter.SetColor(color)
- rasterizer.Rasterize(painter)
- }
-}
-func BenchmarkFreetypeNonZeroWinding(b *testing.B) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
-
- for i := 0; i < b.N; i++ {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := raster.NewRasterizer(200, 200)
- rasterizer.UseNonZeroWinding = true
- rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
- for j := 0; j < len(poly); j = j + 2 {
- rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
- }
- painter := raster.NewRGBAPainter(img)
- painter.SetColor(color)
- rasterizer.Rasterize(painter)
- }
-}
-
-func BenchmarkRasterizerNonZeroWinding(b *testing.B) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
- tr := [6]float64{1, 0, 0, 1, 0, 0}
- for i := 0; i < b.N; i++ {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := NewRasterizer8BitsSample(200, 200)
- rasterizer.RenderNonZeroWinding(img, &color, &poly, tr)
- }
-}
-
-func BenchmarkRasterizer(b *testing.B) {
- var p Path
- p.LineTo(10, 190)
- c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
- c.Segment(&p, flattening_threshold)
- poly := Polygon(p.points)
- color := color.RGBA{0, 0, 0, 0xff}
- tr := [6]float64{1, 0, 0, 1, 0, 0}
- for i := 0; i < b.N; i++ {
- img := image.NewRGBA(image.Rect(0, 0, 200, 200))
- rasterizer := NewRasterizer8BitsSample(200, 200)
- rasterizer.RenderEvenOdd(img, &color, &poly, tr)
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/rgba_interpolation.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/rgba_interpolation.go
deleted file mode 100644
index 92534e7eb..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/rgba_interpolation.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-// see http://pippin.gimp.org/image_processing/chap_resampling.html
-
-package draw2d
-
-import (
- "image"
- "image/color"
- "image/draw"
- "math"
-)
-
-type ImageFilter int
-
-const (
- LinearFilter ImageFilter = iota
- BilinearFilter
- BicubicFilter
-)
-
-//see http://pippin.gimp.org/image_processing/chap_resampling.html
-func getColorLinear(img image.Image, x, y float64) color.Color {
- return img.At(int(x), int(y))
-}
-
-func getColorBilinear(img image.Image, x, y float64) color.Color {
- x0 := math.Floor(x)
- y0 := math.Floor(y)
- dx := x - x0
- dy := y - y0
-
- rt, gt, bt, at := img.At(int(x0), int(y0)).RGBA()
- r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = img.At(int(x0+1), int(y0)).RGBA()
- r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = img.At(int(x0+1), int(y0+1)).RGBA()
- r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = img.At(int(x0), int(y0+1)).RGBA()
- r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
-
- r := int(lerp(lerp(r0, r1, dx), lerp(r3, r2, dx), dy))
- g := int(lerp(lerp(g0, g1, dx), lerp(g3, g2, dx), dy))
- b := int(lerp(lerp(b0, b1, dx), lerp(b3, b2, dx), dy))
- a := int(lerp(lerp(a0, a1, dx), lerp(a3, a2, dx), dy))
- return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
-}
-
-/**
--- LERP
--- /lerp/, vi.,n.
---
--- Quasi-acronym for Linear Interpolation, used as a verb or noun for
--- the operation. "Bresenham's algorithm lerps incrementally between the
--- two endpoints of the line." (From Jargon File (4.4.4, 14 Aug 2003)
-*/
-func lerp(v1, v2, ratio float64) float64 {
- return v1*(1-ratio) + v2*ratio
-}
-
-func getColorCubicRow(img image.Image, x, y, offset float64) color.Color {
- c0 := img.At(int(x), int(y))
- c1 := img.At(int(x+1), int(y))
- c2 := img.At(int(x+2), int(y))
- c3 := img.At(int(x+3), int(y))
- rt, gt, bt, at := c0.RGBA()
- r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c1.RGBA()
- r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c2.RGBA()
- r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c3.RGBA()
- r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
- r, g, b, a := cubic(offset, r0, r1, r2, r3), cubic(offset, g0, g1, g2, g3), cubic(offset, b0, b1, b2, b3), cubic(offset, a0, a1, a2, a3)
- return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
-}
-
-func getColorBicubic(img image.Image, x, y float64) color.Color {
- x0 := math.Floor(x)
- y0 := math.Floor(y)
- dx := x - x0
- dy := y - y0
- c0 := getColorCubicRow(img, x0-1, y0-1, dx)
- c1 := getColorCubicRow(img, x0-1, y0, dx)
- c2 := getColorCubicRow(img, x0-1, y0+1, dx)
- c3 := getColorCubicRow(img, x0-1, y0+2, dx)
- rt, gt, bt, at := c0.RGBA()
- r0, g0, b0, a0 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c1.RGBA()
- r1, g1, b1, a1 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c2.RGBA()
- r2, g2, b2, a2 := float64(rt), float64(gt), float64(bt), float64(at)
- rt, gt, bt, at = c3.RGBA()
- r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at)
- r, g, b, a := cubic(dy, r0, r1, r2, r3), cubic(dy, g0, g1, g2, g3), cubic(dy, b0, b1, b2, b3), cubic(dy, a0, a1, a2, a3)
- return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
-}
-
-func cubic(offset, v0, v1, v2, v3 float64) uint32 {
- // offset is the offset of the sampled value between v1 and v2
- return uint32(((((-7*v0+21*v1-21*v2+7*v3)*offset+
- (15*v0-36*v1+27*v2-6*v3))*offset+
- (-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0)
-}
-
-func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) {
- bounds := src.Bounds()
- x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y)
- tr.TransformRectangle(&x0, &y0, &x1, &y1)
- var x, y, u, v float64
- var c1, c2, cr color.Color
- var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32
- var color color.RGBA
- for x = x0; x < x1; x++ {
- for y = y0; y < y1; y++ {
- u = x
- v = y
- tr.InverseTransform(&u, &v)
- if bounds.Min.X <= int(u) && bounds.Max.X > int(u) && bounds.Min.Y <= int(v) && bounds.Max.Y > int(v) {
- c1 = dest.At(int(x), int(y))
- switch filter {
- case LinearFilter:
- c2 = src.At(int(u), int(v))
- case BilinearFilter:
- c2 = getColorBilinear(src, u, v)
- case BicubicFilter:
- c2 = getColorBicubic(src, u, v)
- }
- switch op {
- case draw.Over:
- r1, g1, b1, a1 = c1.RGBA()
- r2, g2, b2, a2 = c2.RGBA()
- ia = M - a2
- r = ((r1 * ia) / M) + r2
- g = ((g1 * ia) / M) + g2
- b = ((b1 * ia) / M) + b2
- a = ((a1 * ia) / M) + a2
- color.R = uint8(r >> 8)
- color.G = uint8(g >> 8)
- color.B = uint8(b >> 8)
- color.A = uint8(a >> 8)
- cr = color
- default:
- cr = c2
- }
- dest.Set(int(x), int(y), cr)
- }
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stack_gc.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stack_gc.go
deleted file mode 100644
index b2cf63fc4..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stack_gc.go
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/truetype"
- "image"
- "image/color"
-)
-
-type StackGraphicContext struct {
- Current *ContextStack
-}
-
-type ContextStack struct {
- Tr MatrixTransform
- Path *PathStorage
- LineWidth float64
- Dash []float64
- DashOffset float64
- StrokeColor color.Color
- FillColor color.Color
- FillRule FillRule
- Cap Cap
- Join Join
- FontSize float64
- FontData FontData
-
- font *truetype.Font
- // fontSize and dpi are used to calculate scale. scale is the number of
- // 26.6 fixed point units in 1 em.
- scale int32
-
- previous *ContextStack
-}
-
-/**
- * Create a new Graphic context from an image
- */
-func NewStackGraphicContext() *StackGraphicContext {
- gc := &StackGraphicContext{}
- gc.Current = new(ContextStack)
- gc.Current.Tr = NewIdentityMatrix()
- gc.Current.Path = NewPathStorage()
- gc.Current.LineWidth = 1.0
- gc.Current.StrokeColor = image.Black
- gc.Current.FillColor = image.White
- gc.Current.Cap = RoundCap
- gc.Current.FillRule = FillRuleEvenOdd
- gc.Current.Join = RoundJoin
- gc.Current.FontSize = 10
- gc.Current.FontData = defaultFontData
- return gc
-}
-
-func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform {
- return gc.Current.Tr
-}
-
-func (gc *StackGraphicContext) SetMatrixTransform(Tr MatrixTransform) {
- gc.Current.Tr = Tr
-}
-
-func (gc *StackGraphicContext) ComposeMatrixTransform(Tr MatrixTransform) {
- gc.Current.Tr = Tr.Multiply(gc.Current.Tr)
-}
-
-func (gc *StackGraphicContext) Rotate(angle float64) {
- gc.Current.Tr = NewRotationMatrix(angle).Multiply(gc.Current.Tr)
-}
-
-func (gc *StackGraphicContext) Translate(tx, ty float64) {
- gc.Current.Tr = NewTranslationMatrix(tx, ty).Multiply(gc.Current.Tr)
-}
-
-func (gc *StackGraphicContext) Scale(sx, sy float64) {
- gc.Current.Tr = NewScaleMatrix(sx, sy).Multiply(gc.Current.Tr)
-}
-
-func (gc *StackGraphicContext) SetStrokeColor(c color.Color) {
- gc.Current.StrokeColor = c
-}
-
-func (gc *StackGraphicContext) SetFillColor(c color.Color) {
- gc.Current.FillColor = c
-}
-
-func (gc *StackGraphicContext) SetFillRule(f FillRule) {
- gc.Current.FillRule = f
-}
-
-func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) {
- gc.Current.LineWidth = LineWidth
-}
-
-func (gc *StackGraphicContext) SetLineCap(Cap Cap) {
- gc.Current.Cap = Cap
-}
-
-func (gc *StackGraphicContext) SetLineJoin(Join Join) {
- gc.Current.Join = Join
-}
-
-func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
- gc.Current.Dash = Dash
- gc.Current.DashOffset = DashOffset
-}
-
-func (gc *StackGraphicContext) SetFontSize(FontSize float64) {
- gc.Current.FontSize = FontSize
-}
-
-func (gc *StackGraphicContext) GetFontSize() float64 {
- return gc.Current.FontSize
-}
-
-func (gc *StackGraphicContext) SetFontData(FontData FontData) {
- gc.Current.FontData = FontData
-}
-
-func (gc *StackGraphicContext) GetFontData() FontData {
- return gc.Current.FontData
-}
-
-func (gc *StackGraphicContext) BeginPath() {
- gc.Current.Path.Clear()
-}
-
-func (gc *StackGraphicContext) IsEmpty() bool {
- return gc.Current.Path.IsEmpty()
-}
-
-func (gc *StackGraphicContext) LastPoint() (float64, float64) {
- return gc.Current.Path.LastPoint()
-}
-
-func (gc *StackGraphicContext) MoveTo(x, y float64) {
- gc.Current.Path.MoveTo(x, y)
-}
-
-func (gc *StackGraphicContext) RMoveTo(dx, dy float64) {
- gc.Current.Path.RMoveTo(dx, dy)
-}
-
-func (gc *StackGraphicContext) LineTo(x, y float64) {
- gc.Current.Path.LineTo(x, y)
-}
-
-func (gc *StackGraphicContext) RLineTo(dx, dy float64) {
- gc.Current.Path.RLineTo(dx, dy)
-}
-
-func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) {
- gc.Current.Path.QuadCurveTo(cx, cy, x, y)
-}
-
-func (gc *StackGraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float64) {
- gc.Current.Path.RQuadCurveTo(dcx, dcy, dx, dy)
-}
-
-func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
- gc.Current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
-}
-
-func (gc *StackGraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) {
- gc.Current.Path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy)
-}
-
-func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
- gc.Current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle)
-}
-
-func (gc *StackGraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) {
- gc.Current.Path.RArcTo(dcx, dcy, rx, ry, startAngle, angle)
-}
-
-func (gc *StackGraphicContext) Close() {
- gc.Current.Path.Close()
-}
-
-func (gc *StackGraphicContext) Save() {
- context := new(ContextStack)
- context.FontSize = gc.Current.FontSize
- context.FontData = gc.Current.FontData
- context.LineWidth = gc.Current.LineWidth
- context.StrokeColor = gc.Current.StrokeColor
- context.FillColor = gc.Current.FillColor
- context.FillRule = gc.Current.FillRule
- context.Dash = gc.Current.Dash
- context.DashOffset = gc.Current.DashOffset
- context.Cap = gc.Current.Cap
- context.Join = gc.Current.Join
- context.Path = gc.Current.Path.Copy()
- context.font = gc.Current.font
- context.scale = gc.Current.scale
- copy(context.Tr[:], gc.Current.Tr[:])
- context.previous = gc.Current
- gc.Current = context
-}
-
-func (gc *StackGraphicContext) Restore() {
- if gc.Current.previous != nil {
- oldContext := gc.Current
- gc.Current = gc.Current.previous
- oldContext.previous = nil
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stroker.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stroker.go
deleted file mode 100644
index 9331187f6..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stroker.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 13/12/2010 by Laurent Le Goff
-
-package draw2d
-
-type Cap int
-
-const (
- RoundCap Cap = iota
- ButtCap
- SquareCap
-)
-
-type Join int
-
-const (
- BevelJoin Join = iota
- RoundJoin
- MiterJoin
-)
-
-type LineStroker struct {
- Next VertexConverter
- HalfLineWidth float64
- Cap Cap
- Join Join
- vertices []float64
- rewind []float64
- x, y, nx, ny float64
- command VertexCommand
-}
-
-func NewLineStroker(c Cap, j Join, converter VertexConverter) *LineStroker {
- l := new(LineStroker)
- l.Next = converter
- l.HalfLineWidth = 0.5
- l.vertices = make([]float64, 0, 256)
- l.rewind = make([]float64, 0, 256)
- l.Cap = c
- l.Join = j
- l.command = VertexNoCommand
- return l
-}
-
-func (l *LineStroker) NextCommand(command VertexCommand) {
- l.command = command
- if command == VertexStopCommand {
- l.Next.NextCommand(VertexStartCommand)
- for i, j := 0, 1; j < len(l.vertices); i, j = i+2, j+2 {
- l.Next.Vertex(l.vertices[i], l.vertices[j])
- l.Next.NextCommand(VertexNoCommand)
- }
- for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 {
- l.Next.NextCommand(VertexNoCommand)
- l.Next.Vertex(l.rewind[i], l.rewind[j])
- }
- if len(l.vertices) > 1 {
- l.Next.NextCommand(VertexNoCommand)
- l.Next.Vertex(l.vertices[0], l.vertices[1])
- }
- l.Next.NextCommand(VertexStopCommand)
- // reinit vertices
- l.vertices = l.vertices[0:0]
- l.rewind = l.rewind[0:0]
- l.x, l.y, l.nx, l.ny = 0, 0, 0, 0
- }
-}
-
-func (l *LineStroker) Vertex(x, y float64) {
- switch l.command {
- case VertexNoCommand:
- l.line(l.x, l.y, x, y)
- case VertexJoinCommand:
- l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
- case VertexStartCommand:
- l.x, l.y = x, y
- case VertexCloseCommand:
- l.line(l.x, l.y, x, y)
- l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
- l.closePolygon()
- }
- l.command = VertexNoCommand
-}
-
-func (l *LineStroker) appendVertex(vertices ...float64) {
- s := len(vertices) / 2
- if len(l.vertices)+s >= cap(l.vertices) {
- v := make([]float64, len(l.vertices), cap(l.vertices)+128)
- copy(v, l.vertices)
- l.vertices = v
- v = make([]float64, len(l.rewind), cap(l.rewind)+128)
- copy(v, l.rewind)
- l.rewind = v
- }
-
- copy(l.vertices[len(l.vertices):len(l.vertices)+s], vertices[:s])
- l.vertices = l.vertices[0 : len(l.vertices)+s]
- copy(l.rewind[len(l.rewind):len(l.rewind)+s], vertices[s:])
- l.rewind = l.rewind[0 : len(l.rewind)+s]
-
-}
-
-func (l *LineStroker) closePolygon() {
- if len(l.vertices) > 1 {
- l.appendVertex(l.vertices[0], l.vertices[1], l.rewind[0], l.rewind[1])
- }
-}
-
-func (l *LineStroker) line(x1, y1, x2, y2 float64) {
- dx := (x2 - x1)
- dy := (y2 - y1)
- d := vectorDistance(dx, dy)
- if d != 0 {
- nx := dy * l.HalfLineWidth / d
- ny := -(dx * l.HalfLineWidth / d)
- l.appendVertex(x1+nx, y1+ny, x2+nx, y2+ny, x1-nx, y1-ny, x2-nx, y2-ny)
- l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
- }
-}
-
-func (l *LineStroker) joinLine(x1, y1, nx1, ny1, x2, y2 float64) {
- dx := (x2 - x1)
- dy := (y2 - y1)
- d := vectorDistance(dx, dy)
-
- if d != 0 {
- nx := dy * l.HalfLineWidth / d
- ny := -(dx * l.HalfLineWidth / d)
- /* l.join(x1, y1, x1 + nx, y1 - ny, nx, ny, x1 + ny2, y1 + nx2, nx2, ny2)
- l.join(x1, y1, x1 - ny1, y1 - nx1, nx1, ny1, x1 - ny2, y1 - nx2, nx2, ny2)*/
-
- l.appendVertex(x1+nx, y1+ny, x2+nx, y2+ny, x1-nx, y1-ny, x2-nx, y2-ny)
- l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/transform.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/transform.go
deleted file mode 100644
index 1d89bfa9b..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/transform.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-import (
- "code.google.com/p/freetype-go/freetype/raster"
- "math"
-)
-
-type MatrixTransform [6]float64
-
-const (
- epsilon = 1e-6
-)
-
-func (tr MatrixTransform) Determinant() float64 {
- return tr[0]*tr[3] - tr[1]*tr[2]
-}
-
-func (tr MatrixTransform) Transform(points ...*float64) {
- for i, j := 0, 1; j < len(points); i, j = i+2, j+2 {
- x := *points[i]
- y := *points[j]
- *points[i] = x*tr[0] + y*tr[2] + tr[4]
- *points[j] = x*tr[1] + y*tr[3] + tr[5]
- }
-}
-
-func (tr MatrixTransform) TransformArray(points []float64) {
- for i, j := 0, 1; j < len(points); i, j = i+2, j+2 {
- x := points[i]
- y := points[j]
- points[i] = x*tr[0] + y*tr[2] + tr[4]
- points[j] = x*tr[1] + y*tr[3] + tr[5]
- }
-}
-
-func (tr MatrixTransform) TransformRectangle(x0, y0, x2, y2 *float64) {
- x1 := *x2
- y1 := *y0
- x3 := *x0
- y3 := *y2
- tr.Transform(x0, y0, &x1, &y1, x2, y2, &x3, &y3)
- *x0, x1 = minMax(*x0, x1)
- *x2, x3 = minMax(*x2, x3)
- *y0, y1 = minMax(*y0, y1)
- *y2, y3 = minMax(*y2, y3)
-
- *x0 = min(*x0, *x2)
- *y0 = min(*y0, *y2)
- *x2 = max(x1, x3)
- *y2 = max(y1, y3)
-}
-
-func (tr MatrixTransform) TransformRasterPoint(points ...*raster.Point) {
- for _, point := range points {
- x := float64(point.X) / 256
- y := float64(point.Y) / 256
- point.X = raster.Fix32((x*tr[0] + y*tr[2] + tr[4]) * 256)
- point.Y = raster.Fix32((x*tr[1] + y*tr[3] + tr[5]) * 256)
- }
-}
-
-func (tr MatrixTransform) InverseTransform(points ...*float64) {
- d := tr.Determinant() // matrix determinant
- for i, j := 0, 1; j < len(points); i, j = i+2, j+2 {
- x := *points[i]
- y := *points[j]
- *points[i] = ((x-tr[4])*tr[3] - (y-tr[5])*tr[2]) / d
- *points[j] = ((y-tr[5])*tr[0] - (x-tr[4])*tr[1]) / d
- }
-}
-
-// ******************** Vector transformations ********************
-
-func (tr MatrixTransform) VectorTransform(points ...*float64) {
- for i, j := 0, 1; j < len(points); i, j = i+2, j+2 {
- x := *points[i]
- y := *points[j]
- *points[i] = x*tr[0] + y*tr[2]
- *points[j] = x*tr[1] + y*tr[3]
- }
-}
-
-// ******************** Transformations creation ********************
-
-/** Creates an identity transformation. */
-func NewIdentityMatrix() MatrixTransform {
- return [6]float64{1, 0, 0, 1, 0, 0}
-}
-
-/**
- * Creates a transformation with a translation, that,
- * transform point1 into point2.
- */
-func NewTranslationMatrix(tx, ty float64) MatrixTransform {
- return [6]float64{1, 0, 0, 1, tx, ty}
-}
-
-/**
- * Creates a transformation with a sx, sy scale factor
- */
-func NewScaleMatrix(sx, sy float64) MatrixTransform {
- return [6]float64{sx, 0, 0, sy, 0, 0}
-}
-
-/**
- * Creates a rotation transformation.
- */
-func NewRotationMatrix(angle float64) MatrixTransform {
- c := math.Cos(angle)
- s := math.Sin(angle)
- return [6]float64{c, s, -s, c, 0, 0}
-}
-
-/**
- * Creates a transformation, combining a scale and a translation, that transform rectangle1 into rectangle2.
- */
-func NewMatrixTransform(rectangle1, rectangle2 [4]float64) MatrixTransform {
- xScale := (rectangle2[2] - rectangle2[0]) / (rectangle1[2] - rectangle1[0])
- yScale := (rectangle2[3] - rectangle2[1]) / (rectangle1[3] - rectangle1[1])
- xOffset := rectangle2[0] - (rectangle1[0] * xScale)
- yOffset := rectangle2[1] - (rectangle1[1] * yScale)
- return [6]float64{xScale, 0, 0, yScale, xOffset, yOffset}
-}
-
-// ******************** Transformations operations ********************
-
-/**
- * Returns a transformation that is the inverse of the given transformation.
- */
-func (tr MatrixTransform) GetInverseTransformation() MatrixTransform {
- d := tr.Determinant() // matrix determinant
- return [6]float64{
- tr[3] / d,
- -tr[1] / d,
- -tr[2] / d,
- tr[0] / d,
- (tr[2]*tr[5] - tr[3]*tr[4]) / d,
- (tr[1]*tr[4] - tr[0]*tr[5]) / d}
-}
-
-func (tr1 MatrixTransform) Multiply(tr2 MatrixTransform) MatrixTransform {
- return [6]float64{
- tr1[0]*tr2[0] + tr1[1]*tr2[2],
- tr1[1]*tr2[3] + tr1[0]*tr2[1],
- tr1[2]*tr2[0] + tr1[3]*tr2[2],
- tr1[3]*tr2[3] + tr1[2]*tr2[1],
- tr1[4]*tr2[0] + tr1[5]*tr2[2] + tr2[4],
- tr1[5]*tr2[3] + tr1[4]*tr2[1] + tr2[5]}
-}
-
-func (tr *MatrixTransform) Scale(sx, sy float64) *MatrixTransform {
- tr[0] = sx * tr[0]
- tr[1] = sx * tr[1]
- tr[2] = sy * tr[2]
- tr[3] = sy * tr[3]
- return tr
-}
-
-func (tr *MatrixTransform) Translate(tx, ty float64) *MatrixTransform {
- tr[4] = tx*tr[0] + ty*tr[2] + tr[4]
- tr[5] = ty*tr[3] + tx*tr[1] + tr[5]
- return tr
-}
-
-func (tr *MatrixTransform) Rotate(angle float64) *MatrixTransform {
- c := math.Cos(angle)
- s := math.Sin(angle)
- t0 := c*tr[0] + s*tr[2]
- t1 := s*tr[3] + c*tr[1]
- t2 := c*tr[2] - s*tr[0]
- t3 := c*tr[3] - s*tr[1]
- tr[0] = t0
- tr[1] = t1
- tr[2] = t2
- tr[3] = t3
- return tr
-}
-
-func (tr MatrixTransform) GetTranslation() (x, y float64) {
- return tr[4], tr[5]
-}
-
-func (tr MatrixTransform) GetScaling() (x, y float64) {
- return tr[0], tr[3]
-}
-
-func (tr MatrixTransform) GetScale() float64 {
- x := 0.707106781*tr[0] + 0.707106781*tr[1]
- y := 0.707106781*tr[2] + 0.707106781*tr[3]
- return math.Sqrt(x*x + y*y)
-}
-
-func (tr MatrixTransform) GetMaxAbsScaling() (s float64) {
- sx := math.Abs(tr[0])
- sy := math.Abs(tr[3])
- if sx > sy {
- return sx
- }
- return sy
-}
-
-func (tr MatrixTransform) GetMinAbsScaling() (s float64) {
- sx := math.Abs(tr[0])
- sy := math.Abs(tr[3])
- if sx > sy {
- return sy
- }
- return sx
-}
-
-// ******************** Testing ********************
-
-/**
- * Tests if a two transformation are equal. A tolerance is applied when
- * comparing matrix elements.
- */
-func (tr1 MatrixTransform) Equals(tr2 MatrixTransform) bool {
- for i := 0; i < 6; i = i + 1 {
- if !fequals(tr1[i], tr2[i]) {
- return false
- }
- }
- return true
-}
-
-/**
- * Tests if a transformation is the identity transformation. A tolerance
- * is applied when comparing matrix elements.
- */
-func (tr MatrixTransform) IsIdentity() bool {
- return fequals(tr[4], 0) && fequals(tr[5], 0) && tr.IsTranslation()
-}
-
-/**
- * Tests if a transformation is is a pure translation. A tolerance
- * is applied when comparing matrix elements.
- */
-func (tr MatrixTransform) IsTranslation() bool {
- return fequals(tr[0], 1) && fequals(tr[1], 0) && fequals(tr[2], 0) && fequals(tr[3], 1)
-}
-
-/**
- * Compares two floats.
- * return true if the distance between the two floats is less than epsilon, false otherwise
- */
-func fequals(float1, float2 float64) bool {
- return math.Abs(float1-float2) <= epsilon
-}
-
-// this VertexConverter apply the Matrix transformation tr
-type VertexMatrixTransform struct {
- tr MatrixTransform
- Next VertexConverter
-}
-
-func NewVertexMatrixTransform(tr MatrixTransform, converter VertexConverter) *VertexMatrixTransform {
- return &VertexMatrixTransform{tr, converter}
-}
-
-// Vertex Matrix Transform
-func (vmt *VertexMatrixTransform) NextCommand(command VertexCommand) {
- vmt.Next.NextCommand(command)
-}
-
-func (vmt *VertexMatrixTransform) Vertex(x, y float64) {
- u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
- v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
- vmt.Next.Vertex(u, v)
-}
-
-// this adder apply a Matrix transformation to points
-type MatrixTransformAdder struct {
- tr MatrixTransform
- next raster.Adder
-}
-
-func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) *MatrixTransformAdder {
- return &MatrixTransformAdder{tr, adder}
-}
-
-// Start starts a new curve at the given point.
-func (mta MatrixTransformAdder) Start(a raster.Point) {
- mta.tr.TransformRasterPoint(&a)
- mta.next.Start(a)
-}
-
-// Add1 adds a linear segment to the current curve.
-func (mta MatrixTransformAdder) Add1(b raster.Point) {
- mta.tr.TransformRasterPoint(&b)
- mta.next.Add1(b)
-}
-
-// Add2 adds a quadratic segment to the current curve.
-func (mta MatrixTransformAdder) Add2(b, c raster.Point) {
- mta.tr.TransformRasterPoint(&b, &c)
- mta.next.Add2(b, c)
-}
-
-// Add3 adds a cubic segment to the current curve.
-func (mta MatrixTransformAdder) Add3(b, c, d raster.Point) {
- mta.tr.TransformRasterPoint(&b, &c, &d)
- mta.next.Add3(b, c, d)
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/vertex2d.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/vertex2d.go
deleted file mode 100644
index 4e4d4fd83..000000000
--- a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/vertex2d.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2010 The draw2d Authors. All rights reserved.
-// created: 21/11/2010 by Laurent Le Goff
-
-package draw2d
-
-type VertexCommand byte
-
-const (
- VertexNoCommand VertexCommand = iota
- VertexStartCommand
- VertexJoinCommand
- VertexCloseCommand
- VertexStopCommand
-)
-
-type VertexConverter interface {
- NextCommand(cmd VertexCommand)
- Vertex(x, y float64)
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go
deleted file mode 100644
index 63c86e6ab..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package raster
-
-import (
- "fmt"
- "math"
-)
-
-// A Fix32 is a 24.8 fixed point number.
-type Fix32 int32
-
-// A Fix64 is a 48.16 fixed point number.
-type Fix64 int64
-
-// String returns a human-readable representation of a 24.8 fixed point number.
-// For example, the number one-and-a-quarter becomes "1:064".
-func (x Fix32) String() string {
- if x < 0 {
- x = -x
- return fmt.Sprintf("-%d:%03d", int32(x/256), int32(x%256))
- }
- return fmt.Sprintf("%d:%03d", int32(x/256), int32(x%256))
-}
-
-// String returns a human-readable representation of a 48.16 fixed point number.
-// For example, the number one-and-a-quarter becomes "1:16384".
-func (x Fix64) String() string {
- if x < 0 {
- x = -x
- return fmt.Sprintf("-%d:%05d", int64(x/65536), int64(x%65536))
- }
- return fmt.Sprintf("%d:%05d", int64(x/65536), int64(x%65536))
-}
-
-// maxAbs returns the maximum of abs(a) and abs(b).
-func maxAbs(a, b Fix32) Fix32 {
- if a < 0 {
- a = -a
- }
- if b < 0 {
- b = -b
- }
- if a < b {
- return b
- }
- return a
-}
-
-// A Point represents a two-dimensional point or vector, in 24.8 fixed point
-// format.
-type Point struct {
- X, Y Fix32
-}
-
-// String returns a human-readable representation of a Point.
-func (p Point) String() string {
- return "(" + p.X.String() + ", " + p.Y.String() + ")"
-}
-
-// Add returns the vector p + q.
-func (p Point) Add(q Point) Point {
- return Point{p.X + q.X, p.Y + q.Y}
-}
-
-// Sub returns the vector p - q.
-func (p Point) Sub(q Point) Point {
- return Point{p.X - q.X, p.Y - q.Y}
-}
-
-// Mul returns the vector k * p.
-func (p Point) Mul(k Fix32) Point {
- return Point{p.X * k / 256, p.Y * k / 256}
-}
-
-// Neg returns the vector -p, or equivalently p rotated by 180 degrees.
-func (p Point) Neg() Point {
- return Point{-p.X, -p.Y}
-}
-
-// Dot returns the dot product p·q.
-func (p Point) Dot(q Point) Fix64 {
- px, py := int64(p.X), int64(p.Y)
- qx, qy := int64(q.X), int64(q.Y)
- return Fix64(px*qx + py*qy)
-}
-
-// Len returns the length of the vector p.
-func (p Point) Len() Fix32 {
- // TODO(nigeltao): use fixed point math.
- x := float64(p.X)
- y := float64(p.Y)
- return Fix32(math.Sqrt(x*x + y*y))
-}
-
-// Norm returns the vector p normalized to the given length, or the zero Point
-// if p is degenerate.
-func (p Point) Norm(length Fix32) Point {
- d := p.Len()
- if d == 0 {
- return Point{}
- }
- s, t := int64(length), int64(d)
- x := int64(p.X) * s / t
- y := int64(p.Y) * s / t
- return Point{Fix32(x), Fix32(y)}
-}
-
-// Rot45CW returns the vector p rotated clockwise by 45 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot45CW is {1/√2, 1/√2}.
-func (p Point) Rot45CW() Point {
- // 181/256 is approximately 1/√2, or sin(π/4).
- px, py := int64(p.X), int64(p.Y)
- qx := (+px - py) * 181 / 256
- qy := (+px + py) * 181 / 256
- return Point{Fix32(qx), Fix32(qy)}
-}
-
-// Rot90CW returns the vector p rotated clockwise by 90 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}.
-func (p Point) Rot90CW() Point {
- return Point{-p.Y, p.X}
-}
-
-// Rot135CW returns the vector p rotated clockwise by 135 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot135CW is {-1/√2, 1/√2}.
-func (p Point) Rot135CW() Point {
- // 181/256 is approximately 1/√2, or sin(π/4).
- px, py := int64(p.X), int64(p.Y)
- qx := (-px - py) * 181 / 256
- qy := (+px - py) * 181 / 256
- return Point{Fix32(qx), Fix32(qy)}
-}
-
-// Rot45CCW returns the vector p rotated counter-clockwise by 45 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}.
-func (p Point) Rot45CCW() Point {
- // 181/256 is approximately 1/√2, or sin(π/4).
- px, py := int64(p.X), int64(p.Y)
- qx := (+px + py) * 181 / 256
- qy := (-px + py) * 181 / 256
- return Point{Fix32(qx), Fix32(qy)}
-}
-
-// Rot90CCW returns the vector p rotated counter-clockwise by 90 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot90CCW is {0, -1}.
-func (p Point) Rot90CCW() Point {
- return Point{p.Y, -p.X}
-}
-
-// Rot135CCW returns the vector p rotated counter-clockwise by 135 degrees.
-// Note that the Y-axis grows downwards, so {1, 0}.Rot135CCW is {-1/√2, -1/√2}.
-func (p Point) Rot135CCW() Point {
- // 181/256 is approximately 1/√2, or sin(π/4).
- px, py := int64(p.X), int64(p.Y)
- qx := (-px + py) * 181 / 256
- qy := (-px - py) * 181 / 256
- return Point{Fix32(qx), Fix32(qy)}
-}
-
-// An Adder accumulates points on a curve.
-type Adder interface {
- // Start starts a new curve at the given point.
- Start(a Point)
- // Add1 adds a linear segment to the current curve.
- Add1(b Point)
- // Add2 adds a quadratic segment to the current curve.
- Add2(b, c Point)
- // Add3 adds a cubic segment to the current curve.
- Add3(b, c, d Point)
-}
-
-// A Path is a sequence of curves, and a curve is a start point followed by a
-// sequence of linear, quadratic or cubic segments.
-type Path []Fix32
-
-// String returns a human-readable representation of a Path.
-func (p Path) String() string {
- s := ""
- for i := 0; i < len(p); {
- if i != 0 {
- s += " "
- }
- switch p[i] {
- case 0:
- s += "S0" + fmt.Sprint([]Fix32(p[i+1:i+3]))
- i += 4
- case 1:
- s += "A1" + fmt.Sprint([]Fix32(p[i+1:i+3]))
- i += 4
- case 2:
- s += "A2" + fmt.Sprint([]Fix32(p[i+1:i+5]))
- i += 6
- case 3:
- s += "A3" + fmt.Sprint([]Fix32(p[i+1:i+7]))
- i += 8
- default:
- panic("freetype/raster: bad path")
- }
- }
- return s
-}
-
-// Clear cancels any previous calls to p.Start or p.AddXxx.
-func (p *Path) Clear() {
- *p = (*p)[:0]
-}
-
-// Start starts a new curve at the given point.
-func (p *Path) Start(a Point) {
- *p = append(*p, 0, a.X, a.Y, 0)
-}
-
-// Add1 adds a linear segment to the current curve.
-func (p *Path) Add1(b Point) {
- *p = append(*p, 1, b.X, b.Y, 1)
-}
-
-// Add2 adds a quadratic segment to the current curve.
-func (p *Path) Add2(b, c Point) {
- *p = append(*p, 2, b.X, b.Y, c.X, c.Y, 2)
-}
-
-// Add3 adds a cubic segment to the current curve.
-func (p *Path) Add3(b, c, d Point) {
- *p = append(*p, 3, b.X, b.Y, c.X, c.Y, d.X, d.Y, 3)
-}
-
-// AddPath adds the Path q to p.
-func (p *Path) AddPath(q Path) {
- *p = append(*p, q...)
-}
-
-// AddStroke adds a stroked Path.
-func (p *Path) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
- Stroke(p, q, width, cr, jr)
-}
-
-// firstPoint returns the first point in a non-empty Path.
-func (p Path) firstPoint() Point {
- return Point{p[1], p[2]}
-}
-
-// lastPoint returns the last point in a non-empty Path.
-func (p Path) lastPoint() Point {
- return Point{p[len(p)-3], p[len(p)-2]}
-}
-
-// addPathReversed adds q reversed to p.
-// For example, if q consists of a linear segment from A to B followed by a
-// quadratic segment from B to C to D, then the values of q looks like:
-// index: 01234567890123
-// value: 0AA01BB12CCDD2
-// So, when adding q backwards to p, we want to Add2(C, B) followed by Add1(A).
-func addPathReversed(p Adder, q Path) {
- if len(q) == 0 {
- return
- }
- i := len(q) - 1
- for {
- switch q[i] {
- case 0:
- return
- case 1:
- i -= 4
- p.Add1(Point{q[i-2], q[i-1]})
- case 2:
- i -= 6
- p.Add2(Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
- case 3:
- i -= 8
- p.Add3(Point{q[i+4], q[i+5]}, Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
- default:
- panic("freetype/raster: bad path")
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go
deleted file mode 100644
index 13cccc192..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package raster
-
-import (
- "image"
- "image/color"
- "image/draw"
- "math"
-)
-
-// A Span is a horizontal segment of pixels with constant alpha. X0 is an
-// inclusive bound and X1 is exclusive, the same as for slices. A fully
-// opaque Span has A == 1<<32 - 1.
-type Span struct {
- Y, X0, X1 int
- A uint32
-}
-
-// A Painter knows how to paint a batch of Spans. Rasterization may involve
-// Painting multiple batches, and done will be true for the final batch.
-// The Spans' Y values are monotonically increasing during a rasterization.
-// Paint may use all of ss as scratch space during the call.
-type Painter interface {
- Paint(ss []Span, done bool)
-}
-
-// The PainterFunc type adapts an ordinary function to the Painter interface.
-type PainterFunc func(ss []Span, done bool)
-
-// Paint just delegates the call to f.
-func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
-
-// An AlphaOverPainter is a Painter that paints Spans onto an image.Alpha
-// using the Over Porter-Duff composition operator.
-type AlphaOverPainter struct {
- Image *image.Alpha
-}
-
-// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
-func (r AlphaOverPainter) Paint(ss []Span, done bool) {
- b := r.Image.Bounds()
- for _, s := range ss {
- if s.Y < b.Min.Y {
- continue
- }
- if s.Y >= b.Max.Y {
- return
- }
- if s.X0 < b.Min.X {
- s.X0 = b.Min.X
- }
- if s.X1 > b.Max.X {
- s.X1 = b.Max.X
- }
- if s.X0 >= s.X1 {
- continue
- }
- base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
- p := r.Image.Pix[base+s.X0 : base+s.X1]
- a := int(s.A >> 24)
- for i, c := range p {
- v := int(c)
- p[i] = uint8((v*255 + (255-v)*a) / 255)
- }
- }
-}
-
-// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
-func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
- return AlphaOverPainter{m}
-}
-
-// An AlphaSrcPainter is a Painter that paints Spans onto an image.Alpha
-// using the Src Porter-Duff composition operator.
-type AlphaSrcPainter struct {
- Image *image.Alpha
-}
-
-// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
-func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
- b := r.Image.Bounds()
- for _, s := range ss {
- if s.Y < b.Min.Y {
- continue
- }
- if s.Y >= b.Max.Y {
- return
- }
- if s.X0 < b.Min.X {
- s.X0 = b.Min.X
- }
- if s.X1 > b.Max.X {
- s.X1 = b.Max.X
- }
- if s.X0 >= s.X1 {
- continue
- }
- base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
- p := r.Image.Pix[base+s.X0 : base+s.X1]
- color := uint8(s.A >> 24)
- for i := range p {
- p[i] = color
- }
- }
-}
-
-// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
-func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
- return AlphaSrcPainter{m}
-}
-
-type RGBAPainter struct {
- // The image to compose onto.
- Image *image.RGBA
- // The Porter-Duff composition operator.
- Op draw.Op
- // The 16-bit color to paint the spans.
- cr, cg, cb, ca uint32
-}
-
-// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
-func (r *RGBAPainter) Paint(ss []Span, done bool) {
- b := r.Image.Bounds()
- for _, s := range ss {
- if s.Y < b.Min.Y {
- continue
- }
- if s.Y >= b.Max.Y {
- return
- }
- if s.X0 < b.Min.X {
- s.X0 = b.Min.X
- }
- if s.X1 > b.Max.X {
- s.X1 = b.Max.X
- }
- if s.X0 >= s.X1 {
- continue
- }
- // This code is similar to drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go.
- ma := s.A >> 16
- const m = 1<<16 - 1
- i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
- i1 := i0 + (s.X1-s.X0)*4
- if r.Op == draw.Over {
- for i := i0; i < i1; i += 4 {
- dr := uint32(r.Image.Pix[i+0])
- dg := uint32(r.Image.Pix[i+1])
- db := uint32(r.Image.Pix[i+2])
- da := uint32(r.Image.Pix[i+3])
- a := (m - (r.ca * ma / m)) * 0x101
- r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
- r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
- r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
- r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
- }
- } else {
- for i := i0; i < i1; i += 4 {
- r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
- r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
- r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
- r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
- }
- }
- }
-}
-
-// SetColor sets the color to paint the spans.
-func (r *RGBAPainter) SetColor(c color.Color) {
- r.cr, r.cg, r.cb, r.ca = c.RGBA()
-}
-
-// NewRGBAPainter creates a new RGBAPainter for the given image.
-func NewRGBAPainter(m *image.RGBA) *RGBAPainter {
- return &RGBAPainter{Image: m}
-}
-
-// A MonochromePainter wraps another Painter, quantizing each Span's alpha to
-// be either fully opaque or fully transparent.
-type MonochromePainter struct {
- Painter Painter
- y, x0, x1 int
-}
-
-// Paint delegates to the wrapped Painter after quantizing each Span's alpha
-// value and merging adjacent fully opaque Spans.
-func (m *MonochromePainter) Paint(ss []Span, done bool) {
- // We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
- j := 0
- for _, s := range ss {
- if s.A >= 1<<31 {
- if m.y == s.Y && m.x1 == s.X0 {
- m.x1 = s.X1
- } else {
- ss[j] = Span{m.y, m.x0, m.x1, 1<<32 - 1}
- j++
- m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
- }
- }
- }
- if done {
- // Flush the accumulated Span.
- finalSpan := Span{m.y, m.x0, m.x1, 1<<32 - 1}
- if j < len(ss) {
- ss[j] = finalSpan
- j++
- m.Painter.Paint(ss[:j], true)
- } else if j == len(ss) {
- m.Painter.Paint(ss, false)
- if cap(ss) > 0 {
- ss = ss[:1]
- } else {
- ss = make([]Span, 1)
- }
- ss[0] = finalSpan
- m.Painter.Paint(ss, true)
- } else {
- panic("unreachable")
- }
- // Reset the accumulator, so that this Painter can be re-used.
- m.y, m.x0, m.x1 = 0, 0, 0
- } else {
- m.Painter.Paint(ss[:j], false)
- }
-}
-
-// NewMonochromePainter creates a new MonochromePainter that wraps the given
-// Painter.
-func NewMonochromePainter(p Painter) *MonochromePainter {
- return &MonochromePainter{Painter: p}
-}
-
-// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
-// on each Span's alpha value.
-type GammaCorrectionPainter struct {
- // The wrapped Painter.
- Painter Painter
- // Precomputed alpha values for linear interpolation, with fully opaque == 1<<16-1.
- a [256]uint16
- // Whether gamma correction is a no-op.
- gammaIsOne bool
-}
-
-// Paint delegates to the wrapped Painter after performing gamma-correction
-// on each Span.
-func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
- if !g.gammaIsOne {
- const (
- M = 0x1010101 // 255*M == 1<<32-1
- N = 0x8080 // N = M>>9, and N < 1<<16-1
- )
- for i, s := range ss {
- if s.A == 0 || s.A == 1<<32-1 {
- continue
- }
- p, q := s.A/M, (s.A%M)>>9
- // The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
- a := uint32(g.a[p])*(N-q) + uint32(g.a[p+1])*q
- a = (a + N/2) / N
- // Convert the alpha from 16-bit (which is g.a's range) to 32-bit.
- a |= a << 16
- ss[i].A = a
- }
- }
- g.Painter.Paint(ss, done)
-}
-
-// SetGamma sets the gamma value.
-func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
- if gamma == 1.0 {
- g.gammaIsOne = true
- return
- }
- g.gammaIsOne = false
- for i := 0; i < 256; i++ {
- a := float64(i) / 0xff
- a = math.Pow(a, gamma)
- g.a[i] = uint16(0xffff * a)
- }
-}
-
-// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
-// the given Painter.
-func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
- g := &GammaCorrectionPainter{Painter: p}
- g.SetGamma(gamma)
- return g
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go
deleted file mode 100644
index 45af7eaa2..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go
+++ /dev/null
@@ -1,579 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-// The raster package provides an anti-aliasing 2-D rasterizer.
-//
-// It is part of the larger Freetype-Go suite of font-related packages,
-// but the raster package is not specific to font rasterization, and can
-// be used standalone without any other Freetype-Go package.
-//
-// Rasterization is done by the same area/coverage accumulation algorithm
-// as the Freetype "smooth" module, and the Anti-Grain Geometry library.
-// A description of the area/coverage algorithm is at
-// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
-package raster
-
-import (
- "strconv"
-)
-
-// A cell is part of a linked list (for a given yi co-ordinate) of accumulated
-// area/coverage for the pixel at (xi, yi).
-type cell struct {
- xi int
- area, cover int
- next int
-}
-
-type Rasterizer struct {
- // If false, the default behavior is to use the even-odd winding fill
- // rule during Rasterize.
- UseNonZeroWinding bool
- // An offset (in pixels) to the painted spans.
- Dx, Dy int
-
- // The width of the Rasterizer. The height is implicit in len(cellIndex).
- width int
- // splitScaleN is the scaling factor used to determine how many times
- // to decompose a quadratic or cubic segment into a linear approximation.
- splitScale2, splitScale3 int
-
- // The current pen position.
- a Point
- // The current cell and its area/coverage being accumulated.
- xi, yi int
- area, cover int
-
- // Saved cells.
- cell []cell
- // Linked list of cells, one per row.
- cellIndex []int
- // Buffers.
- cellBuf [256]cell
- cellIndexBuf [64]int
- spanBuf [64]Span
-}
-
-// findCell returns the index in r.cell for the cell corresponding to
-// (r.xi, r.yi). The cell is created if necessary.
-func (r *Rasterizer) findCell() int {
- if r.yi < 0 || r.yi >= len(r.cellIndex) {
- return -1
- }
- xi := r.xi
- if xi < 0 {
- xi = -1
- } else if xi > r.width {
- xi = r.width
- }
- i, prev := r.cellIndex[r.yi], -1
- for i != -1 && r.cell[i].xi <= xi {
- if r.cell[i].xi == xi {
- return i
- }
- i, prev = r.cell[i].next, i
- }
- c := len(r.cell)
- if c == cap(r.cell) {
- buf := make([]cell, c, 4*c)
- copy(buf, r.cell)
- r.cell = buf[0 : c+1]
- } else {
- r.cell = r.cell[0 : c+1]
- }
- r.cell[c] = cell{xi, 0, 0, i}
- if prev == -1 {
- r.cellIndex[r.yi] = c
- } else {
- r.cell[prev].next = c
- }
- return c
-}
-
-// saveCell saves any accumulated r.area/r.cover for (r.xi, r.yi).
-func (r *Rasterizer) saveCell() {
- if r.area != 0 || r.cover != 0 {
- i := r.findCell()
- if i != -1 {
- r.cell[i].area += r.area
- r.cell[i].cover += r.cover
- }
- r.area = 0
- r.cover = 0
- }
-}
-
-// setCell sets the (xi, yi) cell that r is accumulating area/coverage for.
-func (r *Rasterizer) setCell(xi, yi int) {
- if r.xi != xi || r.yi != yi {
- r.saveCell()
- r.xi, r.yi = xi, yi
- }
-}
-
-// scan accumulates area/coverage for the yi'th scanline, going from
-// x0 to x1 in the horizontal direction (in 24.8 fixed point co-ordinates)
-// and from y0f to y1f fractional vertical units within that scanline.
-func (r *Rasterizer) scan(yi int, x0, y0f, x1, y1f Fix32) {
- // Break the 24.8 fixed point X co-ordinates into integral and fractional parts.
- x0i := int(x0) / 256
- x0f := x0 - Fix32(256*x0i)
- x1i := int(x1) / 256
- x1f := x1 - Fix32(256*x1i)
-
- // A perfectly horizontal scan.
- if y0f == y1f {
- r.setCell(x1i, yi)
- return
- }
- dx, dy := x1-x0, y1f-y0f
- // A single cell scan.
- if x0i == x1i {
- r.area += int((x0f + x1f) * dy)
- r.cover += int(dy)
- return
- }
- // There are at least two cells. Apart from the first and last cells,
- // all intermediate cells go through the full width of the cell,
- // or 256 units in 24.8 fixed point format.
- var (
- p, q, edge0, edge1 Fix32
- xiDelta int
- )
- if dx > 0 {
- p, q = (256-x0f)*dy, dx
- edge0, edge1, xiDelta = 0, 256, 1
- } else {
- p, q = x0f*dy, -dx
- edge0, edge1, xiDelta = 256, 0, -1
- }
- yDelta, yRem := p/q, p%q
- if yRem < 0 {
- yDelta -= 1
- yRem += q
- }
- // Do the first cell.
- xi, y := x0i, y0f
- r.area += int((x0f + edge1) * yDelta)
- r.cover += int(yDelta)
- xi, y = xi+xiDelta, y+yDelta
- r.setCell(xi, yi)
- if xi != x1i {
- // Do all the intermediate cells.
- p = 256 * (y1f - y + yDelta)
- fullDelta, fullRem := p/q, p%q
- if fullRem < 0 {
- fullDelta -= 1
- fullRem += q
- }
- yRem -= q
- for xi != x1i {
- yDelta = fullDelta
- yRem += fullRem
- if yRem >= 0 {
- yDelta += 1
- yRem -= q
- }
- r.area += int(256 * yDelta)
- r.cover += int(yDelta)
- xi, y = xi+xiDelta, y+yDelta
- r.setCell(xi, yi)
- }
- }
- // Do the last cell.
- yDelta = y1f - y
- r.area += int((edge0 + x1f) * yDelta)
- r.cover += int(yDelta)
-}
-
-// Start starts a new curve at the given point.
-func (r *Rasterizer) Start(a Point) {
- r.setCell(int(a.X/256), int(a.Y/256))
- r.a = a
-}
-
-// Add1 adds a linear segment to the current curve.
-func (r *Rasterizer) Add1(b Point) {
- x0, y0 := r.a.X, r.a.Y
- x1, y1 := b.X, b.Y
- dx, dy := x1-x0, y1-y0
- // Break the 24.8 fixed point Y co-ordinates into integral and fractional parts.
- y0i := int(y0) / 256
- y0f := y0 - Fix32(256*y0i)
- y1i := int(y1) / 256
- y1f := y1 - Fix32(256*y1i)
-
- if y0i == y1i {
- // There is only one scanline.
- r.scan(y0i, x0, y0f, x1, y1f)
-
- } else if dx == 0 {
- // This is a vertical line segment. We avoid calling r.scan and instead
- // manipulate r.area and r.cover directly.
- var (
- edge0, edge1 Fix32
- yiDelta int
- )
- if dy > 0 {
- edge0, edge1, yiDelta = 0, 256, 1
- } else {
- edge0, edge1, yiDelta = 256, 0, -1
- }
- x0i, yi := int(x0)/256, y0i
- x0fTimes2 := (int(x0) - (256 * x0i)) * 2
- // Do the first pixel.
- dcover := int(edge1 - y0f)
- darea := int(x0fTimes2 * dcover)
- r.area += darea
- r.cover += dcover
- yi += yiDelta
- r.setCell(x0i, yi)
- // Do all the intermediate pixels.
- dcover = int(edge1 - edge0)
- darea = int(x0fTimes2 * dcover)
- for yi != y1i {
- r.area += darea
- r.cover += dcover
- yi += yiDelta
- r.setCell(x0i, yi)
- }
- // Do the last pixel.
- dcover = int(y1f - edge0)
- darea = int(x0fTimes2 * dcover)
- r.area += darea
- r.cover += dcover
-
- } else {
- // There are at least two scanlines. Apart from the first and last scanlines,
- // all intermediate scanlines go through the full height of the row, or 256
- // units in 24.8 fixed point format.
- var (
- p, q, edge0, edge1 Fix32
- yiDelta int
- )
- if dy > 0 {
- p, q = (256-y0f)*dx, dy
- edge0, edge1, yiDelta = 0, 256, 1
- } else {
- p, q = y0f*dx, -dy
- edge0, edge1, yiDelta = 256, 0, -1
- }
- xDelta, xRem := p/q, p%q
- if xRem < 0 {
- xDelta -= 1
- xRem += q
- }
- // Do the first scanline.
- x, yi := x0, y0i
- r.scan(yi, x, y0f, x+xDelta, edge1)
- x, yi = x+xDelta, yi+yiDelta
- r.setCell(int(x)/256, yi)
- if yi != y1i {
- // Do all the intermediate scanlines.
- p = 256 * dx
- fullDelta, fullRem := p/q, p%q
- if fullRem < 0 {
- fullDelta -= 1
- fullRem += q
- }
- xRem -= q
- for yi != y1i {
- xDelta = fullDelta
- xRem += fullRem
- if xRem >= 0 {
- xDelta += 1
- xRem -= q
- }
- r.scan(yi, x, edge0, x+xDelta, edge1)
- x, yi = x+xDelta, yi+yiDelta
- r.setCell(int(x)/256, yi)
- }
- }
- // Do the last scanline.
- r.scan(yi, x, edge0, x1, y1f)
- }
- // The next lineTo starts from b.
- r.a = b
-}
-
-// Add2 adds a quadratic segment to the current curve.
-func (r *Rasterizer) Add2(b, c Point) {
- // Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
- // Specifically, how much the middle point b deviates from (a+c)/2.
- dev := maxAbs(r.a.X-2*b.X+c.X, r.a.Y-2*b.Y+c.Y) / Fix32(r.splitScale2)
- nsplit := 0
- for dev > 0 {
- dev /= 4
- nsplit++
- }
- // dev is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
- const maxNsplit = 16
- if nsplit > maxNsplit {
- panic("freetype/raster: Add2 nsplit too large: " + strconv.Itoa(nsplit))
- }
- // Recursively decompose the curve nSplit levels deep.
- var (
- pStack [2*maxNsplit + 3]Point
- sStack [maxNsplit + 1]int
- i int
- )
- sStack[0] = nsplit
- pStack[0] = c
- pStack[1] = b
- pStack[2] = r.a
- for i >= 0 {
- s := sStack[i]
- p := pStack[2*i:]
- if s > 0 {
- // Split the quadratic curve p[:3] into an equivalent set of two shorter curves:
- // p[:3] and p[2:5]. The new p[4] is the old p[2], and p[0] is unchanged.
- mx := p[1].X
- p[4].X = p[2].X
- p[3].X = (p[4].X + mx) / 2
- p[1].X = (p[0].X + mx) / 2
- p[2].X = (p[1].X + p[3].X) / 2
- my := p[1].Y
- p[4].Y = p[2].Y
- p[3].Y = (p[4].Y + my) / 2
- p[1].Y = (p[0].Y + my) / 2
- p[2].Y = (p[1].Y + p[3].Y) / 2
- // The two shorter curves have one less split to do.
- sStack[i] = s - 1
- sStack[i+1] = s - 1
- i++
- } else {
- // Replace the level-0 quadratic with a two-linear-piece approximation.
- midx := (p[0].X + 2*p[1].X + p[2].X) / 4
- midy := (p[0].Y + 2*p[1].Y + p[2].Y) / 4
- r.Add1(Point{midx, midy})
- r.Add1(p[0])
- i--
- }
- }
-}
-
-// Add3 adds a cubic segment to the current curve.
-func (r *Rasterizer) Add3(b, c, d Point) {
- // Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
- dev2 := maxAbs(r.a.X-3*(b.X+c.X)+d.X, r.a.Y-3*(b.Y+c.Y)+d.Y) / Fix32(r.splitScale2)
- dev3 := maxAbs(r.a.X-2*b.X+d.X, r.a.Y-2*b.Y+d.Y) / Fix32(r.splitScale3)
- nsplit := 0
- for dev2 > 0 || dev3 > 0 {
- dev2 /= 8
- dev3 /= 4
- nsplit++
- }
- // devN is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
- const maxNsplit = 16
- if nsplit > maxNsplit {
- panic("freetype/raster: Add3 nsplit too large: " + strconv.Itoa(nsplit))
- }
- // Recursively decompose the curve nSplit levels deep.
- var (
- pStack [3*maxNsplit + 4]Point
- sStack [maxNsplit + 1]int
- i int
- )
- sStack[0] = nsplit
- pStack[0] = d
- pStack[1] = c
- pStack[2] = b
- pStack[3] = r.a
- for i >= 0 {
- s := sStack[i]
- p := pStack[3*i:]
- if s > 0 {
- // Split the cubic curve p[:4] into an equivalent set of two shorter curves:
- // p[:4] and p[3:7]. The new p[6] is the old p[3], and p[0] is unchanged.
- m01x := (p[0].X + p[1].X) / 2
- m12x := (p[1].X + p[2].X) / 2
- m23x := (p[2].X + p[3].X) / 2
- p[6].X = p[3].X
- p[5].X = m23x
- p[1].X = m01x
- p[2].X = (m01x + m12x) / 2
- p[4].X = (m12x + m23x) / 2
- p[3].X = (p[2].X + p[4].X) / 2
- m01y := (p[0].Y + p[1].Y) / 2
- m12y := (p[1].Y + p[2].Y) / 2
- m23y := (p[2].Y + p[3].Y) / 2
- p[6].Y = p[3].Y
- p[5].Y = m23y
- p[1].Y = m01y
- p[2].Y = (m01y + m12y) / 2
- p[4].Y = (m12y + m23y) / 2
- p[3].Y = (p[2].Y + p[4].Y) / 2
- // The two shorter curves have one less split to do.
- sStack[i] = s - 1
- sStack[i+1] = s - 1
- i++
- } else {
- // Replace the level-0 cubic with a two-linear-piece approximation.
- midx := (p[0].X + 3*(p[1].X+p[2].X) + p[3].X) / 8
- midy := (p[0].Y + 3*(p[1].Y+p[2].Y) + p[3].Y) / 8
- r.Add1(Point{midx, midy})
- r.Add1(p[0])
- i--
- }
- }
-}
-
-// AddPath adds the given Path.
-func (r *Rasterizer) AddPath(p Path) {
- for i := 0; i < len(p); {
- switch p[i] {
- case 0:
- r.Start(Point{p[i+1], p[i+2]})
- i += 4
- case 1:
- r.Add1(Point{p[i+1], p[i+2]})
- i += 4
- case 2:
- r.Add2(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]})
- i += 6
- case 3:
- r.Add3(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]}, Point{p[i+5], p[i+6]})
- i += 8
- default:
- panic("freetype/raster: bad path")
- }
- }
-}
-
-// AddStroke adds a stroked Path.
-func (r *Rasterizer) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
- Stroke(r, q, width, cr, jr)
-}
-
-// Converts an area value to a uint32 alpha value. A completely filled pixel
-// corresponds to an area of 256*256*2, and an alpha of 1<<32-1. The
-// conversion of area values greater than this depends on the winding rule:
-// even-odd or non-zero.
-func (r *Rasterizer) areaToAlpha(area int) uint32 {
- // The C Freetype implementation (version 2.3.12) does "alpha := area>>1" without
- // the +1. Round-to-nearest gives a more symmetric result than round-down.
- // The C implementation also returns 8-bit alpha, not 32-bit alpha.
- a := (area + 1) >> 1
- if a < 0 {
- a = -a
- }
- alpha := uint32(a)
- if r.UseNonZeroWinding {
- if alpha > 0xffff {
- alpha = 0xffff
- }
- } else {
- alpha &= 0x1ffff
- if alpha > 0x10000 {
- alpha = 0x20000 - alpha
- } else if alpha == 0x10000 {
- alpha = 0x0ffff
- }
- }
- alpha |= alpha << 16
- return alpha
-}
-
-// Rasterize converts r's accumulated curves into Spans for p. The Spans
-// passed to p are non-overlapping, and sorted by Y and then X. They all
-// have non-zero width (and 0 <= X0 < X1 <= r.width) and non-zero A, except
-// for the final Span, which has Y, X0, X1 and A all equal to zero.
-func (r *Rasterizer) Rasterize(p Painter) {
- r.saveCell()
- s := 0
- for yi := 0; yi < len(r.cellIndex); yi++ {
- xi, cover := 0, 0
- for c := r.cellIndex[yi]; c != -1; c = r.cell[c].next {
- if cover != 0 && r.cell[c].xi > xi {
- alpha := r.areaToAlpha(cover * 256 * 2)
- if alpha != 0 {
- xi0, xi1 := xi, r.cell[c].xi
- if xi0 < 0 {
- xi0 = 0
- }
- if xi1 >= r.width {
- xi1 = r.width
- }
- if xi0 < xi1 {
- r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
- s++
- }
- }
- }
- cover += r.cell[c].cover
- alpha := r.areaToAlpha(cover*256*2 - r.cell[c].area)
- xi = r.cell[c].xi + 1
- if alpha != 0 {
- xi0, xi1 := r.cell[c].xi, xi
- if xi0 < 0 {
- xi0 = 0
- }
- if xi1 >= r.width {
- xi1 = r.width
- }
- if xi0 < xi1 {
- r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
- s++
- }
- }
- if s > len(r.spanBuf)-2 {
- p.Paint(r.spanBuf[:s], false)
- s = 0
- }
- }
- }
- p.Paint(r.spanBuf[:s], true)
-}
-
-// Clear cancels any previous calls to r.Start or r.AddXxx.
-func (r *Rasterizer) Clear() {
- r.a = Point{}
- r.xi = 0
- r.yi = 0
- r.area = 0
- r.cover = 0
- r.cell = r.cell[:0]
- for i := 0; i < len(r.cellIndex); i++ {
- r.cellIndex[i] = -1
- }
-}
-
-// SetBounds sets the maximum width and height of the rasterized image and
-// calls Clear. The width and height are in pixels, not Fix32 units.
-func (r *Rasterizer) SetBounds(width, height int) {
- if width < 0 {
- width = 0
- }
- if height < 0 {
- height = 0
- }
- // Use the same ssN heuristic as the C Freetype implementation.
- // The C implementation uses the values 32, 16, but those are in
- // 26.6 fixed point units, and we use 24.8 fixed point everywhere.
- ss2, ss3 := 128, 64
- if width > 24 || height > 24 {
- ss2, ss3 = 2*ss2, 2*ss3
- if width > 120 || height > 120 {
- ss2, ss3 = 2*ss2, 2*ss3
- }
- }
- r.width = width
- r.splitScale2 = ss2
- r.splitScale3 = ss3
- r.cell = r.cellBuf[:0]
- if height > len(r.cellIndexBuf) {
- r.cellIndex = make([]int, height)
- } else {
- r.cellIndex = r.cellIndexBuf[:height]
- }
- r.Clear()
-}
-
-// NewRasterizer creates a new Rasterizer with the given bounds.
-func NewRasterizer(width, height int) *Rasterizer {
- r := new(Rasterizer)
- r.SetBounds(width, height)
- return r
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go
deleted file mode 100644
index d49b1cee9..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package raster
-
-// Two points are considered practically equal if the square of the distance
-// between them is less than one quarter (i.e. 16384 / 65536 in Fix64).
-const epsilon = 16384
-
-// A Capper signifies how to begin or end a stroked path.
-type Capper interface {
- // Cap adds a cap to p given a pivot point and the normal vector of a
- // terminal segment. The normal's length is half of the stroke width.
- Cap(p Adder, halfWidth Fix32, pivot, n1 Point)
-}
-
-// The CapperFunc type adapts an ordinary function to be a Capper.
-type CapperFunc func(Adder, Fix32, Point, Point)
-
-func (f CapperFunc) Cap(p Adder, halfWidth Fix32, pivot, n1 Point) {
- f(p, halfWidth, pivot, n1)
-}
-
-// A Joiner signifies how to join interior nodes of a stroked path.
-type Joiner interface {
- // Join adds a join to the two sides of a stroked path given a pivot
- // point and the normal vectors of the trailing and leading segments.
- // Both normals have length equal to half of the stroke width.
- Join(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point)
-}
-
-// The JoinerFunc type adapts an ordinary function to be a Joiner.
-type JoinerFunc func(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point)
-
-func (f JoinerFunc) Join(lhs, rhs Adder, halfWidth Fix32, pivot, n0, n1 Point) {
- f(lhs, rhs, halfWidth, pivot, n0, n1)
-}
-
-// RoundCapper adds round caps to a stroked path.
-var RoundCapper Capper = CapperFunc(roundCapper)
-
-func roundCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
- // The cubic Bézier approximation to a circle involves the magic number
- // (√2 - 1) * 4/3, which is approximately 141/256.
- const k = 141
- e := n1.Rot90CCW()
- side := pivot.Add(e)
- start, end := pivot.Sub(n1), pivot.Add(n1)
- d, e := n1.Mul(k), e.Mul(k)
- p.Add3(start.Add(e), side.Sub(d), side)
- p.Add3(side.Add(d), end.Add(e), end)
-}
-
-// ButtCapper adds butt caps to a stroked path.
-var ButtCapper Capper = CapperFunc(buttCapper)
-
-func buttCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
- p.Add1(pivot.Add(n1))
-}
-
-// SquareCapper adds square caps to a stroked path.
-var SquareCapper Capper = CapperFunc(squareCapper)
-
-func squareCapper(p Adder, halfWidth Fix32, pivot, n1 Point) {
- e := n1.Rot90CCW()
- side := pivot.Add(e)
- p.Add1(side.Sub(n1))
- p.Add1(side.Add(n1))
- p.Add1(pivot.Add(n1))
-}
-
-// RoundJoiner adds round joins to a stroked path.
-var RoundJoiner Joiner = JoinerFunc(roundJoiner)
-
-func roundJoiner(lhs, rhs Adder, haflWidth Fix32, pivot, n0, n1 Point) {
- dot := n0.Rot90CW().Dot(n1)
- if dot >= 0 {
- addArc(lhs, pivot, n0, n1)
- rhs.Add1(pivot.Sub(n1))
- } else {
- lhs.Add1(pivot.Add(n1))
- addArc(rhs, pivot, n0.Neg(), n1.Neg())
- }
-}
-
-// BevelJoiner adds bevel joins to a stroked path.
-var BevelJoiner Joiner = JoinerFunc(bevelJoiner)
-
-func bevelJoiner(lhs, rhs Adder, haflWidth Fix32, pivot, n0, n1 Point) {
- lhs.Add1(pivot.Add(n1))
- rhs.Add1(pivot.Sub(n1))
-}
-
-// addArc adds a circular arc from pivot+n0 to pivot+n1 to p. The shorter of
-// the two possible arcs is taken, i.e. the one spanning <= 180 degrees.
-// The two vectors n0 and n1 must be of equal length.
-func addArc(p Adder, pivot, n0, n1 Point) {
- // r2 is the square of the length of n0.
- r2 := n0.Dot(n0)
- if r2 < epsilon {
- // The arc radius is so small that we collapse to a straight line.
- p.Add1(pivot.Add(n1))
- return
- }
- // We approximate the arc by 0, 1, 2 or 3 45-degree quadratic segments plus
- // a final quadratic segment from s to n1. Each 45-degree segment has control
- // points {1, 0}, {1, tan(π/8)} and {1/√2, 1/√2} suitably scaled, rotated and
- // translated. tan(π/8) is approximately 106/256.
- const tpo8 = 106
- var s Point
- // We determine which octant the angle between n0 and n1 is in via three dot products.
- // m0, m1 and m2 are n0 rotated clockwise by 45, 90 and 135 degrees.
- m0 := n0.Rot45CW()
- m1 := n0.Rot90CW()
- m2 := m0.Rot90CW()
- if m1.Dot(n1) >= 0 {
- if n0.Dot(n1) >= 0 {
- if m2.Dot(n1) <= 0 {
- // n1 is between 0 and 45 degrees clockwise of n0.
- s = n0
- } else {
- // n1 is between 45 and 90 degrees clockwise of n0.
- p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0))
- s = m0
- }
- } else {
- pm1, n0t := pivot.Add(m1), n0.Mul(tpo8)
- p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0))
- p.Add2(pm1.Add(n0t), pm1)
- if m0.Dot(n1) >= 0 {
- // n1 is between 90 and 135 degrees clockwise of n0.
- s = m1
- } else {
- // n1 is between 135 and 180 degrees clockwise of n0.
- p.Add2(pm1.Sub(n0t), pivot.Add(m2))
- s = m2
- }
- }
- } else {
- if n0.Dot(n1) >= 0 {
- if m0.Dot(n1) >= 0 {
- // n1 is between 0 and 45 degrees counter-clockwise of n0.
- s = n0
- } else {
- // n1 is between 45 and 90 degrees counter-clockwise of n0.
- p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2))
- s = m2.Neg()
- }
- } else {
- pm1, n0t := pivot.Sub(m1), n0.Mul(tpo8)
- p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2))
- p.Add2(pm1.Add(n0t), pm1)
- if m2.Dot(n1) <= 0 {
- // n1 is between 90 and 135 degrees counter-clockwise of n0.
- s = m1.Neg()
- } else {
- // n1 is between 135 and 180 degrees counter-clockwise of n0.
- p.Add2(pm1.Sub(n0t), pivot.Sub(m0))
- s = m0.Neg()
- }
- }
- }
- // The final quadratic segment has two endpoints s and n1 and the middle
- // control point is a multiple of s.Add(n1), i.e. it is on the angle bisector
- // of those two points. The multiple ranges between 128/256 and 150/256 as
- // the angle between s and n1 ranges between 0 and 45 degrees.
- // When the angle is 0 degrees (i.e. s and n1 are coincident) then s.Add(n1)
- // is twice s and so the middle control point of the degenerate quadratic
- // segment should be half s.Add(n1), and half = 128/256.
- // When the angle is 45 degrees then 150/256 is the ratio of the lengths of
- // the two vectors {1, tan(π/8)} and {1 + 1/√2, 1/√2}.
- // d is the normalized dot product between s and n1. Since the angle ranges
- // between 0 and 45 degrees then d ranges between 256/256 and 181/256.
- d := 256 * s.Dot(n1) / r2
- multiple := Fix32(150 - 22*(d-181)/(256-181))
- p.Add2(pivot.Add(s.Add(n1).Mul(multiple)), pivot.Add(n1))
-}
-
-// midpoint returns the midpoint of two Points.
-func midpoint(a, b Point) Point {
- return Point{(a.X + b.X) / 2, (a.Y + b.Y) / 2}
-}
-
-// angleGreaterThan45 returns whether the angle between two vectors is more
-// than 45 degrees.
-func angleGreaterThan45(v0, v1 Point) bool {
- v := v0.Rot45CCW()
- return v.Dot(v1) < 0 || v.Rot90CW().Dot(v1) < 0
-}
-
-// interpolate returns the point (1-t)*a + t*b.
-func interpolate(a, b Point, t Fix64) Point {
- s := 65536 - t
- x := s*Fix64(a.X) + t*Fix64(b.X)
- y := s*Fix64(a.Y) + t*Fix64(b.Y)
- return Point{Fix32(x >> 16), Fix32(y >> 16)}
-}
-
-// curviest2 returns the value of t for which the quadratic parametric curve
-// (1-t)²*a + 2*t*(1-t).b + t²*c has maximum curvature.
-//
-// The curvature of the parametric curve f(t) = (x(t), y(t)) is
-// |x′y″-y′x″| / (x′²+y′²)^(3/2).
-//
-// Let d = b-a and e = c-2*b+a, so that f′(t) = 2*d+2*e*t and f″(t) = 2*e.
-// The curvature's numerator is (2*dx+2*ex*t)*(2*ey)-(2*dy+2*ey*t)*(2*ex),
-// which simplifies to 4*dx*ey-4*dy*ex, which is constant with respect to t.
-//
-// Thus, curvature is extreme where the denominator is extreme, i.e. where
-// (x′²+y′²) is extreme. The first order condition is that
-// 2*x′*x″+2*y′*y″ = 0, or (dx+ex*t)*ex + (dy+ey*t)*ey = 0.
-// Solving for t gives t = -(dx*ex+dy*ey) / (ex*ex+ey*ey).
-func curviest2(a, b, c Point) Fix64 {
- dx := int64(b.X - a.X)
- dy := int64(b.Y - a.Y)
- ex := int64(c.X - 2*b.X + a.X)
- ey := int64(c.Y - 2*b.Y + a.Y)
- if ex == 0 && ey == 0 {
- return 32768
- }
- return Fix64(-65536 * (dx*ex + dy*ey) / (ex*ex + ey*ey))
-}
-
-// A stroker holds state for stroking a path.
-type stroker struct {
- // p is the destination that records the stroked path.
- p Adder
- // u is the half-width of the stroke.
- u Fix32
- // cr and jr specify how to end and connect path segments.
- cr Capper
- jr Joiner
- // r is the reverse path. Stroking a path involves constructing two
- // parallel paths 2*u apart. The first path is added immediately to p,
- // the second path is accumulated in r and eventually added in reverse.
- r Path
- // a is the most recent segment point. anorm is the segment normal of
- // length u at that point.
- a, anorm Point
-}
-
-// addNonCurvy2 adds a quadratic segment to the stroker, where the segment
-// defined by (k.a, b, c) achieves maximum curvature at either k.a or c.
-func (k *stroker) addNonCurvy2(b, c Point) {
- // We repeatedly divide the segment at its middle until it is straight
- // enough to approximate the stroke by just translating the control points.
- // ds and ps are stacks of depths and points. t is the top of the stack.
- const maxDepth = 5
- var (
- ds [maxDepth + 1]int
- ps [2*maxDepth + 3]Point
- t int
- )
- // Initially the ps stack has one quadratic segment of depth zero.
- ds[0] = 0
- ps[2] = k.a
- ps[1] = b
- ps[0] = c
- anorm := k.anorm
- var cnorm Point
-
- for {
- depth := ds[t]
- a := ps[2*t+2]
- b := ps[2*t+1]
- c := ps[2*t+0]
- ab := b.Sub(a)
- bc := c.Sub(b)
- abIsSmall := ab.Dot(ab) < Fix64(1<<16)
- bcIsSmall := bc.Dot(bc) < Fix64(1<<16)
- if abIsSmall && bcIsSmall {
- // Approximate the segment by a circular arc.
- cnorm = bc.Norm(k.u).Rot90CCW()
- mac := midpoint(a, c)
- addArc(k.p, mac, anorm, cnorm)
- addArc(&k.r, mac, anorm.Neg(), cnorm.Neg())
- } else if depth < maxDepth && angleGreaterThan45(ab, bc) {
- // Divide the segment in two and push both halves on the stack.
- mab := midpoint(a, b)
- mbc := midpoint(b, c)
- t++
- ds[t+0] = depth + 1
- ds[t-1] = depth + 1
- ps[2*t+2] = a
- ps[2*t+1] = mab
- ps[2*t+0] = midpoint(mab, mbc)
- ps[2*t-1] = mbc
- continue
- } else {
- // Translate the control points.
- bnorm := c.Sub(a).Norm(k.u).Rot90CCW()
- cnorm = bc.Norm(k.u).Rot90CCW()
- k.p.Add2(b.Add(bnorm), c.Add(cnorm))
- k.r.Add2(b.Sub(bnorm), c.Sub(cnorm))
- }
- if t == 0 {
- k.a, k.anorm = c, cnorm
- return
- }
- t--
- anorm = cnorm
- }
- panic("unreachable")
-}
-
-// Add1 adds a linear segment to the stroker.
-func (k *stroker) Add1(b Point) {
- bnorm := b.Sub(k.a).Norm(k.u).Rot90CCW()
- if len(k.r) == 0 {
- k.p.Start(k.a.Add(bnorm))
- k.r.Start(k.a.Sub(bnorm))
- } else {
- k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, bnorm)
- }
- k.p.Add1(b.Add(bnorm))
- k.r.Add1(b.Sub(bnorm))
- k.a, k.anorm = b, bnorm
-}
-
-// Add2 adds a quadratic segment to the stroker.
-func (k *stroker) Add2(b, c Point) {
- ab := b.Sub(k.a)
- bc := c.Sub(b)
- abnorm := ab.Norm(k.u).Rot90CCW()
- if len(k.r) == 0 {
- k.p.Start(k.a.Add(abnorm))
- k.r.Start(k.a.Sub(abnorm))
- } else {
- k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, abnorm)
- }
-
- // Approximate nearly-degenerate quadratics by linear segments.
- abIsSmall := ab.Dot(ab) < epsilon
- bcIsSmall := bc.Dot(bc) < epsilon
- if abIsSmall || bcIsSmall {
- acnorm := c.Sub(k.a).Norm(k.u).Rot90CCW()
- k.p.Add1(c.Add(acnorm))
- k.r.Add1(c.Sub(acnorm))
- k.a, k.anorm = c, acnorm
- return
- }
-
- // The quadratic segment (k.a, b, c) has a point of maximum curvature.
- // If this occurs at an end point, we process the segment as a whole.
- t := curviest2(k.a, b, c)
- if t <= 0 || t >= 65536 {
- k.addNonCurvy2(b, c)
- return
- }
-
- // Otherwise, we perform a de Casteljau decomposition at the point of
- // maximum curvature and process the two straighter parts.
- mab := interpolate(k.a, b, t)
- mbc := interpolate(b, c, t)
- mabc := interpolate(mab, mbc, t)
-
- // If the vectors ab and bc are close to being in opposite directions,
- // then the decomposition can become unstable, so we approximate the
- // quadratic segment by two linear segments joined by an arc.
- bcnorm := bc.Norm(k.u).Rot90CCW()
- if abnorm.Dot(bcnorm) < -Fix64(k.u)*Fix64(k.u)*2047/2048 {
- pArc := abnorm.Dot(bc) < 0
-
- k.p.Add1(mabc.Add(abnorm))
- if pArc {
- z := abnorm.Rot90CW()
- addArc(k.p, mabc, abnorm, z)
- addArc(k.p, mabc, z, bcnorm)
- }
- k.p.Add1(mabc.Add(bcnorm))
- k.p.Add1(c.Add(bcnorm))
-
- k.r.Add1(mabc.Sub(abnorm))
- if !pArc {
- z := abnorm.Rot90CW()
- addArc(&k.r, mabc, abnorm.Neg(), z)
- addArc(&k.r, mabc, z, bcnorm.Neg())
- }
- k.r.Add1(mabc.Sub(bcnorm))
- k.r.Add1(c.Sub(bcnorm))
-
- k.a, k.anorm = c, bcnorm
- return
- }
-
- // Process the decomposed parts.
- k.addNonCurvy2(mab, mabc)
- k.addNonCurvy2(mbc, c)
-}
-
-// Add3 adds a cubic segment to the stroker.
-func (k *stroker) Add3(b, c, d Point) {
- panic("freetype/raster: stroke unimplemented for cubic segments")
-}
-
-// stroke adds the stroked Path q to p, where q consists of exactly one curve.
-func (k *stroker) stroke(q Path) {
- // Stroking is implemented by deriving two paths each k.u apart from q.
- // The left-hand-side path is added immediately to k.p; the right-hand-side
- // path is accumulated in k.r. Once we've finished adding the LHS to k.p,
- // we add the RHS in reverse order.
- k.r = make(Path, 0, len(q))
- k.a = Point{q[1], q[2]}
- for i := 4; i < len(q); {
- switch q[i] {
- case 1:
- k.Add1(Point{q[i+1], q[i+2]})
- i += 4
- case 2:
- k.Add2(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]})
- i += 6
- case 3:
- k.Add3(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]}, Point{q[i+5], q[i+6]})
- i += 8
- default:
- panic("freetype/raster: bad path")
- }
- }
- if len(k.r) == 0 {
- return
- }
- // TODO(nigeltao): if q is a closed curve then we should join the first and
- // last segments instead of capping them.
- k.cr.Cap(k.p, k.u, q.lastPoint(), k.anorm.Neg())
- addPathReversed(k.p, k.r)
- pivot := q.firstPoint()
- k.cr.Cap(k.p, k.u, pivot, pivot.Sub(Point{k.r[1], k.r[2]}))
-}
-
-// Stroke adds q stroked with the given width to p. The result is typically
-// self-intersecting and should be rasterized with UseNonZeroWinding.
-// cr and jr may be nil, which defaults to a RoundCapper or RoundJoiner.
-func Stroke(p Adder, q Path, width Fix32, cr Capper, jr Joiner) {
- if len(q) == 0 {
- return
- }
- if cr == nil {
- cr = RoundCapper
- }
- if jr == nil {
- jr = RoundJoiner
- }
- if q[0] != 0 {
- panic("freetype/raster: bad path")
- }
- s := stroker{p: p, u: width / 2, cr: cr, jr: jr}
- i := 0
- for j := 4; j < len(q); {
- switch q[j] {
- case 0:
- s.stroke(q[i:j])
- i, j = j, j+4
- case 1:
- j += 4
- case 2:
- j += 6
- case 3:
- j += 8
- default:
- panic("freetype/raster: bad path")
- }
- }
- s.stroke(q[i:])
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go
deleted file mode 100644
index b5f327851..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go
+++ /dev/null
@@ -1,530 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package truetype
-
-// Hinting is the policy for snapping a glyph's contours to pixel boundaries.
-type Hinting int32
-
-const (
- // NoHinting means to not perform any hinting.
- NoHinting Hinting = iota
- // FullHinting means to use the font's hinting instructions.
- FullHinting
-
- // TODO: implement VerticalHinting.
-)
-
-// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
-// ``off'' control point.
-type Point struct {
- X, Y int32
- // The Flags' LSB means whether or not this Point is ``on'' the contour.
- // Other bits are reserved for internal use.
- Flags uint32
-}
-
-// A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a
-// series of glyphs from a Font.
-type GlyphBuf struct {
- // AdvanceWidth is the glyph's advance width.
- AdvanceWidth int32
- // B is the glyph's bounding box.
- B Bounds
- // Point contains all Points from all contours of the glyph. If
- // hinting was used to load a glyph then Unhinted contains those
- // Points before they were hinted, and InFontUnits contains those
- // Points before they were hinted and scaled.
- Point, Unhinted, InFontUnits []Point
- // End is the point indexes of the end point of each countour. The
- // length of End is the number of contours in the glyph. The i'th
- // contour consists of points Point[End[i-1]:End[i]], where End[-1]
- // is interpreted to mean zero.
- End []int
-
- font *Font
- scale int32
- hinting Hinting
- hinter hinter
- // phantomPoints are the co-ordinates of the synthetic phantom points
- // used for hinting and bounding box calculations.
- phantomPoints [4]Point
- // pp1x is the X co-ordinate of the first phantom point. The '1' is
- // using 1-based indexing; pp1x is almost always phantomPoints[0].X.
- // TODO: eliminate this and consistently use phantomPoints[0].X.
- pp1x int32
- // metricsSet is whether the glyph's metrics have been set yet. For a
- // compound glyph, a sub-glyph may override the outer glyph's metrics.
- metricsSet bool
- // tmp is a scratch buffer.
- tmp []Point
-}
-
-// Flags for decoding a glyph's contours. These flags are documented at
-// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
-const (
- flagOnCurve = 1 << iota
- flagXShortVector
- flagYShortVector
- flagRepeat
- flagPositiveXShortVector
- flagPositiveYShortVector
-
- // The remaining flags are for internal use.
- flagTouchedX
- flagTouchedY
-)
-
-// The same flag bits (0x10 and 0x20) are overloaded to have two meanings,
-// dependent on the value of the flag{X,Y}ShortVector bits.
-const (
- flagThisXIsSame = flagPositiveXShortVector
- flagThisYIsSame = flagPositiveYShortVector
-)
-
-// Load loads a glyph's contours from a Font, overwriting any previously
-// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point
-// units in 1 em, i is the glyph index, and h is the hinting policy.
-func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
- g.Point = g.Point[:0]
- g.Unhinted = g.Unhinted[:0]
- g.InFontUnits = g.InFontUnits[:0]
- g.End = g.End[:0]
- g.font = f
- g.hinting = h
- g.scale = scale
- g.pp1x = 0
- g.phantomPoints = [4]Point{}
- g.metricsSet = false
-
- if h != NoHinting {
- if err := g.hinter.init(f, scale); err != nil {
- return err
- }
- }
- if err := g.load(0, i, true); err != nil {
- return err
- }
- // TODO: this selection of either g.pp1x or g.phantomPoints[0].X isn't ideal,
- // and should be cleaned up once we have all the testScaling tests passing,
- // plus additional tests for Freetype-Go's bounding boxes matching C Freetype's.
- pp1x := g.pp1x
- if h != NoHinting {
- pp1x = g.phantomPoints[0].X
- }
- if pp1x != 0 {
- for i := range g.Point {
- g.Point[i].X -= pp1x
- }
- }
-
- advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X
- if h != NoHinting {
- if len(f.hdmx) >= 8 {
- if n := u32(f.hdmx, 4); n > 3+uint32(i) {
- for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] {
- if int32(hdmx[0]) == scale>>6 {
- advanceWidth = int32(hdmx[2+i]) << 6
- break
- }
- }
- }
- }
- advanceWidth = (advanceWidth + 32) &^ 63
- }
- g.AdvanceWidth = advanceWidth
-
- // Set g.B to the 'control box', which is the bounding box of the Bézier
- // curves' control points. This is easier to calculate, no smaller than
- // and often equal to the tightest possible bounding box of the curves
- // themselves. This approach is what C Freetype does. We can't just scale
- // the nominal bounding box in the glyf data as the hinting process and
- // phantom point adjustment may move points outside of that box.
- if len(g.Point) == 0 {
- g.B = Bounds{}
- } else {
- p := g.Point[0]
- g.B.XMin = p.X
- g.B.XMax = p.X
- g.B.YMin = p.Y
- g.B.YMax = p.Y
- for _, p := range g.Point[1:] {
- if g.B.XMin > p.X {
- g.B.XMin = p.X
- } else if g.B.XMax < p.X {
- g.B.XMax = p.X
- }
- if g.B.YMin > p.Y {
- g.B.YMin = p.Y
- } else if g.B.YMax < p.Y {
- g.B.YMax = p.Y
- }
- }
- // Snap the box to the grid, if hinting is on.
- if h != NoHinting {
- g.B.XMin &^= 63
- g.B.YMin &^= 63
- g.B.XMax += 63
- g.B.XMax &^= 63
- g.B.YMax += 63
- g.B.YMax &^= 63
- }
- }
- return nil
-}
-
-func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) {
- // The recursion limit here is arbitrary, but defends against malformed glyphs.
- if recursion >= 32 {
- return UnsupportedError("excessive compound glyph recursion")
- }
- // Find the relevant slice of g.font.glyf.
- var g0, g1 uint32
- if g.font.locaOffsetFormat == locaOffsetFormatShort {
- g0 = 2 * uint32(u16(g.font.loca, 2*int(i)))
- g1 = 2 * uint32(u16(g.font.loca, 2*int(i)+2))
- } else {
- g0 = u32(g.font.loca, 4*int(i))
- g1 = u32(g.font.loca, 4*int(i)+4)
- }
-
- // Decode the contour count and nominal bounding box, from the first
- // 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4
- // and 6, are unused.
- glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, int32(0), int32(0)
- if g0+10 <= g1 {
- glyf = g.font.glyf[g0:g1]
- ne = int(int16(u16(glyf, 0)))
- boundsXMin = int32(int16(u16(glyf, 2)))
- boundsYMax = int32(int16(u16(glyf, 8)))
- }
-
- // Create the phantom points.
- uhm, pp1x := g.font.unscaledHMetric(i), int32(0)
- uvm := g.font.unscaledVMetric(i, boundsYMax)
- g.phantomPoints = [4]Point{
- {X: boundsXMin - uhm.LeftSideBearing},
- {X: boundsXMin - uhm.LeftSideBearing + uhm.AdvanceWidth},
- {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing},
- {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing - uvm.AdvanceHeight},
- }
- if len(glyf) == 0 {
- g.addPhantomsAndScale(len(g.Point), len(g.Point), true, true)
- copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
- g.Point = g.Point[:len(g.Point)-4]
- return nil
- }
-
- // Load and hint the contours.
- if ne < 0 {
- if ne != -1 {
- // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that
- // "the values -2, -3, and so forth, are reserved for future use."
- return UnsupportedError("negative number of contours")
- }
- pp1x = g.font.scale(g.scale * (boundsXMin - uhm.LeftSideBearing))
- if err := g.loadCompound(recursion, uhm, i, glyf, useMyMetrics); err != nil {
- return err
- }
- } else {
- np0, ne0 := len(g.Point), len(g.End)
- program := g.loadSimple(glyf, ne)
- g.addPhantomsAndScale(np0, np0, true, true)
- pp1x = g.Point[len(g.Point)-4].X
- if g.hinting != NoHinting {
- if len(program) != 0 {
- err := g.hinter.run(
- program,
- g.Point[np0:],
- g.Unhinted[np0:],
- g.InFontUnits[np0:],
- g.End[ne0:],
- )
- if err != nil {
- return err
- }
- }
- // Drop the four phantom points.
- g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4]
- g.Unhinted = g.Unhinted[:len(g.Unhinted)-4]
- }
- if useMyMetrics {
- copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
- }
- g.Point = g.Point[:len(g.Point)-4]
- if np0 != 0 {
- // The hinting program expects the []End values to be indexed relative
- // to the inner glyph, not the outer glyph, so we delay adding np0 until
- // after the hinting program (if any) has run.
- for i := ne0; i < len(g.End); i++ {
- g.End[i] += np0
- }
- }
- }
- if useMyMetrics && !g.metricsSet {
- g.metricsSet = true
- g.pp1x = pp1x
- }
- return nil
-}
-
-// loadOffset is the initial offset for loadSimple and loadCompound. The first
-// 10 bytes are the number of contours and the bounding box.
-const loadOffset = 10
-
-func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
- offset := loadOffset
- for i := 0; i < ne; i++ {
- g.End = append(g.End, 1+int(u16(glyf, offset)))
- offset += 2
- }
-
- // Note the TrueType hinting instructions.
- instrLen := int(u16(glyf, offset))
- offset += 2
- program = glyf[offset : offset+instrLen]
- offset += instrLen
-
- np0 := len(g.Point)
- np1 := np0 + int(g.End[len(g.End)-1])
-
- // Decode the flags.
- for i := np0; i < np1; {
- c := uint32(glyf[offset])
- offset++
- g.Point = append(g.Point, Point{Flags: c})
- i++
- if c&flagRepeat != 0 {
- count := glyf[offset]
- offset++
- for ; count > 0; count-- {
- g.Point = append(g.Point, Point{Flags: c})
- i++
- }
- }
- }
-
- // Decode the co-ordinates.
- var x int16
- for i := np0; i < np1; i++ {
- f := g.Point[i].Flags
- if f&flagXShortVector != 0 {
- dx := int16(glyf[offset])
- offset++
- if f&flagPositiveXShortVector == 0 {
- x -= dx
- } else {
- x += dx
- }
- } else if f&flagThisXIsSame == 0 {
- x += int16(u16(glyf, offset))
- offset += 2
- }
- g.Point[i].X = int32(x)
- }
- var y int16
- for i := np0; i < np1; i++ {
- f := g.Point[i].Flags
- if f&flagYShortVector != 0 {
- dy := int16(glyf[offset])
- offset++
- if f&flagPositiveYShortVector == 0 {
- y -= dy
- } else {
- y += dy
- }
- } else if f&flagThisYIsSame == 0 {
- y += int16(u16(glyf, offset))
- offset += 2
- }
- g.Point[i].Y = int32(y)
- }
-
- return program
-}
-
-func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
- glyf []byte, useMyMetrics bool) error {
-
- // Flags for decoding a compound glyph. These flags are documented at
- // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
- const (
- flagArg1And2AreWords = 1 << iota
- flagArgsAreXYValues
- flagRoundXYToGrid
- flagWeHaveAScale
- flagUnused
- flagMoreComponents
- flagWeHaveAnXAndYScale
- flagWeHaveATwoByTwo
- flagWeHaveInstructions
- flagUseMyMetrics
- flagOverlapCompound
- )
- np0, ne0 := len(g.Point), len(g.End)
- offset := loadOffset
- for {
- flags := u16(glyf, offset)
- component := Index(u16(glyf, offset+2))
- dx, dy, transform, hasTransform := int32(0), int32(0), [4]int32{}, false
- if flags&flagArg1And2AreWords != 0 {
- dx = int32(int16(u16(glyf, offset+4)))
- dy = int32(int16(u16(glyf, offset+6)))
- offset += 8
- } else {
- dx = int32(int16(int8(glyf[offset+4])))
- dy = int32(int16(int8(glyf[offset+5])))
- offset += 6
- }
- if flags&flagArgsAreXYValues == 0 {
- return UnsupportedError("compound glyph transform vector")
- }
- if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 {
- hasTransform = true
- switch {
- case flags&flagWeHaveAScale != 0:
- transform[0] = int32(int16(u16(glyf, offset+0)))
- transform[3] = transform[0]
- offset += 2
- case flags&flagWeHaveAnXAndYScale != 0:
- transform[0] = int32(int16(u16(glyf, offset+0)))
- transform[3] = int32(int16(u16(glyf, offset+2)))
- offset += 4
- case flags&flagWeHaveATwoByTwo != 0:
- transform[0] = int32(int16(u16(glyf, offset+0)))
- transform[1] = int32(int16(u16(glyf, offset+2)))
- transform[2] = int32(int16(u16(glyf, offset+4)))
- transform[3] = int32(int16(u16(glyf, offset+6)))
- offset += 8
- }
- }
- savedPP := g.phantomPoints
- np0 := len(g.Point)
- componentUMM := useMyMetrics && (flags&flagUseMyMetrics != 0)
- if err := g.load(recursion+1, component, componentUMM); err != nil {
- return err
- }
- if flags&flagUseMyMetrics == 0 {
- g.phantomPoints = savedPP
- }
- if hasTransform {
- for j := np0; j < len(g.Point); j++ {
- p := &g.Point[j]
- newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) +
- int32((int64(p.Y)*int64(transform[2])+1<<13)>>14)
- newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) +
- int32((int64(p.Y)*int64(transform[3])+1<<13)>>14)
- p.X, p.Y = newX, newY
- }
- }
- dx = g.font.scale(g.scale * dx)
- dy = g.font.scale(g.scale * dy)
- if flags&flagRoundXYToGrid != 0 {
- dx = (dx + 32) &^ 63
- dy = (dy + 32) &^ 63
- }
- for j := np0; j < len(g.Point); j++ {
- p := &g.Point[j]
- p.X += dx
- p.Y += dy
- }
- // TODO: also adjust g.InFontUnits and g.Unhinted?
- if flags&flagMoreComponents == 0 {
- break
- }
- }
-
- instrLen := 0
- if g.hinting != NoHinting && offset+2 <= len(glyf) {
- instrLen = int(u16(glyf, offset))
- offset += 2
- }
-
- g.addPhantomsAndScale(np0, len(g.Point), false, instrLen > 0)
- points, ends := g.Point[np0:], g.End[ne0:]
- g.Point = g.Point[:len(g.Point)-4]
- for j := range points {
- points[j].Flags &^= flagTouchedX | flagTouchedY
- }
-
- if instrLen == 0 {
- if !g.metricsSet {
- copy(g.phantomPoints[:], points[len(points)-4:])
- }
- return nil
- }
-
- // Hint the compound glyph.
- program := glyf[offset : offset+instrLen]
- // Temporarily adjust the ends to be relative to this compound glyph.
- if np0 != 0 {
- for i := range ends {
- ends[i] -= np0
- }
- }
- // Hinting instructions of a composite glyph completely refer to the
- // (already) hinted subglyphs.
- g.tmp = append(g.tmp[:0], points...)
- if err := g.hinter.run(program, points, g.tmp, g.tmp, ends); err != nil {
- return err
- }
- if np0 != 0 {
- for i := range ends {
- ends[i] += np0
- }
- }
- if !g.metricsSet {
- copy(g.phantomPoints[:], points[len(points)-4:])
- }
- return nil
-}
-
-func (g *GlyphBuf) addPhantomsAndScale(np0, np1 int, simple, adjust bool) {
- // Add the four phantom points.
- g.Point = append(g.Point, g.phantomPoints[:]...)
- // Scale the points.
- if simple && g.hinting != NoHinting {
- g.InFontUnits = append(g.InFontUnits, g.Point[np1:]...)
- }
- for i := np1; i < len(g.Point); i++ {
- p := &g.Point[i]
- p.X = g.font.scale(g.scale * p.X)
- p.Y = g.font.scale(g.scale * p.Y)
- }
- if g.hinting == NoHinting {
- return
- }
- // Round the 1st phantom point to the grid, shifting all other points equally.
- // Note that "all other points" starts from np0, not np1.
- // TODO: delete this adjustment and the np0/np1 distinction, when
- // we update the compatibility tests to C Freetype 2.5.3.
- // See http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=05c786d990390a7ca18e62962641dac740bacb06
- if adjust {
- pp1x := g.Point[len(g.Point)-4].X
- if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 {
- for i := np0; i < len(g.Point); i++ {
- g.Point[i].X += dx
- }
- }
- }
- if simple {
- g.Unhinted = append(g.Unhinted, g.Point[np1:]...)
- }
- // Round the 2nd and 4th phantom point to the grid.
- p := &g.Point[len(g.Point)-3]
- p.X = (p.X + 32) &^ 63
- p = &g.Point[len(g.Point)-1]
- p.Y = (p.Y + 32) &^ 63
-}
-
-// TODO: is this necessary? The zero-valued GlyphBuf is perfectly usable.
-
-// NewGlyphBuf returns a newly allocated GlyphBuf.
-func NewGlyphBuf() *GlyphBuf {
- return &GlyphBuf{
- Point: make([]Point, 0, 256),
- End: make([]int, 0, 32),
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go
deleted file mode 100644
index 26c631436..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go
+++ /dev/null
@@ -1,1764 +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"
-)
-
-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 int32
-
- // 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 []f26dot6
-}
-
-// 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 f26dot6
- // Delta base / shift.
- deltaBase, deltaShift int32
- // Minimum distance.
- minDist f26dot6
- // Loop count.
- loop int32
- // Rounding policy.
- roundPeriod, roundPhase, roundThreshold f26dot6
- 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 an f26dot6.
- deltaBase: 9,
- deltaShift: 3,
- minDist: 1 << 6, // 1 as an f26dot6.
- loop: 1,
- roundPeriod: 1 << 6, // 1 as an f26dot6.
- roundThreshold: 1 << 5, // 1/2 as an f26dot6.
- 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 int32) 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 + int32(rx)
- p.Y = a0.Y + int32(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 = f26dot6(h.stack[top])
-
- case opELSE:
- opcode = 1
- goto ifelse
-
- case opJMPR:
- top--
- pc += int(h.stack[top])
- continue
-
- case opSCVTCI:
- top--
- h.gs.controlValueCutIn = f26dot6(h.stack[top])
-
- case opSSWCI:
- top--
- h.gs.singleWidthCutIn = f26dot6(h.stack[top])
-
- case opSSW:
- top--
- h.gs.singleWidth = f26dot6(h.font.scale(h.scale * 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(f26dot6(q.X-p.X), f26dot6(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 := f26dot6(0)
- if opcode == opMDAP1 {
- distance = dotProduct(f26dot6(p.X), f26dot6(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 := f26dot6(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(f26dot6(p.X-oldP.X), f26dot6(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(f26dot6(p.X-curP.X), f26dot6(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(f26dot6(p.X-oldP.X), f26dot6(p.Y-oldP.Y), h.gs.dv)
- p = h.point(2, current, i)
- curDist := dotProduct(f26dot6(p.X-curP.X), f26dot6(p.Y-curP.Y), h.gs.pv)
- newDist := f26dot6(0)
- if oldDist != 0 {
- if oldRange != 0 {
- newDist = f26dot6(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 := f26dot6(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(f26dot6(p.X-ref.X), f26dot6(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(f26dot6(p.X-ref.X), f26dot6(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 = int32((int64(distance) * int64(h.gs.fv[0])) >> 14)
- p.Y = int32((int64(distance) * int64(h.gs.fv[1])) >> 14)
- *q = *p
- }
- p := h.point(0, current, i)
- oldDist := dotProduct(f26dot6(p.X), f26dot6(p.Y), h.gs.pv)
- if opcode == opMIAP1 {
- if (distance - oldDist).abs() > 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], f26dot6(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(f26dot6(p.X), f26dot6(p.Y), h.gs.pv))
- } else {
- p := h.point(2, unhinted, i)
- // Using dv as per C Freetype.
- h.stack[top-1] = int32(dotProduct(f26dot6(p.X), f26dot6(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(f26dot6(p.X), f26dot6(p.Y), h.gs.pv)
- h.move(p, f26dot6(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(f26dot6(p.X-q.X), f26dot6(p.Y-q.Y), v))
- if scale {
- d = int32(int64(d*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] = 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(f26dot6(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(f26dot6(h.stack[top-1]).div(f26dot6(h.stack[top])))
-
- case opMUL:
- top--
- h.stack[top-1] = int32(f26dot6(h.stack[top-1]).mul(f26dot6(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(f26dot6(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], f26dot6(h.font.scale(h.scale*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 * f26dot6((h.stack[top]>>4)&0x03) / 4
- if x := h.stack[top] & 0x0f; x != 0 {
- h.gs.roundThreshold = h.gs.roundPeriod * f26dot6(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 := f26dot6(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(f26dot6(p0.X-p1.X), f26dot6(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(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
- oldDist = f26dot6(h.font.scale(h.scale * int32(oldDist)))
- }
-
- // Single-width cut-in test.
- if x := (oldDist - h.gs.singleWidth).abs(); 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(f26dot6(p.X-ref.X), f26dot6(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 (cvtDist - h.gs.singleWidth).abs() < 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(f26dot6(p.X-ref.X), f26dot6(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(f26dot6(p.X-ref.X), f26dot6(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]) &&
- ((cvtDist - oldDist).abs() > 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 := (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] += f26dot6(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, f26dot6(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([]f26dot6, 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] = f26dot6(h.font.scale(h.scale * int32(int16(unscaled))))
- }
-}
-
-// getScaledCVT returns the scaled value from the font's Control Value Table.
-func (h *hinter) getScaledCVT(i int32) f26dot6 {
- 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 f26dot6) {
- 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 f26dot6, touch bool) {
- fvx := int64(h.gs.fv[0])
- pvx := int64(h.gs.pv[0])
- if fvx == 0x4000 && pvx == 0x4000 {
- p.X += int32(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 += int32(distance)
- if touch {
- p.Flags |= flagTouchedY
- }
- return
- }
-
- fvDotPv := (fvx*pvx + fvy*pvy) >> 14
-
- if fvx != 0 {
- p.X += int32(mulDiv(fvx, int64(distance), fvDotPv))
- if touch {
- p.Flags |= flagTouchedX
- }
- }
-
- if fvy != 0 {
- p.Y += int32(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 int32
- 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 int32
- 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 int32
- 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 + int32(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 int32
- 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 f26dot6, 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(f26dot6(p.X-q.X), f26dot6(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)}
-}
-
-// f26dot6 is a 26.6 fixed point number.
-type f26dot6 int32
-
-// abs returns abs(x) in 26.6 fixed point arithmetic.
-func (x f26dot6) abs() f26dot6 {
- if x < 0 {
- return -x
- }
- return x
-}
-
-// div returns x/y in 26.6 fixed point arithmetic.
-func (x f26dot6) div(y f26dot6) f26dot6 {
- return f26dot6((int64(x) << 6) / int64(y))
-}
-
-// mul returns x*y in 26.6 fixed point arithmetic.
-func (x f26dot6) mul(y f26dot6) f26dot6 {
- return f26dot6((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 f26dot6((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 f26dot6, q [2]f2dot14) f26dot6 {
- // 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 f26dot6((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 f26dot6) f26dot6 {
- 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/code.google.com/p/freetype-go/freetype/truetype/hint_test.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go
deleted file mode 100644
index c8b8d604d..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go
+++ /dev/null
@@ -1,673 +0,0 @@
-// Copyright 2012 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package truetype
-
-import (
- "reflect"
- "strings"
- "testing"
-)
-
-func TestBytecode(t *testing.T) {
- testCases := []struct {
- desc string
- prog []byte
- want []int32
- errStr string
- }{
- {
- "underflow",
- []byte{
- opDUP,
- },
- nil,
- "underflow",
- },
- {
- "infinite loop",
- []byte{
- opPUSHW000, // [-1]
- 0xff,
- 0xff,
- opDUP, // [-1, -1]
- opJMPR, // [-1]
- },
- nil,
- "too many steps",
- },
- {
- "unbalanced if/else",
- []byte{
- opPUSHB000, // [0]
- 0,
- opIF,
- },
- nil,
- "unbalanced",
- },
- {
- "vector set/gets",
- []byte{
- opSVTCA1, // []
- opGPV, // [0x4000, 0]
- opSVTCA0, // [0x4000, 0]
- opGFV, // [0x4000, 0, 0, 0x4000]
- opNEG, // [0x4000, 0, 0, -0x4000]
- opSPVFS, // [0x4000, 0]
- opSFVTPV, // [0x4000, 0]
- opPUSHB000, // [0x4000, 0, 1]
- 1,
- opGFV, // [0x4000, 0, 1, 0, -0x4000]
- opPUSHB000, // [0x4000, 0, 1, 0, -0x4000, 2]
- 2,
- },
- []int32{0x4000, 0, 1, 0, -0x4000, 2},
- "",
- },
- {
- "jumps",
- []byte{
- opPUSHB001, // [10, 2]
- 10,
- 2,
- opJMPR, // [10]
- opDUP, // not executed
- opDUP, // [10, 10]
- opPUSHB010, // [10, 10, 20, 2, 1]
- 20,
- 2,
- 1,
- opJROT, // [10, 10, 20]
- opDUP, // not executed
- opDUP, // [10, 10, 20, 20]
- opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
- 30,
- 2,
- 1,
- opJROF, // [10, 10, 20, 20, 30]
- opDUP, // [10, 10, 20, 20, 30, 30]
- opDUP, // [10, 10, 20, 20, 30, 30, 30]
- },
- []int32{10, 10, 20, 20, 30, 30, 30},
- "",
- },
- {
- "stack ops",
- []byte{
- opPUSHB010, // [10, 20, 30]
- 10,
- 20,
- 30,
- opCLEAR, // []
- opPUSHB010, // [40, 50, 60]
- 40,
- 50,
- 60,
- opSWAP, // [40, 60, 50]
- opDUP, // [40, 60, 50, 50]
- opDUP, // [40, 60, 50, 50, 50]
- opPOP, // [40, 60, 50, 50]
- opDEPTH, // [40, 60, 50, 50, 4]
- opCINDEX, // [40, 60, 50, 50, 40]
- opPUSHB000, // [40, 60, 50, 50, 40, 4]
- 4,
- opMINDEX, // [40, 50, 50, 40, 60]
- },
- []int32{40, 50, 50, 40, 60},
- "",
- },
- {
- "push ops",
- []byte{
- opPUSHB000, // [255]
- 255,
- opPUSHW001, // [255, -2, 253]
- 255,
- 254,
- 0,
- 253,
- opNPUSHB, // [1, -2, 253, 1, 2]
- 2,
- 1,
- 2,
- opNPUSHW, // [1, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809]
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- },
- []int32{255, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809},
- "",
- },
- {
- "store ops",
- []byte{
- opPUSHB011, // [1, 22, 3, 44]
- 1,
- 22,
- 3,
- 44,
- opWS, // [1, 22]
- opWS, // []
- opPUSHB000, // [3]
- 3,
- opRS, // [44]
- },
- []int32{44},
- "",
- },
- {
- "comparison ops",
- []byte{
- opPUSHB001, // [10, 20]
- 10,
- 20,
- opLT, // [1]
- opPUSHB001, // [1, 10, 20]
- 10,
- 20,
- opLTEQ, // [1, 1]
- opPUSHB001, // [1, 1, 10, 20]
- 10,
- 20,
- opGT, // [1, 1, 0]
- opPUSHB001, // [1, 1, 0, 10, 20]
- 10,
- 20,
- opGTEQ, // [1, 1, 0, 0]
- opEQ, // [1, 1, 1]
- opNEQ, // [1, 0]
- },
- []int32{1, 0},
- "",
- },
- {
- "odd/even",
- // Calculate odd(2+31/64), odd(2+32/64), even(2), even(1).
- []byte{
- opPUSHB000, // [159]
- 159,
- opODD, // [0]
- opPUSHB000, // [0, 160]
- 160,
- opODD, // [0, 1]
- opPUSHB000, // [0, 1, 128]
- 128,
- opEVEN, // [0, 1, 1]
- opPUSHB000, // [0, 1, 1, 64]
- 64,
- opEVEN, // [0, 1, 1, 0]
- },
- []int32{0, 1, 1, 0},
- "",
- },
- {
- "if true",
- []byte{
- opPUSHB001, // [255, 1]
- 255,
- 1,
- opIF,
- opPUSHB000, // [255, 2]
- 2,
- opEIF,
- opPUSHB000, // [255, 2, 254]
- 254,
- },
- []int32{255, 2, 254},
- "",
- },
- {
- "if false",
- []byte{
- opPUSHB001, // [255, 0]
- 255,
- 0,
- opIF,
- opPUSHB000, // [255]
- 2,
- opEIF,
- opPUSHB000, // [255, 254]
- 254,
- },
- []int32{255, 254},
- "",
- },
- {
- "if/else true",
- []byte{
- opPUSHB000, // [1]
- 1,
- opIF,
- opPUSHB000, // [2]
- 2,
- opELSE,
- opPUSHB000, // not executed
- 3,
- opEIF,
- },
- []int32{2},
- "",
- },
- {
- "if/else false",
- []byte{
- opPUSHB000, // [0]
- 0,
- opIF,
- opPUSHB000, // not executed
- 2,
- opELSE,
- opPUSHB000, // [3]
- 3,
- opEIF,
- },
- []int32{3},
- "",
- },
- {
- "if/else true if/else false",
- // 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
- []byte{
- opPUSHB010, // [255, 0, 1]
- 255,
- 0,
- 1,
- opIF,
- opIF,
- opPUSHB001, // not executed
- 0x58,
- 0x58,
- opELSE,
- opPUSHW000, // [255, 0x5858]
- 0x58,
- 0x58,
- opEIF,
- opELSE,
- opIF,
- opNPUSHB, // not executed
- 3,
- 0x58,
- 0x58,
- 0x58,
- opELSE,
- opNPUSHW, // not executed
- 2,
- 0x58,
- 0x58,
- 0x58,
- 0x58,
- opEIF,
- opEIF,
- opPUSHB000, // [255, 0x5858, 254]
- 254,
- },
- []int32{255, 0x5858, 254},
- "",
- },
- {
- "if/else false if/else true",
- // 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
- []byte{
- opPUSHB010, // [255, 1, 0]
- 255,
- 1,
- 0,
- opIF,
- opIF,
- opPUSHB001, // not executed
- 0x58,
- 0x58,
- opELSE,
- opPUSHW000, // not executed
- 0x58,
- 0x58,
- opEIF,
- opELSE,
- opIF,
- opNPUSHB, // [255, 0x58, 0x58, 0x58]
- 3,
- 0x58,
- 0x58,
- 0x58,
- opELSE,
- opNPUSHW, // not executed
- 2,
- 0x58,
- 0x58,
- 0x58,
- 0x58,
- opEIF,
- opEIF,
- opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
- 254,
- },
- []int32{255, 0x58, 0x58, 0x58, 254},
- "",
- },
- {
- "logical ops",
- []byte{
- opPUSHB010, // [0, 10, 20]
- 0,
- 10,
- 20,
- opAND, // [0, 1]
- opOR, // [1]
- opNOT, // [0]
- },
- []int32{0},
- "",
- },
- {
- "arithmetic ops",
- // Calculate abs((-(1 - (2*3)))/2 + 1/64).
- // The answer is 5/2 + 1/64 in ideal numbers, or 161 in 26.6 fixed point math.
- []byte{
- opPUSHB010, // [64, 128, 192]
- 1 << 6,
- 2 << 6,
- 3 << 6,
- opMUL, // [64, 384]
- opSUB, // [-320]
- opNEG, // [320]
- opPUSHB000, // [320, 128]
- 2 << 6,
- opDIV, // [160]
- opPUSHB000, // [160, 1]
- 1,
- opADD, // [161]
- opABS, // [161]
- },
- []int32{161},
- "",
- },
- {
- "floor, ceiling",
- []byte{
- opPUSHB000, // [96]
- 96,
- opFLOOR, // [64]
- opPUSHB000, // [64, 96]
- 96,
- opCEILING, // [64, 128]
- },
- []int32{64, 128},
- "",
- },
- {
- "rounding",
- // Round 1.40625 (which is 90/64) under various rounding policies.
- // See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
- []byte{
- opROFF, // []
- opPUSHB000, // [90]
- 90,
- opROUND00, // [90]
- opRTG, // [90]
- opPUSHB000, // [90, 90]
- 90,
- opROUND00, // [90, 64]
- opRTHG, // [90, 64]
- opPUSHB000, // [90, 64, 90]
- 90,
- opROUND00, // [90, 64, 96]
- opRDTG, // [90, 64, 96]
- opPUSHB000, // [90, 64, 96, 90]
- 90,
- opROUND00, // [90, 64, 96, 64]
- opRUTG, // [90, 64, 96, 64]
- opPUSHB000, // [90, 64, 96, 64, 90]
- 90,
- opROUND00, // [90, 64, 96, 64, 128]
- opRTDG, // [90, 64, 96, 64, 128]
- opPUSHB000, // [90, 64, 96, 64, 128, 90]
- 90,
- opROUND00, // [90, 64, 96, 64, 128, 96]
- },
- []int32{90, 64, 96, 64, 128, 96},
- "",
- },
- {
- "super-rounding",
- // See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
- // and the sign preservation steps of the "Order of rounding operations" section.
- []byte{
- opPUSHB000, // [0x58]
- 0x58,
- opSROUND, // []
- opPUSHW000, // [-81]
- 0xff,
- 0xaf,
- opROUND00, // [-80]
- opPUSHW000, // [-80, -80]
- 0xff,
- 0xb0,
- opROUND00, // [-80, -80]
- opPUSHW000, // [-80, -80, -17]
- 0xff,
- 0xef,
- opROUND00, // [-80, -80, -16]
- opPUSHW000, // [-80, -80, -16, -16]
- 0xff,
- 0xf0,
- opROUND00, // [-80, -80, -16, -16]
- opPUSHB000, // [-80, -80, -16, -16, 0]
- 0,
- opROUND00, // [-80, -80, -16, -16, 16]
- opPUSHB000, // [-80, -80, -16, -16, 16, 16]
- 16,
- opROUND00, // [-80, -80, -16, -16, 16, 16]
- opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47]
- 47,
- opROUND00, // [-80, -80, -16, -16, 16, 16, 16]
- opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48]
- 48,
- opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80]
- },
- []int32{-80, -80, -16, -16, 16, 16, 16, 80},
- "",
- },
- {
- "roll",
- []byte{
- opPUSHB010, // [1, 2, 3]
- 1,
- 2,
- 3,
- opROLL, // [2, 3, 1]
- },
- []int32{2, 3, 1},
- "",
- },
- {
- "max/min",
- []byte{
- opPUSHW001, // [-2, -3]
- 0xff,
- 0xfe,
- 0xff,
- 0xfd,
- opMAX, // [-2]
- opPUSHW001, // [-2, -4, -5]
- 0xff,
- 0xfc,
- 0xff,
- 0xfb,
- opMIN, // [-2, -5]
- },
- []int32{-2, -5},
- "",
- },
- {
- "functions",
- []byte{
- opPUSHB011, // [3, 7, 0, 3]
- 3,
- 7,
- 0,
- 3,
-
- opFDEF, // Function #3 (not called)
- opPUSHB000,
- 98,
- opENDF,
-
- opFDEF, // Function #0
- opDUP,
- opADD,
- opENDF,
-
- opFDEF, // Function #7
- opPUSHB001,
- 10,
- 0,
- opCALL,
- opDUP,
- opENDF,
-
- opFDEF, // Function #3 (again)
- opPUSHB000,
- 99,
- opENDF,
-
- opPUSHB001, // [2, 0]
- 2,
- 0,
- opCALL, // [4]
- opPUSHB000, // [4, 3]
- 3,
- opLOOPCALL, // [99, 99, 99, 99]
- opPUSHB000, // [99, 99, 99, 99, 7]
- 7,
- opCALL, // [99, 99, 99, 99, 20, 20]
- },
- []int32{99, 99, 99, 99, 20, 20},
- "",
- },
- }
-
- for _, tc := range testCases {
- h := &hinter{}
- h.init(&Font{
- maxStorage: 32,
- maxStackElements: 100,
- }, 768)
- err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
- if err != nil {
- errStr = err.Error()
- }
- if tc.errStr != "" {
- if errStr == "" {
- t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
- } else if !strings.Contains(errStr, tc.errStr) {
- t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
- }
- continue
- }
- if errStr != "" {
- t.Errorf("%s: got error %q, want none", tc.desc, errStr)
- continue
- }
- got := h.stack[:len(tc.want)]
- if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
- continue
- }
- }
-}
-
-// TestMove tests that the hinter.move method matches the output of the C
-// Freetype implementation.
-func TestMove(t *testing.T) {
- h, p := hinter{}, Point{}
- testCases := []struct {
- pvX, pvY, fvX, fvY f2dot14
- wantX, wantY int32
- }{
- {+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
- {+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
- {-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
- {-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
- {+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
- {+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
- {+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
- {+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
- {+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
- {+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
- {-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
- {-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
- {-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
- {-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
- {+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
- {-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
- {+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
- {-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
- {-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
- {+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
- {+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
- }
- for _, tc := range testCases {
- p = Point{}
- h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
- h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
- h.move(&p, 1000, true)
- tx := p.Flags&flagTouchedX != 0
- ty := p.Flags&flagTouchedY != 0
- wantTX := tc.fvX != 0
- wantTY := tc.fvY != 0
- if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
- t.Errorf("pv=%v, fv=%v\ngot %d, %d, %t, %t\nwant %d, %d, %t, %t",
- h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
- continue
- }
-
- // Check that p is aligned with the freedom vector.
- a := int64(p.X) * int64(tc.fvY)
- b := int64(p.Y) * int64(tc.fvX)
- if a != b {
- t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
- continue
- }
-
- // Check that the projected p is 1000 away from the origin.
- dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
- if dotProd != 1000 {
- t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
- continue
- }
- }
-}
-
-// TestNormalize tests that the normalize function matches the output of the C
-// Freetype implementation.
-func TestNormalize(t *testing.T) {
- testCases := [][2]f2dot14{
- {-15895, 3974},
- {-15543, 5181},
- {-14654, 7327},
- {-11585, 11585},
- {0, 16384},
- {11585, 11585},
- {14654, 7327},
- {15543, 5181},
- {15895, 3974},
- {16066, 3213},
- {16161, 2694},
- {16219, 2317},
- {16257, 2032},
- {16284, 1809},
- }
- for i, want := range testCases {
- got := normalize(f2dot14(i)-4, 1)
- if got != want {
- t.Errorf("i=%d: got %v, want %v", i, got, want)
- }
- }
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go
deleted file mode 100644
index 1880e1e63..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/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/code.google.com/p/freetype-go/freetype/truetype/truetype.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go
deleted file mode 100644
index 96ceef547..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go
+++ /dev/null
@@ -1,554 +0,0 @@
-// Copyright 2010 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-// Package truetype provides a parser for the TTF and TTC file formats.
-// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/
-// and http://www.microsoft.com/typography/otspec/
-//
-// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font
-// metrics and control points. All these methods take a scale parameter, which
-// is the number of device units in 1 em. For example, if 1 em is 10 pixels and
-// 1 pixel is 64 units, then scale is 640. If the device space involves pixels,
-// 64 units per pixel is recommended, since that is what the bytecode hinter
-// uses when snapping point co-ordinates to the pixel grid.
-//
-// To measure a TrueType font in ideal FUnit space, use scale equal to
-// font.FUnitsPerEm().
-package truetype
-
-import (
- "fmt"
-)
-
-// An Index is a Font's index of a rune.
-type Index uint16
-
-// A Bounds holds the co-ordinate range of one or more glyphs.
-// The endpoints are inclusive.
-type Bounds struct {
- XMin, YMin, XMax, YMax int32
-}
-
-// An HMetric holds the horizontal metrics of a single glyph.
-type HMetric struct {
- AdvanceWidth, LeftSideBearing int32
-}
-
-// A VMetric holds the vertical metrics of a single glyph.
-type VMetric struct {
- AdvanceHeight, TopSideBearing int32
-}
-
-// A FormatError reports that the input is not a valid TrueType font.
-type FormatError string
-
-func (e FormatError) Error() string {
- return "freetype: invalid TrueType format: " + string(e)
-}
-
-// An UnsupportedError reports that the input uses a valid but unimplemented
-// TrueType feature.
-type UnsupportedError string
-
-func (e UnsupportedError) Error() string {
- return "freetype: unsupported TrueType feature: " + string(e)
-}
-
-// u32 returns the big-endian uint32 at b[i:].
-func u32(b []byte, i int) uint32 {
- return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
-}
-
-// u16 returns the big-endian uint16 at b[i:].
-func u16(b []byte, i int) uint16 {
- return uint16(b[i])<<8 | uint16(b[i+1])
-}
-
-// readTable returns a slice of the TTF data given by a table's directory entry.
-func readTable(ttf []byte, offsetLength []byte) ([]byte, error) {
- offset := int(u32(offsetLength, 0))
- if offset < 0 {
- return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset)))
- }
- length := int(u32(offsetLength, 4))
- if length < 0 {
- return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length)))
- }
- end := offset + length
- if end < 0 || end > len(ttf) {
- return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length)))
- }
- return ttf[offset:end], nil
-}
-
-const (
- locaOffsetFormatUnknown int = iota
- locaOffsetFormatShort
- locaOffsetFormatLong
-)
-
-// A cm holds a parsed cmap entry.
-type cm struct {
- start, end, delta, offset uint32
-}
-
-// A Font represents a Truetype font.
-type Font struct {
- // Tables sliced from the TTF data. The different tables are documented
- // at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
- cmap, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, os2, prep, vmtx []byte
-
- cmapIndexes []byte
-
- // Cached values derived from the raw ttf data.
- cm []cm
- locaOffsetFormat int
- nGlyph, nHMetric, nKern int
- fUnitsPerEm int32
- bounds Bounds
- // Values from the maxp section.
- maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16
-}
-
-func (f *Font) parseCmap() error {
- const (
- cmapFormat4 = 4
- cmapFormat12 = 12
- languageIndependent = 0
-
- // A 32-bit encoding consists of a most-significant 16-bit Platform ID and a
- // least-significant 16-bit Platform Specific ID. The magic numbers are
- // specified at https://www.microsoft.com/typography/otspec/name.htm
- unicodeEncoding = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0)
- microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol)
- microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2)
- microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4)
- )
-
- if len(f.cmap) < 4 {
- return FormatError("cmap too short")
- }
- nsubtab := int(u16(f.cmap, 2))
- if len(f.cmap) < 8*nsubtab+4 {
- return FormatError("cmap too short")
- }
- offset, found, x := 0, false, 4
- for i := 0; i < nsubtab; i++ {
- // We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32.
- // All values are big-endian.
- pidPsid, o := u32(f.cmap, x), u32(f.cmap, x+4)
- x += 8
- // We prefer the Unicode cmap encoding. Failing to find that, we fall
- // back onto the Microsoft cmap encoding.
- if pidPsid == unicodeEncoding {
- offset, found = int(o), true
- break
-
- } else if pidPsid == microsoftSymbolEncoding ||
- pidPsid == microsoftUCS2Encoding ||
- pidPsid == microsoftUCS4Encoding {
-
- offset, found = int(o), true
- // We don't break out of the for loop, so that Unicode can override Microsoft.
- }
- }
- if !found {
- return UnsupportedError("cmap encoding")
- }
- if offset <= 0 || offset > len(f.cmap) {
- return FormatError("bad cmap offset")
- }
-
- cmapFormat := u16(f.cmap, offset)
- switch cmapFormat {
- case cmapFormat4:
- language := u16(f.cmap, offset+4)
- if language != languageIndependent {
- return UnsupportedError(fmt.Sprintf("language: %d", language))
- }
- segCountX2 := int(u16(f.cmap, offset+6))
- if segCountX2%2 == 1 {
- return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2))
- }
- segCount := segCountX2 / 2
- offset += 14
- f.cm = make([]cm, segCount)
- for i := 0; i < segCount; i++ {
- f.cm[i].end = uint32(u16(f.cmap, offset))
- offset += 2
- }
- offset += 2
- for i := 0; i < segCount; i++ {
- f.cm[i].start = uint32(u16(f.cmap, offset))
- offset += 2
- }
- for i := 0; i < segCount; i++ {
- f.cm[i].delta = uint32(u16(f.cmap, offset))
- offset += 2
- }
- for i := 0; i < segCount; i++ {
- f.cm[i].offset = uint32(u16(f.cmap, offset))
- offset += 2
- }
- f.cmapIndexes = f.cmap[offset:]
- return nil
-
- case cmapFormat12:
- if u16(f.cmap, offset+2) != 0 {
- return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4]))
- }
- length := u32(f.cmap, offset+4)
- language := u32(f.cmap, offset+8)
- if language != languageIndependent {
- return UnsupportedError(fmt.Sprintf("language: %d", language))
- }
- nGroups := u32(f.cmap, offset+12)
- if length != 12*nGroups+16 {
- return FormatError("inconsistent cmap length")
- }
- offset += 16
- f.cm = make([]cm, nGroups)
- for i := uint32(0); i < nGroups; i++ {
- f.cm[i].start = u32(f.cmap, offset+0)
- f.cm[i].end = u32(f.cmap, offset+4)
- f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start
- offset += 12
- }
- return nil
- }
- return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat))
-}
-
-func (f *Font) parseHead() error {
- if len(f.head) != 54 {
- return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
- }
- f.fUnitsPerEm = int32(u16(f.head, 18))
- f.bounds.XMin = int32(int16(u16(f.head, 36)))
- f.bounds.YMin = int32(int16(u16(f.head, 38)))
- f.bounds.XMax = int32(int16(u16(f.head, 40)))
- f.bounds.YMax = int32(int16(u16(f.head, 42)))
- switch i := u16(f.head, 50); i {
- case 0:
- f.locaOffsetFormat = locaOffsetFormatShort
- case 1:
- f.locaOffsetFormat = locaOffsetFormatLong
- default:
- return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i))
- }
- return nil
-}
-
-func (f *Font) parseHhea() error {
- if len(f.hhea) != 36 {
- return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea)))
- }
- f.nHMetric = int(u16(f.hhea, 34))
- if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) {
- return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx)))
- }
- return nil
-}
-
-func (f *Font) parseKern() error {
- // Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says:
- // "Previous versions of the 'kern' table defined both the version and nTables fields in the header
- // as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged
- // (although AAT can sense an old kerning table and still make correct use of it). Microsoft
- // Windows still uses the older format for the 'kern' table and will not recognize the newer one.
- // Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS
- // and Windows should use the old format."
- // Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format,
- // just like the C Freetype implementation.
- if len(f.kern) == 0 {
- if f.nKern != 0 {
- return FormatError("bad kern table length")
- }
- return nil
- }
- if len(f.kern) < 18 {
- return FormatError("kern data too short")
- }
- version, offset := u16(f.kern, 0), 2
- if version != 0 {
- return UnsupportedError(fmt.Sprintf("kern version: %d", version))
- }
- n, offset := u16(f.kern, offset), offset+2
- if n != 1 {
- return UnsupportedError(fmt.Sprintf("kern nTables: %d", n))
- }
- offset += 2
- length, offset := int(u16(f.kern, offset)), offset+2
- coverage, offset := u16(f.kern, offset), offset+2
- if coverage != 0x0001 {
- // We only support horizontal kerning.
- return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage))
- }
- f.nKern, offset = int(u16(f.kern, offset)), offset+2
- if 6*f.nKern != length-14 {
- return FormatError("bad kern table length")
- }
- return nil
-}
-
-func (f *Font) parseMaxp() error {
- if len(f.maxp) != 32 {
- return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp)))
- }
- f.nGlyph = int(u16(f.maxp, 4))
- f.maxTwilightPoints = u16(f.maxp, 16)
- f.maxStorage = u16(f.maxp, 18)
- f.maxFunctionDefs = u16(f.maxp, 20)
- f.maxStackElements = u16(f.maxp, 24)
- return nil
-}
-
-// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
-func (f *Font) scale(x int32) int32 {
- if x >= 0 {
- x += f.fUnitsPerEm / 2
- } else {
- x -= f.fUnitsPerEm / 2
- }
- return x / f.fUnitsPerEm
-}
-
-// Bounds returns the union of a Font's glyphs' bounds.
-func (f *Font) Bounds(scale int32) Bounds {
- b := f.bounds
- b.XMin = f.scale(scale * b.XMin)
- b.YMin = f.scale(scale * b.YMin)
- b.XMax = f.scale(scale * b.XMax)
- b.YMax = f.scale(scale * b.YMax)
- return b
-}
-
-// FUnitsPerEm returns the number of FUnits in a Font's em-square's side.
-func (f *Font) FUnitsPerEm() int32 {
- return f.fUnitsPerEm
-}
-
-// Index returns a Font's index for the given rune.
-func (f *Font) Index(x rune) Index {
- c := uint32(x)
- for i, j := 0, len(f.cm); i < j; {
- h := i + (j-i)/2
- cm := &f.cm[h]
- if c < cm.start {
- j = h
- } else if cm.end < c {
- i = h + 1
- } else if cm.offset == 0 {
- return Index(c + cm.delta)
- } else {
- offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start))
- return Index(u16(f.cmapIndexes, offset))
- }
- }
- return 0
-}
-
-// unscaledHMetric returns the unscaled horizontal metrics for the glyph with
-// the given index.
-func (f *Font) unscaledHMetric(i Index) (h HMetric) {
- j := int(i)
- if j < 0 || f.nGlyph <= j {
- return HMetric{}
- }
- if j >= f.nHMetric {
- p := 4 * (f.nHMetric - 1)
- return HMetric{
- AdvanceWidth: int32(u16(f.hmtx, p)),
- LeftSideBearing: int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
- }
- }
- return HMetric{
- AdvanceWidth: int32(u16(f.hmtx, 4*j)),
- LeftSideBearing: int32(int16(u16(f.hmtx, 4*j+2))),
- }
-}
-
-// HMetric returns the horizontal metrics for the glyph with the given index.
-func (f *Font) HMetric(scale int32, i Index) HMetric {
- h := f.unscaledHMetric(i)
- h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
- h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
- return h
-}
-
-// unscaledVMetric returns the unscaled vertical metrics for the glyph with
-// the given index. yMax is the top of the glyph's bounding box.
-func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
- j := int(i)
- if j < 0 || f.nGlyph <= j {
- return VMetric{}
- }
- if 4*j+4 <= len(f.vmtx) {
- return VMetric{
- AdvanceHeight: int32(u16(f.vmtx, 4*j)),
- TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))),
- }
- }
- // The OS/2 table has grown over time.
- // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html
- // says that it was originally 68 bytes. Optional fields, including
- // the ascender and descender, are described at
- // http://www.microsoft.com/typography/otspec/os2.htm
- if len(f.os2) >= 72 {
- sTypoAscender := int32(int16(u16(f.os2, 68)))
- sTypoDescender := int32(int16(u16(f.os2, 70)))
- return VMetric{
- AdvanceHeight: sTypoAscender - sTypoDescender,
- TopSideBearing: sTypoAscender - yMax,
- }
- }
- return VMetric{
- AdvanceHeight: f.fUnitsPerEm,
- TopSideBearing: 0,
- }
-}
-
-// VMetric returns the vertical metrics for the glyph with the given index.
-func (f *Font) VMetric(scale int32, i Index) VMetric {
- // TODO: should 0 be bounds.YMax?
- v := f.unscaledVMetric(i, 0)
- v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
- v.TopSideBearing = f.scale(scale * v.TopSideBearing)
- return v
-}
-
-// Kerning returns the kerning for the given glyph pair.
-func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
- if f.nKern == 0 {
- return 0
- }
- g := uint32(i0)<<16 | uint32(i1)
- lo, hi := 0, f.nKern
- for lo < hi {
- i := (lo + hi) / 2
- ig := u32(f.kern, 18+6*i)
- if ig < g {
- lo = i + 1
- } else if ig > g {
- hi = i
- } else {
- return f.scale(scale * int32(int16(u16(f.kern, 22+6*i))))
- }
- }
- return 0
-}
-
-// Parse returns a new Font for the given TTF or TTC data.
-//
-// For TrueType Collections, the first font in the collection is parsed.
-func Parse(ttf []byte) (font *Font, err error) {
- return parse(ttf, 0)
-}
-
-func parse(ttf []byte, offset int) (font *Font, err error) {
- if len(ttf)-offset < 12 {
- err = FormatError("TTF data is too short")
- return
- }
- originalOffset := offset
- magic, offset := u32(ttf, offset), offset+4
- switch magic {
- case 0x00010000:
- // No-op.
- case 0x74746366: // "ttcf" as a big-endian uint32.
- if originalOffset != 0 {
- err = FormatError("recursive TTC")
- return
- }
- ttcVersion, offset := u32(ttf, offset), offset+4
- if ttcVersion != 0x00010000 {
- // TODO: support TTC version 2.0, once I have such a .ttc file to test with.
- err = FormatError("bad TTC version")
- return
- }
- numFonts, offset := int(u32(ttf, offset)), offset+4
- if numFonts <= 0 {
- err = FormatError("bad number of TTC fonts")
- return
- }
- if len(ttf[offset:])/4 < numFonts {
- err = FormatError("TTC offset table is too short")
- return
- }
- // TODO: provide an API to select which font in a TrueType collection to return,
- // not just the first one. This may require an API to parse a TTC's name tables,
- // so users of this package can select the font in a TTC by name.
- offset = int(u32(ttf, offset))
- if offset <= 0 || offset > len(ttf) {
- err = FormatError("bad TTC offset")
- return
- }
- return parse(ttf, offset)
- default:
- err = FormatError("bad TTF version")
- return
- }
- n, offset := int(u16(ttf, offset)), offset+2
- if len(ttf) < 16*n+12 {
- err = FormatError("TTF data is too short")
- return
- }
- f := new(Font)
- // Assign the table slices.
- for i := 0; i < n; i++ {
- x := 16*i + 12
- switch string(ttf[x : x+4]) {
- case "cmap":
- f.cmap, err = readTable(ttf, ttf[x+8:x+16])
- case "cvt ":
- f.cvt, err = readTable(ttf, ttf[x+8:x+16])
- case "fpgm":
- f.fpgm, err = readTable(ttf, ttf[x+8:x+16])
- case "glyf":
- f.glyf, err = readTable(ttf, ttf[x+8:x+16])
- case "hdmx":
- f.hdmx, err = readTable(ttf, ttf[x+8:x+16])
- case "head":
- f.head, err = readTable(ttf, ttf[x+8:x+16])
- case "hhea":
- f.hhea, err = readTable(ttf, ttf[x+8:x+16])
- case "hmtx":
- f.hmtx, err = readTable(ttf, ttf[x+8:x+16])
- case "kern":
- f.kern, err = readTable(ttf, ttf[x+8:x+16])
- case "loca":
- f.loca, err = readTable(ttf, ttf[x+8:x+16])
- case "maxp":
- f.maxp, err = readTable(ttf, ttf[x+8:x+16])
- case "OS/2":
- f.os2, err = readTable(ttf, ttf[x+8:x+16])
- case "prep":
- f.prep, err = readTable(ttf, ttf[x+8:x+16])
- case "vmtx":
- f.vmtx, err = readTable(ttf, ttf[x+8:x+16])
- }
- if err != nil {
- return
- }
- }
- // Parse and sanity-check the TTF data.
- if err = f.parseHead(); err != nil {
- return
- }
- if err = f.parseMaxp(); err != nil {
- return
- }
- if err = f.parseCmap(); err != nil {
- return
- }
- if err = f.parseKern(); err != nil {
- return
- }
- if err = f.parseHhea(); err != nil {
- return
- }
- font = f
- return
-}
diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go
deleted file mode 100644
index 9ef6ec8d2..000000000
--- a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go
+++ /dev/null
@@ -1,366 +0,0 @@
-// Copyright 2012 The Freetype-Go Authors. All rights reserved.
-// Use of this source code is governed by your choice of either the
-// FreeType License or the GNU General Public License version 2 (or
-// any later version), both of which can be found in the LICENSE file.
-
-package truetype
-
-import (
- "bufio"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "testing"
-)
-
-func parseTestdataFont(name string) (font *Font, testdataIsOptional bool, err error) {
- b, err := ioutil.ReadFile(fmt.Sprintf("../../testdata/%s.ttf", name))
- if err != nil {
- // The "x-foo" fonts are optional tests, as they are not checked
- // in for copyright or file size reasons.
- return nil, strings.HasPrefix(name, "x-"), fmt.Errorf("%s: ReadFile: %v", name, err)
- }
- font, err = Parse(b)
- if err != nil {
- return nil, true, fmt.Errorf("%s: Parse: %v", name, err)
- }
- return font, false, nil
-}
-
-// TestParse tests that the luxisr.ttf metrics and glyphs are parsed correctly.
-// The numerical values can be manually verified by examining luxisr.ttx.
-func TestParse(t *testing.T) {
- font, _, err := parseTestdataFont("luxisr")
- if err != nil {
- t.Fatal(err)
- }
- if got, want := font.FUnitsPerEm(), int32(2048); got != want {
- t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
- }
- fupe := font.FUnitsPerEm()
- if got, want := font.Bounds(fupe), (Bounds{-441, -432, 2024, 2033}); got != want {
- t.Errorf("Bounds: got %v, want %v", got, want)
- }
-
- i0 := font.Index('A')
- i1 := font.Index('V')
- if i0 != 36 || i1 != 57 {
- t.Fatalf("Index: i0, i1 = %d, %d, want 36, 57", i0, i1)
- }
- if got, want := font.HMetric(fupe, i0), (HMetric{1366, 19}); got != want {
- t.Errorf("HMetric: got %v, want %v", got, want)
- }
- if got, want := font.VMetric(fupe, i0), (VMetric{2465, 553}); got != want {
- t.Errorf("VMetric: got %v, want %v", got, want)
- }
- if got, want := font.Kerning(fupe, i0, i1), int32(-144); got != want {
- t.Errorf("Kerning: got %v, want %v", got, want)
- }
-
- g := NewGlyphBuf()
- err = g.Load(font, fupe, i0, NoHinting)
- if err != nil {
- t.Fatalf("Load: %v", err)
- }
- g0 := &GlyphBuf{
- B: g.B,
- Point: g.Point,
- End: g.End,
- }
- g1 := &GlyphBuf{
- B: Bounds{19, 0, 1342, 1480},
- Point: []Point{
- {19, 0, 51},
- {581, 1480, 1},
- {789, 1480, 51},
- {1342, 0, 1},
- {1116, 0, 35},
- {962, 410, 3},
- {368, 410, 33},
- {214, 0, 3},
- {428, 566, 19},
- {904, 566, 33},
- {667, 1200, 3},
- },
- End: []int{8, 11},
- }
- if got, want := fmt.Sprint(g0), fmt.Sprint(g1); got != want {
- t.Errorf("GlyphBuf:\ngot %v\nwant %v", got, want)
- }
-}
-
-func TestIndex(t *testing.T) {
- testCases := map[string]map[rune]Index{
- "luxisr": {
- ' ': 3,
- '!': 4,
- 'A': 36,
- 'V': 57,
- 'É': 101,
- 'fl': 193,
- '\u22c5': 385,
- '中': 0,
- },
-
- // The x-etc test cases use those versions of the .ttf files provided
- // by Ubuntu 14.04. See testdata/make-other-hinting-txts.sh for details.
-
- "x-arial-bold": {
- ' ': 3,
- '+': 14,
- '0': 19,
- '_': 66,
- 'w': 90,
- '~': 97,
- 'Ä': 98,
- 'fl': 192,
- '½': 242,
- 'σ': 305,
- 'λ': 540,
- 'ỹ': 1275,
- '\u04e9': 1319,
- '中': 0,
- },
- "x-deja-vu-sans-oblique": {
- ' ': 3,
- '*': 13,
- 'Œ': 276,
- 'ω': 861,
- '‡': 2571,
- '⊕': 3110,
- 'fl': 4728,
- '\ufb03': 4729,
- '\ufffd': 4813,
- // TODO: '\U0001f640': ???,
- '中': 0,
- },
- "x-droid-sans-japanese": {
- ' ': 0,
- '\u3000': 3,
- '\u3041': 25,
- '\u30fe': 201,
- '\uff61': 202,
- '\uff67': 208,
- '\uff9e': 263,
- '\uff9f': 264,
- '\u4e00': 265,
- '\u557e': 1000,
- '\u61b6': 2024,
- '\u6ede': 3177,
- '\u7505': 3555,
- '\u81e3': 4602,
- '\u81e5': 4603,
- '\u81e7': 4604,
- '\u81e8': 4605,
- '\u81ea': 4606,
- '\u81ed': 4607,
- '\u81f3': 4608,
- '\u81f4': 4609,
- '\u91c7': 5796,
- '\u9fa0': 6620,
- '\u203e': 12584,
- },
- "x-times-new-roman": {
- ' ': 3,
- ':': 29,
- 'fl': 192,
- 'Ŀ': 273,
- '♠': 388,
- 'Ŗ': 451,
- 'Σ': 520,
- '\u200D': 745,
- 'Ẽ': 1216,
- '\u04e9': 1319,
- '中': 0,
- },
- }
- for name, wants := range testCases {
- font, testdataIsOptional, err := parseTestdataFont(name)
- if err != nil {
- if testdataIsOptional {
- t.Log(err)
- } else {
- t.Fatal(err)
- }
- continue
- }
- for r, want := range wants {
- if got := font.Index(r); got != want {
- t.Errorf("%s: Index of %q, aka %U: got %d, want %d", name, r, r, got, want)
- }
- }
- }
-}
-
-type scalingTestData struct {
- advanceWidth int32
- bounds Bounds
- points []Point
-}
-
-// scalingTestParse parses a line of points like
-// 213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1
-// The line will not have a trailing "\n".
-func scalingTestParse(line string) (ret scalingTestData) {
- next := func(s string) (string, int32) {
- t, i := "", strings.Index(s, " ")
- if i != -1 {
- s, t = s[:i], s[i+1:]
- }
- x, _ := strconv.Atoi(s)
- return t, int32(x)
- }
-
- i := strings.Index(line, ";")
- prefix, line := line[:i], line[i+1:]
-
- prefix, ret.advanceWidth = next(prefix)
- prefix, ret.bounds.XMin = next(prefix)
- prefix, ret.bounds.YMin = next(prefix)
- prefix, ret.bounds.XMax = next(prefix)
- prefix, ret.bounds.YMax = next(prefix)
-
- ret.points = make([]Point, 0, 1+strings.Count(line, ","))
- for len(line) > 0 {
- s := line
- if i := strings.Index(line, ","); i != -1 {
- s, line = line[:i], line[i+1:]
- for len(line) > 0 && line[0] == ' ' {
- line = line[1:]
- }
- } else {
- line = ""
- }
- s, x := next(s)
- s, y := next(s)
- s, f := next(s)
- ret.points = append(ret.points, Point{X: x, Y: y, Flags: uint32(f)})
- }
- return ret
-}
-
-// scalingTestEquals is equivalent to, but faster than, calling
-// reflect.DeepEquals(a, b), and also returns the index of the first non-equal
-// element. It also treats a nil []Point and an empty non-nil []Point as equal.
-// a and b must have equal length.
-func scalingTestEquals(a, b []Point) (index int, equals bool) {
- for i, p := range a {
- if p != b[i] {
- return i, false
- }
- }
- return 0, true
-}
-
-var scalingTestCases = []struct {
- name string
- size int32
-}{
- {"luxisr", 12},
- {"x-arial-bold", 11},
- {"x-deja-vu-sans-oblique", 17},
- {"x-droid-sans-japanese", 9},
- {"x-times-new-roman", 13},
-}
-
-func testScaling(t *testing.T, h Hinting) {
- for _, tc := range scalingTestCases {
- font, testdataIsOptional, err := parseTestdataFont(tc.name)
- if err != nil {
- if testdataIsOptional {
- t.Log(err)
- } else {
- t.Error(err)
- }
- continue
- }
- hintingStr := "sans"
- if h != NoHinting {
- hintingStr = "with"
- }
- f, err := os.Open(fmt.Sprintf(
- "../../testdata/%s-%dpt-%s-hinting.txt", tc.name, tc.size, hintingStr))
- if err != nil {
- t.Errorf("%s: Open: %v", tc.name, err)
- continue
- }
- defer f.Close()
-
- wants := []scalingTestData{}
- scanner := bufio.NewScanner(f)
- if scanner.Scan() {
- major, minor, patch := 0, 0, 0
- _, err := fmt.Sscanf(scanner.Text(), "freetype version %d.%d.%d", &major, &minor, &patch)
- if err != nil {
- t.Errorf("%s: version information: %v", tc.name, err)
- }
- if (major < 2) || (major == 2 && minor < 5) || (major == 2 && minor == 5 && patch < 1) {
- t.Errorf("%s: need freetype version >= 2.5.1.\n"+
- "Try setting LD_LIBRARY_PATH=/path/to/freetype_built_from_src/objs/.libs/\n"+
- "and re-running testdata/make-other-hinting-txts.sh",
- tc.name)
- continue
- }
- } else {
- t.Errorf("%s: no version information", tc.name)
- continue
- }
- for scanner.Scan() {
- wants = append(wants, scalingTestParse(scanner.Text()))
- }
- if err := scanner.Err(); err != nil && err != io.EOF {
- t.Errorf("%s: Scanner: %v", tc.name, err)
- continue
- }
-
- glyphBuf := NewGlyphBuf()
- for i, want := range wants {
- if err = glyphBuf.Load(font, tc.size*64, Index(i), h); err != nil {
- t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
- continue
- }
- got := scalingTestData{
- advanceWidth: glyphBuf.AdvanceWidth,
- bounds: glyphBuf.B,
- points: glyphBuf.Point,
- }
-
- if got.advanceWidth != want.advanceWidth {
- t.Errorf("%s: glyph #%d advance width:\ngot %v\nwant %v",
- tc.name, i, got.advanceWidth, want.advanceWidth)
- continue
- }
-
- if got.bounds != want.bounds {
- t.Errorf("%s: glyph #%d bounds:\ngot %v\nwant %v",
- tc.name, i, got.bounds, want.bounds)
- continue
- }
-
- for i := range got.points {
- got.points[i].Flags &= 0x01
- }
- if len(got.points) != len(want.points) {
- t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\ndifferent slice lengths: %d versus %d",
- tc.name, i, got.points, want.points, len(got.points), len(want.points))
- continue
- }
- if j, equals := scalingTestEquals(got.points, want.points); !equals {
- t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\nat index %d: %v versus %v",
- tc.name, i, got.points, want.points, j, got.points[j], want.points[j])
- continue
- }
- }
- }
-}
-
-func TestScalingSansHinting(t *testing.T) {
- testScaling(t, NoHinting)
-}
-
-func TestScalingWithHinting(t *testing.T) {
- testScaling(t, FullHinting)
-}
diff --git a/api/user.go b/api/user.go
index 6af737df3..79d4bb32c 100644
--- a/api/user.go
+++ b/api/user.go
@@ -5,7 +5,6 @@ package api
import (
"bytes"
- "code.google.com/p/draw2d/draw2d"
l4g "code.google.com/p/log4go"
"fmt"
"github.com/goamz/goamz/aws"
@@ -19,6 +18,7 @@ import (
"hash/fnv"
"image"
"image/color"
+ "image/draw"
_ "image/gif"
_ "image/jpeg"
"image/png"
@@ -602,42 +602,13 @@ func createProfileImage(username string, userId string) ([]byte, *model.AppError
h.Write([]byte(userId))
seed := h.Sum32()
- initials := ""
- parts := strings.Split(username, " ")
-
- for _, v := range parts {
-
- if len(v) > 0 {
- initials += string(strings.ToUpper(v)[0])
- }
- }
-
- if len(initials) == 0 {
- initials = "^"
- }
-
- if len(initials) > 2 {
- initials = initials[0:2]
- }
-
- draw2d.SetFontFolder(utils.FindDir("web/static/fonts"))
- i := image.NewRGBA(image.Rect(0, 0, 128, 128))
- gc := draw2d.NewGraphicContext(i)
- draw2d.Rect(gc, 0, 0, 128, 128)
- gc.SetFillColor(colors[int(seed)%len(colors)])
- gc.Fill()
- gc.SetFontSize(50)
- gc.SetFontData(draw2d.FontData{"luxi", draw2d.FontFamilyMono, draw2d.FontStyleBold | draw2d.FontStyleItalic})
- left, top, right, bottom := gc.GetStringBounds("CH")
- width := (128 - (right - left + 10)) / 2
- height := (128 - (top - bottom + 6)) / 2
- gc.Translate(width, height)
- gc.SetFillColor(image.White)
- gc.FillString(initials)
+ color := colors[int(seed)%len(colors)]
+ img := image.NewRGBA(image.Rect(0, 0, int(utils.Cfg.ImageSettings.ProfileWidth), int(utils.Cfg.ImageSettings.ProfileHeight)))
+ draw.Draw(img, img.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
buf := new(bytes.Buffer)
- if imgErr := png.Encode(buf, i); imgErr != nil {
+ if imgErr := png.Encode(buf, img); imgErr != nil {
return nil, model.NewAppError("getProfileImage", "Could not encode default profile image", imgErr.Error())
} else {
return buf.Bytes(), nil