mobile/font: access to system fonts

This initially supports reading two common system fonts. At some point
there should be a more general Open function, but first I need to work
out how to to turn font names into android file names.

Fixes golang/go#9419.

Change-Id: I8321df873315a5222c39dccf961f742f2e2a7a4c
Reviewed-on: https://go-review.googlesource.com/2059
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw 2014-12-23 13:37:48 -05:00
parent 2b3c96656c
commit a5177c8172
6 changed files with 152 additions and 18 deletions

View File

@ -9,14 +9,13 @@ import (
"fmt"
"image"
"image/draw"
"io/ioutil"
"log"
"math"
"runtime"
"sync"
"time"
"code.google.com/p/freetype-go/freetype"
"golang.org/x/mobile/font"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl/glutil"
)
@ -34,22 +33,7 @@ var fps struct {
// TODO(crawshaw): The gldebug mode needs to complain loudly when GL functions
// are called before init, because often they fail silently.
func fpsInit() {
font := ""
switch runtime.GOOS {
case "android":
font = "/system/fonts/DroidSansMono.ttf"
case "darwin":
font = "/Library/Fonts/Andale Mono.ttf"
case "linux":
font = "/usr/share/fonts/truetype/droid/DroidSansMono.ttf"
default:
panic(fmt.Sprintf("go.mobile/app/debug: unsupported runtime.GOOS %q", runtime.GOOS))
}
b, err := ioutil.ReadFile(font)
if err != nil {
panic(err)
}
b := font.Monospace()
f, err := freetype.ParseFont(b)
if err != nil {
panic(err)

26
font/font.go Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2014 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 font provides platform independent access to system fonts.
package font
// Default returns the default system font.
// The font is encoded as a TTF.
func Default() []byte {
b, err := buildDefault()
if err != nil {
panic(err)
}
return b
}
// Monospace returns the default system fixed-pitch font.
// The font is encoded as a TTF.
func Monospace() []byte {
b, err := buildMonospace()
if err != nil {
panic(err)
}
return b
}

15
font/font_android.go Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2014 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 font
import "io/ioutil"
func buildDefault() ([]byte, error) {
return ioutil.ReadFile("/system/fonts/DroidSans.ttf")
}
func buildMonospace() ([]byte, error) {
return ioutil.ReadFile("/system/fonts/DroidSansMono.ttf")
}

76
font/font_darwin.go Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2014 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 font
/*
#cgo darwin LDFLAGS: -framework CoreFoundation -framework CoreText
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFData.h>
#include <CoreText/CTFont.h>
*/
import "C"
import "unsafe"
func buildFont(f C.CTFontRef) []byte {
ctags := C.CTFontCopyAvailableTables(f, C.kCTFontTableOptionExcludeSynthetic)
tagsCount := C.CFArrayGetCount(ctags)
var tags []uint32
var dataRefs []C.CFDataRef
var dataLens []uint32
for i := C.CFIndex(0); i < tagsCount; i++ {
tag := (C.CTFontTableTag)((uintptr)(C.CFArrayGetValueAtIndex(ctags, i)))
dataRef := C.CTFontCopyTable(f, tag, 0) // retained
tags = append(tags, uint32(tag))
dataRefs = append(dataRefs, dataRef)
dataLens = append(dataLens, uint32(C.CFDataGetLength(dataRef)))
}
totalLen := 0
for _, l := range dataLens {
totalLen += int(l)
}
// Big-endian output.
buf := make([]byte, 0, 12+16*len(tags)+totalLen)
write16 := func(x uint16) { buf = append(buf, byte(x>>8), byte(x)) }
write32 := func(x uint32) { buf = append(buf, byte(x>>24), byte(x>>16), byte(x>>8), byte(x)) }
// File format description: http://www.microsoft.com/typography/otspec/otff.htm
write32(0x00010000) // version 1.0
write16(uint16(len(tags))) // numTables
write16(0) // searchRange
write16(0) // entrySelector
write16(0) // rangeShift
// Table tags, includes offsets into following data segments.
offset := uint32(12 + 16*len(tags)) // offset starts after table tags
for i, tag := range tags {
write32(tag)
write32(0)
write32(offset)
write32(dataLens[i])
offset += dataLens[i]
}
// Data segments.
for i, dataRef := range dataRefs {
data := (*[1<<31 - 2]byte)((unsafe.Pointer)(C.CFDataGetBytePtr(dataRef)))[:dataLens[i]]
buf = append(buf, data...)
C.CFRelease(C.CFTypeRef(dataRef))
}
return buf
}
func buildDefault() ([]byte, error) {
return buildFont(C.CTFontCreateUIFontForLanguage(C.kCTFontSystemFontType, 0, nil)), nil
}
func buildMonospace() ([]byte, error) {
return buildFont(C.CTFontCreateUIFontForLanguage(C.kCTFontUserFixedPitchFontType, 0, nil)), nil
}

17
font/font_linux.go Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2014 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.
// +build !android
package font
import "io/ioutil"
func buildDefault() ([]byte, error) {
return ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSans.ttf")
}
func buildMonospace() ([]byte, error) {
return ioutil.ReadFile("/usr/share/fonts/truetype/droid/DroidSansMono.ttf")
}

16
font/font_test.go Normal file
View File

@ -0,0 +1,16 @@
package font
import (
"testing"
"code.google.com/p/freetype-go/freetype"
)
func TestLoadFonts(t *testing.T) {
if _, err := freetype.ParseFont(Default()); err != nil {
t.Fatalf("default font: %v", err)
}
if _, err := freetype.ParseFont(Monospace()); err != nil {
t.Fatalf("monospace font: %v", err)
}
}