func (self *face) Glyph(dot fixed.Point26_6, char rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { var bounds fixed.Rectangle26_6 var cached bool var cachedGlyph glyph if cachedGlyph, cached = self.cache.get(char); cached { bounds, advance, mask = cachedGlyph.bounds, cachedGlyph.advance, cachedGlyph.mask } if bounds == (fixed.Rectangle26_6{}) || advance == 0 { if bounds, advance, ok = self.GlyphBounds(char); !ok { return } } offset := fixed.Point26_6{ X: abs26_6(bounds.Min.X), Y: self.metrics.Ascent, } origin := C.CGPoint{ x: C.CGFloat(f64(offset.X)), y: C.CGFloat(f64(offset.Y)), } dx := (int(bounds.Max.X+offset.X) >> 6) + 1 dy := (int(self.metrics.Ascent+self.metrics.Descent) >> 6) + 1 dr.Min.X = (int(dot.X) >> 6) - int(origin.x) dr.Min.Y = (int(dot.Y) >> 6) - int(origin.y) dr.Max.X = dr.Min.X + dx dr.Max.Y = dr.Min.Y + dy if mask == nil { alpha := image.NewAlpha(image.Rect(0, 0, dx, dy)) if !C.CTFontGlyphDraw__( self.ref, C.UTF32Char(char), origin, (*C.UInt8)(unsafe.Pointer(&alpha.Pix[0])), C.size_t(alpha.Stride), C.size_t(dx), C.size_t(dy), ) { dr, advance = image.Rectangle{}, 0 return } mask = alpha self.cache.set(glyph{rune: char, bounds: bounds, advance: advance, mask: mask}) } ok = true return }
func makeLineDash(in graphic.LineDash) []C.CGFloat { out := make([]C.CGFloat, len(in)) for i, d := range in { out[i] = C.CGFloat(d) } return out }
func makeCGPathElementPoints(p [3]geom.Point) [3]C.CGPoint { return [3]C.CGPoint{ C.CGPoint{ x: C.CGFloat(p[0].X), y: C.CGFloat(p[0].Y), }, C.CGPoint{ x: C.CGFloat(p[1].X), y: C.CGFloat(p[1].Y), }, C.CGPoint{ x: C.CGFloat(p[2].X), y: C.CGFloat(p[2].Y), }, } }
func (m CGPoint) C() C.CGPoint { return C.CGPoint{C.CGFloat(m.x), C.CGFloat(m.y)} }
func moveWindow(id uintptr, p geom.Point) { C.DesktopWindow_Move(unsafe.Pointer(id), C.CGFloat(p.X), C.CGFloat(p.Y)) }
func makeCGSize(s geom.Size) C.CGSize { return C.CGSize{ width: C.CGFloat(s.W), height: C.CGFloat(s.H), } }
func makeCGPoint(p geom.Point) C.CGPoint { return C.CGPoint{ x: C.CGFloat(p.X), y: C.CGFloat(p.Y), } }
func (self gc) Configure(state graphic.State) { var s C.CGState__ var d []C.CGFloat var p []C.CGPathElement__ if state.Color != nil { r, g, b, a := state.Color.RGBA() s.flags |= C.CGStateHasColor__ s.color[0] = C.CGFloat(r) / 65535 s.color[1] = C.CGFloat(g) / 65535 s.color[2] = C.CGFloat(b) / 65535 s.color[3] = C.CGFloat(a) / 65535 } if state.Transform != nil { tm := state.Transform.TM() s.flags |= C.CGStateHasTransform__ s.transform[0] = C.CGFloat(tm[0]) s.transform[1] = C.CGFloat(tm[1]) s.transform[2] = C.CGFloat(tm[2]) s.transform[3] = C.CGFloat(tm[3]) s.transform[4] = C.CGFloat(tm[4]) s.transform[5] = C.CGFloat(tm[5]) } if state.Opacity != nil { s.flags |= C.CGStateHasAlpha__ s.alpha = C.CGFloat(state.Opacity.Opacity()) } if state.Interpolation != nil { s.flags |= C.CGStateHasInterpolation__ switch state.Interpolation.Interpolation() { case graphic.InterpolationDefault: s.interpolation = C.kCGInterpolationDefault case graphic.InterpolationNone: s.interpolation = C.kCGInterpolationNone case graphic.InterpolationCheap: s.interpolation = C.kCGInterpolationLow case graphic.InterpolationAverage: s.interpolation = C.kCGInterpolationMedium case graphic.InterpolationExpensive: s.interpolation = C.kCGInterpolationHigh } } if state.LineCap != nil { s.flags |= C.CGStateHasLineCap__ switch state.LineCap.LineCap() { case graphic.LineCapButt: s.lineCap = C.kCGLineCapButt case graphic.LineCapSquare: s.lineCap = C.kCGLineCapRound case graphic.LineCapRound: s.lineCap = C.kCGLineCapSquare } } if state.LineJoin != nil { s.flags |= C.CGStateHasLineJoin__ switch state.LineJoin.LineJoin() { case graphic.LineJoinMiter: s.lineJoin = C.kCGLineJoinMiter case graphic.LineJoinRound: s.lineJoin = C.kCGLineJoinRound case graphic.LineJoinBevel: s.lineJoin = C.kCGLineJoinBevel } } if state.LineWidth != nil { s.flags |= C.CGStateHasLineWidth__ s.lineWidth = C.CGFloat(state.LineWidth.LineWidth()) } if state.LineDash != nil { d = makeLineDash(state.LineDash.LineDash()) } if state.Clip != nil { p = makeCGPathElements__(state.Clip.Path()) switch state.ClipRule { case graphic.ClipWindingCount: s.clipRule = C.CGClipWindingCount__ case graphic.ClipEvenOdd: s.clipRule = C.CGClipEvenOdd__ } } self <- func(ctx C.CGContextRef) { if n := len(p); n != 0 { s.flags |= C.CGStateHasClip__ s.clipElements = &p[0] s.clipLength = C.size_t(n) } if n := len(d); n != 0 { s.flags |= C.CGStateHasLineDash__ s.lineDashLengths = &d[0] s.lineDashCount = C.size_t(n) } if s.flags != 0 { C.CGContextConfigure__(ctx, s) } } }
func makeRGBA__(c color.Color) C.RGBA__ { switch x := c.(type) { case color.NRGBA: return C.RGBA__{ R: C.CGFloat(x.R) / 255.0, G: C.CGFloat(x.G) / 255.0, B: C.CGFloat(x.B) / 255.0, A: C.CGFloat(x.A) / 255.0, } case color.NRGBA64: return C.RGBA__{ R: C.CGFloat(x.R) / 65535.0, G: C.CGFloat(x.G) / 65535.0, B: C.CGFloat(x.B) / 65535.0, A: C.CGFloat(x.A) / 65535.0, } } r, g, b, a := c.RGBA() fr := C.CGFloat(r) / 65535.0 fg := C.CGFloat(g) / 65535.0 fb := C.CGFloat(b) / 65535.0 fa := C.CGFloat(a) / 65535.0 if fa != 0.0 { fr /= fa fg /= fa fb /= fa } // The RGBA method gives us pre-multiplied values, but the generic RGB color // constructor expects values between 0 and 1 so we have to convert them // back to non-multiplied. return C.RGBA__{R: fr, G: fg, B: fb, A: fa} }
func newFace(ctfont C.CTFontRef, data text.FaceData) *face { if data.Size == 0.0 { data.Size = 12.0 } if data.DPI == 0.0 { data.DPI = 72.0 } if data.Stretch == 0 { data.Stretch = font.StretchNormal } if data.Style == 0 { data.Style = font.StyleNormal } if data.Weight == 0 { data.Weight = font.WeightNormal } data.Hinting = font.HintingNone scale := C.CGFloat(data.DPI / 72.0) traits := C.CTFontSymbolicTraits(C.kCTFontUIOptimizedTrait) switch data.Stretch { case font.StretchUltraCondensed, font.StretchExtraCondensed, font.StretchCondensed, font.StretchSemiCondensed: data.Stretch = font.StretchCondensed traits |= C.kCTFontCondensedTrait case font.StretchSemiExpanded, font.StretchExpanded, font.StretchExtraExpanded, font.StretchUltraExpanded: data.Stretch = font.StretchExpanded traits |= C.kCTFontExpandedTrait } switch data.Style { case font.StyleItalic, font.StyleOblique: data.Style = font.StyleItalic traits |= C.kCTFontItalicTrait } switch data.Weight { case font.WeightMedium, font.WeightSemiBold, font.WeightBold, font.WeightExtraBold, font.WeightBlack: data.Weight = font.WeightBold traits |= C.kCTFontBoldTrait } tm := C.CGAffineTransform{a: scale, d: scale} ref := C.CTFontCreateCopyWithSymbolicTraits( ctfont, C.CGFloat(data.Size), &tm, traits, C.kCTFontItalicTrait|C.kCTFontBoldTrait|C.kCTFontExpandedTrait|C.kCTFontCondensedTrait|C.kCTFontUIOptimizedTrait, ) if ref == nil { // The request couldn't be satisfied, no font in the system were found // that matched the face configuration. // We create a simple copy of the font without changing the symbolic // traits. ref = C.CTFontCreateCopyWithSymbolicTraits( ctfont, C.CGFloat(data.Size), &tm, 0, 0, ) if ref == nil { panic(fmt.Sprintf("CoreText failed to create a CTFontRef for %#v", data)) } } self := &face{ ref: ref, data: data, } runtime.SetFinalizer(self, (*face).release) self.metrics.Ascent = i26_6(C.CTFontGetAscent(ref)) self.metrics.Descent = i26_6(C.CTFontGetDescent(ref)) self.metrics.Height = self.metrics.Ascent + self.metrics.Descent + i26_6(C.CTFontGetLeading(ref)) name := C.CTFontCopyFullName(ref) defer C.CFRelease(C.CFTypeRef(name)) self.name = CFStringToGoString(name) self.cache.index = make(map[rune]int, glyphCacheSize) return self }
func (m CGSize) C() C.CGSize { return C.CGSize{C.CGFloat(m.width), C.CGFloat(m.height)} }
func CGColorRGB(r, g, b, a int) CGColor { return CGColor{unsafe.Pointer(C.CGColorCreateGenericRGB(C.CGFloat(r), C.CGFloat(g), C.CGFloat(b), C.CGFloat(a)))} }
func (point Size) innerType() C.NSSize { return C.NSSize{ width: C.CGFloat(point.Width), height: C.CGFloat(point.Height), } }
func (point Point) innerType() C.NSPoint { return C.NSPoint{ x: C.CGFloat(point.X), y: C.CGFloat(point.Y), } }