Этот коммит содержится в:
=Corey Hulen
2015-06-14 23:53:32 -08:00
Коммит 56e74239d6
646 изменённых файлов: 127767 добавлений и 0 удалений

42
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/advanced_path.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
// 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()
}

67
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/arc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,67 @@
// 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)}
}

11
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/Makefile сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,11 @@
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

36
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/arc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,36 @@
// 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)
}

67
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,67 @@
// 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++
}
}
}

696
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,696 @@
// 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
}

262
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/curve_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,262 @@
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)
}
}
}

51
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/quad_float64.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,51 @@
// 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++
}
}
}

336
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curves.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,336 @@
// 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)
}

90
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/dasher.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,90 @@
// 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
}

23
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/demux_converter.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,23 @@
// 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)
}
}

5
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/doc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
// 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

97
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/font.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,97 @@
// 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
}

55
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/gc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,55 @@
// 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)
}

359
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/image.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,359 @@
// 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
}

52
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/math.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,52 @@
// 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
}

92
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/paint.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,92 @@
// 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}
}
*/

27
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,27 @@
// 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()
}

70
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_adder.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,70 @@
// 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)
}
}
}
}

173
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_converter.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,173 @@
// 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
}

190
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/path_storage.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,190 @@
// 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
}

203
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/coverage_table.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,203 @@
// 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
}

320
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerAA.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,320 @@
// 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
}
}
}

303
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV1/fillerAA.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,303 @@
// 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
}
}
}

320
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fillerV2/fillerAA.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,320 @@
// 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
}
}
}

17
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/fixed_point.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,17 @@
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
)

55
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/line.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,55 @@
// 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
}
}
}

581
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/polygon.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,581 @@
// 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
}

200
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/raster/raster_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,200 @@
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)
}
}

150
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/rgba_interpolation.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,150 @@
// 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)
}
}
}
}

208
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stack_gc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,208 @@
// 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
}
}

135
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/stroker.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,135 @@
// 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
}
}

306
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/transform.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,306 @@
// 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)
}

19
Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/vertex2d.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
// 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)
}

280
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/geom.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,280 @@
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
package raster
import (
"fmt"
"math"
)
// A Fix32 is a 24.8 fixed point number.
type Fix32 int32
// A Fix64 is a 48.16 fixed point number.
type Fix64 int64
// String returns a human-readable representation of a 24.8 fixed point number.
// For example, the number one-and-a-quarter becomes "1:064".
func (x Fix32) String() string {
if x < 0 {
x = -x
return fmt.Sprintf("-%d:%03d", int32(x/256), int32(x%256))
}
return fmt.Sprintf("%d:%03d", int32(x/256), int32(x%256))
}
// String returns a human-readable representation of a 48.16 fixed point number.
// For example, the number one-and-a-quarter becomes "1:16384".
func (x Fix64) String() string {
if x < 0 {
x = -x
return fmt.Sprintf("-%d:%05d", int64(x/65536), int64(x%65536))
}
return fmt.Sprintf("%d:%05d", int64(x/65536), int64(x%65536))
}
// maxAbs returns the maximum of abs(a) and abs(b).
func maxAbs(a, b Fix32) Fix32 {
if a < 0 {
a = -a
}
if b < 0 {
b = -b
}
if a < b {
return b
}
return a
}
// A Point represents a two-dimensional point or vector, in 24.8 fixed point
// format.
type Point struct {
X, Y Fix32
}
// String returns a human-readable representation of a Point.
func (p Point) String() string {
return "(" + p.X.String() + ", " + p.Y.String() + ")"
}
// Add returns the vector p + q.
func (p Point) Add(q Point) Point {
return Point{p.X + q.X, p.Y + q.Y}
}
// Sub returns the vector p - q.
func (p Point) Sub(q Point) Point {
return Point{p.X - q.X, p.Y - q.Y}
}
// Mul returns the vector k * p.
func (p Point) Mul(k Fix32) Point {
return Point{p.X * k / 256, p.Y * k / 256}
}
// Neg returns the vector -p, or equivalently p rotated by 180 degrees.
func (p Point) Neg() Point {
return Point{-p.X, -p.Y}
}
// Dot returns the dot product p·q.
func (p Point) Dot(q Point) Fix64 {
px, py := int64(p.X), int64(p.Y)
qx, qy := int64(q.X), int64(q.Y)
return Fix64(px*qx + py*qy)
}
// Len returns the length of the vector p.
func (p Point) Len() Fix32 {
// TODO(nigeltao): use fixed point math.
x := float64(p.X)
y := float64(p.Y)
return Fix32(math.Sqrt(x*x + y*y))
}
// Norm returns the vector p normalized to the given length, or the zero Point
// if p is degenerate.
func (p Point) Norm(length Fix32) Point {
d := p.Len()
if d == 0 {
return Point{}
}
s, t := int64(length), int64(d)
x := int64(p.X) * s / t
y := int64(p.Y) * s / t
return Point{Fix32(x), Fix32(y)}
}
// Rot45CW returns the vector p rotated clockwise by 45 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot45CW is {1/√2, 1/√2}.
func (p Point) Rot45CW() Point {
// 181/256 is approximately 1/√2, or sin(π/4).
px, py := int64(p.X), int64(p.Y)
qx := (+px - py) * 181 / 256
qy := (+px + py) * 181 / 256
return Point{Fix32(qx), Fix32(qy)}
}
// Rot90CW returns the vector p rotated clockwise by 90 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}.
func (p Point) Rot90CW() Point {
return Point{-p.Y, p.X}
}
// Rot135CW returns the vector p rotated clockwise by 135 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot135CW is {-1/√2, 1/√2}.
func (p Point) Rot135CW() Point {
// 181/256 is approximately 1/√2, or sin(π/4).
px, py := int64(p.X), int64(p.Y)
qx := (-px - py) * 181 / 256
qy := (+px - py) * 181 / 256
return Point{Fix32(qx), Fix32(qy)}
}
// Rot45CCW returns the vector p rotated counter-clockwise by 45 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}.
func (p Point) Rot45CCW() Point {
// 181/256 is approximately 1/√2, or sin(π/4).
px, py := int64(p.X), int64(p.Y)
qx := (+px + py) * 181 / 256
qy := (-px + py) * 181 / 256
return Point{Fix32(qx), Fix32(qy)}
}
// Rot90CCW returns the vector p rotated counter-clockwise by 90 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot90CCW is {0, -1}.
func (p Point) Rot90CCW() Point {
return Point{p.Y, -p.X}
}
// Rot135CCW returns the vector p rotated counter-clockwise by 135 degrees.
// Note that the Y-axis grows downwards, so {1, 0}.Rot135CCW is {-1/√2, -1/√2}.
func (p Point) Rot135CCW() Point {
// 181/256 is approximately 1/√2, or sin(π/4).
px, py := int64(p.X), int64(p.Y)
qx := (-px + py) * 181 / 256
qy := (-px - py) * 181 / 256
return Point{Fix32(qx), Fix32(qy)}
}
// An Adder accumulates points on a curve.
type Adder interface {
// Start starts a new curve at the given point.
Start(a Point)
// Add1 adds a linear segment to the current curve.
Add1(b Point)
// Add2 adds a quadratic segment to the current curve.
Add2(b, c Point)
// Add3 adds a cubic segment to the current curve.
Add3(b, c, d Point)
}
// A Path is a sequence of curves, and a curve is a start point followed by a
// sequence of linear, quadratic or cubic segments.
type Path []Fix32
// String returns a human-readable representation of a Path.
func (p Path) String() string {
s := ""
for i := 0; i < len(p); {
if i != 0 {
s += " "
}
switch p[i] {
case 0:
s += "S0" + fmt.Sprint([]Fix32(p[i+1:i+3]))
i += 4
case 1:
s += "A1" + fmt.Sprint([]Fix32(p[i+1:i+3]))
i += 4
case 2:
s += "A2" + fmt.Sprint([]Fix32(p[i+1:i+5]))
i += 6
case 3:
s += "A3" + fmt.Sprint([]Fix32(p[i+1:i+7]))
i += 8
default:
panic("freetype/raster: bad path")
}
}
return s
}
// Clear cancels any previous calls to p.Start or p.AddXxx.
func (p *Path) Clear() {
*p = (*p)[:0]
}
// Start starts a new curve at the given point.
func (p *Path) Start(a Point) {
*p = append(*p, 0, a.X, a.Y, 0)
}
// Add1 adds a linear segment to the current curve.
func (p *Path) Add1(b Point) {
*p = append(*p, 1, b.X, b.Y, 1)
}
// Add2 adds a quadratic segment to the current curve.
func (p *Path) Add2(b, c Point) {
*p = append(*p, 2, b.X, b.Y, c.X, c.Y, 2)
}
// Add3 adds a cubic segment to the current curve.
func (p *Path) Add3(b, c, d Point) {
*p = append(*p, 3, b.X, b.Y, c.X, c.Y, d.X, d.Y, 3)
}
// AddPath adds the Path q to p.
func (p *Path) AddPath(q Path) {
*p = append(*p, q...)
}
// AddStroke adds a stroked Path.
func (p *Path) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
Stroke(p, q, width, cr, jr)
}
// firstPoint returns the first point in a non-empty Path.
func (p Path) firstPoint() Point {
return Point{p[1], p[2]}
}
// lastPoint returns the last point in a non-empty Path.
func (p Path) lastPoint() Point {
return Point{p[len(p)-3], p[len(p)-2]}
}
// addPathReversed adds q reversed to p.
// For example, if q consists of a linear segment from A to B followed by a
// quadratic segment from B to C to D, then the values of q looks like:
// index: 01234567890123
// value: 0AA01BB12CCDD2
// So, when adding q backwards to p, we want to Add2(C, B) followed by Add1(A).
func addPathReversed(p Adder, q Path) {
if len(q) == 0 {
return
}
i := len(q) - 1
for {
switch q[i] {
case 0:
return
case 1:
i -= 4
p.Add1(Point{q[i-2], q[i-1]})
case 2:
i -= 6
p.Add2(Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
case 3:
i -= 8
p.Add3(Point{q[i+4], q[i+5]}, Point{q[i+2], q[i+3]}, Point{q[i-2], q[i-1]})
default:
panic("freetype/raster: bad path")
}
}
}

292
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/paint.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,292 @@
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
package raster
import (
"image"
"image/color"
"image/draw"
"math"
)
// A Span is a horizontal segment of pixels with constant alpha. X0 is an
// inclusive bound and X1 is exclusive, the same as for slices. A fully
// opaque Span has A == 1<<32 - 1.
type Span struct {
Y, X0, X1 int
A uint32
}
// A Painter knows how to paint a batch of Spans. Rasterization may involve
// Painting multiple batches, and done will be true for the final batch.
// The Spans' Y values are monotonically increasing during a rasterization.
// Paint may use all of ss as scratch space during the call.
type Painter interface {
Paint(ss []Span, done bool)
}
// The PainterFunc type adapts an ordinary function to the Painter interface.
type PainterFunc func(ss []Span, done bool)
// Paint just delegates the call to f.
func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
// An AlphaOverPainter is a Painter that paints Spans onto an image.Alpha
// using the Over Porter-Duff composition operator.
type AlphaOverPainter struct {
Image *image.Alpha
}
// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
func (r AlphaOverPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds()
for _, s := range ss {
if s.Y < b.Min.Y {
continue
}
if s.Y >= b.Max.Y {
return
}
if s.X0 < b.Min.X {
s.X0 = b.Min.X
}
if s.X1 > b.Max.X {
s.X1 = b.Max.X
}
if s.X0 >= s.X1 {
continue
}
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
p := r.Image.Pix[base+s.X0 : base+s.X1]
a := int(s.A >> 24)
for i, c := range p {
v := int(c)
p[i] = uint8((v*255 + (255-v)*a) / 255)
}
}
}
// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
return AlphaOverPainter{m}
}
// An AlphaSrcPainter is a Painter that paints Spans onto an image.Alpha
// using the Src Porter-Duff composition operator.
type AlphaSrcPainter struct {
Image *image.Alpha
}
// Paint satisfies the Painter interface by painting ss onto an image.Alpha.
func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds()
for _, s := range ss {
if s.Y < b.Min.Y {
continue
}
if s.Y >= b.Max.Y {
return
}
if s.X0 < b.Min.X {
s.X0 = b.Min.X
}
if s.X1 > b.Max.X {
s.X1 = b.Max.X
}
if s.X0 >= s.X1 {
continue
}
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
p := r.Image.Pix[base+s.X0 : base+s.X1]
color := uint8(s.A >> 24)
for i := range p {
p[i] = color
}
}
}
// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
return AlphaSrcPainter{m}
}
type RGBAPainter struct {
// The image to compose onto.
Image *image.RGBA
// The Porter-Duff composition operator.
Op draw.Op
// The 16-bit color to paint the spans.
cr, cg, cb, ca uint32
}
// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
func (r *RGBAPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds()
for _, s := range ss {
if s.Y < b.Min.Y {
continue
}
if s.Y >= b.Max.Y {
return
}
if s.X0 < b.Min.X {
s.X0 = b.Min.X
}
if s.X1 > b.Max.X {
s.X1 = b.Max.X
}
if s.X0 >= s.X1 {
continue
}
// This code is similar to drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go.
ma := s.A >> 16
const m = 1<<16 - 1
i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
i1 := i0 + (s.X1-s.X0)*4
if r.Op == draw.Over {
for i := i0; i < i1; i += 4 {
dr := uint32(r.Image.Pix[i+0])
dg := uint32(r.Image.Pix[i+1])
db := uint32(r.Image.Pix[i+2])
da := uint32(r.Image.Pix[i+3])
a := (m - (r.ca * ma / m)) * 0x101
r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
}
} else {
for i := i0; i < i1; i += 4 {
r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
}
}
}
}
// SetColor sets the color to paint the spans.
func (r *RGBAPainter) SetColor(c color.Color) {
r.cr, r.cg, r.cb, r.ca = c.RGBA()
}
// NewRGBAPainter creates a new RGBAPainter for the given image.
func NewRGBAPainter(m *image.RGBA) *RGBAPainter {
return &RGBAPainter{Image: m}
}
// A MonochromePainter wraps another Painter, quantizing each Span's alpha to
// be either fully opaque or fully transparent.
type MonochromePainter struct {
Painter Painter
y, x0, x1 int
}
// Paint delegates to the wrapped Painter after quantizing each Span's alpha
// value and merging adjacent fully opaque Spans.
func (m *MonochromePainter) Paint(ss []Span, done bool) {
// We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
j := 0
for _, s := range ss {
if s.A >= 1<<31 {
if m.y == s.Y && m.x1 == s.X0 {
m.x1 = s.X1
} else {
ss[j] = Span{m.y, m.x0, m.x1, 1<<32 - 1}
j++
m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
}
}
}
if done {
// Flush the accumulated Span.
finalSpan := Span{m.y, m.x0, m.x1, 1<<32 - 1}
if j < len(ss) {
ss[j] = finalSpan
j++
m.Painter.Paint(ss[:j], true)
} else if j == len(ss) {
m.Painter.Paint(ss, false)
if cap(ss) > 0 {
ss = ss[:1]
} else {
ss = make([]Span, 1)
}
ss[0] = finalSpan
m.Painter.Paint(ss, true)
} else {
panic("unreachable")
}
// Reset the accumulator, so that this Painter can be re-used.
m.y, m.x0, m.x1 = 0, 0, 0
} else {
m.Painter.Paint(ss[:j], false)
}
}
// NewMonochromePainter creates a new MonochromePainter that wraps the given
// Painter.
func NewMonochromePainter(p Painter) *MonochromePainter {
return &MonochromePainter{Painter: p}
}
// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
// on each Span's alpha value.
type GammaCorrectionPainter struct {
// The wrapped Painter.
Painter Painter
// Precomputed alpha values for linear interpolation, with fully opaque == 1<<16-1.
a [256]uint16
// Whether gamma correction is a no-op.
gammaIsOne bool
}
// Paint delegates to the wrapped Painter after performing gamma-correction
// on each Span.
func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
if !g.gammaIsOne {
const (
M = 0x1010101 // 255*M == 1<<32-1
N = 0x8080 // N = M>>9, and N < 1<<16-1
)
for i, s := range ss {
if s.A == 0 || s.A == 1<<32-1 {
continue
}
p, q := s.A/M, (s.A%M)>>9
// The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
a := uint32(g.a[p])*(N-q) + uint32(g.a[p+1])*q
a = (a + N/2) / N
// Convert the alpha from 16-bit (which is g.a's range) to 32-bit.
a |= a << 16
ss[i].A = a
}
}
g.Painter.Paint(ss, done)
}
// SetGamma sets the gamma value.
func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
if gamma == 1.0 {
g.gammaIsOne = true
return
}
g.gammaIsOne = false
for i := 0; i < 256; i++ {
a := float64(i) / 0xff
a = math.Pow(a, gamma)
g.a[i] = uint16(0xffff * a)
}
}
// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
// the given Painter.
func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
g := &GammaCorrectionPainter{Painter: p}
g.SetGamma(gamma)
return g
}

579
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/raster.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,579 @@
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
// The raster package provides an anti-aliasing 2-D rasterizer.
//
// It is part of the larger Freetype-Go suite of font-related packages,
// but the raster package is not specific to font rasterization, and can
// be used standalone without any other Freetype-Go package.
//
// Rasterization is done by the same area/coverage accumulation algorithm
// as the Freetype "smooth" module, and the Anti-Grain Geometry library.
// A description of the area/coverage algorithm is at
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
package raster
import (
"strconv"
)
// A cell is part of a linked list (for a given yi co-ordinate) of accumulated
// area/coverage for the pixel at (xi, yi).
type cell struct {
xi int
area, cover int
next int
}
type Rasterizer struct {
// If false, the default behavior is to use the even-odd winding fill
// rule during Rasterize.
UseNonZeroWinding bool
// An offset (in pixels) to the painted spans.
Dx, Dy int
// The width of the Rasterizer. The height is implicit in len(cellIndex).
width int
// splitScaleN is the scaling factor used to determine how many times
// to decompose a quadratic or cubic segment into a linear approximation.
splitScale2, splitScale3 int
// The current pen position.
a Point
// The current cell and its area/coverage being accumulated.
xi, yi int
area, cover int
// Saved cells.
cell []cell
// Linked list of cells, one per row.
cellIndex []int
// Buffers.
cellBuf [256]cell
cellIndexBuf [64]int
spanBuf [64]Span
}
// findCell returns the index in r.cell for the cell corresponding to
// (r.xi, r.yi). The cell is created if necessary.
func (r *Rasterizer) findCell() int {
if r.yi < 0 || r.yi >= len(r.cellIndex) {
return -1
}
xi := r.xi
if xi < 0 {
xi = -1
} else if xi > r.width {
xi = r.width
}
i, prev := r.cellIndex[r.yi], -1
for i != -1 && r.cell[i].xi <= xi {
if r.cell[i].xi == xi {
return i
}
i, prev = r.cell[i].next, i
}
c := len(r.cell)
if c == cap(r.cell) {
buf := make([]cell, c, 4*c)
copy(buf, r.cell)
r.cell = buf[0 : c+1]
} else {
r.cell = r.cell[0 : c+1]
}
r.cell[c] = cell{xi, 0, 0, i}
if prev == -1 {
r.cellIndex[r.yi] = c
} else {
r.cell[prev].next = c
}
return c
}
// saveCell saves any accumulated r.area/r.cover for (r.xi, r.yi).
func (r *Rasterizer) saveCell() {
if r.area != 0 || r.cover != 0 {
i := r.findCell()
if i != -1 {
r.cell[i].area += r.area
r.cell[i].cover += r.cover
}
r.area = 0
r.cover = 0
}
}
// setCell sets the (xi, yi) cell that r is accumulating area/coverage for.
func (r *Rasterizer) setCell(xi, yi int) {
if r.xi != xi || r.yi != yi {
r.saveCell()
r.xi, r.yi = xi, yi
}
}
// scan accumulates area/coverage for the yi'th scanline, going from
// x0 to x1 in the horizontal direction (in 24.8 fixed point co-ordinates)
// and from y0f to y1f fractional vertical units within that scanline.
func (r *Rasterizer) scan(yi int, x0, y0f, x1, y1f Fix32) {
// Break the 24.8 fixed point X co-ordinates into integral and fractional parts.
x0i := int(x0) / 256
x0f := x0 - Fix32(256*x0i)
x1i := int(x1) / 256
x1f := x1 - Fix32(256*x1i)
// A perfectly horizontal scan.
if y0f == y1f {
r.setCell(x1i, yi)
return
}
dx, dy := x1-x0, y1f-y0f
// A single cell scan.
if x0i == x1i {
r.area += int((x0f + x1f) * dy)
r.cover += int(dy)
return
}
// There are at least two cells. Apart from the first and last cells,
// all intermediate cells go through the full width of the cell,
// or 256 units in 24.8 fixed point format.
var (
p, q, edge0, edge1 Fix32
xiDelta int
)
if dx > 0 {
p, q = (256-x0f)*dy, dx
edge0, edge1, xiDelta = 0, 256, 1
} else {
p, q = x0f*dy, -dx
edge0, edge1, xiDelta = 256, 0, -1
}
yDelta, yRem := p/q, p%q
if yRem < 0 {
yDelta -= 1
yRem += q
}
// Do the first cell.
xi, y := x0i, y0f
r.area += int((x0f + edge1) * yDelta)
r.cover += int(yDelta)
xi, y = xi+xiDelta, y+yDelta
r.setCell(xi, yi)
if xi != x1i {
// Do all the intermediate cells.
p = 256 * (y1f - y + yDelta)
fullDelta, fullRem := p/q, p%q
if fullRem < 0 {
fullDelta -= 1
fullRem += q
}
yRem -= q
for xi != x1i {
yDelta = fullDelta
yRem += fullRem
if yRem >= 0 {
yDelta += 1
yRem -= q
}
r.area += int(256 * yDelta)
r.cover += int(yDelta)
xi, y = xi+xiDelta, y+yDelta
r.setCell(xi, yi)
}
}
// Do the last cell.
yDelta = y1f - y
r.area += int((edge0 + x1f) * yDelta)
r.cover += int(yDelta)
}
// Start starts a new curve at the given point.
func (r *Rasterizer) Start(a Point) {
r.setCell(int(a.X/256), int(a.Y/256))
r.a = a
}
// Add1 adds a linear segment to the current curve.
func (r *Rasterizer) Add1(b Point) {
x0, y0 := r.a.X, r.a.Y
x1, y1 := b.X, b.Y
dx, dy := x1-x0, y1-y0
// Break the 24.8 fixed point Y co-ordinates into integral and fractional parts.
y0i := int(y0) / 256
y0f := y0 - Fix32(256*y0i)
y1i := int(y1) / 256
y1f := y1 - Fix32(256*y1i)
if y0i == y1i {
// There is only one scanline.
r.scan(y0i, x0, y0f, x1, y1f)
} else if dx == 0 {
// This is a vertical line segment. We avoid calling r.scan and instead
// manipulate r.area and r.cover directly.
var (
edge0, edge1 Fix32
yiDelta int
)
if dy > 0 {
edge0, edge1, yiDelta = 0, 256, 1
} else {
edge0, edge1, yiDelta = 256, 0, -1
}
x0i, yi := int(x0)/256, y0i
x0fTimes2 := (int(x0) - (256 * x0i)) * 2
// Do the first pixel.
dcover := int(edge1 - y0f)
darea := int(x0fTimes2 * dcover)
r.area += darea
r.cover += dcover
yi += yiDelta
r.setCell(x0i, yi)
// Do all the intermediate pixels.
dcover = int(edge1 - edge0)
darea = int(x0fTimes2 * dcover)
for yi != y1i {
r.area += darea
r.cover += dcover
yi += yiDelta
r.setCell(x0i, yi)
}
// Do the last pixel.
dcover = int(y1f - edge0)
darea = int(x0fTimes2 * dcover)
r.area += darea
r.cover += dcover
} else {
// There are at least two scanlines. Apart from the first and last scanlines,
// all intermediate scanlines go through the full height of the row, or 256
// units in 24.8 fixed point format.
var (
p, q, edge0, edge1 Fix32
yiDelta int
)
if dy > 0 {
p, q = (256-y0f)*dx, dy
edge0, edge1, yiDelta = 0, 256, 1
} else {
p, q = y0f*dx, -dy
edge0, edge1, yiDelta = 256, 0, -1
}
xDelta, xRem := p/q, p%q
if xRem < 0 {
xDelta -= 1
xRem += q
}
// Do the first scanline.
x, yi := x0, y0i
r.scan(yi, x, y0f, x+xDelta, edge1)
x, yi = x+xDelta, yi+yiDelta
r.setCell(int(x)/256, yi)
if yi != y1i {
// Do all the intermediate scanlines.
p = 256 * dx
fullDelta, fullRem := p/q, p%q
if fullRem < 0 {
fullDelta -= 1
fullRem += q
}
xRem -= q
for yi != y1i {
xDelta = fullDelta
xRem += fullRem
if xRem >= 0 {
xDelta += 1
xRem -= q
}
r.scan(yi, x, edge0, x+xDelta, edge1)
x, yi = x+xDelta, yi+yiDelta
r.setCell(int(x)/256, yi)
}
}
// Do the last scanline.
r.scan(yi, x, edge0, x1, y1f)
}
// The next lineTo starts from b.
r.a = b
}
// Add2 adds a quadratic segment to the current curve.
func (r *Rasterizer) Add2(b, c Point) {
// Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
// Specifically, how much the middle point b deviates from (a+c)/2.
dev := maxAbs(r.a.X-2*b.X+c.X, r.a.Y-2*b.Y+c.Y) / Fix32(r.splitScale2)
nsplit := 0
for dev > 0 {
dev /= 4
nsplit++
}
// dev is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
const maxNsplit = 16
if nsplit > maxNsplit {
panic("freetype/raster: Add2 nsplit too large: " + strconv.Itoa(nsplit))
}
// Recursively decompose the curve nSplit levels deep.
var (
pStack [2*maxNsplit + 3]Point
sStack [maxNsplit + 1]int
i int
)
sStack[0] = nsplit
pStack[0] = c
pStack[1] = b
pStack[2] = r.a
for i >= 0 {
s := sStack[i]
p := pStack[2*i:]
if s > 0 {
// Split the quadratic curve p[:3] into an equivalent set of two shorter curves:
// p[:3] and p[2:5]. The new p[4] is the old p[2], and p[0] is unchanged.
mx := p[1].X
p[4].X = p[2].X
p[3].X = (p[4].X + mx) / 2
p[1].X = (p[0].X + mx) / 2
p[2].X = (p[1].X + p[3].X) / 2
my := p[1].Y
p[4].Y = p[2].Y
p[3].Y = (p[4].Y + my) / 2
p[1].Y = (p[0].Y + my) / 2
p[2].Y = (p[1].Y + p[3].Y) / 2
// The two shorter curves have one less split to do.
sStack[i] = s - 1
sStack[i+1] = s - 1
i++
} else {
// Replace the level-0 quadratic with a two-linear-piece approximation.
midx := (p[0].X + 2*p[1].X + p[2].X) / 4
midy := (p[0].Y + 2*p[1].Y + p[2].Y) / 4
r.Add1(Point{midx, midy})
r.Add1(p[0])
i--
}
}
}
// Add3 adds a cubic segment to the current curve.
func (r *Rasterizer) Add3(b, c, d Point) {
// Calculate nSplit (the number of recursive decompositions) based on how `curvy' it is.
dev2 := maxAbs(r.a.X-3*(b.X+c.X)+d.X, r.a.Y-3*(b.Y+c.Y)+d.Y) / Fix32(r.splitScale2)
dev3 := maxAbs(r.a.X-2*b.X+d.X, r.a.Y-2*b.Y+d.Y) / Fix32(r.splitScale3)
nsplit := 0
for dev2 > 0 || dev3 > 0 {
dev2 /= 8
dev3 /= 4
nsplit++
}
// devN is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit is 16.
const maxNsplit = 16
if nsplit > maxNsplit {
panic("freetype/raster: Add3 nsplit too large: " + strconv.Itoa(nsplit))
}
// Recursively decompose the curve nSplit levels deep.
var (
pStack [3*maxNsplit + 4]Point
sStack [maxNsplit + 1]int
i int
)
sStack[0] = nsplit
pStack[0] = d
pStack[1] = c
pStack[2] = b
pStack[3] = r.a
for i >= 0 {
s := sStack[i]
p := pStack[3*i:]
if s > 0 {
// Split the cubic curve p[:4] into an equivalent set of two shorter curves:
// p[:4] and p[3:7]. The new p[6] is the old p[3], and p[0] is unchanged.
m01x := (p[0].X + p[1].X) / 2
m12x := (p[1].X + p[2].X) / 2
m23x := (p[2].X + p[3].X) / 2
p[6].X = p[3].X
p[5].X = m23x
p[1].X = m01x
p[2].X = (m01x + m12x) / 2
p[4].X = (m12x + m23x) / 2
p[3].X = (p[2].X + p[4].X) / 2
m01y := (p[0].Y + p[1].Y) / 2
m12y := (p[1].Y + p[2].Y) / 2
m23y := (p[2].Y + p[3].Y) / 2
p[6].Y = p[3].Y
p[5].Y = m23y
p[1].Y = m01y
p[2].Y = (m01y + m12y) / 2
p[4].Y = (m12y + m23y) / 2
p[3].Y = (p[2].Y + p[4].Y) / 2
// The two shorter curves have one less split to do.
sStack[i] = s - 1
sStack[i+1] = s - 1
i++
} else {
// Replace the level-0 cubic with a two-linear-piece approximation.
midx := (p[0].X + 3*(p[1].X+p[2].X) + p[3].X) / 8
midy := (p[0].Y + 3*(p[1].Y+p[2].Y) + p[3].Y) / 8
r.Add1(Point{midx, midy})
r.Add1(p[0])
i--
}
}
}
// AddPath adds the given Path.
func (r *Rasterizer) AddPath(p Path) {
for i := 0; i < len(p); {
switch p[i] {
case 0:
r.Start(Point{p[i+1], p[i+2]})
i += 4
case 1:
r.Add1(Point{p[i+1], p[i+2]})
i += 4
case 2:
r.Add2(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]})
i += 6
case 3:
r.Add3(Point{p[i+1], p[i+2]}, Point{p[i+3], p[i+4]}, Point{p[i+5], p[i+6]})
i += 8
default:
panic("freetype/raster: bad path")
}
}
}
// AddStroke adds a stroked Path.
func (r *Rasterizer) AddStroke(q Path, width Fix32, cr Capper, jr Joiner) {
Stroke(r, q, width, cr, jr)
}
// Converts an area value to a uint32 alpha value. A completely filled pixel
// corresponds to an area of 256*256*2, and an alpha of 1<<32-1. The
// conversion of area values greater than this depends on the winding rule:
// even-odd or non-zero.
func (r *Rasterizer) areaToAlpha(area int) uint32 {
// The C Freetype implementation (version 2.3.12) does "alpha := area>>1" without
// the +1. Round-to-nearest gives a more symmetric result than round-down.
// The C implementation also returns 8-bit alpha, not 32-bit alpha.
a := (area + 1) >> 1
if a < 0 {
a = -a
}
alpha := uint32(a)
if r.UseNonZeroWinding {
if alpha > 0xffff {
alpha = 0xffff
}
} else {
alpha &= 0x1ffff
if alpha > 0x10000 {
alpha = 0x20000 - alpha
} else if alpha == 0x10000 {
alpha = 0x0ffff
}
}
alpha |= alpha << 16
return alpha
}
// Rasterize converts r's accumulated curves into Spans for p. The Spans
// passed to p are non-overlapping, and sorted by Y and then X. They all
// have non-zero width (and 0 <= X0 < X1 <= r.width) and non-zero A, except
// for the final Span, which has Y, X0, X1 and A all equal to zero.
func (r *Rasterizer) Rasterize(p Painter) {
r.saveCell()
s := 0
for yi := 0; yi < len(r.cellIndex); yi++ {
xi, cover := 0, 0
for c := r.cellIndex[yi]; c != -1; c = r.cell[c].next {
if cover != 0 && r.cell[c].xi > xi {
alpha := r.areaToAlpha(cover * 256 * 2)
if alpha != 0 {
xi0, xi1 := xi, r.cell[c].xi
if xi0 < 0 {
xi0 = 0
}
if xi1 >= r.width {
xi1 = r.width
}
if xi0 < xi1 {
r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
s++
}
}
}
cover += r.cell[c].cover
alpha := r.areaToAlpha(cover*256*2 - r.cell[c].area)
xi = r.cell[c].xi + 1
if alpha != 0 {
xi0, xi1 := r.cell[c].xi, xi
if xi0 < 0 {
xi0 = 0
}
if xi1 >= r.width {
xi1 = r.width
}
if xi0 < xi1 {
r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha}
s++
}
}
if s > len(r.spanBuf)-2 {
p.Paint(r.spanBuf[:s], false)
s = 0
}
}
}
p.Paint(r.spanBuf[:s], true)
}
// Clear cancels any previous calls to r.Start or r.AddXxx.
func (r *Rasterizer) Clear() {
r.a = Point{}
r.xi = 0
r.yi = 0
r.area = 0
r.cover = 0
r.cell = r.cell[:0]
for i := 0; i < len(r.cellIndex); i++ {
r.cellIndex[i] = -1
}
}
// SetBounds sets the maximum width and height of the rasterized image and
// calls Clear. The width and height are in pixels, not Fix32 units.
func (r *Rasterizer) SetBounds(width, height int) {
if width < 0 {
width = 0
}
if height < 0 {
height = 0
}
// Use the same ssN heuristic as the C Freetype implementation.
// The C implementation uses the values 32, 16, but those are in
// 26.6 fixed point units, and we use 24.8 fixed point everywhere.
ss2, ss3 := 128, 64
if width > 24 || height > 24 {
ss2, ss3 = 2*ss2, 2*ss3
if width > 120 || height > 120 {
ss2, ss3 = 2*ss2, 2*ss3
}
}
r.width = width
r.splitScale2 = ss2
r.splitScale3 = ss3
r.cell = r.cellBuf[:0]
if height > len(r.cellIndexBuf) {
r.cellIndex = make([]int, height)
} else {
r.cellIndex = r.cellIndexBuf[:height]
}
r.Clear()
}
// NewRasterizer creates a new Rasterizer with the given bounds.
func NewRasterizer(width, height int) *Rasterizer {
r := new(Rasterizer)
r.SetBounds(width, height)
return r
}

466
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/raster/stroke.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,466 @@
// 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
// |xy″-yx″| / (x²+y²)^(3/2).
//
// Let d = b-a and e = c-2*b+a, so that f(t) = 2*d+2*e*t and f″(t) = 2*e.
// The curvature's numerator is (2*dx+2*ex*t)*(2*ey)-(2*dy+2*ey*t)*(2*ex),
// which simplifies to 4*dx*ey-4*dy*ex, which is constant with respect to t.
//
// Thus, curvature is extreme where the denominator is extreme, i.e. where
// (x²+y²) is extreme. The first order condition is that
// 2*x*x″+2*y*y″ = 0, or (dx+ex*t)*ex + (dy+ey*t)*ey = 0.
// Solving for t gives t = -(dx*ex+dy*ey) / (ex*ex+ey*ey).
func curviest2(a, b, c Point) Fix64 {
dx := int64(b.X - a.X)
dy := int64(b.Y - a.Y)
ex := int64(c.X - 2*b.X + a.X)
ey := int64(c.Y - 2*b.Y + a.Y)
if ex == 0 && ey == 0 {
return 32768
}
return Fix64(-65536 * (dx*ex + dy*ey) / (ex*ex + ey*ey))
}
// A stroker holds state for stroking a path.
type stroker struct {
// p is the destination that records the stroked path.
p Adder
// u is the half-width of the stroke.
u Fix32
// cr and jr specify how to end and connect path segments.
cr Capper
jr Joiner
// r is the reverse path. Stroking a path involves constructing two
// parallel paths 2*u apart. The first path is added immediately to p,
// the second path is accumulated in r and eventually added in reverse.
r Path
// a is the most recent segment point. anorm is the segment normal of
// length u at that point.
a, anorm Point
}
// addNonCurvy2 adds a quadratic segment to the stroker, where the segment
// defined by (k.a, b, c) achieves maximum curvature at either k.a or c.
func (k *stroker) addNonCurvy2(b, c Point) {
// We repeatedly divide the segment at its middle until it is straight
// enough to approximate the stroke by just translating the control points.
// ds and ps are stacks of depths and points. t is the top of the stack.
const maxDepth = 5
var (
ds [maxDepth + 1]int
ps [2*maxDepth + 3]Point
t int
)
// Initially the ps stack has one quadratic segment of depth zero.
ds[0] = 0
ps[2] = k.a
ps[1] = b
ps[0] = c
anorm := k.anorm
var cnorm Point
for {
depth := ds[t]
a := ps[2*t+2]
b := ps[2*t+1]
c := ps[2*t+0]
ab := b.Sub(a)
bc := c.Sub(b)
abIsSmall := ab.Dot(ab) < Fix64(1<<16)
bcIsSmall := bc.Dot(bc) < Fix64(1<<16)
if abIsSmall && bcIsSmall {
// Approximate the segment by a circular arc.
cnorm = bc.Norm(k.u).Rot90CCW()
mac := midpoint(a, c)
addArc(k.p, mac, anorm, cnorm)
addArc(&k.r, mac, anorm.Neg(), cnorm.Neg())
} else if depth < maxDepth && angleGreaterThan45(ab, bc) {
// Divide the segment in two and push both halves on the stack.
mab := midpoint(a, b)
mbc := midpoint(b, c)
t++
ds[t+0] = depth + 1
ds[t-1] = depth + 1
ps[2*t+2] = a
ps[2*t+1] = mab
ps[2*t+0] = midpoint(mab, mbc)
ps[2*t-1] = mbc
continue
} else {
// Translate the control points.
bnorm := c.Sub(a).Norm(k.u).Rot90CCW()
cnorm = bc.Norm(k.u).Rot90CCW()
k.p.Add2(b.Add(bnorm), c.Add(cnorm))
k.r.Add2(b.Sub(bnorm), c.Sub(cnorm))
}
if t == 0 {
k.a, k.anorm = c, cnorm
return
}
t--
anorm = cnorm
}
panic("unreachable")
}
// Add1 adds a linear segment to the stroker.
func (k *stroker) Add1(b Point) {
bnorm := b.Sub(k.a).Norm(k.u).Rot90CCW()
if len(k.r) == 0 {
k.p.Start(k.a.Add(bnorm))
k.r.Start(k.a.Sub(bnorm))
} else {
k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, bnorm)
}
k.p.Add1(b.Add(bnorm))
k.r.Add1(b.Sub(bnorm))
k.a, k.anorm = b, bnorm
}
// Add2 adds a quadratic segment to the stroker.
func (k *stroker) Add2(b, c Point) {
ab := b.Sub(k.a)
bc := c.Sub(b)
abnorm := ab.Norm(k.u).Rot90CCW()
if len(k.r) == 0 {
k.p.Start(k.a.Add(abnorm))
k.r.Start(k.a.Sub(abnorm))
} else {
k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, abnorm)
}
// Approximate nearly-degenerate quadratics by linear segments.
abIsSmall := ab.Dot(ab) < epsilon
bcIsSmall := bc.Dot(bc) < epsilon
if abIsSmall || bcIsSmall {
acnorm := c.Sub(k.a).Norm(k.u).Rot90CCW()
k.p.Add1(c.Add(acnorm))
k.r.Add1(c.Sub(acnorm))
k.a, k.anorm = c, acnorm
return
}
// The quadratic segment (k.a, b, c) has a point of maximum curvature.
// If this occurs at an end point, we process the segment as a whole.
t := curviest2(k.a, b, c)
if t <= 0 || t >= 65536 {
k.addNonCurvy2(b, c)
return
}
// Otherwise, we perform a de Casteljau decomposition at the point of
// maximum curvature and process the two straighter parts.
mab := interpolate(k.a, b, t)
mbc := interpolate(b, c, t)
mabc := interpolate(mab, mbc, t)
// If the vectors ab and bc are close to being in opposite directions,
// then the decomposition can become unstable, so we approximate the
// quadratic segment by two linear segments joined by an arc.
bcnorm := bc.Norm(k.u).Rot90CCW()
if abnorm.Dot(bcnorm) < -Fix64(k.u)*Fix64(k.u)*2047/2048 {
pArc := abnorm.Dot(bc) < 0
k.p.Add1(mabc.Add(abnorm))
if pArc {
z := abnorm.Rot90CW()
addArc(k.p, mabc, abnorm, z)
addArc(k.p, mabc, z, bcnorm)
}
k.p.Add1(mabc.Add(bcnorm))
k.p.Add1(c.Add(bcnorm))
k.r.Add1(mabc.Sub(abnorm))
if !pArc {
z := abnorm.Rot90CW()
addArc(&k.r, mabc, abnorm.Neg(), z)
addArc(&k.r, mabc, z, bcnorm.Neg())
}
k.r.Add1(mabc.Sub(bcnorm))
k.r.Add1(c.Sub(bcnorm))
k.a, k.anorm = c, bcnorm
return
}
// Process the decomposed parts.
k.addNonCurvy2(mab, mabc)
k.addNonCurvy2(mbc, c)
}
// Add3 adds a cubic segment to the stroker.
func (k *stroker) Add3(b, c, d Point) {
panic("freetype/raster: stroke unimplemented for cubic segments")
}
// stroke adds the stroked Path q to p, where q consists of exactly one curve.
func (k *stroker) stroke(q Path) {
// Stroking is implemented by deriving two paths each k.u apart from q.
// The left-hand-side path is added immediately to k.p; the right-hand-side
// path is accumulated in k.r. Once we've finished adding the LHS to k.p,
// we add the RHS in reverse order.
k.r = make(Path, 0, len(q))
k.a = Point{q[1], q[2]}
for i := 4; i < len(q); {
switch q[i] {
case 1:
k.Add1(Point{q[i+1], q[i+2]})
i += 4
case 2:
k.Add2(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]})
i += 6
case 3:
k.Add3(Point{q[i+1], q[i+2]}, Point{q[i+3], q[i+4]}, Point{q[i+5], q[i+6]})
i += 8
default:
panic("freetype/raster: bad path")
}
}
if len(k.r) == 0 {
return
}
// TODO(nigeltao): if q is a closed curve then we should join the first and
// last segments instead of capping them.
k.cr.Cap(k.p, k.u, q.lastPoint(), k.anorm.Neg())
addPathReversed(k.p, k.r)
pivot := q.firstPoint()
k.cr.Cap(k.p, k.u, pivot, pivot.Sub(Point{k.r[1], k.r[2]}))
}
// Stroke adds q stroked with the given width to p. The result is typically
// self-intersecting and should be rasterized with UseNonZeroWinding.
// cr and jr may be nil, which defaults to a RoundCapper or RoundJoiner.
func Stroke(p Adder, q Path, width Fix32, cr Capper, jr Joiner) {
if len(q) == 0 {
return
}
if cr == nil {
cr = RoundCapper
}
if jr == nil {
jr = RoundJoiner
}
if q[0] != 0 {
panic("freetype/raster: bad path")
}
s := stroker{p: p, u: width / 2, cr: cr, jr: jr}
i := 0
for j := 4; j < len(q); {
switch q[j] {
case 0:
s.stroke(q[i:j])
i, j = j, j+4
case 1:
j += 4
case 2:
j += 6
case 3:
j += 8
default:
panic("freetype/raster: bad path")
}
}
s.stroke(q[i:])
}

530
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,530 @@
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
package truetype
// Hinting is the policy for snapping a glyph's contours to pixel boundaries.
type Hinting int32
const (
// NoHinting means to not perform any hinting.
NoHinting Hinting = iota
// FullHinting means to use the font's hinting instructions.
FullHinting
// TODO: implement VerticalHinting.
)
// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
// ``off'' control point.
type Point struct {
X, Y int32
// The Flags' LSB means whether or not this Point is ``on'' the contour.
// Other bits are reserved for internal use.
Flags uint32
}
// A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a
// series of glyphs from a Font.
type GlyphBuf struct {
// AdvanceWidth is the glyph's advance width.
AdvanceWidth int32
// B is the glyph's bounding box.
B Bounds
// Point contains all Points from all contours of the glyph. If
// hinting was used to load a glyph then Unhinted contains those
// Points before they were hinted, and InFontUnits contains those
// Points before they were hinted and scaled.
Point, Unhinted, InFontUnits []Point
// End is the point indexes of the end point of each countour. The
// length of End is the number of contours in the glyph. The i'th
// contour consists of points Point[End[i-1]:End[i]], where End[-1]
// is interpreted to mean zero.
End []int
font *Font
scale int32
hinting Hinting
hinter hinter
// phantomPoints are the co-ordinates of the synthetic phantom points
// used for hinting and bounding box calculations.
phantomPoints [4]Point
// pp1x is the X co-ordinate of the first phantom point. The '1' is
// using 1-based indexing; pp1x is almost always phantomPoints[0].X.
// TODO: eliminate this and consistently use phantomPoints[0].X.
pp1x int32
// metricsSet is whether the glyph's metrics have been set yet. For a
// compound glyph, a sub-glyph may override the outer glyph's metrics.
metricsSet bool
// tmp is a scratch buffer.
tmp []Point
}
// Flags for decoding a glyph's contours. These flags are documented at
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
const (
flagOnCurve = 1 << iota
flagXShortVector
flagYShortVector
flagRepeat
flagPositiveXShortVector
flagPositiveYShortVector
// The remaining flags are for internal use.
flagTouchedX
flagTouchedY
)
// The same flag bits (0x10 and 0x20) are overloaded to have two meanings,
// dependent on the value of the flag{X,Y}ShortVector bits.
const (
flagThisXIsSame = flagPositiveXShortVector
flagThisYIsSame = flagPositiveYShortVector
)
// Load loads a glyph's contours from a Font, overwriting any previously
// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point
// units in 1 em, i is the glyph index, and h is the hinting policy.
func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
g.Point = g.Point[:0]
g.Unhinted = g.Unhinted[:0]
g.InFontUnits = g.InFontUnits[:0]
g.End = g.End[:0]
g.font = f
g.hinting = h
g.scale = scale
g.pp1x = 0
g.phantomPoints = [4]Point{}
g.metricsSet = false
if h != NoHinting {
if err := g.hinter.init(f, scale); err != nil {
return err
}
}
if err := g.load(0, i, true); err != nil {
return err
}
// TODO: this selection of either g.pp1x or g.phantomPoints[0].X isn't ideal,
// and should be cleaned up once we have all the testScaling tests passing,
// plus additional tests for Freetype-Go's bounding boxes matching C Freetype's.
pp1x := g.pp1x
if h != NoHinting {
pp1x = g.phantomPoints[0].X
}
if pp1x != 0 {
for i := range g.Point {
g.Point[i].X -= pp1x
}
}
advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X
if h != NoHinting {
if len(f.hdmx) >= 8 {
if n := u32(f.hdmx, 4); n > 3+uint32(i) {
for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] {
if int32(hdmx[0]) == scale>>6 {
advanceWidth = int32(hdmx[2+i]) << 6
break
}
}
}
}
advanceWidth = (advanceWidth + 32) &^ 63
}
g.AdvanceWidth = advanceWidth
// Set g.B to the 'control box', which is the bounding box of the Bézier
// curves' control points. This is easier to calculate, no smaller than
// and often equal to the tightest possible bounding box of the curves
// themselves. This approach is what C Freetype does. We can't just scale
// the nominal bounding box in the glyf data as the hinting process and
// phantom point adjustment may move points outside of that box.
if len(g.Point) == 0 {
g.B = Bounds{}
} else {
p := g.Point[0]
g.B.XMin = p.X
g.B.XMax = p.X
g.B.YMin = p.Y
g.B.YMax = p.Y
for _, p := range g.Point[1:] {
if g.B.XMin > p.X {
g.B.XMin = p.X
} else if g.B.XMax < p.X {
g.B.XMax = p.X
}
if g.B.YMin > p.Y {
g.B.YMin = p.Y
} else if g.B.YMax < p.Y {
g.B.YMax = p.Y
}
}
// Snap the box to the grid, if hinting is on.
if h != NoHinting {
g.B.XMin &^= 63
g.B.YMin &^= 63
g.B.XMax += 63
g.B.XMax &^= 63
g.B.YMax += 63
g.B.YMax &^= 63
}
}
return nil
}
func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) {
// The recursion limit here is arbitrary, but defends against malformed glyphs.
if recursion >= 32 {
return UnsupportedError("excessive compound glyph recursion")
}
// Find the relevant slice of g.font.glyf.
var g0, g1 uint32
if g.font.locaOffsetFormat == locaOffsetFormatShort {
g0 = 2 * uint32(u16(g.font.loca, 2*int(i)))
g1 = 2 * uint32(u16(g.font.loca, 2*int(i)+2))
} else {
g0 = u32(g.font.loca, 4*int(i))
g1 = u32(g.font.loca, 4*int(i)+4)
}
// Decode the contour count and nominal bounding box, from the first
// 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4
// and 6, are unused.
glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, int32(0), int32(0)
if g0+10 <= g1 {
glyf = g.font.glyf[g0:g1]
ne = int(int16(u16(glyf, 0)))
boundsXMin = int32(int16(u16(glyf, 2)))
boundsYMax = int32(int16(u16(glyf, 8)))
}
// Create the phantom points.
uhm, pp1x := g.font.unscaledHMetric(i), int32(0)
uvm := g.font.unscaledVMetric(i, boundsYMax)
g.phantomPoints = [4]Point{
{X: boundsXMin - uhm.LeftSideBearing},
{X: boundsXMin - uhm.LeftSideBearing + uhm.AdvanceWidth},
{X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing},
{X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing - uvm.AdvanceHeight},
}
if len(glyf) == 0 {
g.addPhantomsAndScale(len(g.Point), len(g.Point), true, true)
copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
g.Point = g.Point[:len(g.Point)-4]
return nil
}
// Load and hint the contours.
if ne < 0 {
if ne != -1 {
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that
// "the values -2, -3, and so forth, are reserved for future use."
return UnsupportedError("negative number of contours")
}
pp1x = g.font.scale(g.scale * (boundsXMin - uhm.LeftSideBearing))
if err := g.loadCompound(recursion, uhm, i, glyf, useMyMetrics); err != nil {
return err
}
} else {
np0, ne0 := len(g.Point), len(g.End)
program := g.loadSimple(glyf, ne)
g.addPhantomsAndScale(np0, np0, true, true)
pp1x = g.Point[len(g.Point)-4].X
if g.hinting != NoHinting {
if len(program) != 0 {
err := g.hinter.run(
program,
g.Point[np0:],
g.Unhinted[np0:],
g.InFontUnits[np0:],
g.End[ne0:],
)
if err != nil {
return err
}
}
// Drop the four phantom points.
g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4]
g.Unhinted = g.Unhinted[:len(g.Unhinted)-4]
}
if useMyMetrics {
copy(g.phantomPoints[:], g.Point[len(g.Point)-4:])
}
g.Point = g.Point[:len(g.Point)-4]
if np0 != 0 {
// The hinting program expects the []End values to be indexed relative
// to the inner glyph, not the outer glyph, so we delay adding np0 until
// after the hinting program (if any) has run.
for i := ne0; i < len(g.End); i++ {
g.End[i] += np0
}
}
}
if useMyMetrics && !g.metricsSet {
g.metricsSet = true
g.pp1x = pp1x
}
return nil
}
// loadOffset is the initial offset for loadSimple and loadCompound. The first
// 10 bytes are the number of contours and the bounding box.
const loadOffset = 10
func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
offset := loadOffset
for i := 0; i < ne; i++ {
g.End = append(g.End, 1+int(u16(glyf, offset)))
offset += 2
}
// Note the TrueType hinting instructions.
instrLen := int(u16(glyf, offset))
offset += 2
program = glyf[offset : offset+instrLen]
offset += instrLen
np0 := len(g.Point)
np1 := np0 + int(g.End[len(g.End)-1])
// Decode the flags.
for i := np0; i < np1; {
c := uint32(glyf[offset])
offset++
g.Point = append(g.Point, Point{Flags: c})
i++
if c&flagRepeat != 0 {
count := glyf[offset]
offset++
for ; count > 0; count-- {
g.Point = append(g.Point, Point{Flags: c})
i++
}
}
}
// Decode the co-ordinates.
var x int16
for i := np0; i < np1; i++ {
f := g.Point[i].Flags
if f&flagXShortVector != 0 {
dx := int16(glyf[offset])
offset++
if f&flagPositiveXShortVector == 0 {
x -= dx
} else {
x += dx
}
} else if f&flagThisXIsSame == 0 {
x += int16(u16(glyf, offset))
offset += 2
}
g.Point[i].X = int32(x)
}
var y int16
for i := np0; i < np1; i++ {
f := g.Point[i].Flags
if f&flagYShortVector != 0 {
dy := int16(glyf[offset])
offset++
if f&flagPositiveYShortVector == 0 {
y -= dy
} else {
y += dy
}
} else if f&flagThisYIsSame == 0 {
y += int16(u16(glyf, offset))
offset += 2
}
g.Point[i].Y = int32(y)
}
return program
}
func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
glyf []byte, useMyMetrics bool) error {
// Flags for decoding a compound glyph. These flags are documented at
// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
const (
flagArg1And2AreWords = 1 << iota
flagArgsAreXYValues
flagRoundXYToGrid
flagWeHaveAScale
flagUnused
flagMoreComponents
flagWeHaveAnXAndYScale
flagWeHaveATwoByTwo
flagWeHaveInstructions
flagUseMyMetrics
flagOverlapCompound
)
np0, ne0 := len(g.Point), len(g.End)
offset := loadOffset
for {
flags := u16(glyf, offset)
component := Index(u16(glyf, offset+2))
dx, dy, transform, hasTransform := int32(0), int32(0), [4]int32{}, false
if flags&flagArg1And2AreWords != 0 {
dx = int32(int16(u16(glyf, offset+4)))
dy = int32(int16(u16(glyf, offset+6)))
offset += 8
} else {
dx = int32(int16(int8(glyf[offset+4])))
dy = int32(int16(int8(glyf[offset+5])))
offset += 6
}
if flags&flagArgsAreXYValues == 0 {
return UnsupportedError("compound glyph transform vector")
}
if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 {
hasTransform = true
switch {
case flags&flagWeHaveAScale != 0:
transform[0] = int32(int16(u16(glyf, offset+0)))
transform[3] = transform[0]
offset += 2
case flags&flagWeHaveAnXAndYScale != 0:
transform[0] = int32(int16(u16(glyf, offset+0)))
transform[3] = int32(int16(u16(glyf, offset+2)))
offset += 4
case flags&flagWeHaveATwoByTwo != 0:
transform[0] = int32(int16(u16(glyf, offset+0)))
transform[1] = int32(int16(u16(glyf, offset+2)))
transform[2] = int32(int16(u16(glyf, offset+4)))
transform[3] = int32(int16(u16(glyf, offset+6)))
offset += 8
}
}
savedPP := g.phantomPoints
np0 := len(g.Point)
componentUMM := useMyMetrics && (flags&flagUseMyMetrics != 0)
if err := g.load(recursion+1, component, componentUMM); err != nil {
return err
}
if flags&flagUseMyMetrics == 0 {
g.phantomPoints = savedPP
}
if hasTransform {
for j := np0; j < len(g.Point); j++ {
p := &g.Point[j]
newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) +
int32((int64(p.Y)*int64(transform[2])+1<<13)>>14)
newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) +
int32((int64(p.Y)*int64(transform[3])+1<<13)>>14)
p.X, p.Y = newX, newY
}
}
dx = g.font.scale(g.scale * dx)
dy = g.font.scale(g.scale * dy)
if flags&flagRoundXYToGrid != 0 {
dx = (dx + 32) &^ 63
dy = (dy + 32) &^ 63
}
for j := np0; j < len(g.Point); j++ {
p := &g.Point[j]
p.X += dx
p.Y += dy
}
// TODO: also adjust g.InFontUnits and g.Unhinted?
if flags&flagMoreComponents == 0 {
break
}
}
instrLen := 0
if g.hinting != NoHinting && offset+2 <= len(glyf) {
instrLen = int(u16(glyf, offset))
offset += 2
}
g.addPhantomsAndScale(np0, len(g.Point), false, instrLen > 0)
points, ends := g.Point[np0:], g.End[ne0:]
g.Point = g.Point[:len(g.Point)-4]
for j := range points {
points[j].Flags &^= flagTouchedX | flagTouchedY
}
if instrLen == 0 {
if !g.metricsSet {
copy(g.phantomPoints[:], points[len(points)-4:])
}
return nil
}
// Hint the compound glyph.
program := glyf[offset : offset+instrLen]
// Temporarily adjust the ends to be relative to this compound glyph.
if np0 != 0 {
for i := range ends {
ends[i] -= np0
}
}
// Hinting instructions of a composite glyph completely refer to the
// (already) hinted subglyphs.
g.tmp = append(g.tmp[:0], points...)
if err := g.hinter.run(program, points, g.tmp, g.tmp, ends); err != nil {
return err
}
if np0 != 0 {
for i := range ends {
ends[i] += np0
}
}
if !g.metricsSet {
copy(g.phantomPoints[:], points[len(points)-4:])
}
return nil
}
func (g *GlyphBuf) addPhantomsAndScale(np0, np1 int, simple, adjust bool) {
// Add the four phantom points.
g.Point = append(g.Point, g.phantomPoints[:]...)
// Scale the points.
if simple && g.hinting != NoHinting {
g.InFontUnits = append(g.InFontUnits, g.Point[np1:]...)
}
for i := np1; i < len(g.Point); i++ {
p := &g.Point[i]
p.X = g.font.scale(g.scale * p.X)
p.Y = g.font.scale(g.scale * p.Y)
}
if g.hinting == NoHinting {
return
}
// Round the 1st phantom point to the grid, shifting all other points equally.
// Note that "all other points" starts from np0, not np1.
// TODO: delete this adjustment and the np0/np1 distinction, when
// we update the compatibility tests to C Freetype 2.5.3.
// See http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=05c786d990390a7ca18e62962641dac740bacb06
if adjust {
pp1x := g.Point[len(g.Point)-4].X
if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 {
for i := np0; i < len(g.Point); i++ {
g.Point[i].X += dx
}
}
}
if simple {
g.Unhinted = append(g.Unhinted, g.Point[np1:]...)
}
// Round the 2nd and 4th phantom point to the grid.
p := &g.Point[len(g.Point)-3]
p.X = (p.X + 32) &^ 63
p = &g.Point[len(g.Point)-1]
p.Y = (p.Y + 32) &^ 63
}
// TODO: is this necessary? The zero-valued GlyphBuf is perfectly usable.
// NewGlyphBuf returns a newly allocated GlyphBuf.
func NewGlyphBuf() *GlyphBuf {
return &GlyphBuf{
Point: make([]Point, 0, 256),
End: make([]int, 0, 32),
}
}

1764
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint.go сгенерированный поставляемый Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

673
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/hint_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,673 @@
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
package truetype
import (
"reflect"
"strings"
"testing"
)
func TestBytecode(t *testing.T) {
testCases := []struct {
desc string
prog []byte
want []int32
errStr string
}{
{
"underflow",
[]byte{
opDUP,
},
nil,
"underflow",
},
{
"infinite loop",
[]byte{
opPUSHW000, // [-1]
0xff,
0xff,
opDUP, // [-1, -1]
opJMPR, // [-1]
},
nil,
"too many steps",
},
{
"unbalanced if/else",
[]byte{
opPUSHB000, // [0]
0,
opIF,
},
nil,
"unbalanced",
},
{
"vector set/gets",
[]byte{
opSVTCA1, // []
opGPV, // [0x4000, 0]
opSVTCA0, // [0x4000, 0]
opGFV, // [0x4000, 0, 0, 0x4000]
opNEG, // [0x4000, 0, 0, -0x4000]
opSPVFS, // [0x4000, 0]
opSFVTPV, // [0x4000, 0]
opPUSHB000, // [0x4000, 0, 1]
1,
opGFV, // [0x4000, 0, 1, 0, -0x4000]
opPUSHB000, // [0x4000, 0, 1, 0, -0x4000, 2]
2,
},
[]int32{0x4000, 0, 1, 0, -0x4000, 2},
"",
},
{
"jumps",
[]byte{
opPUSHB001, // [10, 2]
10,
2,
opJMPR, // [10]
opDUP, // not executed
opDUP, // [10, 10]
opPUSHB010, // [10, 10, 20, 2, 1]
20,
2,
1,
opJROT, // [10, 10, 20]
opDUP, // not executed
opDUP, // [10, 10, 20, 20]
opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
30,
2,
1,
opJROF, // [10, 10, 20, 20, 30]
opDUP, // [10, 10, 20, 20, 30, 30]
opDUP, // [10, 10, 20, 20, 30, 30, 30]
},
[]int32{10, 10, 20, 20, 30, 30, 30},
"",
},
{
"stack ops",
[]byte{
opPUSHB010, // [10, 20, 30]
10,
20,
30,
opCLEAR, // []
opPUSHB010, // [40, 50, 60]
40,
50,
60,
opSWAP, // [40, 60, 50]
opDUP, // [40, 60, 50, 50]
opDUP, // [40, 60, 50, 50, 50]
opPOP, // [40, 60, 50, 50]
opDEPTH, // [40, 60, 50, 50, 4]
opCINDEX, // [40, 60, 50, 50, 40]
opPUSHB000, // [40, 60, 50, 50, 40, 4]
4,
opMINDEX, // [40, 50, 50, 40, 60]
},
[]int32{40, 50, 50, 40, 60},
"",
},
{
"push ops",
[]byte{
opPUSHB000, // [255]
255,
opPUSHW001, // [255, -2, 253]
255,
254,
0,
253,
opNPUSHB, // [1, -2, 253, 1, 2]
2,
1,
2,
opNPUSHW, // [1, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809]
3,
4,
5,
6,
7,
8,
9,
},
[]int32{255, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809},
"",
},
{
"store ops",
[]byte{
opPUSHB011, // [1, 22, 3, 44]
1,
22,
3,
44,
opWS, // [1, 22]
opWS, // []
opPUSHB000, // [3]
3,
opRS, // [44]
},
[]int32{44},
"",
},
{
"comparison ops",
[]byte{
opPUSHB001, // [10, 20]
10,
20,
opLT, // [1]
opPUSHB001, // [1, 10, 20]
10,
20,
opLTEQ, // [1, 1]
opPUSHB001, // [1, 1, 10, 20]
10,
20,
opGT, // [1, 1, 0]
opPUSHB001, // [1, 1, 0, 10, 20]
10,
20,
opGTEQ, // [1, 1, 0, 0]
opEQ, // [1, 1, 1]
opNEQ, // [1, 0]
},
[]int32{1, 0},
"",
},
{
"odd/even",
// Calculate odd(2+31/64), odd(2+32/64), even(2), even(1).
[]byte{
opPUSHB000, // [159]
159,
opODD, // [0]
opPUSHB000, // [0, 160]
160,
opODD, // [0, 1]
opPUSHB000, // [0, 1, 128]
128,
opEVEN, // [0, 1, 1]
opPUSHB000, // [0, 1, 1, 64]
64,
opEVEN, // [0, 1, 1, 0]
},
[]int32{0, 1, 1, 0},
"",
},
{
"if true",
[]byte{
opPUSHB001, // [255, 1]
255,
1,
opIF,
opPUSHB000, // [255, 2]
2,
opEIF,
opPUSHB000, // [255, 2, 254]
254,
},
[]int32{255, 2, 254},
"",
},
{
"if false",
[]byte{
opPUSHB001, // [255, 0]
255,
0,
opIF,
opPUSHB000, // [255]
2,
opEIF,
opPUSHB000, // [255, 254]
254,
},
[]int32{255, 254},
"",
},
{
"if/else true",
[]byte{
opPUSHB000, // [1]
1,
opIF,
opPUSHB000, // [2]
2,
opELSE,
opPUSHB000, // not executed
3,
opEIF,
},
[]int32{2},
"",
},
{
"if/else false",
[]byte{
opPUSHB000, // [0]
0,
opIF,
opPUSHB000, // not executed
2,
opELSE,
opPUSHB000, // [3]
3,
opEIF,
},
[]int32{3},
"",
},
{
"if/else true if/else false",
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
[]byte{
opPUSHB010, // [255, 0, 1]
255,
0,
1,
opIF,
opIF,
opPUSHB001, // not executed
0x58,
0x58,
opELSE,
opPUSHW000, // [255, 0x5858]
0x58,
0x58,
opEIF,
opELSE,
opIF,
opNPUSHB, // not executed
3,
0x58,
0x58,
0x58,
opELSE,
opNPUSHW, // not executed
2,
0x58,
0x58,
0x58,
0x58,
opEIF,
opEIF,
opPUSHB000, // [255, 0x5858, 254]
254,
},
[]int32{255, 0x5858, 254},
"",
},
{
"if/else false if/else true",
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
[]byte{
opPUSHB010, // [255, 1, 0]
255,
1,
0,
opIF,
opIF,
opPUSHB001, // not executed
0x58,
0x58,
opELSE,
opPUSHW000, // not executed
0x58,
0x58,
opEIF,
opELSE,
opIF,
opNPUSHB, // [255, 0x58, 0x58, 0x58]
3,
0x58,
0x58,
0x58,
opELSE,
opNPUSHW, // not executed
2,
0x58,
0x58,
0x58,
0x58,
opEIF,
opEIF,
opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
254,
},
[]int32{255, 0x58, 0x58, 0x58, 254},
"",
},
{
"logical ops",
[]byte{
opPUSHB010, // [0, 10, 20]
0,
10,
20,
opAND, // [0, 1]
opOR, // [1]
opNOT, // [0]
},
[]int32{0},
"",
},
{
"arithmetic ops",
// Calculate abs((-(1 - (2*3)))/2 + 1/64).
// The answer is 5/2 + 1/64 in ideal numbers, or 161 in 26.6 fixed point math.
[]byte{
opPUSHB010, // [64, 128, 192]
1 << 6,
2 << 6,
3 << 6,
opMUL, // [64, 384]
opSUB, // [-320]
opNEG, // [320]
opPUSHB000, // [320, 128]
2 << 6,
opDIV, // [160]
opPUSHB000, // [160, 1]
1,
opADD, // [161]
opABS, // [161]
},
[]int32{161},
"",
},
{
"floor, ceiling",
[]byte{
opPUSHB000, // [96]
96,
opFLOOR, // [64]
opPUSHB000, // [64, 96]
96,
opCEILING, // [64, 128]
},
[]int32{64, 128},
"",
},
{
"rounding",
// Round 1.40625 (which is 90/64) under various rounding policies.
// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
[]byte{
opROFF, // []
opPUSHB000, // [90]
90,
opROUND00, // [90]
opRTG, // [90]
opPUSHB000, // [90, 90]
90,
opROUND00, // [90, 64]
opRTHG, // [90, 64]
opPUSHB000, // [90, 64, 90]
90,
opROUND00, // [90, 64, 96]
opRDTG, // [90, 64, 96]
opPUSHB000, // [90, 64, 96, 90]
90,
opROUND00, // [90, 64, 96, 64]
opRUTG, // [90, 64, 96, 64]
opPUSHB000, // [90, 64, 96, 64, 90]
90,
opROUND00, // [90, 64, 96, 64, 128]
opRTDG, // [90, 64, 96, 64, 128]
opPUSHB000, // [90, 64, 96, 64, 128, 90]
90,
opROUND00, // [90, 64, 96, 64, 128, 96]
},
[]int32{90, 64, 96, 64, 128, 96},
"",
},
{
"super-rounding",
// See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
// and the sign preservation steps of the "Order of rounding operations" section.
[]byte{
opPUSHB000, // [0x58]
0x58,
opSROUND, // []
opPUSHW000, // [-81]
0xff,
0xaf,
opROUND00, // [-80]
opPUSHW000, // [-80, -80]
0xff,
0xb0,
opROUND00, // [-80, -80]
opPUSHW000, // [-80, -80, -17]
0xff,
0xef,
opROUND00, // [-80, -80, -16]
opPUSHW000, // [-80, -80, -16, -16]
0xff,
0xf0,
opROUND00, // [-80, -80, -16, -16]
opPUSHB000, // [-80, -80, -16, -16, 0]
0,
opROUND00, // [-80, -80, -16, -16, 16]
opPUSHB000, // [-80, -80, -16, -16, 16, 16]
16,
opROUND00, // [-80, -80, -16, -16, 16, 16]
opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47]
47,
opROUND00, // [-80, -80, -16, -16, 16, 16, 16]
opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48]
48,
opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80]
},
[]int32{-80, -80, -16, -16, 16, 16, 16, 80},
"",
},
{
"roll",
[]byte{
opPUSHB010, // [1, 2, 3]
1,
2,
3,
opROLL, // [2, 3, 1]
},
[]int32{2, 3, 1},
"",
},
{
"max/min",
[]byte{
opPUSHW001, // [-2, -3]
0xff,
0xfe,
0xff,
0xfd,
opMAX, // [-2]
opPUSHW001, // [-2, -4, -5]
0xff,
0xfc,
0xff,
0xfb,
opMIN, // [-2, -5]
},
[]int32{-2, -5},
"",
},
{
"functions",
[]byte{
opPUSHB011, // [3, 7, 0, 3]
3,
7,
0,
3,
opFDEF, // Function #3 (not called)
opPUSHB000,
98,
opENDF,
opFDEF, // Function #0
opDUP,
opADD,
opENDF,
opFDEF, // Function #7
opPUSHB001,
10,
0,
opCALL,
opDUP,
opENDF,
opFDEF, // Function #3 (again)
opPUSHB000,
99,
opENDF,
opPUSHB001, // [2, 0]
2,
0,
opCALL, // [4]
opPUSHB000, // [4, 3]
3,
opLOOPCALL, // [99, 99, 99, 99]
opPUSHB000, // [99, 99, 99, 99, 7]
7,
opCALL, // [99, 99, 99, 99, 20, 20]
},
[]int32{99, 99, 99, 99, 20, 20},
"",
},
}
for _, tc := range testCases {
h := &hinter{}
h.init(&Font{
maxStorage: 32,
maxStackElements: 100,
}, 768)
err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
if err != nil {
errStr = err.Error()
}
if tc.errStr != "" {
if errStr == "" {
t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
} else if !strings.Contains(errStr, tc.errStr) {
t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
}
continue
}
if errStr != "" {
t.Errorf("%s: got error %q, want none", tc.desc, errStr)
continue
}
got := h.stack[:len(tc.want)]
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
continue
}
}
}
// TestMove tests that the hinter.move method matches the output of the C
// Freetype implementation.
func TestMove(t *testing.T) {
h, p := hinter{}, Point{}
testCases := []struct {
pvX, pvY, fvX, fvY f2dot14
wantX, wantY int32
}{
{+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
{+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
{-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
{-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
{+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
{+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
{+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
{+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
{+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
{+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
{-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
{-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
{-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
{-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
{+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
{-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
{+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
{-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
{-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
{+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
{+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
}
for _, tc := range testCases {
p = Point{}
h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
h.move(&p, 1000, true)
tx := p.Flags&flagTouchedX != 0
ty := p.Flags&flagTouchedY != 0
wantTX := tc.fvX != 0
wantTY := tc.fvY != 0
if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
t.Errorf("pv=%v, fv=%v\ngot %d, %d, %t, %t\nwant %d, %d, %t, %t",
h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
continue
}
// Check that p is aligned with the freedom vector.
a := int64(p.X) * int64(tc.fvY)
b := int64(p.Y) * int64(tc.fvX)
if a != b {
t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
continue
}
// Check that the projected p is 1000 away from the origin.
dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
if dotProd != 1000 {
t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
continue
}
}
}
// TestNormalize tests that the normalize function matches the output of the C
// Freetype implementation.
func TestNormalize(t *testing.T) {
testCases := [][2]f2dot14{
{-15895, 3974},
{-15543, 5181},
{-14654, 7327},
{-11585, 11585},
{0, 16384},
{11585, 11585},
{14654, 7327},
{15543, 5181},
{15895, 3974},
{16066, 3213},
{16161, 2694},
{16219, 2317},
{16257, 2032},
{16284, 1809},
}
for i, want := range testCases {
got := normalize(f2dot14(i)-4, 1)
if got != want {
t.Errorf("i=%d: got %v, want %v", i, got, want)
}
}
}

289
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/opcodes.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,289 @@
// Copyright 2012 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
package truetype
// The Truetype opcodes are summarized at
// https://developer.apple.com/fonts/TTRefMan/RM07/appendixA.html
const (
opSVTCA0 = 0x00 // Set freedom and projection Vectors To Coordinate Axis
opSVTCA1 = 0x01 // .
opSPVTCA0 = 0x02 // Set Projection Vector To Coordinate Axis
opSPVTCA1 = 0x03 // .
opSFVTCA0 = 0x04 // Set Freedom Vector to Coordinate Axis
opSFVTCA1 = 0x05 // .
opSPVTL0 = 0x06 // Set Projection Vector To Line
opSPVTL1 = 0x07 // .
opSFVTL0 = 0x08 // Set Freedom Vector To Line
opSFVTL1 = 0x09 // .
opSPVFS = 0x0a // Set Projection Vector From Stack
opSFVFS = 0x0b // Set Freedom Vector From Stack
opGPV = 0x0c // Get Projection Vector
opGFV = 0x0d // Get Freedom Vector
opSFVTPV = 0x0e // Set Freedom Vector To Projection Vector
opISECT = 0x0f // moves point p to the InterSECTion of two lines
opSRP0 = 0x10 // Set Reference Point 0
opSRP1 = 0x11 // Set Reference Point 1
opSRP2 = 0x12 // Set Reference Point 2
opSZP0 = 0x13 // Set Zone Pointer 0
opSZP1 = 0x14 // Set Zone Pointer 1
opSZP2 = 0x15 // Set Zone Pointer 2
opSZPS = 0x16 // Set Zone PointerS
opSLOOP = 0x17 // Set LOOP variable
opRTG = 0x18 // Round To Grid
opRTHG = 0x19 // Round To Half Grid
opSMD = 0x1a // Set Minimum Distance
opELSE = 0x1b // ELSE clause
opJMPR = 0x1c // JuMP Relative
opSCVTCI = 0x1d // Set Control Value Table Cut-In
opSSWCI = 0x1e // Set Single Width Cut-In
opSSW = 0x1f // Set Single Width
opDUP = 0x20 // DUPlicate top stack element
opPOP = 0x21 // POP top stack element
opCLEAR = 0x22 // CLEAR the stack
opSWAP = 0x23 // SWAP the top two elements on the stack
opDEPTH = 0x24 // DEPTH of the stack
opCINDEX = 0x25 // Copy the INDEXed element to the top of the stack
opMINDEX = 0x26 // Move the INDEXed element to the top of the stack
opALIGNPTS = 0x27 // ALIGN PoinTS
op_0x28 = 0x28 // deprecated
opUTP = 0x29 // UnTouch Point
opLOOPCALL = 0x2a // LOOP and CALL function
opCALL = 0x2b // CALL function
opFDEF = 0x2c // Function DEFinition
opENDF = 0x2d // END Function definition
opMDAP0 = 0x2e // Move Direct Absolute Point
opMDAP1 = 0x2f // .
opIUP0 = 0x30 // Interpolate Untouched Points through the outline
opIUP1 = 0x31 // .
opSHP0 = 0x32 // SHift Point using reference point
opSHP1 = 0x33 // .
opSHC0 = 0x34 // SHift Contour using reference point
opSHC1 = 0x35 // .
opSHZ0 = 0x36 // SHift Zone using reference point
opSHZ1 = 0x37 // .
opSHPIX = 0x38 // SHift point by a PIXel amount
opIP = 0x39 // Interpolate Point
opMSIRP0 = 0x3a // Move Stack Indirect Relative Point
opMSIRP1 = 0x3b // .
opALIGNRP = 0x3c // ALIGN to Reference Point
opRTDG = 0x3d // Round To Double Grid
opMIAP0 = 0x3e // Move Indirect Absolute Point
opMIAP1 = 0x3f // .
opNPUSHB = 0x40 // PUSH N Bytes
opNPUSHW = 0x41 // PUSH N Words
opWS = 0x42 // Write Store
opRS = 0x43 // Read Store
opWCVTP = 0x44 // Write Control Value Table in Pixel units
opRCVT = 0x45 // Read Control Value Table entry
opGC0 = 0x46 // Get Coordinate projected onto the projection vector
opGC1 = 0x47 // .
opSCFS = 0x48 // Sets Coordinate From the Stack using projection vector and freedom vector
opMD0 = 0x49 // Measure Distance
opMD1 = 0x4a // .
opMPPEM = 0x4b // Measure Pixels Per EM
opMPS = 0x4c // Measure Point Size
opFLIPON = 0x4d // set the auto FLIP Boolean to ON
opFLIPOFF = 0x4e // set the auto FLIP Boolean to OFF
opDEBUG = 0x4f // DEBUG call
opLT = 0x50 // Less Than
opLTEQ = 0x51 // Less Than or EQual
opGT = 0x52 // Greater Than
opGTEQ = 0x53 // Greater Than or EQual
opEQ = 0x54 // EQual
opNEQ = 0x55 // Not EQual
opODD = 0x56 // ODD
opEVEN = 0x57 // EVEN
opIF = 0x58 // IF test
opEIF = 0x59 // End IF
opAND = 0x5a // logical AND
opOR = 0x5b // logical OR
opNOT = 0x5c // logical NOT
opDELTAP1 = 0x5d // DELTA exception P1
opSDB = 0x5e // Set Delta Base in the graphics state
opSDS = 0x5f // Set Delta Shift in the graphics state
opADD = 0x60 // ADD
opSUB = 0x61 // SUBtract
opDIV = 0x62 // DIVide
opMUL = 0x63 // MULtiply
opABS = 0x64 // ABSolute value
opNEG = 0x65 // NEGate
opFLOOR = 0x66 // FLOOR
opCEILING = 0x67 // CEILING
opROUND00 = 0x68 // ROUND value
opROUND01 = 0x69 // .
opROUND10 = 0x6a // .
opROUND11 = 0x6b // .
opNROUND00 = 0x6c // No ROUNDing of value
opNROUND01 = 0x6d // .
opNROUND10 = 0x6e // .
opNROUND11 = 0x6f // .
opWCVTF = 0x70 // Write Control Value Table in Funits
opDELTAP2 = 0x71 // DELTA exception P2
opDELTAP3 = 0x72 // DELTA exception P3
opDELTAC1 = 0x73 // DELTA exception C1
opDELTAC2 = 0x74 // DELTA exception C2
opDELTAC3 = 0x75 // DELTA exception C3
opSROUND = 0x76 // Super ROUND
opS45ROUND = 0x77 // Super ROUND 45 degrees
opJROT = 0x78 // Jump Relative On True
opJROF = 0x79 // Jump Relative On False
opROFF = 0x7a // Round OFF
op_0x7b = 0x7b // deprecated
opRUTG = 0x7c // Round Up To Grid
opRDTG = 0x7d // Round Down To Grid
opSANGW = 0x7e // Set ANGle Weight
opAA = 0x7f // Adjust Angle
opFLIPPT = 0x80 // FLIP PoinT
opFLIPRGON = 0x81 // FLIP RanGe ON
opFLIPRGOFF = 0x82 // FLIP RanGe OFF
op_0x83 = 0x83 // deprecated
op_0x84 = 0x84 // deprecated
opSCANCTRL = 0x85 // SCAN conversion ConTRoL
opSDPVTL0 = 0x86 // Set Dual Projection Vector To Line
opSDPVTL1 = 0x87 // .
opGETINFO = 0x88 // GET INFOrmation
opIDEF = 0x89 // Instruction DEFinition
opROLL = 0x8a // ROLL the top three stack elements
opMAX = 0x8b // MAXimum of top two stack elements
opMIN = 0x8c // MINimum of top two stack elements
opSCANTYPE = 0x8d // SCANTYPE
opINSTCTRL = 0x8e // INSTRuction execution ConTRoL
op_0x8f = 0x8f
op_0x90 = 0x90
op_0x91 = 0x91
op_0x92 = 0x92
op_0x93 = 0x93
op_0x94 = 0x94
op_0x95 = 0x95
op_0x96 = 0x96
op_0x97 = 0x97
op_0x98 = 0x98
op_0x99 = 0x99
op_0x9a = 0x9a
op_0x9b = 0x9b
op_0x9c = 0x9c
op_0x9d = 0x9d
op_0x9e = 0x9e
op_0x9f = 0x9f
op_0xa0 = 0xa0
op_0xa1 = 0xa1
op_0xa2 = 0xa2
op_0xa3 = 0xa3
op_0xa4 = 0xa4
op_0xa5 = 0xa5
op_0xa6 = 0xa6
op_0xa7 = 0xa7
op_0xa8 = 0xa8
op_0xa9 = 0xa9
op_0xaa = 0xaa
op_0xab = 0xab
op_0xac = 0xac
op_0xad = 0xad
op_0xae = 0xae
op_0xaf = 0xaf
opPUSHB000 = 0xb0 // PUSH Bytes
opPUSHB001 = 0xb1 // .
opPUSHB010 = 0xb2 // .
opPUSHB011 = 0xb3 // .
opPUSHB100 = 0xb4 // .
opPUSHB101 = 0xb5 // .
opPUSHB110 = 0xb6 // .
opPUSHB111 = 0xb7 // .
opPUSHW000 = 0xb8 // PUSH Words
opPUSHW001 = 0xb9 // .
opPUSHW010 = 0xba // .
opPUSHW011 = 0xbb // .
opPUSHW100 = 0xbc // .
opPUSHW101 = 0xbd // .
opPUSHW110 = 0xbe // .
opPUSHW111 = 0xbf // .
opMDRP00000 = 0xc0 // Move Direct Relative Point
opMDRP00001 = 0xc1 // .
opMDRP00010 = 0xc2 // .
opMDRP00011 = 0xc3 // .
opMDRP00100 = 0xc4 // .
opMDRP00101 = 0xc5 // .
opMDRP00110 = 0xc6 // .
opMDRP00111 = 0xc7 // .
opMDRP01000 = 0xc8 // .
opMDRP01001 = 0xc9 // .
opMDRP01010 = 0xca // .
opMDRP01011 = 0xcb // .
opMDRP01100 = 0xcc // .
opMDRP01101 = 0xcd // .
opMDRP01110 = 0xce // .
opMDRP01111 = 0xcf // .
opMDRP10000 = 0xd0 // .
opMDRP10001 = 0xd1 // .
opMDRP10010 = 0xd2 // .
opMDRP10011 = 0xd3 // .
opMDRP10100 = 0xd4 // .
opMDRP10101 = 0xd5 // .
opMDRP10110 = 0xd6 // .
opMDRP10111 = 0xd7 // .
opMDRP11000 = 0xd8 // .
opMDRP11001 = 0xd9 // .
opMDRP11010 = 0xda // .
opMDRP11011 = 0xdb // .
opMDRP11100 = 0xdc // .
opMDRP11101 = 0xdd // .
opMDRP11110 = 0xde // .
opMDRP11111 = 0xdf // .
opMIRP00000 = 0xe0 // Move Indirect Relative Point
opMIRP00001 = 0xe1 // .
opMIRP00010 = 0xe2 // .
opMIRP00011 = 0xe3 // .
opMIRP00100 = 0xe4 // .
opMIRP00101 = 0xe5 // .
opMIRP00110 = 0xe6 // .
opMIRP00111 = 0xe7 // .
opMIRP01000 = 0xe8 // .
opMIRP01001 = 0xe9 // .
opMIRP01010 = 0xea // .
opMIRP01011 = 0xeb // .
opMIRP01100 = 0xec // .
opMIRP01101 = 0xed // .
opMIRP01110 = 0xee // .
opMIRP01111 = 0xef // .
opMIRP10000 = 0xf0 // .
opMIRP10001 = 0xf1 // .
opMIRP10010 = 0xf2 // .
opMIRP10011 = 0xf3 // .
opMIRP10100 = 0xf4 // .
opMIRP10101 = 0xf5 // .
opMIRP10110 = 0xf6 // .
opMIRP10111 = 0xf7 // .
opMIRP11000 = 0xf8 // .
opMIRP11001 = 0xf9 // .
opMIRP11010 = 0xfa // .
opMIRP11011 = 0xfb // .
opMIRP11100 = 0xfc // .
opMIRP11101 = 0xfd // .
opMIRP11110 = 0xfe // .
opMIRP11111 = 0xff // .
)
// popCount is the number of stack elements that each opcode pops.
var popCount = [256]uint8{
// 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, // 0x00 - 0x0f
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1f
1, 1, 0, 2, 0, 1, 1, 2, 0, 1, 2, 1, 1, 0, 1, 1, // 0x20 - 0x2f
0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f
0, 0, 2, 1, 2, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, // 0x40 - 0x4f
2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, // 0x50 - 0x5f
2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6f
2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 1, // 0x70 - 0x7f
0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, 0, // 0x80 - 0x8f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xf0 - 0xff
}

554
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,554 @@
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.
// Package truetype provides a parser for the TTF and TTC file formats.
// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/
// and http://www.microsoft.com/typography/otspec/
//
// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font
// metrics and control points. All these methods take a scale parameter, which
// is the number of device units in 1 em. For example, if 1 em is 10 pixels and
// 1 pixel is 64 units, then scale is 640. If the device space involves pixels,
// 64 units per pixel is recommended, since that is what the bytecode hinter
// uses when snapping point co-ordinates to the pixel grid.
//
// To measure a TrueType font in ideal FUnit space, use scale equal to
// font.FUnitsPerEm().
package truetype
import (
"fmt"
)
// An Index is a Font's index of a rune.
type Index uint16
// A Bounds holds the co-ordinate range of one or more glyphs.
// The endpoints are inclusive.
type Bounds struct {
XMin, YMin, XMax, YMax int32
}
// An HMetric holds the horizontal metrics of a single glyph.
type HMetric struct {
AdvanceWidth, LeftSideBearing int32
}
// A VMetric holds the vertical metrics of a single glyph.
type VMetric struct {
AdvanceHeight, TopSideBearing int32
}
// A FormatError reports that the input is not a valid TrueType font.
type FormatError string
func (e FormatError) Error() string {
return "freetype: invalid TrueType format: " + string(e)
}
// An UnsupportedError reports that the input uses a valid but unimplemented
// TrueType feature.
type UnsupportedError string
func (e UnsupportedError) Error() string {
return "freetype: unsupported TrueType feature: " + string(e)
}
// u32 returns the big-endian uint32 at b[i:].
func u32(b []byte, i int) uint32 {
return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
}
// u16 returns the big-endian uint16 at b[i:].
func u16(b []byte, i int) uint16 {
return uint16(b[i])<<8 | uint16(b[i+1])
}
// readTable returns a slice of the TTF data given by a table's directory entry.
func readTable(ttf []byte, offsetLength []byte) ([]byte, error) {
offset := int(u32(offsetLength, 0))
if offset < 0 {
return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset)))
}
length := int(u32(offsetLength, 4))
if length < 0 {
return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length)))
}
end := offset + length
if end < 0 || end > len(ttf) {
return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length)))
}
return ttf[offset:end], nil
}
const (
locaOffsetFormatUnknown int = iota
locaOffsetFormatShort
locaOffsetFormatLong
)
// A cm holds a parsed cmap entry.
type cm struct {
start, end, delta, offset uint32
}
// A Font represents a Truetype font.
type Font struct {
// Tables sliced from the TTF data. The different tables are documented
// at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
cmap, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, os2, prep, vmtx []byte
cmapIndexes []byte
// Cached values derived from the raw ttf data.
cm []cm
locaOffsetFormat int
nGlyph, nHMetric, nKern int
fUnitsPerEm int32
bounds Bounds
// Values from the maxp section.
maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16
}
func (f *Font) parseCmap() error {
const (
cmapFormat4 = 4
cmapFormat12 = 12
languageIndependent = 0
// A 32-bit encoding consists of a most-significant 16-bit Platform ID and a
// least-significant 16-bit Platform Specific ID. The magic numbers are
// specified at https://www.microsoft.com/typography/otspec/name.htm
unicodeEncoding = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0)
microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol)
microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2)
microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4)
)
if len(f.cmap) < 4 {
return FormatError("cmap too short")
}
nsubtab := int(u16(f.cmap, 2))
if len(f.cmap) < 8*nsubtab+4 {
return FormatError("cmap too short")
}
offset, found, x := 0, false, 4
for i := 0; i < nsubtab; i++ {
// We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32.
// All values are big-endian.
pidPsid, o := u32(f.cmap, x), u32(f.cmap, x+4)
x += 8
// We prefer the Unicode cmap encoding. Failing to find that, we fall
// back onto the Microsoft cmap encoding.
if pidPsid == unicodeEncoding {
offset, found = int(o), true
break
} else if pidPsid == microsoftSymbolEncoding ||
pidPsid == microsoftUCS2Encoding ||
pidPsid == microsoftUCS4Encoding {
offset, found = int(o), true
// We don't break out of the for loop, so that Unicode can override Microsoft.
}
}
if !found {
return UnsupportedError("cmap encoding")
}
if offset <= 0 || offset > len(f.cmap) {
return FormatError("bad cmap offset")
}
cmapFormat := u16(f.cmap, offset)
switch cmapFormat {
case cmapFormat4:
language := u16(f.cmap, offset+4)
if language != languageIndependent {
return UnsupportedError(fmt.Sprintf("language: %d", language))
}
segCountX2 := int(u16(f.cmap, offset+6))
if segCountX2%2 == 1 {
return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2))
}
segCount := segCountX2 / 2
offset += 14
f.cm = make([]cm, segCount)
for i := 0; i < segCount; i++ {
f.cm[i].end = uint32(u16(f.cmap, offset))
offset += 2
}
offset += 2
for i := 0; i < segCount; i++ {
f.cm[i].start = uint32(u16(f.cmap, offset))
offset += 2
}
for i := 0; i < segCount; i++ {
f.cm[i].delta = uint32(u16(f.cmap, offset))
offset += 2
}
for i := 0; i < segCount; i++ {
f.cm[i].offset = uint32(u16(f.cmap, offset))
offset += 2
}
f.cmapIndexes = f.cmap[offset:]
return nil
case cmapFormat12:
if u16(f.cmap, offset+2) != 0 {
return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4]))
}
length := u32(f.cmap, offset+4)
language := u32(f.cmap, offset+8)
if language != languageIndependent {
return UnsupportedError(fmt.Sprintf("language: %d", language))
}
nGroups := u32(f.cmap, offset+12)
if length != 12*nGroups+16 {
return FormatError("inconsistent cmap length")
}
offset += 16
f.cm = make([]cm, nGroups)
for i := uint32(0); i < nGroups; i++ {
f.cm[i].start = u32(f.cmap, offset+0)
f.cm[i].end = u32(f.cmap, offset+4)
f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start
offset += 12
}
return nil
}
return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat))
}
func (f *Font) parseHead() error {
if len(f.head) != 54 {
return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
}
f.fUnitsPerEm = int32(u16(f.head, 18))
f.bounds.XMin = int32(int16(u16(f.head, 36)))
f.bounds.YMin = int32(int16(u16(f.head, 38)))
f.bounds.XMax = int32(int16(u16(f.head, 40)))
f.bounds.YMax = int32(int16(u16(f.head, 42)))
switch i := u16(f.head, 50); i {
case 0:
f.locaOffsetFormat = locaOffsetFormatShort
case 1:
f.locaOffsetFormat = locaOffsetFormatLong
default:
return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i))
}
return nil
}
func (f *Font) parseHhea() error {
if len(f.hhea) != 36 {
return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea)))
}
f.nHMetric = int(u16(f.hhea, 34))
if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) {
return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx)))
}
return nil
}
func (f *Font) parseKern() error {
// Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says:
// "Previous versions of the 'kern' table defined both the version and nTables fields in the header
// as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged
// (although AAT can sense an old kerning table and still make correct use of it). Microsoft
// Windows still uses the older format for the 'kern' table and will not recognize the newer one.
// Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS
// and Windows should use the old format."
// Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format,
// just like the C Freetype implementation.
if len(f.kern) == 0 {
if f.nKern != 0 {
return FormatError("bad kern table length")
}
return nil
}
if len(f.kern) < 18 {
return FormatError("kern data too short")
}
version, offset := u16(f.kern, 0), 2
if version != 0 {
return UnsupportedError(fmt.Sprintf("kern version: %d", version))
}
n, offset := u16(f.kern, offset), offset+2
if n != 1 {
return UnsupportedError(fmt.Sprintf("kern nTables: %d", n))
}
offset += 2
length, offset := int(u16(f.kern, offset)), offset+2
coverage, offset := u16(f.kern, offset), offset+2
if coverage != 0x0001 {
// We only support horizontal kerning.
return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage))
}
f.nKern, offset = int(u16(f.kern, offset)), offset+2
if 6*f.nKern != length-14 {
return FormatError("bad kern table length")
}
return nil
}
func (f *Font) parseMaxp() error {
if len(f.maxp) != 32 {
return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp)))
}
f.nGlyph = int(u16(f.maxp, 4))
f.maxTwilightPoints = u16(f.maxp, 16)
f.maxStorage = u16(f.maxp, 18)
f.maxFunctionDefs = u16(f.maxp, 20)
f.maxStackElements = u16(f.maxp, 24)
return nil
}
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
func (f *Font) scale(x int32) int32 {
if x >= 0 {
x += f.fUnitsPerEm / 2
} else {
x -= f.fUnitsPerEm / 2
}
return x / f.fUnitsPerEm
}
// Bounds returns the union of a Font's glyphs' bounds.
func (f *Font) Bounds(scale int32) Bounds {
b := f.bounds
b.XMin = f.scale(scale * b.XMin)
b.YMin = f.scale(scale * b.YMin)
b.XMax = f.scale(scale * b.XMax)
b.YMax = f.scale(scale * b.YMax)
return b
}
// FUnitsPerEm returns the number of FUnits in a Font's em-square's side.
func (f *Font) FUnitsPerEm() int32 {
return f.fUnitsPerEm
}
// Index returns a Font's index for the given rune.
func (f *Font) Index(x rune) Index {
c := uint32(x)
for i, j := 0, len(f.cm); i < j; {
h := i + (j-i)/2
cm := &f.cm[h]
if c < cm.start {
j = h
} else if cm.end < c {
i = h + 1
} else if cm.offset == 0 {
return Index(c + cm.delta)
} else {
offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start))
return Index(u16(f.cmapIndexes, offset))
}
}
return 0
}
// unscaledHMetric returns the unscaled horizontal metrics for the glyph with
// the given index.
func (f *Font) unscaledHMetric(i Index) (h HMetric) {
j := int(i)
if j < 0 || f.nGlyph <= j {
return HMetric{}
}
if j >= f.nHMetric {
p := 4 * (f.nHMetric - 1)
return HMetric{
AdvanceWidth: int32(u16(f.hmtx, p)),
LeftSideBearing: int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
}
}
return HMetric{
AdvanceWidth: int32(u16(f.hmtx, 4*j)),
LeftSideBearing: int32(int16(u16(f.hmtx, 4*j+2))),
}
}
// HMetric returns the horizontal metrics for the glyph with the given index.
func (f *Font) HMetric(scale int32, i Index) HMetric {
h := f.unscaledHMetric(i)
h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
return h
}
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
// the given index. yMax is the top of the glyph's bounding box.
func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
j := int(i)
if j < 0 || f.nGlyph <= j {
return VMetric{}
}
if 4*j+4 <= len(f.vmtx) {
return VMetric{
AdvanceHeight: int32(u16(f.vmtx, 4*j)),
TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))),
}
}
// The OS/2 table has grown over time.
// https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html
// says that it was originally 68 bytes. Optional fields, including
// the ascender and descender, are described at
// http://www.microsoft.com/typography/otspec/os2.htm
if len(f.os2) >= 72 {
sTypoAscender := int32(int16(u16(f.os2, 68)))
sTypoDescender := int32(int16(u16(f.os2, 70)))
return VMetric{
AdvanceHeight: sTypoAscender - sTypoDescender,
TopSideBearing: sTypoAscender - yMax,
}
}
return VMetric{
AdvanceHeight: f.fUnitsPerEm,
TopSideBearing: 0,
}
}
// VMetric returns the vertical metrics for the glyph with the given index.
func (f *Font) VMetric(scale int32, i Index) VMetric {
// TODO: should 0 be bounds.YMax?
v := f.unscaledVMetric(i, 0)
v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
v.TopSideBearing = f.scale(scale * v.TopSideBearing)
return v
}
// Kerning returns the kerning for the given glyph pair.
func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
if f.nKern == 0 {
return 0
}
g := uint32(i0)<<16 | uint32(i1)
lo, hi := 0, f.nKern
for lo < hi {
i := (lo + hi) / 2
ig := u32(f.kern, 18+6*i)
if ig < g {
lo = i + 1
} else if ig > g {
hi = i
} else {
return f.scale(scale * int32(int16(u16(f.kern, 22+6*i))))
}
}
return 0
}
// Parse returns a new Font for the given TTF or TTC data.
//
// For TrueType Collections, the first font in the collection is parsed.
func Parse(ttf []byte) (font *Font, err error) {
return parse(ttf, 0)
}
func parse(ttf []byte, offset int) (font *Font, err error) {
if len(ttf)-offset < 12 {
err = FormatError("TTF data is too short")
return
}
originalOffset := offset
magic, offset := u32(ttf, offset), offset+4
switch magic {
case 0x00010000:
// No-op.
case 0x74746366: // "ttcf" as a big-endian uint32.
if originalOffset != 0 {
err = FormatError("recursive TTC")
return
}
ttcVersion, offset := u32(ttf, offset), offset+4
if ttcVersion != 0x00010000 {
// TODO: support TTC version 2.0, once I have such a .ttc file to test with.
err = FormatError("bad TTC version")
return
}
numFonts, offset := int(u32(ttf, offset)), offset+4
if numFonts <= 0 {
err = FormatError("bad number of TTC fonts")
return
}
if len(ttf[offset:])/4 < numFonts {
err = FormatError("TTC offset table is too short")
return
}
// TODO: provide an API to select which font in a TrueType collection to return,
// not just the first one. This may require an API to parse a TTC's name tables,
// so users of this package can select the font in a TTC by name.
offset = int(u32(ttf, offset))
if offset <= 0 || offset > len(ttf) {
err = FormatError("bad TTC offset")
return
}
return parse(ttf, offset)
default:
err = FormatError("bad TTF version")
return
}
n, offset := int(u16(ttf, offset)), offset+2
if len(ttf) < 16*n+12 {
err = FormatError("TTF data is too short")
return
}
f := new(Font)
// Assign the table slices.
for i := 0; i < n; i++ {
x := 16*i + 12
switch string(ttf[x : x+4]) {
case "cmap":
f.cmap, err = readTable(ttf, ttf[x+8:x+16])
case "cvt ":
f.cvt, err = readTable(ttf, ttf[x+8:x+16])
case "fpgm":
f.fpgm, err = readTable(ttf, ttf[x+8:x+16])
case "glyf":
f.glyf, err = readTable(ttf, ttf[x+8:x+16])
case "hdmx":
f.hdmx, err = readTable(ttf, ttf[x+8:x+16])
case "head":
f.head, err = readTable(ttf, ttf[x+8:x+16])
case "hhea":
f.hhea, err = readTable(ttf, ttf[x+8:x+16])
case "hmtx":
f.hmtx, err = readTable(ttf, ttf[x+8:x+16])
case "kern":
f.kern, err = readTable(ttf, ttf[x+8:x+16])
case "loca":
f.loca, err = readTable(ttf, ttf[x+8:x+16])
case "maxp":
f.maxp, err = readTable(ttf, ttf[x+8:x+16])
case "OS/2":
f.os2, err = readTable(ttf, ttf[x+8:x+16])
case "prep":
f.prep, err = readTable(ttf, ttf[x+8:x+16])
case "vmtx":
f.vmtx, err = readTable(ttf, ttf[x+8:x+16])
}
if err != nil {
return
}
}
// Parse and sanity-check the TTF data.
if err = f.parseHead(); err != nil {
return
}
if err = f.parseMaxp(); err != nil {
return
}
if err = f.parseCmap(); err != nil {
return
}
if err = f.parseKern(); err != nil {
return
}
if err = f.parseHhea(); err != nil {
return
}
font = f
return
}

366
Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,366 @@
// 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)
}

27
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,27 @@
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

84
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,84 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) UUID {
uuid := NewUUID()
if uuid != nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCEPerson(Person, uint32(os.Getuid()))
func NewDCEPerson() UUID {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCEGroup(Group, uint32(os.Getgid()))
func NewDCEGroup() UUID {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID or false.
func (uuid UUID) Domain() (Domain, bool) {
if v, _ := uuid.Version(); v != 2 {
return 0, false
}
return Domain(uuid[9]), true
}
// Id returns the id for a Version 2 UUID or false.
func (uuid UUID) Id() (uint32, bool) {
if v, _ := uuid.Version(); v != 2 {
return 0, false
}
return binary.BigEndian.Uint32(uuid[0:4]), true
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

8
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,8 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The uuid package generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
package uuid

53
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,53 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known Name Space IDs and UUIDs
var (
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
NIL = Parse("00000000-0000-0000-0000-000000000000")
)
// NewHash returns a new UUID dervied from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space)
h.Write([]byte(data))
s := h.Sum(nil)
uuid := make([]byte, 16)
copy(uuid, s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data.
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data.
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

30
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/json.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,30 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "errors"
func (u UUID) MarshalJSON() ([]byte, error) {
if len(u) == 0 {
return []byte(`""`), nil
}
return []byte(`"` + u.String() + `"`), nil
}
func (u *UUID) UnmarshalJSON(data []byte) error {
if len(data) == 0 || string(data) == `""` {
return nil
}
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
return errors.New("invalid UUID format")
}
data = data[1 : len(data)-1]
uu := Parse(string(data))
if uu == nil {
return errors.New("invalid UUID format")
}
*u = uu
return nil
}

32
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/json_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/json"
"reflect"
"testing"
)
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
func TestJSON(t *testing.T) {
type S struct {
ID1 UUID
ID2 UUID
}
s1 := S{ID1: testUUID}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}

101
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,101 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "net"
var (
interfaces []net.Interface // cached list of interfaces
ifname string // name of interface being used
nodeID []byte // hardware for version 1 UUIDs
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil && name != "" {
return false
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
if setNodeID(ifs.HardwareAddr) {
ifname = ifs.Name
return true
}
}
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
if nodeID == nil {
nodeID = make([]byte, 6)
}
randomBits(nodeID)
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
if nodeID == nil {
SetNodeInterface("")
}
nid := make([]byte, 6)
copy(nid, nodeID)
return nid
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if setNodeID(id) {
ifname = "user"
return true
}
return false
}
func setNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
if nodeID == nil {
nodeID = make([]byte, 6)
}
copy(nodeID, id)
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
if len(uuid) != 16 {
return nil
}
node := make([]byte, 6)
copy(node, uuid[10:])
return node
}

66
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/seq_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,66 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"flag"
"runtime"
"testing"
"time"
)
// This test is only run when --regressions is passed on the go test line.
var regressions = flag.Bool("regressions", false, "run uuid regression tests")
// TestClockSeqRace tests for a particular race condition of returning two
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
// condition, before being fixed, nearly always occured in under 30 seconds.
func TestClockSeqRace(t *testing.T) {
if !*regressions {
t.Skip("skipping regression tests")
}
duration := time.Minute
done := make(chan struct{})
defer close(done)
ch := make(chan UUID, 10000)
ncpu := runtime.NumCPU()
switch ncpu {
case 0, 1:
// We can't run the test effectively.
t.Skip("skipping race test, only one CPU detected")
return
default:
runtime.GOMAXPROCS(ncpu)
}
for i := 0; i < ncpu; i++ {
go func() {
for {
select {
case <-done:
return
case ch <- NewUUID():
}
}
}()
}
uuids := make(map[string]bool)
cnt := 0
start := time.Now()
for u := range ch {
s := u.String()
if uuids[s] {
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
return
}
uuids[s] = true
if time.Since(start) > duration {
return
}
cnt++
}
}

132
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,132 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
mu sync.Mutex
lasttime uint64 // last time we returned
clock_seq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer mu.Unlock()
mu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clock_seq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clock_seq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence a new random
// clock sequence is generated the first time a clock sequence is requested by
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
// for
func ClockSequence() int {
defer mu.Unlock()
mu.Lock()
return clockSequence()
}
func clockSequence() int {
if clock_seq == 0 {
setClockSequence(-1)
}
return int(clock_seq & 0x3fff)
}
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer mu.Unlock()
mu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
old_seq := clock_seq
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if old_seq != clock_seq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. It returns false if uuid is not valid. The time is only well defined
// for version 1 and 2 UUIDs.
func (uuid UUID) Time() (Time, bool) {
if len(uuid) != 16 {
return 0, false
}
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time), true
}
// ClockSequence returns the clock sequence encoded in uuid. It returns false
// if uuid is not valid. The clock sequence is only well defined for version 1
// and 2 UUIDs.
func (uuid UUID) ClockSequence() (int, bool) {
if len(uuid) != 16 {
return 0, false
}
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
}

43
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,43 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = []byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts the the first two hex bytes of x into a byte.
func xtob(x string) (byte, bool) {
b1 := xvalues[x[0]]
b2 := xvalues[x[1]]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

163
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,163 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"strings"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID []byte
// A Version represents a UUIDs version.
type Version byte
// A Variant represents a UUIDs variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
var rander = rand.Reader // random function
// New returns a new random (version 4) UUID as a string. It is a convenience
// function for NewRandom().String().
func New() string {
return NewRandom().String()
}
// Parse decodes s into a UUID or returns nil. Both the UUID form of
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
func Parse(s string) UUID {
if len(s) == 36+9 {
if strings.ToLower(s[:9]) != "urn:uuid:" {
return nil
}
s = s[9:]
} else if len(s) != 36 {
return nil
}
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return nil
}
uuid := make([]byte, 16)
for i, x := range []int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
if v, ok := xtob(s[x:]); !ok {
return nil
} else {
uuid[i] = v
}
}
return uuid
}
// Equal returns true if uuid1 and uuid2 are equal.
func Equal(uuid1, uuid2 UUID) bool {
return bytes.Equal(uuid1, uuid2)
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
if uuid == nil || len(uuid) != 16 {
return ""
}
b := []byte(uuid)
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
if uuid == nil || len(uuid) != 16 {
return ""
}
b := []byte(uuid)
return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x",
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
}
// Variant returns the variant encoded in uuid. It returns Invalid if
// uuid is invalid.
func (uuid UUID) Variant() Variant {
if len(uuid) != 16 {
return Invalid
}
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
panic("unreachable")
}
// Version returns the verison of uuid. It returns false if uuid is not
// valid.
func (uuid UUID) Version() (Version, bool) {
if len(uuid) != 16 {
return 0, false
}
return Version(uuid[6] >> 4), true
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implents io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}

390
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,390 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"fmt"
"os"
"strings"
"testing"
"time"
)
type test struct {
in string
version Version
variant Variant
isuuid bool
}
var tests = []test{
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
}
var constants = []struct {
c interface{}
name string
}{
{Person, "Person"},
{Group, "Group"},
{Org, "Org"},
{Invalid, "Invalid"},
{RFC4122, "RFC4122"},
{Reserved, "Reserved"},
{Microsoft, "Microsoft"},
{Future, "Future"},
{Domain(17), "Domain17"},
{Variant(42), "BadVariant42"},
}
func testTest(t *testing.T, in string, tt test) {
uuid := Parse(in)
if ok := (uuid != nil); ok != tt.isuuid {
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if uuid == nil {
return
}
if v := uuid.Variant(); v != tt.variant {
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
}
if v, _ := uuid.Version(); v != tt.version {
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
}
}
func TestUUID(t *testing.T) {
for _, tt := range tests {
testTest(t, tt.in, tt)
testTest(t, strings.ToUpper(tt.in), tt)
}
}
func TestConstants(t *testing.T) {
for x, tt := range constants {
v, ok := tt.c.(fmt.Stringer)
if !ok {
t.Errorf("%x: %v: not a stringer", x, v)
} else if s := v.String(); s != tt.name {
v, _ := tt.c.(int)
t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name)
}
}
}
func TestRandomUUID(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
uuid := NewRandom()
s := uuid.String()
if m[s] {
t.Errorf("NewRandom returned duplicated UUID %s\n", s)
}
m[s] = true
if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s\n", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d\n", uuid.Variant())
}
}
}
func TestNew(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
s := New()
if m[s] {
t.Errorf("New returned duplicated UUID %s\n", s)
}
m[s] = true
uuid := Parse(s)
if uuid == nil {
t.Errorf("New returned %q which does not decode\n", s)
continue
}
if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s\n", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d\n", uuid.Variant())
}
}
}
func clockSeq(t *testing.T, uuid UUID) int {
seq, ok := uuid.ClockSequence()
if !ok {
t.Fatalf("%s: invalid clock sequence\n", uuid)
}
return seq
}
func TestClockSeq(t *testing.T) {
// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
defer func(orig func() time.Time) { timeNow = orig }(timeNow)
monTime := time.Now()
timeNow = func() time.Time {
monTime = monTime.Add(1 * time.Second)
return monTime
}
SetClockSequence(-1)
uuid1 := NewUUID()
uuid2 := NewUUID()
if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2))
}
SetClockSequence(-1)
uuid2 = NewUUID()
// Just on the very off chance we generated the same sequence
// two times we try again.
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
SetClockSequence(-1)
uuid2 = NewUUID()
}
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1))
}
SetClockSequence(0x1234)
uuid1 = NewUUID()
if seq := clockSeq(t, uuid1); seq != 0x1234 {
t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq)
}
}
func TestCoding(t *testing.T) {
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
data := UUID{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
if v := data.String(); v != text {
t.Errorf("%x: encoded to %s, expected %s\n", data, v, text)
}
if v := data.URN(); v != urn {
t.Errorf("%x: urn is %s, expected %s\n", data, v, urn)
}
uuid := Parse(text)
if !Equal(uuid, data) {
t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data)
}
}
func TestVersion1(t *testing.T) {
uuid1 := NewUUID()
uuid2 := NewUUID()
if Equal(uuid1, uuid2) {
t.Errorf("%s:duplicate uuid\n", uuid1)
}
if v, _ := uuid1.Version(); v != 1 {
t.Errorf("%s: version %s expected 1\n", uuid1, v)
}
if v, _ := uuid2.Version(); v != 1 {
t.Errorf("%s: version %s expected 1\n", uuid2, v)
}
n1 := uuid1.NodeID()
n2 := uuid2.NodeID()
if !bytes.Equal(n1, n2) {
t.Errorf("Different nodes %x != %x\n", n1, n2)
}
t1, ok := uuid1.Time()
if !ok {
t.Errorf("%s: invalid time\n", uuid1)
}
t2, ok := uuid2.Time()
if !ok {
t.Errorf("%s: invalid time\n", uuid2)
}
q1, ok := uuid1.ClockSequence()
if !ok {
t.Errorf("%s: invalid clock sequence\n", uuid1)
}
q2, ok := uuid2.ClockSequence()
if !ok {
t.Errorf("%s: invalid clock sequence", uuid2)
}
switch {
case t1 == t2 && q1 == q2:
t.Errorf("time stopped\n")
case t1 > t2 && q1 == q2:
t.Errorf("time reversed\n")
case t1 < t2 && q1 != q2:
t.Errorf("clock sequence chaned unexpectedly\n")
}
}
func TestNodeAndTime(t *testing.T) {
// Time is February 5, 1998 12:30:23.136364800 AM GMT
uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
ts, ok := uuid.Time()
if ok {
c := time.Unix(ts.UnixTime())
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
if !c.Equal(want) {
t.Errorf("Got time %v, want %v", c, want)
}
} else {
t.Errorf("%s: bad time\n", uuid)
}
if !bytes.Equal(node, uuid.NodeID()) {
t.Errorf("Expected node %v got %v\n", node, uuid.NodeID())
}
}
func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
if uuid != want {
t.Errorf("MD5: got %q expected %q\n", uuid, want)
}
}
func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
if uuid != want {
t.Errorf("SHA1: got %q expected %q\n", uuid, want)
}
}
func TestNodeID(t *testing.T) {
nid := []byte{1, 2, 3, 4, 5, 6}
SetNodeInterface("")
s := NodeInterface()
if s == "" || s == "user" {
t.Errorf("NodeInterface %q after SetInteface\n", s)
}
node1 := NodeID()
if node1 == nil {
t.Errorf("NodeID nil after SetNodeInterface\n", s)
}
SetNodeID(nid)
s = NodeInterface()
if s != "user" {
t.Errorf("Expected NodeInterface %q got %q\n", "user", s)
}
node2 := NodeID()
if node2 == nil {
t.Errorf("NodeID nil after SetNodeID\n", s)
}
if bytes.Equal(node1, node2) {
t.Errorf("NodeID not changed after SetNodeID\n", s)
} else if !bytes.Equal(nid, node2) {
t.Errorf("NodeID is %x, expected %x\n", node2, nid)
}
}
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
if uuid == nil {
t.Errorf("%s failed\n", name)
return
}
if v, _ := uuid.Version(); v != 2 {
t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v)
return
}
if v, ok := uuid.Domain(); !ok || v != domain {
if !ok {
t.Errorf("%s: %d: Domain failed\n", name, uuid)
} else {
t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v)
}
}
if v, ok := uuid.Id(); !ok || v != id {
if !ok {
t.Errorf("%s: %d: Id failed\n", name, uuid)
} else {
t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v)
}
}
}
func TestDCE(t *testing.T) {
testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678)
testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid()))
testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid()))
}
type badRand struct{}
func (r badRand) Read(buf []byte) (int, error) {
for i, _ := range buf {
buf[i] = byte(i)
}
return len(buf), nil
}
func TestBadRand(t *testing.T) {
SetRand(badRand{})
uuid1 := New()
uuid2 := New()
if uuid1 != uuid2 {
t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2)
}
SetRand(nil)
uuid1 = New()
uuid2 = New()
if uuid1 == uuid2 {
t.Errorf("unexecpted duplicates, got %q\n", uuid1)
}
}

41
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,41 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil.
func NewUUID() UUID {
if nodeID == nil {
SetNodeInterface("")
}
now, seq, err := GetTime()
if err != nil {
return nil
}
uuid := make([]byte, 16)
time_low := uint32(now & 0xffffffff)
time_mid := uint16((now >> 32) & 0xffff)
time_hi := uint16((now >> 48) & 0x0fff)
time_hi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], time_low)
binary.BigEndian.PutUint16(uuid[4:], time_mid)
binary.BigEndian.PutUint16(uuid[6:], time_hi)
binary.BigEndian.PutUint16(uuid[8:], seq)
copy(uuid[10:], nodeID)
return uuid
}

25
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,25 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
// Random returns a Random (Version 4) UUID or panics.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() UUID {
uuid := make([]byte, 16)
randomBits([]byte(uuid))
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid
}

35
Godeps/_workspace/src/code.google.com/p/go.crypto/bcrypt/base64.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,35 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bcrypt
import "encoding/base64"
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var bcEncoding = base64.NewEncoding(alphabet)
func base64Encode(src []byte) []byte {
n := bcEncoding.EncodedLen(len(src))
dst := make([]byte, n)
bcEncoding.Encode(dst, src)
for dst[n-1] == '=' {
n--
}
return dst[:n]
}
func base64Decode(src []byte) ([]byte, error) {
numOfEquals := 4 - (len(src) % 4)
for i := 0; i < numOfEquals; i++ {
src = append(src, '=')
}
dst := make([]byte, bcEncoding.DecodedLen(len(src)))
n, err := bcEncoding.Decode(dst, src)
if err != nil {
return nil, err
}
return dst[:n], nil
}

294
Godeps/_workspace/src/code.google.com/p/go.crypto/bcrypt/bcrypt.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,294 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
package bcrypt
// The code is a port of Provos and Mazières's C implementation.
import (
"crypto/rand"
"crypto/subtle"
"errors"
"fmt"
"golang.org/x/crypto/blowfish"
"io"
"strconv"
)
const (
MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword
MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
)
// The error returned from CompareHashAndPassword when a password and hash do
// not match.
var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
// The error returned from CompareHashAndPassword when a hash is too short to
// be a bcrypt hash.
var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
// The error returned from CompareHashAndPassword when a hash was created with
// a bcrypt algorithm newer than this implementation.
type HashVersionTooNewError byte
func (hv HashVersionTooNewError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
}
// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
type InvalidHashPrefixError byte
func (ih InvalidHashPrefixError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
}
type InvalidCostError int
func (ic InvalidCostError) Error() string {
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
}
const (
majorVersion = '2'
minorVersion = 'a'
maxSaltSize = 16
maxCryptedHashSize = 23
encodedSaltSize = 22
encodedHashSize = 31
minHashSize = 59
)
// magicCipherData is an IV for the 64 Blowfish encryption calls in
// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
var magicCipherData = []byte{
0x4f, 0x72, 0x70, 0x68,
0x65, 0x61, 0x6e, 0x42,
0x65, 0x68, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x53,
0x63, 0x72, 0x79, 0x44,
0x6f, 0x75, 0x62, 0x74,
}
type hashed struct {
hash []byte
salt []byte
cost int // allowed range is MinCost to MaxCost
major byte
minor byte
}
// GenerateFromPassword returns the bcrypt hash of the password at the given
// cost. If the cost given is less than MinCost, the cost will be set to
// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
// to compare the returned hashed password with its cleartext version.
func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
p, err := newFromPassword(password, cost)
if err != nil {
return nil, err
}
return p.Hash(), nil
}
// CompareHashAndPassword compares a bcrypt hashed password with its possible
// plaintext equivalent. Returns nil on success, or an error on failure.
func CompareHashAndPassword(hashedPassword, password []byte) error {
p, err := newFromHash(hashedPassword)
if err != nil {
return err
}
otherHash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return err
}
otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
return nil
}
return ErrMismatchedHashAndPassword
}
// Cost returns the hashing cost used to create the given hashed
// password. When, in the future, the hashing cost of a password system needs
// to be increased in order to adjust for greater computational power, this
// function allows one to establish which passwords need to be updated.
func Cost(hashedPassword []byte) (int, error) {
p, err := newFromHash(hashedPassword)
if err != nil {
return 0, err
}
return p.cost, nil
}
func newFromPassword(password []byte, cost int) (*hashed, error) {
if cost < MinCost {
cost = DefaultCost
}
p := new(hashed)
p.major = majorVersion
p.minor = minorVersion
err := checkCost(cost)
if err != nil {
return nil, err
}
p.cost = cost
unencodedSalt := make([]byte, maxSaltSize)
_, err = io.ReadFull(rand.Reader, unencodedSalt)
if err != nil {
return nil, err
}
p.salt = base64Encode(unencodedSalt)
hash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return nil, err
}
p.hash = hash
return p, err
}
func newFromHash(hashedSecret []byte) (*hashed, error) {
if len(hashedSecret) < minHashSize {
return nil, ErrHashTooShort
}
p := new(hashed)
n, err := p.decodeVersion(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
n, err = p.decodeCost(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
// The "+2" is here because we'll have to append at most 2 '=' to the salt
// when base64 decoding it in expensiveBlowfishSetup().
p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
copy(p.salt, hashedSecret[:encodedSaltSize])
hashedSecret = hashedSecret[encodedSaltSize:]
p.hash = make([]byte, len(hashedSecret))
copy(p.hash, hashedSecret)
return p, nil
}
func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
cipherData := make([]byte, len(magicCipherData))
copy(cipherData, magicCipherData)
c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
if err != nil {
return nil, err
}
for i := 0; i < 24; i += 8 {
for j := 0; j < 64; j++ {
c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
}
}
// Bug compatibility with C bcrypt implementations. We only encode 23 of
// the 24 bytes encrypted.
hsh := base64Encode(cipherData[:maxCryptedHashSize])
return hsh, nil
}
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
csalt, err := base64Decode(salt)
if err != nil {
return nil, err
}
// Bug compatibility with C bcrypt implementations. They use the trailing
// NULL in the key string during expansion.
ckey := append(key, 0)
c, err := blowfish.NewSaltedCipher(ckey, csalt)
if err != nil {
return nil, err
}
var i, rounds uint64
rounds = 1 << cost
for i = 0; i < rounds; i++ {
blowfish.ExpandKey(ckey, c)
blowfish.ExpandKey(csalt, c)
}
return c, nil
}
func (p *hashed) Hash() []byte {
arr := make([]byte, 60)
arr[0] = '$'
arr[1] = p.major
n := 2
if p.minor != 0 {
arr[2] = p.minor
n = 3
}
arr[n] = '$'
n += 1
copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
n += 2
arr[n] = '$'
n += 1
copy(arr[n:], p.salt)
n += encodedSaltSize
copy(arr[n:], p.hash)
n += encodedHashSize
return arr[:n]
}
func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
if sbytes[0] != '$' {
return -1, InvalidHashPrefixError(sbytes[0])
}
if sbytes[1] > majorVersion {
return -1, HashVersionTooNewError(sbytes[1])
}
p.major = sbytes[1]
n := 3
if sbytes[2] != '$' {
p.minor = sbytes[2]
n++
}
return n, nil
}
// sbytes should begin where decodeVersion left off.
func (p *hashed) decodeCost(sbytes []byte) (int, error) {
cost, err := strconv.Atoi(string(sbytes[0:2]))
if err != nil {
return -1, err
}
err = checkCost(cost)
if err != nil {
return -1, err
}
p.cost = cost
return 3, nil
}
func (p *hashed) String() string {
return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
}
func checkCost(cost int) error {
if cost < MinCost || cost > MaxCost {
return InvalidCostError(cost)
}
return nil
}

226
Godeps/_workspace/src/code.google.com/p/go.crypto/bcrypt/bcrypt_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,226 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bcrypt
import (
"bytes"
"fmt"
"testing"
)
func TestBcryptingIsEasy(t *testing.T) {
pass := []byte("mypassword")
hp, err := GenerateFromPassword(pass, 0)
if err != nil {
t.Fatalf("GenerateFromPassword error: %s", err)
}
if CompareHashAndPassword(hp, pass) != nil {
t.Errorf("%v should hash %s correctly", hp, pass)
}
notPass := "notthepass"
err = CompareHashAndPassword(hp, []byte(notPass))
if err != ErrMismatchedHashAndPassword {
t.Errorf("%v and %s should be mismatched", hp, notPass)
}
}
func TestBcryptingIsCorrect(t *testing.T) {
pass := []byte("allmine")
salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
hash, err := bcrypt(pass, 10, salt)
if err != nil {
t.Fatalf("bcrypt blew up: %v", err)
}
if !bytes.HasSuffix(expectedHash, hash) {
t.Errorf("%v should be the suffix of %v", hash, expectedHash)
}
h, err := newFromHash(expectedHash)
if err != nil {
t.Errorf("Unable to parse %s: %v", string(expectedHash), err)
}
// This is not the safe way to compare these hashes. We do this only for
// testing clarity. Use bcrypt.CompareHashAndPassword()
if err == nil && !bytes.Equal(expectedHash, h.Hash()) {
t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash)
}
}
func TestVeryShortPasswords(t *testing.T) {
key := []byte("k")
salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
_, err := bcrypt(key, 10, salt)
if err != nil {
t.Errorf("One byte key resulted in error: %s", err)
}
}
func TestTooLongPasswordsWork(t *testing.T) {
salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
// One byte over the usual 56 byte limit that blowfish has
tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456")
tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C")
hash, err := bcrypt(tooLongPass, 10, salt)
if err != nil {
t.Fatalf("bcrypt blew up on long password: %v", err)
}
if !bytes.HasSuffix(tooLongExpected, hash) {
t.Errorf("%v should be the suffix of %v", hash, tooLongExpected)
}
}
type InvalidHashTest struct {
err error
hash []byte
}
var invalidTests = []InvalidHashTest{
{ErrHashTooShort, []byte("$2a$10$fooo")},
{ErrHashTooShort, []byte("$2a")},
{HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
{InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
{InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
}
func TestInvalidHashErrors(t *testing.T) {
check := func(name string, expected, err error) {
if err == nil {
t.Errorf("%s: Should have returned an error", name)
}
if err != nil && err != expected {
t.Errorf("%s gave err %v but should have given %v", name, err, expected)
}
}
for _, iht := range invalidTests {
_, err := newFromHash(iht.hash)
check("newFromHash", iht.err, err)
err = CompareHashAndPassword(iht.hash, []byte("anything"))
check("CompareHashAndPassword", iht.err, err)
}
}
func TestUnpaddedBase64Encoding(t *testing.T) {
original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30}
encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe")
encoded := base64Encode(original)
if !bytes.Equal(encodedOriginal, encoded) {
t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal)
}
decoded, err := base64Decode(encodedOriginal)
if err != nil {
t.Fatalf("base64Decode blew up: %s", err)
}
if !bytes.Equal(decoded, original) {
t.Errorf("Decoded %v should have equaled %v", decoded, original)
}
}
func TestCost(t *testing.T) {
suffix := "XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C"
for _, vers := range []string{"2a", "2"} {
for _, cost := range []int{4, 10} {
s := fmt.Sprintf("$%s$%02d$%s", vers, cost, suffix)
h := []byte(s)
actual, err := Cost(h)
if err != nil {
t.Errorf("Cost, error: %s", err)
continue
}
if actual != cost {
t.Errorf("Cost, expected: %d, actual: %d", cost, actual)
}
}
}
_, err := Cost([]byte("$a$a$" + suffix))
if err == nil {
t.Errorf("Cost, malformed but no error returned")
}
}
func TestCostValidationInHash(t *testing.T) {
if testing.Short() {
return
}
pass := []byte("mypassword")
for c := 0; c < MinCost; c++ {
p, _ := newFromPassword(pass, c)
if p.cost != DefaultCost {
t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost)
}
}
p, _ := newFromPassword(pass, 14)
if p.cost != 14 {
t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost)
}
hp, _ := newFromHash(p.Hash())
if p.cost != hp.cost {
t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost)
}
_, err := newFromPassword(pass, 32)
if err == nil {
t.Fatalf("newFromPassword: should return a cost error")
}
if err != InvalidCostError(32) {
t.Errorf("newFromPassword: should return cost error, got %#v", err)
}
}
func TestCostReturnsWithLeadingZeroes(t *testing.T) {
hp, _ := newFromPassword([]byte("abcdefgh"), 7)
cost := hp.Hash()[4:7]
expected := []byte("07$")
if !bytes.Equal(expected, cost) {
t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected)
}
}
func TestMinorNotRequired(t *testing.T) {
noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
h, err := newFromHash(noMinorHash)
if err != nil {
t.Fatalf("No minor hash blew up: %s", err)
}
if h.minor != 0 {
t.Errorf("Should leave minor version at 0, but was %d", h.minor)
}
if !bytes.Equal(noMinorHash, h.Hash()) {
t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash())
}
}
func BenchmarkEqual(b *testing.B) {
b.StopTimer()
passwd := []byte("somepasswordyoulike")
hash, _ := GenerateFromPassword(passwd, 10)
b.StartTimer()
for i := 0; i < b.N; i++ {
CompareHashAndPassword(hash, passwd)
}
}
func BenchmarkGeneration(b *testing.B) {
b.StopTimer()
passwd := []byte("mylongpassword1234")
b.StartTimer()
for i := 0; i < b.N; i++ {
GenerateFromPassword(passwd, 10)
}
}

4
Godeps/_workspace/src/code.google.com/p/log4go/.hgtags сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,4 @@
4fbe6aadba231e838a449d340e43bdaab0bf85bd go.weekly.2012-02-07
56168fd53249d639c25c74ced881fffb20d27be9 go.weekly.2012-02-22
56168fd53249d639c25c74ced881fffb20d27be9 go.weekly.2012-02-22
5c22fbd77d91f54d76cdbdee05318699754c44cc go.weekly.2012-02-22

13
Godeps/_workspace/src/code.google.com/p/log4go/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
Copyright (c) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

12
Godeps/_workspace/src/code.google.com/p/log4go/README сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,12 @@
Please see http://log4go.googlecode.com/
Installation:
- Run `goinstall log4go.googlecode.com/hg`
Usage:
- Add the following import:
import l4g "log4go.googlecode.com/hg"
Acknowledgements:
- pomack
For providing awesome patches to bring log4go up to the latest Go spec

288
Godeps/_workspace/src/code.google.com/p/log4go/config.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,288 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
type xmlProperty struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
}
type xmlFilter struct {
Enabled string `xml:"enabled,attr"`
Tag string `xml:"tag"`
Level string `xml:"level"`
Type string `xml:"type"`
Property []xmlProperty `xml:"property"`
}
type xmlLoggerConfig struct {
Filter []xmlFilter `xml:"filter"`
}
// Load XML configuration; see examples/example.xml for documentation
func (log Logger) LoadConfiguration(filename string) {
log.Close()
// Open the configuration file
fd, err := os.Open(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
os.Exit(1)
}
contents, err := ioutil.ReadAll(fd)
if err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
os.Exit(1)
}
xc := new(xmlLoggerConfig)
if err := xml.Unmarshal(contents, xc); err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
os.Exit(1)
}
for _, xmlfilt := range xc.Filter {
var filt LogWriter
var lvl level
bad, good, enabled := false, true, false
// Check required children
if len(xmlfilt.Enabled) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
bad = true
} else {
enabled = xmlfilt.Enabled != "false"
}
if len(xmlfilt.Tag) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
bad = true
}
if len(xmlfilt.Type) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
bad = true
}
if len(xmlfilt.Level) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
bad = true
}
switch xmlfilt.Level {
case "FINEST":
lvl = FINEST
case "FINE":
lvl = FINE
case "DEBUG":
lvl = DEBUG
case "TRACE":
lvl = TRACE
case "INFO":
lvl = INFO
case "WARNING":
lvl = WARNING
case "ERROR":
lvl = ERROR
case "CRITICAL":
lvl = CRITICAL
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
bad = true
}
// Just so all of the required attributes are errored at the same time if missing
if bad {
os.Exit(1)
}
switch xmlfilt.Type {
case "console":
filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
case "file":
filt, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
case "xml":
filt, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
case "socket":
filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
os.Exit(1)
}
// Just so all of the required params are errored at the same time if wrong
if !good {
os.Exit(1)
}
// If we're disabled (syntax and correctness checks only), don't add to logger
if !enabled {
continue
}
log[xmlfilt.Tag] = &Filter{lvl, filt}
}
}
func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (ConsoleLogWriter, bool) {
// Parse properties
for _, prop := range props {
switch prop.Name {
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
}
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true
}
return NewConsoleLogWriter(), true
}
// Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
func strToNumSuffix(str string, mult int) int {
num := 1
if len(str) > 1 {
switch str[len(str)-1] {
case 'G', 'g':
num *= mult
fallthrough
case 'M', 'm':
num *= mult
fallthrough
case 'K', 'k':
num *= mult
str = str[0 : len(str)-1]
}
}
parsed, _ := strconv.Atoi(str)
return parsed * num
}
func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
file := ""
format := "[%D %T] [%L] (%S) %M"
maxlines := 0
maxsize := 0
daily := false
rotate := false
// Parse properties
for _, prop := range props {
switch prop.Name {
case "filename":
file = strings.Trim(prop.Value, " \r\n")
case "format":
format = strings.Trim(prop.Value, " \r\n")
case "maxlines":
maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
case "maxsize":
maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
case "daily":
daily = strings.Trim(prop.Value, " \r\n") != "false"
case "rotate":
rotate = strings.Trim(prop.Value, " \r\n") != "false"
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
}
}
// Check properties
if len(file) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
return nil, false
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true
}
flw := NewFileLogWriter(file, rotate)
flw.SetFormat(format)
flw.SetRotateLines(maxlines)
flw.SetRotateSize(maxsize)
flw.SetRotateDaily(daily)
return flw, true
}
func xmlToXMLLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
file := ""
maxrecords := 0
maxsize := 0
daily := false
rotate := false
// Parse properties
for _, prop := range props {
switch prop.Name {
case "filename":
file = strings.Trim(prop.Value, " \r\n")
case "maxrecords":
maxrecords = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
case "maxsize":
maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
case "daily":
daily = strings.Trim(prop.Value, " \r\n") != "false"
case "rotate":
rotate = strings.Trim(prop.Value, " \r\n") != "false"
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for xml filter in %s\n", prop.Name, filename)
}
}
// Check properties
if len(file) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for xml filter missing in %s\n", "filename", filename)
return nil, false
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true
}
xlw := NewXMLLogWriter(file, rotate)
xlw.SetRotateLines(maxrecords)
xlw.SetRotateSize(maxsize)
xlw.SetRotateDaily(daily)
return xlw, true
}
func xmlToSocketLogWriter(filename string, props []xmlProperty, enabled bool) (SocketLogWriter, bool) {
endpoint := ""
protocol := "udp"
// Parse properties
for _, prop := range props {
switch prop.Name {
case "endpoint":
endpoint = strings.Trim(prop.Value, " \r\n")
case "protocol":
protocol = strings.Trim(prop.Value, " \r\n")
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
}
}
// Check properties
if len(endpoint) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "endpoint", filename)
return nil, false
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true
}
return NewSocketLogWriter(protocol, endpoint), true
}

13
Godeps/_workspace/src/code.google.com/p/log4go/examples/ConsoleLogWriter_Manual.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
package main
import (
"time"
)
import l4g "code.google.com/p/log4go"
func main() {
log := l4g.NewLogger()
log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
}

57
Godeps/_workspace/src/code.google.com/p/log4go/examples/FileLogWriter_Manual.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,57 @@
package main
import (
"bufio"
"fmt"
"io"
"os"
"time"
)
import l4g "code.google.com/p/log4go"
const (
filename = "flw.log"
)
func main() {
// Get a new logger instance
log := l4g.NewLogger()
// Create a default logger that is logging messages of FINE or higher
log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false))
log.Close()
/* Can also specify manually via the following: (these are the defaults) */
flw := l4g.NewFileLogWriter(filename, false)
flw.SetFormat("[%D %T] [%L] (%S) %M")
flw.SetRotate(false)
flw.SetRotateSize(0)
flw.SetRotateLines(0)
flw.SetRotateDaily(false)
log.AddFilter("file", l4g.FINE, flw)
// Log some experimental messages
log.Finest("Everything is created now (notice that I will not be printing to the file)")
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
log.Critical("Time to close out!")
// Close the log
log.Close()
// Print what was logged to the file (yes, I know I'm skipping error checking)
fd, _ := os.Open(filename)
in := bufio.NewReader(fd)
fmt.Print("Messages logged to file were: (line numbers not included)\n")
for lineno := 1; ; lineno++ {
line, err := in.ReadString('\n')
if err == io.EOF {
break
}
fmt.Printf("%3d:\t%s", lineno, line)
}
fd.Close()
// Remove the file so it's not lying around
os.Remove(filename)
}

42
Godeps/_workspace/src/code.google.com/p/log4go/examples/SimpleNetLogServer.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
package main
import (
"flag"
"fmt"
"net"
"os"
)
var (
port = flag.String("p", "12124", "Port number to listen on")
)
func e(err error) {
if err != nil {
fmt.Printf("Erroring out: %s\n", err)
os.Exit(1)
}
}
func main() {
flag.Parse()
// Bind to the port
bind, err := net.ResolveUDPAddr("0.0.0.0:" + *port)
e(err)
// Create listener
listener, err := net.ListenUDP("udp", bind)
e(err)
fmt.Printf("Listening to port %s...\n", *port)
for {
// read into a new buffer
buffer := make([]byte, 1024)
_, _, err := listener.ReadFrom(buffer)
e(err)
// log to standard output
fmt.Println(string(buffer))
}
}

18
Godeps/_workspace/src/code.google.com/p/log4go/examples/SocketLogWriter_Manual.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,18 @@
package main
import (
"time"
)
import l4g "code.google.com/p/log4go"
func main() {
log := l4g.NewLogger()
log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
// Run `nc -u -l -p 12124` or similar before you run this to see the following message
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
// This makes sure the output stream buffer is written
log.Close()
}

13
Godeps/_workspace/src/code.google.com/p/log4go/examples/XMLConfigurationExample.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
package main
import l4g "code.google.com/p/log4go"
func main() {
// Load the configuration (isn't this easy?)
l4g.LoadConfiguration("example.xml")
// And now we're ready!
l4g.Finest("This will only go to those of you really cool UDP kids! If you change enabled=true.")
l4g.Debug("Oh no! %d + %d = %d!", 2, 2, 2+2)
l4g.Info("About that time, eh chaps?")
}

47
Godeps/_workspace/src/code.google.com/p/log4go/examples/example.xml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,47 @@
<logging>
<filter enabled="true">
<tag>stdout</tag>
<type>console</type>
<!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->
<level>DEBUG</level>
</filter>
<filter enabled="true">
<tag>file</tag>
<type>file</type>
<level>FINEST</level>
<property name="filename">test.log</property>
<!--
%T - Time (15:04:05 MST)
%t - Time (15:04)
%D - Date (2006/01/02)
%d - Date (01/02/06)
%L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
%S - Source
%M - Message
It ignores unknown format strings (and removes them)
Recommended: "[%D %T] [%L] (%S) %M"
-->
<property name="format">[%D %T] [%L] (%S) %M</property>
<property name="rotate">false</property> <!-- true enables log rotation, otherwise append -->
<property name="maxsize">0M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
<property name="maxlines">0K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
<property name="daily">true</property> <!-- Automatically rotates when a log message is written after midnight -->
</filter>
<filter enabled="true">
<tag>xmllog</tag>
<type>xml</type>
<level>TRACE</level>
<property name="filename">trace.xml</property>
<property name="rotate">true</property> <!-- true enables log rotation, otherwise append -->
<property name="maxsize">100M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
<property name="maxrecords">6K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
<property name="daily">false</property> <!-- Automatically rotates when a log message is written after midnight -->
</filter>
<filter enabled="false"><!-- enabled=false means this logger won't actually be created -->
<tag>donotopen</tag>
<type>socket</type>
<level>FINEST</level>
<property name="endpoint">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->
<property name="protocol">udp</property> <!-- tcp or udp -->
</filter>
</logging>

239
Godeps/_workspace/src/code.google.com/p/log4go/filelog.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,239 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"os"
"fmt"
"time"
)
// This log writer sends output to a file
type FileLogWriter struct {
rec chan *LogRecord
rot chan bool
// The opened file
filename string
file *os.File
// The logging format
format string
// File header/trailer
header, trailer string
// Rotate at linecount
maxlines int
maxlines_curlines int
// Rotate at size
maxsize int
maxsize_cursize int
// Rotate daily
daily bool
daily_opendate int
// Keep old logfiles (.001, .002, etc)
rotate bool
}
// This is the FileLogWriter's output method
func (w *FileLogWriter) LogWrite(rec *LogRecord) {
w.rec <- rec
}
func (w *FileLogWriter) Close() {
close(w.rec)
}
// NewFileLogWriter creates a new LogWriter which writes to the given file and
// has rotation enabled if rotate is true.
//
// If rotate is true, any time a new log file is opened, the old one is renamed
// with a .### extension to preserve it. The various Set* methods can be used
// to configure log rotation based on lines, size, and daily.
//
// The standard log-line format is:
// [%D %T] [%L] (%S) %M
func NewFileLogWriter(fname string, rotate bool) *FileLogWriter {
w := &FileLogWriter{
rec: make(chan *LogRecord, LogBufferLength),
rot: make(chan bool),
filename: fname,
format: "[%D %T] [%L] (%S) %M",
rotate: rotate,
}
// open the file for the first time
if err := w.intRotate(); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
return nil
}
go func() {
defer func() {
if w.file != nil {
fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
w.file.Close()
}
}()
for {
select {
case <-w.rot:
if err := w.intRotate(); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
return
}
case rec, ok := <-w.rec:
if !ok {
return
}
now := time.Now()
if (w.maxlines > 0 && w.maxlines_curlines >= w.maxlines) ||
(w.maxsize > 0 && w.maxsize_cursize >= w.maxsize) ||
(w.daily && now.Day() != w.daily_opendate) {
if err := w.intRotate(); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
return
}
}
// Perform the write
n, err := fmt.Fprint(w.file, FormatLogRecord(w.format, rec))
if err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
return
}
// Update the counts
w.maxlines_curlines++
w.maxsize_cursize += n
}
}
}()
return w
}
// Request that the logs rotate
func (w *FileLogWriter) Rotate() {
w.rot <- true
}
// If this is called in a threaded context, it MUST be synchronized
func (w *FileLogWriter) intRotate() error {
// Close any log file that may be open
if w.file != nil {
fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
w.file.Close()
}
// If we are keeping log files, move it to the next available number
if w.rotate {
_, err := os.Lstat(w.filename)
if err == nil { // file exists
// Find the next available number
num := 1
fname := ""
for ; err == nil && num <= 999; num++ {
fname = w.filename + fmt.Sprintf(".%03d", num)
_, err = os.Lstat(fname)
}
// return error if the last file checked still existed
if err == nil {
return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.filename)
}
// Rename the file to its newfound home
err = os.Rename(w.filename, fname)
if err != nil {
return fmt.Errorf("Rotate: %s\n", err)
}
}
}
// Open the log file
fd, err := os.OpenFile(w.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
if err != nil {
return err
}
w.file = fd
now := time.Now()
fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: now}))
// Set the daily open date to the current date
w.daily_opendate = now.Day()
// initialize rotation values
w.maxlines_curlines = 0
w.maxsize_cursize = 0
return nil
}
// Set the logging format (chainable). Must be called before the first log
// message is written.
func (w *FileLogWriter) SetFormat(format string) *FileLogWriter {
w.format = format
return w
}
// Set the logfile header and footer (chainable). Must be called before the first log
// message is written. These are formatted similar to the FormatLogRecord (e.g.
// you can use %D and %T in your header/footer for date and time).
func (w *FileLogWriter) SetHeadFoot(head, foot string) *FileLogWriter {
w.header, w.trailer = head, foot
if w.maxlines_curlines == 0 {
fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: time.Now()}))
}
return w
}
// Set rotate at linecount (chainable). Must be called before the first log
// message is written.
func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter {
//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateLines: %v\n", maxlines)
w.maxlines = maxlines
return w
}
// Set rotate at size (chainable). Must be called before the first log message
// is written.
func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter {
//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateSize: %v\n", maxsize)
w.maxsize = maxsize
return w
}
// Set rotate daily (chainable). Must be called before the first log message is
// written.
func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter {
//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateDaily: %v\n", daily)
w.daily = daily
return w
}
// SetRotate changes whether or not the old logs are kept. (chainable) Must be
// called before the first log message is written. If rotate is false, the
// files are overwritten; otherwise, they are rotated to another file before the
// new log is opened.
func (w *FileLogWriter) SetRotate(rotate bool) *FileLogWriter {
//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotate: %v\n", rotate)
w.rotate = rotate
return w
}
// NewXMLLogWriter is a utility method for creating a FileLogWriter set up to
// output XML record log messages instead of line-based ones.
func NewXMLLogWriter(fname string, rotate bool) *FileLogWriter {
return NewFileLogWriter(fname, rotate).SetFormat(
` <record level="%L">
<timestamp>%D %T</timestamp>
<source>%S</source>
<message>%M</message>
</record>`).SetHeadFoot("<log created=\"%D %T\">", "</log>")
}

484
Godeps/_workspace/src/code.google.com/p/log4go/log4go.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,484 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
// Package log4go provides level-based and highly configurable logging.
//
// Enhanced Logging
//
// This is inspired by the logging functionality in Java. Essentially, you create a Logger
// object and create output filters for it. You can send whatever you want to the Logger,
// and it will filter that based on your settings and send it to the outputs. This way, you
// can put as much debug code in your program as you want, and when you're done you can filter
// out the mundane messages so only the important ones show up.
//
// Utility functions are provided to make life easier. Here is some example code to get started:
//
// log := log4go.NewLogger()
// log.AddFilter("stdout", log4go.DEBUG, log4go.NewConsoleLogWriter())
// log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
// log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
//
// The first two lines can be combined with the utility NewDefaultLogger:
//
// log := log4go.NewDefaultLogger(log4go.DEBUG)
// log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
// log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
//
// Usage notes:
// - The ConsoleLogWriter does not display the source of the message to standard
// output, but the FileLogWriter does.
// - The utility functions (Info, Debug, Warn, etc) derive their source from the
// calling function, and this incurs extra overhead.
//
// Changes from 2.0:
// - The external interface has remained mostly stable, but a lot of the
// internals have been changed, so if you depended on any of this or created
// your own LogWriter, then you will probably have to update your code. In
// particular, Logger is now a map and ConsoleLogWriter is now a channel
// behind-the-scenes, and the LogWrite method no longer has return values.
//
// Future work: (please let me know if you think I should work on any of these particularly)
// - Log file rotation
// - Logging configuration files ala log4j
// - Have the ability to remove filters?
// - Have GetInfoChannel, GetDebugChannel, etc return a chan string that allows
// for another method of logging
// - Add an XML filter type
package log4go
import (
"errors"
"os"
"fmt"
"time"
"strings"
"runtime"
)
// Version information
const (
L4G_VERSION = "log4go-v3.0.1"
L4G_MAJOR = 3
L4G_MINOR = 0
L4G_BUILD = 1
)
/****** Constants ******/
// These are the integer logging levels used by the logger
type level int
const (
FINEST level = iota
FINE
DEBUG
TRACE
INFO
WARNING
ERROR
CRITICAL
)
// Logging level strings
var (
levelStrings = [...]string{"FNST", "FINE", "DEBG", "TRAC", "INFO", "WARN", "EROR", "CRIT"}
)
func (l level) String() string {
if l < 0 || int(l) > len(levelStrings) {
return "UNKNOWN"
}
return levelStrings[int(l)]
}
/****** Variables ******/
var (
// LogBufferLength specifies how many log messages a particular log4go
// logger can buffer at a time before writing them.
LogBufferLength = 32
)
/****** LogRecord ******/
// A LogRecord contains all of the pertinent information for each message
type LogRecord struct {
Level level // The log level
Created time.Time // The time at which the log message was created (nanoseconds)
Source string // The message source
Message string // The log message
}
/****** LogWriter ******/
// This is an interface for anything that should be able to write logs
type LogWriter interface {
// This will be called to log a LogRecord message.
LogWrite(rec *LogRecord)
// This should clean up anything lingering about the LogWriter, as it is called before
// the LogWriter is removed. LogWrite should not be called after Close.
Close()
}
/****** Logger ******/
// A Filter represents the log level below which no log records are written to
// the associated LogWriter.
type Filter struct {
Level level
LogWriter
}
// A Logger represents a collection of Filters through which log messages are
// written.
type Logger map[string]*Filter
// Create a new logger.
//
// DEPRECATED: Use make(Logger) instead.
func NewLogger() Logger {
os.Stderr.WriteString("warning: use of deprecated NewLogger\n")
return make(Logger)
}
// Create a new logger with a "stdout" filter configured to send log messages at
// or above lvl to standard output.
//
// DEPRECATED: use NewDefaultLogger instead.
func NewConsoleLogger(lvl level) Logger {
os.Stderr.WriteString("warning: use of deprecated NewConsoleLogger\n")
return Logger{
"stdout": &Filter{lvl, NewConsoleLogWriter()},
}
}
// Create a new logger with a "stdout" filter configured to send log messages at
// or above lvl to standard output.
func NewDefaultLogger(lvl level) Logger {
return Logger{
"stdout": &Filter{lvl, NewConsoleLogWriter()},
}
}
// Closes all log writers in preparation for exiting the program or a
// reconfiguration of logging. Calling this is not really imperative, unless
// you want to guarantee that all log messages are written. Close removes
// all filters (and thus all LogWriters) from the logger.
func (log Logger) Close() {
// Close all open loggers
for name, filt := range log {
filt.Close()
delete(log, name)
}
}
// Add a new LogWriter to the Logger which will only log messages at lvl or
// higher. This function should not be called from multiple goroutines.
// Returns the logger for chaining.
func (log Logger) AddFilter(name string, lvl level, writer LogWriter) Logger {
log[name] = &Filter{lvl, writer}
return log
}
/******* Logging *******/
// Send a formatted log message internally
func (log Logger) intLogf(lvl level, format string, args ...interface{}) {
skip := true
// Determine if any logging will be done
for _, filt := range log {
if lvl >= filt.Level {
skip = false
break
}
}
if skip {
return
}
// Determine caller func
pc, _, lineno, ok := runtime.Caller(2)
src := ""
if ok {
src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
}
msg := format
if len(args) > 0 {
msg = fmt.Sprintf(format, args...)
}
// Make the log record
rec := &LogRecord{
Level: lvl,
Created: time.Now(),
Source: src,
Message: msg,
}
// Dispatch the logs
for _, filt := range log {
if lvl < filt.Level {
continue
}
filt.LogWrite(rec)
}
}
// Send a closure log message internally
func (log Logger) intLogc(lvl level, closure func() string) {
skip := true
// Determine if any logging will be done
for _, filt := range log {
if lvl >= filt.Level {
skip = false
break
}
}
if skip {
return
}
// Determine caller func
pc, _, lineno, ok := runtime.Caller(2)
src := ""
if ok {
src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
}
// Make the log record
rec := &LogRecord{
Level: lvl,
Created: time.Now(),
Source: src,
Message: closure(),
}
// Dispatch the logs
for _, filt := range log {
if lvl < filt.Level {
continue
}
filt.LogWrite(rec)
}
}
// Send a log message with manual level, source, and message.
func (log Logger) Log(lvl level, source, message string) {
skip := true
// Determine if any logging will be done
for _, filt := range log {
if lvl >= filt.Level {
skip = false
break
}
}
if skip {
return
}
// Make the log record
rec := &LogRecord{
Level: lvl,
Created: time.Now(),
Source: source,
Message: message,
}
// Dispatch the logs
for _, filt := range log {
if lvl < filt.Level {
continue
}
filt.LogWrite(rec)
}
}
// Logf logs a formatted log message at the given log level, using the caller as
// its source.
func (log Logger) Logf(lvl level, format string, args ...interface{}) {
log.intLogf(lvl, format, args...)
}
// Logc logs a string returned by the closure at the given log level, using the caller as
// its source. If no log message would be written, the closure is never called.
func (log Logger) Logc(lvl level, closure func() string) {
log.intLogc(lvl, closure)
}
// Finest logs a message at the finest log level.
// See Debug for an explanation of the arguments.
func (log Logger) Finest(arg0 interface{}, args ...interface{}) {
const (
lvl = FINEST
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
log.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
log.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Fine logs a message at the fine log level.
// See Debug for an explanation of the arguments.
func (log Logger) Fine(arg0 interface{}, args ...interface{}) {
const (
lvl = FINE
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
log.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
log.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Debug is a utility method for debug log messages.
// The behavior of Debug depends on the first argument:
// - arg0 is a string
// When given a string as the first argument, this behaves like Logf but with
// the DEBUG log level: the first argument is interpreted as a format for the
// latter arguments.
// - arg0 is a func()string
// When given a closure of type func()string, this logs the string returned by
// the closure iff it will be logged. The closure runs at most one time.
// - arg0 is interface{}
// When given anything else, the log message will be each of the arguments
// formatted with %v and separated by spaces (ala Sprint).
func (log Logger) Debug(arg0 interface{}, args ...interface{}) {
const (
lvl = DEBUG
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
log.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
log.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Trace logs a message at the trace log level.
// See Debug for an explanation of the arguments.
func (log Logger) Trace(arg0 interface{}, args ...interface{}) {
const (
lvl = TRACE
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
log.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
log.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Info logs a message at the info log level.
// See Debug for an explanation of the arguments.
func (log Logger) Info(arg0 interface{}, args ...interface{}) {
const (
lvl = INFO
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
log.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
log.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Warn logs a message at the warning log level and returns the formatted error.
// At the warning level and higher, there is no performance benefit if the
// message is not actually logged, because all formats are processed and all
// closures are executed to format the error message.
// See Debug for further explanation of the arguments.
func (log Logger) Warn(arg0 interface{}, args ...interface{}) error {
const (
lvl = WARNING
)
var msg string
switch first := arg0.(type) {
case string:
// Use the string as a format string
msg = fmt.Sprintf(first, args...)
case func() string:
// Log the closure (no other arguments used)
msg = first()
default:
// Build a format string so that it will be similar to Sprint
msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
}
log.intLogf(lvl, msg)
return errors.New(msg)
}
// Error logs a message at the error log level and returns the formatted error,
// See Warn for an explanation of the performance and Debug for an explanation
// of the parameters.
func (log Logger) Error(arg0 interface{}, args ...interface{}) error {
const (
lvl = ERROR
)
var msg string
switch first := arg0.(type) {
case string:
// Use the string as a format string
msg = fmt.Sprintf(first, args...)
case func() string:
// Log the closure (no other arguments used)
msg = first()
default:
// Build a format string so that it will be similar to Sprint
msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
}
log.intLogf(lvl, msg)
return errors.New(msg)
}
// Critical logs a message at the critical log level and returns the formatted error,
// See Warn for an explanation of the performance and Debug for an explanation
// of the parameters.
func (log Logger) Critical(arg0 interface{}, args ...interface{}) error {
const (
lvl = CRITICAL
)
var msg string
switch first := arg0.(type) {
case string:
// Use the string as a format string
msg = fmt.Sprintf(first, args...)
case func() string:
// Log the closure (no other arguments used)
msg = first()
default:
// Build a format string so that it will be similar to Sprint
msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
}
log.intLogf(lvl, msg)
return errors.New(msg)
}

534
Godeps/_workspace/src/code.google.com/p/log4go/log4go_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,534 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"testing"
"time"
)
const testLogFile = "_logtest.log"
var now time.Time = time.Unix(0, 1234567890123456789).In(time.UTC)
func newLogRecord(lvl level, src string, msg string) *LogRecord {
return &LogRecord{
Level: lvl,
Source: src,
Created: now,
Message: msg,
}
}
func TestELog(t *testing.T) {
fmt.Printf("Testing %s\n", L4G_VERSION)
lr := newLogRecord(CRITICAL, "source", "message")
if lr.Level != CRITICAL {
t.Errorf("Incorrect level: %d should be %d", lr.Level, CRITICAL)
}
if lr.Source != "source" {
t.Errorf("Incorrect source: %s should be %s", lr.Source, "source")
}
if lr.Message != "message" {
t.Errorf("Incorrect message: %s should be %s", lr.Source, "message")
}
}
var formatTests = []struct {
Test string
Record *LogRecord
Formats map[string]string
}{
{
Test: "Standard formats",
Record: &LogRecord{
Level: ERROR,
Source: "source",
Message: "message",
Created: now,
},
Formats: map[string]string{
// TODO(kevlar): How can I do this so it'll work outside of PST?
FORMAT_DEFAULT: "[2009/02/13 23:31:30 UTC] [EROR] (source) message\n",
FORMAT_SHORT: "[23:31 02/13/09] [EROR] message\n",
FORMAT_ABBREV: "[EROR] message\n",
},
},
}
func TestFormatLogRecord(t *testing.T) {
for _, test := range formatTests {
name := test.Test
for fmt, want := range test.Formats {
if got := FormatLogRecord(fmt, test.Record); got != want {
t.Errorf("%s - %s:", name, fmt)
t.Errorf(" got %q", got)
t.Errorf(" want %q", want)
}
}
}
}
var logRecordWriteTests = []struct {
Test string
Record *LogRecord
Console string
}{
{
Test: "Normal message",
Record: &LogRecord{
Level: CRITICAL,
Source: "source",
Message: "message",
Created: now,
},
Console: "[02/13/09 23:31:30] [CRIT] message\n",
},
}
func TestConsoleLogWriter(t *testing.T) {
console := make(ConsoleLogWriter)
r, w := io.Pipe()
go console.run(w)
defer console.Close()
buf := make([]byte, 1024)
for _, test := range logRecordWriteTests {
name := test.Test
console.LogWrite(test.Record)
n, _ := r.Read(buf)
if got, want := string(buf[:n]), test.Console; got != want {
t.Errorf("%s: got %q", name, got)
t.Errorf("%s: want %q", name, want)
}
}
}
func TestFileLogWriter(t *testing.T) {
defer func(buflen int) {
LogBufferLength = buflen
}(LogBufferLength)
LogBufferLength = 0
w := NewFileLogWriter(testLogFile, false)
if w == nil {
t.Fatalf("Invalid return: w should not be nil")
}
defer os.Remove(testLogFile)
w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
w.Close()
runtime.Gosched()
if contents, err := ioutil.ReadFile(testLogFile); err != nil {
t.Errorf("read(%q): %s", testLogFile, err)
} else if len(contents) != 50 {
t.Errorf("malformed filelog: %q (%d bytes)", string(contents), len(contents))
}
}
func TestXMLLogWriter(t *testing.T) {
defer func(buflen int) {
LogBufferLength = buflen
}(LogBufferLength)
LogBufferLength = 0
w := NewXMLLogWriter(testLogFile, false)
if w == nil {
t.Fatalf("Invalid return: w should not be nil")
}
defer os.Remove(testLogFile)
w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
w.Close()
runtime.Gosched()
if contents, err := ioutil.ReadFile(testLogFile); err != nil {
t.Errorf("read(%q): %s", testLogFile, err)
} else if len(contents) != 185 {
t.Errorf("malformed xmllog: %q (%d bytes)", string(contents), len(contents))
}
}
func TestLogger(t *testing.T) {
sl := NewDefaultLogger(WARNING)
if sl == nil {
t.Fatalf("NewDefaultLogger should never return nil")
}
if lw, exist := sl["stdout"]; lw == nil || exist != true {
t.Fatalf("NewDefaultLogger produced invalid logger (DNE or nil)")
}
if sl["stdout"].Level != WARNING {
t.Fatalf("NewDefaultLogger produced invalid logger (incorrect level)")
}
if len(sl) != 1 {
t.Fatalf("NewDefaultLogger produced invalid logger (incorrect map count)")
}
//func (l *Logger) AddFilter(name string, level int, writer LogWriter) {}
l := make(Logger)
l.AddFilter("stdout", DEBUG, NewConsoleLogWriter())
if lw, exist := l["stdout"]; lw == nil || exist != true {
t.Fatalf("AddFilter produced invalid logger (DNE or nil)")
}
if l["stdout"].Level != DEBUG {
t.Fatalf("AddFilter produced invalid logger (incorrect level)")
}
if len(l) != 1 {
t.Fatalf("AddFilter produced invalid logger (incorrect map count)")
}
//func (l *Logger) Warn(format string, args ...interface{}) error {}
if err := l.Warn("%s %d %#v", "Warning:", 1, []int{}); err.Error() != "Warning: 1 []int{}" {
t.Errorf("Warn returned invalid error: %s", err)
}
//func (l *Logger) Error(format string, args ...interface{}) error {}
if err := l.Error("%s %d %#v", "Error:", 10, []string{}); err.Error() != "Error: 10 []string{}" {
t.Errorf("Error returned invalid error: %s", err)
}
//func (l *Logger) Critical(format string, args ...interface{}) error {}
if err := l.Critical("%s %d %#v", "Critical:", 100, []int64{}); err.Error() != "Critical: 100 []int64{}" {
t.Errorf("Critical returned invalid error: %s", err)
}
// Already tested or basically untestable
//func (l *Logger) Log(level int, source, message string) {}
//func (l *Logger) Logf(level int, format string, args ...interface{}) {}
//func (l *Logger) intLogf(level int, format string, args ...interface{}) string {}
//func (l *Logger) Finest(format string, args ...interface{}) {}
//func (l *Logger) Fine(format string, args ...interface{}) {}
//func (l *Logger) Debug(format string, args ...interface{}) {}
//func (l *Logger) Trace(format string, args ...interface{}) {}
//func (l *Logger) Info(format string, args ...interface{}) {}
}
func TestLogOutput(t *testing.T) {
const (
expected = "fdf3e51e444da56b4cb400f30bc47424"
)
// Unbuffered output
defer func(buflen int) {
LogBufferLength = buflen
}(LogBufferLength)
LogBufferLength = 0
l := make(Logger)
// Delete and open the output log without a timestamp (for a constant md5sum)
l.AddFilter("file", FINEST, NewFileLogWriter(testLogFile, false).SetFormat("[%L] %M"))
defer os.Remove(testLogFile)
// Send some log messages
l.Log(CRITICAL, "testsrc1", fmt.Sprintf("This message is level %d", int(CRITICAL)))
l.Logf(ERROR, "This message is level %v", ERROR)
l.Logf(WARNING, "This message is level %s", WARNING)
l.Logc(INFO, func() string { return "This message is level INFO" })
l.Trace("This message is level %d", int(TRACE))
l.Debug("This message is level %s", DEBUG)
l.Fine(func() string { return fmt.Sprintf("This message is level %v", FINE) })
l.Finest("This message is level %v", FINEST)
l.Finest(FINEST, "is also this message's level")
l.Close()
contents, err := ioutil.ReadFile(testLogFile)
if err != nil {
t.Fatalf("Could not read output log: %s", err)
}
sum := md5.New()
sum.Write(contents)
if sumstr := hex.EncodeToString(sum.Sum(nil)); sumstr != expected {
t.Errorf("--- Log Contents:\n%s---", string(contents))
t.Fatalf("Checksum does not match: %s (expecting %s)", sumstr, expected)
}
}
func TestCountMallocs(t *testing.T) {
const N = 1
var m runtime.MemStats
getMallocs := func() uint64 {
runtime.ReadMemStats(&m)
return m.Mallocs
}
// Console logger
sl := NewDefaultLogger(INFO)
mallocs := 0 - getMallocs()
for i := 0; i < N; i++ {
sl.Log(WARNING, "here", "This is a WARNING message")
}
mallocs += getMallocs()
fmt.Printf("mallocs per sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
// Console logger formatted
mallocs = 0 - getMallocs()
for i := 0; i < N; i++ {
sl.Logf(WARNING, "%s is a log message with level %d", "This", WARNING)
}
mallocs += getMallocs()
fmt.Printf("mallocs per sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
// Console logger (not logged)
sl = NewDefaultLogger(INFO)
mallocs = 0 - getMallocs()
for i := 0; i < N; i++ {
sl.Log(DEBUG, "here", "This is a DEBUG log message")
}
mallocs += getMallocs()
fmt.Printf("mallocs per unlogged sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
// Console logger formatted (not logged)
mallocs = 0 - getMallocs()
for i := 0; i < N; i++ {
sl.Logf(DEBUG, "%s is a log message with level %d", "This", DEBUG)
}
mallocs += getMallocs()
fmt.Printf("mallocs per unlogged sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
}
func TestXMLConfig(t *testing.T) {
const (
configfile = "example.xml"
)
fd, err := os.Create(configfile)
if err != nil {
t.Fatalf("Could not open %s for writing: %s", configfile, err)
}
fmt.Fprintln(fd, "<logging>")
fmt.Fprintln(fd, " <filter enabled=\"true\">")
fmt.Fprintln(fd, " <tag>stdout</tag>")
fmt.Fprintln(fd, " <type>console</type>")
fmt.Fprintln(fd, " <!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->")
fmt.Fprintln(fd, " <level>DEBUG</level>")
fmt.Fprintln(fd, " </filter>")
fmt.Fprintln(fd, " <filter enabled=\"true\">")
fmt.Fprintln(fd, " <tag>file</tag>")
fmt.Fprintln(fd, " <type>file</type>")
fmt.Fprintln(fd, " <level>FINEST</level>")
fmt.Fprintln(fd, " <property name=\"filename\">test.log</property>")
fmt.Fprintln(fd, " <!--")
fmt.Fprintln(fd, " %T - Time (15:04:05 MST)")
fmt.Fprintln(fd, " %t - Time (15:04)")
fmt.Fprintln(fd, " %D - Date (2006/01/02)")
fmt.Fprintln(fd, " %d - Date (01/02/06)")
fmt.Fprintln(fd, " %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)")
fmt.Fprintln(fd, " %S - Source")
fmt.Fprintln(fd, " %M - Message")
fmt.Fprintln(fd, " It ignores unknown format strings (and removes them)")
fmt.Fprintln(fd, " Recommended: \"[%D %T] [%L] (%S) %M\"")
fmt.Fprintln(fd, " -->")
fmt.Fprintln(fd, " <property name=\"format\">[%D %T] [%L] (%S) %M</property>")
fmt.Fprintln(fd, " <property name=\"rotate\">false</property> <!-- true enables log rotation, otherwise append -->")
fmt.Fprintln(fd, " <property name=\"maxsize\">0M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
fmt.Fprintln(fd, " <property name=\"maxlines\">0K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
fmt.Fprintln(fd, " <property name=\"daily\">true</property> <!-- Automatically rotates when a log message is written after midnight -->")
fmt.Fprintln(fd, " </filter>")
fmt.Fprintln(fd, " <filter enabled=\"true\">")
fmt.Fprintln(fd, " <tag>xmllog</tag>")
fmt.Fprintln(fd, " <type>xml</type>")
fmt.Fprintln(fd, " <level>TRACE</level>")
fmt.Fprintln(fd, " <property name=\"filename\">trace.xml</property>")
fmt.Fprintln(fd, " <property name=\"rotate\">true</property> <!-- true enables log rotation, otherwise append -->")
fmt.Fprintln(fd, " <property name=\"maxsize\">100M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
fmt.Fprintln(fd, " <property name=\"maxrecords\">6K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
fmt.Fprintln(fd, " <property name=\"daily\">false</property> <!-- Automatically rotates when a log message is written after midnight -->")
fmt.Fprintln(fd, " </filter>")
fmt.Fprintln(fd, " <filter enabled=\"false\"><!-- enabled=false means this logger won't actually be created -->")
fmt.Fprintln(fd, " <tag>donotopen</tag>")
fmt.Fprintln(fd, " <type>socket</type>")
fmt.Fprintln(fd, " <level>FINEST</level>")
fmt.Fprintln(fd, " <property name=\"endpoint\">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->")
fmt.Fprintln(fd, " <property name=\"protocol\">udp</property> <!-- tcp or udp -->")
fmt.Fprintln(fd, " </filter>")
fmt.Fprintln(fd, "</logging>")
fd.Close()
log := make(Logger)
log.LoadConfiguration(configfile)
defer os.Remove("trace.xml")
defer os.Remove("test.log")
defer log.Close()
// Make sure we got all loggers
if len(log) != 3 {
t.Fatalf("XMLConfig: Expected 3 filters, found %d", len(log))
}
// Make sure they're the right keys
if _, ok := log["stdout"]; !ok {
t.Errorf("XMLConfig: Expected stdout logger")
}
if _, ok := log["file"]; !ok {
t.Fatalf("XMLConfig: Expected file logger")
}
if _, ok := log["xmllog"]; !ok {
t.Fatalf("XMLConfig: Expected xmllog logger")
}
// Make sure they're the right type
if _, ok := log["stdout"].LogWriter.(ConsoleLogWriter); !ok {
t.Fatalf("XMLConfig: Expected stdout to be ConsoleLogWriter, found %T", log["stdout"].LogWriter)
}
if _, ok := log["file"].LogWriter.(*FileLogWriter); !ok {
t.Fatalf("XMLConfig: Expected file to be *FileLogWriter, found %T", log["file"].LogWriter)
}
if _, ok := log["xmllog"].LogWriter.(*FileLogWriter); !ok {
t.Fatalf("XMLConfig: Expected xmllog to be *FileLogWriter, found %T", log["xmllog"].LogWriter)
}
// Make sure levels are set
if lvl := log["stdout"].Level; lvl != DEBUG {
t.Errorf("XMLConfig: Expected stdout to be set to level %d, found %d", DEBUG, lvl)
}
if lvl := log["file"].Level; lvl != FINEST {
t.Errorf("XMLConfig: Expected file to be set to level %d, found %d", FINEST, lvl)
}
if lvl := log["xmllog"].Level; lvl != TRACE {
t.Errorf("XMLConfig: Expected xmllog to be set to level %d, found %d", TRACE, lvl)
}
// Make sure the w is open and points to the right file
if fname := log["file"].LogWriter.(*FileLogWriter).file.Name(); fname != "test.log" {
t.Errorf("XMLConfig: Expected file to have opened %s, found %s", "test.log", fname)
}
// Make sure the XLW is open and points to the right file
if fname := log["xmllog"].LogWriter.(*FileLogWriter).file.Name(); fname != "trace.xml" {
t.Errorf("XMLConfig: Expected xmllog to have opened %s, found %s", "trace.xml", fname)
}
// Move XML log file
os.Rename(configfile, "examples/"+configfile) // Keep this so that an example with the documentation is available
}
func BenchmarkFormatLogRecord(b *testing.B) {
const updateEvery = 1
rec := &LogRecord{
Level: CRITICAL,
Created: now,
Source: "source",
Message: "message",
}
for i := 0; i < b.N; i++ {
rec.Created = rec.Created.Add(1 * time.Second / updateEvery)
if i%2 == 0 {
FormatLogRecord(FORMAT_DEFAULT, rec)
} else {
FormatLogRecord(FORMAT_SHORT, rec)
}
}
}
func BenchmarkConsoleLog(b *testing.B) {
/* This doesn't seem to work on OS X
sink, err := os.Open(os.DevNull)
if err != nil {
panic(err)
}
if err := syscall.Dup2(int(sink.Fd()), syscall.Stdout); err != nil {
panic(err)
}
*/
stdout = ioutil.Discard
sl := NewDefaultLogger(INFO)
for i := 0; i < b.N; i++ {
sl.Log(WARNING, "here", "This is a log message")
}
}
func BenchmarkConsoleNotLogged(b *testing.B) {
sl := NewDefaultLogger(INFO)
for i := 0; i < b.N; i++ {
sl.Log(DEBUG, "here", "This is a log message")
}
}
func BenchmarkConsoleUtilLog(b *testing.B) {
sl := NewDefaultLogger(INFO)
for i := 0; i < b.N; i++ {
sl.Info("%s is a log message", "This")
}
}
func BenchmarkConsoleUtilNotLog(b *testing.B) {
sl := NewDefaultLogger(INFO)
for i := 0; i < b.N; i++ {
sl.Debug("%s is a log message", "This")
}
}
func BenchmarkFileLog(b *testing.B) {
sl := make(Logger)
b.StopTimer()
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
b.StartTimer()
for i := 0; i < b.N; i++ {
sl.Log(WARNING, "here", "This is a log message")
}
b.StopTimer()
os.Remove("benchlog.log")
}
func BenchmarkFileNotLogged(b *testing.B) {
sl := make(Logger)
b.StopTimer()
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
b.StartTimer()
for i := 0; i < b.N; i++ {
sl.Log(DEBUG, "here", "This is a log message")
}
b.StopTimer()
os.Remove("benchlog.log")
}
func BenchmarkFileUtilLog(b *testing.B) {
sl := make(Logger)
b.StopTimer()
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
b.StartTimer()
for i := 0; i < b.N; i++ {
sl.Info("%s is a log message", "This")
}
b.StopTimer()
os.Remove("benchlog.log")
}
func BenchmarkFileUtilNotLog(b *testing.B) {
sl := make(Logger)
b.StopTimer()
sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
b.StartTimer()
for i := 0; i < b.N; i++ {
sl.Debug("%s is a log message", "This")
}
b.StopTimer()
os.Remove("benchlog.log")
}
// Benchmark results (darwin amd64 6g)
//elog.BenchmarkConsoleLog 100000 22819 ns/op
//elog.BenchmarkConsoleNotLogged 2000000 879 ns/op
//elog.BenchmarkConsoleUtilLog 50000 34380 ns/op
//elog.BenchmarkConsoleUtilNotLog 1000000 1339 ns/op
//elog.BenchmarkFileLog 100000 26497 ns/op
//elog.BenchmarkFileNotLogged 2000000 821 ns/op
//elog.BenchmarkFileUtilLog 50000 33945 ns/op
//elog.BenchmarkFileUtilNotLog 1000000 1258 ns/op

122
Godeps/_workspace/src/code.google.com/p/log4go/pattlog.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,122 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"fmt"
"bytes"
"io"
)
const (
FORMAT_DEFAULT = "[%D %T] [%L] (%S) %M"
FORMAT_SHORT = "[%t %d] [%L] %M"
FORMAT_ABBREV = "[%L] %M"
)
type formatCacheType struct {
LastUpdateSeconds int64
shortTime, shortDate string
longTime, longDate string
}
var formatCache = &formatCacheType{}
// Known format codes:
// %T - Time (15:04:05 MST)
// %t - Time (15:04)
// %D - Date (2006/01/02)
// %d - Date (01/02/06)
// %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
// %S - Source
// %M - Message
// Ignores unknown formats
// Recommended: "[%D %T] [%L] (%S) %M"
func FormatLogRecord(format string, rec *LogRecord) string {
if rec == nil {
return "<nil>"
}
if len(format) == 0 {
return ""
}
out := bytes.NewBuffer(make([]byte, 0, 64))
secs := rec.Created.UnixNano() / 1e9
cache := *formatCache
if cache.LastUpdateSeconds != secs {
month, day, year := rec.Created.Month(), rec.Created.Day(), rec.Created.Year()
hour, minute, second := rec.Created.Hour(), rec.Created.Minute(), rec.Created.Second()
zone, _ := rec.Created.Zone()
updated := &formatCacheType{
LastUpdateSeconds: secs,
shortTime: fmt.Sprintf("%02d:%02d", hour, minute),
shortDate: fmt.Sprintf("%02d/%02d/%02d", month, day, year%100),
longTime: fmt.Sprintf("%02d:%02d:%02d %s", hour, minute, second, zone),
longDate: fmt.Sprintf("%04d/%02d/%02d", year, month, day),
}
cache = *updated
formatCache = updated
}
// Split the string into pieces by % signs
pieces := bytes.Split([]byte(format), []byte{'%'})
// Iterate over the pieces, replacing known formats
for i, piece := range pieces {
if i > 0 && len(piece) > 0 {
switch piece[0] {
case 'T':
out.WriteString(cache.longTime)
case 't':
out.WriteString(cache.shortTime)
case 'D':
out.WriteString(cache.longDate)
case 'd':
out.WriteString(cache.shortDate)
case 'L':
out.WriteString(levelStrings[rec.Level])
case 'S':
out.WriteString(rec.Source)
case 'M':
out.WriteString(rec.Message)
}
if len(piece) > 1 {
out.Write(piece[1:])
}
} else if len(piece) > 0 {
out.Write(piece)
}
}
out.WriteByte('\n')
return out.String()
}
// This is the standard writer that prints to standard output.
type FormatLogWriter chan *LogRecord
// This creates a new FormatLogWriter
func NewFormatLogWriter(out io.Writer, format string) FormatLogWriter {
records := make(FormatLogWriter, LogBufferLength)
go records.run(out, format)
return records
}
func (w FormatLogWriter) run(out io.Writer, format string) {
for rec := range w {
fmt.Fprint(out, FormatLogRecord(format, rec))
}
}
// This is the FormatLogWriter's output method. This will block if the output
// buffer is full.
func (w FormatLogWriter) LogWrite(rec *LogRecord) {
w <- rec
}
// Close stops the logger from sending messages to standard output. Attempts to
// send log messages to this logger after a Close have undefined behavior.
func (w FormatLogWriter) Close() {
close(w)
}

57
Godeps/_workspace/src/code.google.com/p/log4go/socklog.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,57 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"encoding/json"
"fmt"
"net"
"os"
)
// This log writer sends output to a socket
type SocketLogWriter chan *LogRecord
// This is the SocketLogWriter's output method
func (w SocketLogWriter) LogWrite(rec *LogRecord) {
w <- rec
}
func (w SocketLogWriter) Close() {
close(w)
}
func NewSocketLogWriter(proto, hostport string) SocketLogWriter {
sock, err := net.Dial(proto, hostport)
if err != nil {
fmt.Fprintf(os.Stderr, "NewSocketLogWriter(%q): %s\n", hostport, err)
return nil
}
w := SocketLogWriter(make(chan *LogRecord, LogBufferLength))
go func() {
defer func() {
if sock != nil && proto == "tcp" {
sock.Close()
}
}()
for rec := range w {
// Marshall into JSON
js, err := json.Marshal(rec)
if err != nil {
fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
return
}
_, err = sock.Write(js)
if err != nil {
fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
return
}
}
}()
return w
}

45
Godeps/_workspace/src/code.google.com/p/log4go/termlog.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,45 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"io"
"os"
"fmt"
)
var stdout io.Writer = os.Stdout
// This is the standard writer that prints to standard output.
type ConsoleLogWriter chan *LogRecord
// This creates a new ConsoleLogWriter
func NewConsoleLogWriter() ConsoleLogWriter {
records := make(ConsoleLogWriter, LogBufferLength)
go records.run(stdout)
return records
}
func (w ConsoleLogWriter) run(out io.Writer) {
var timestr string
var timestrAt int64
for rec := range w {
if at := rec.Created.UnixNano() / 1e9; at != timestrAt {
timestr, timestrAt = rec.Created.Format("01/02/06 15:04:05"), at
}
fmt.Fprint(out, "[", timestr, "] [", levelStrings[rec.Level], "] ", rec.Message, "\n")
}
}
// This is the ConsoleLogWriter's output method. This will block if the output
// buffer is full.
func (w ConsoleLogWriter) LogWrite(rec *LogRecord) {
w <- rec
}
// Close stops the logger from sending messages to standard output. Attempts to
// send log messages to this logger after a Close have undefined behavior.
func (w ConsoleLogWriter) Close() {
close(w)
}

278
Godeps/_workspace/src/code.google.com/p/log4go/wrapper.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,278 @@
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"errors"
"os"
"fmt"
"strings"
)
var (
Global Logger
)
func init() {
Global = NewDefaultLogger(DEBUG)
}
// Wrapper for (*Logger).LoadConfiguration
func LoadConfiguration(filename string) {
Global.LoadConfiguration(filename)
}
// Wrapper for (*Logger).AddFilter
func AddFilter(name string, lvl level, writer LogWriter) {
Global.AddFilter(name, lvl, writer)
}
// Wrapper for (*Logger).Close (closes and removes all logwriters)
func Close() {
Global.Close()
}
func Crash(args ...interface{}) {
if len(args) > 0 {
Global.intLogf(CRITICAL, strings.Repeat(" %v", len(args))[1:], args...)
}
panic(args)
}
// Logs the given message and crashes the program
func Crashf(format string, args ...interface{}) {
Global.intLogf(CRITICAL, format, args...)
Global.Close() // so that hopefully the messages get logged
panic(fmt.Sprintf(format, args...))
}
// Compatibility with `log`
func Exit(args ...interface{}) {
if len(args) > 0 {
Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
}
Global.Close() // so that hopefully the messages get logged
os.Exit(0)
}
// Compatibility with `log`
func Exitf(format string, args ...interface{}) {
Global.intLogf(ERROR, format, args...)
Global.Close() // so that hopefully the messages get logged
os.Exit(0)
}
// Compatibility with `log`
func Stderr(args ...interface{}) {
if len(args) > 0 {
Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
}
}
// Compatibility with `log`
func Stderrf(format string, args ...interface{}) {
Global.intLogf(ERROR, format, args...)
}
// Compatibility with `log`
func Stdout(args ...interface{}) {
if len(args) > 0 {
Global.intLogf(INFO, strings.Repeat(" %v", len(args))[1:], args...)
}
}
// Compatibility with `log`
func Stdoutf(format string, args ...interface{}) {
Global.intLogf(INFO, format, args...)
}
// Send a log message manually
// Wrapper for (*Logger).Log
func Log(lvl level, source, message string) {
Global.Log(lvl, source, message)
}
// Send a formatted log message easily
// Wrapper for (*Logger).Logf
func Logf(lvl level, format string, args ...interface{}) {
Global.intLogf(lvl, format, args...)
}
// Send a closure log message
// Wrapper for (*Logger).Logc
func Logc(lvl level, closure func() string) {
Global.intLogc(lvl, closure)
}
// Utility for finest log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Finest
func Finest(arg0 interface{}, args ...interface{}) {
const (
lvl = FINEST
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
Global.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Utility for fine log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Fine
func Fine(arg0 interface{}, args ...interface{}) {
const (
lvl = FINE
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
Global.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Utility for debug log messages
// When given a string as the first argument, this behaves like Logf but with the DEBUG log level (e.g. the first argument is interpreted as a format for the latter arguments)
// When given a closure of type func()string, this logs the string returned by the closure iff it will be logged. The closure runs at most one time.
// When given anything else, the log message will be each of the arguments formatted with %v and separated by spaces (ala Sprint).
// Wrapper for (*Logger).Debug
func Debug(arg0 interface{}, args ...interface{}) {
const (
lvl = DEBUG
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
Global.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Utility for trace log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Trace
func Trace(arg0 interface{}, args ...interface{}) {
const (
lvl = TRACE
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
Global.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Utility for info log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Info
func Info(arg0 interface{}, args ...interface{}) {
const (
lvl = INFO
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
case func() string:
// Log the closure (no other arguments used)
Global.intLogc(lvl, first)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
}
}
// Utility for warn log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Warn
func Warn(arg0 interface{}, args ...interface{}) error {
const (
lvl = WARNING
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
return errors.New(fmt.Sprintf(first, args...))
case func() string:
// Log the closure (no other arguments used)
str := first()
Global.intLogf(lvl, "%s", str)
return errors.New(str)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
}
return nil
}
// Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Error
func Error(arg0 interface{}, args ...interface{}) error {
const (
lvl = ERROR
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
return errors.New(fmt.Sprintf(first, args...))
case func() string:
// Log the closure (no other arguments used)
str := first()
Global.intLogf(lvl, "%s", str)
return errors.New(str)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
}
return nil
}
// Utility for critical log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Critical
func Critical(arg0 interface{}, args ...interface{}) error {
const (
lvl = CRITICAL
)
switch first := arg0.(type) {
case string:
// Use the string as a format string
Global.intLogf(lvl, first, args...)
return errors.New(fmt.Sprintf(first, args...))
case func() string:
// Log the closure (no other arguments used)
str := first()
Global.intLogf(lvl, "%s", str)
return errors.New(str)
default:
// Build a format string so that it will be similar to Sprint
Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
}
return nil
}