github.com/jmigpin/editor@v1.6.0/util/fontutil/facecache.go (about)

     1  package fontutil
     2  
     3  import (
     4  	"image"
     5  
     6  	"golang.org/x/image/font"
     7  	"golang.org/x/image/math/fixed"
     8  )
     9  
    10  type FaceCache struct {
    11  	font.Face
    12  	gc  map[rune]*GlyphCache
    13  	gac map[rune]*GlyphAdvanceCache
    14  	gbc map[rune]*GlyphBoundsCache
    15  	kc  map[string]fixed.Int26_6 // kern cache
    16  }
    17  
    18  func NewFaceCache(face font.Face) *FaceCache {
    19  	fc := &FaceCache{Face: face}
    20  	fc.gc = make(map[rune]*GlyphCache)
    21  	fc.gac = make(map[rune]*GlyphAdvanceCache)
    22  	fc.gbc = make(map[rune]*GlyphBoundsCache)
    23  	fc.kc = make(map[string]fixed.Int26_6)
    24  	return fc
    25  }
    26  func (fc *FaceCache) Glyph(dot fixed.Point26_6, ru rune) (
    27  	dr image.Rectangle,
    28  	mask image.Image,
    29  	maskp image.Point,
    30  	advance fixed.Int26_6,
    31  	ok bool,
    32  ) {
    33  	gc, ok := fc.gc[ru]
    34  	if !ok {
    35  		gc = NewGlyphCache(fc.Face, ru)
    36  		fc.gc[ru] = gc
    37  	}
    38  	p := image.Point{dot.X.Floor(), dot.Y.Floor()}
    39  	dr2 := gc.dr.Add(p)
    40  	return dr2, gc.mask, gc.maskp, gc.advance, gc.ok
    41  }
    42  func (fc *FaceCache) GlyphAdvance(ru rune) (advance fixed.Int26_6, ok bool) {
    43  	gac, ok := fc.gac[ru]
    44  	if !ok {
    45  		gac = NewGlyphAdvanceCache(fc.Face, ru)
    46  		fc.gac[ru] = gac
    47  	}
    48  	return gac.advance, gac.ok
    49  }
    50  func (fc *FaceCache) GlyphBounds(ru rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
    51  	gbc, ok := fc.gbc[ru]
    52  	if !ok {
    53  		gbc = NewGlyphBoundsCache(fc.Face, ru)
    54  		fc.gbc[ru] = gbc
    55  	}
    56  	return gbc.bounds, gbc.advance, gbc.ok
    57  }
    58  func (fc *FaceCache) Kern(r0, r1 rune) fixed.Int26_6 {
    59  	i := kernIndex(r0, r1)
    60  	k, ok := fc.kc[i]
    61  	if !ok {
    62  		k = NewKernCache(fc.Face, r0, r1)
    63  		fc.kc[i] = k
    64  	}
    65  	return k
    66  }
    67  
    68  //----------
    69  
    70  type GlyphCache struct {
    71  	dr      image.Rectangle
    72  	mask    image.Image
    73  	maskp   image.Point
    74  	advance fixed.Int26_6
    75  	ok      bool
    76  }
    77  
    78  func NewGlyphCache(face font.Face, ru rune) *GlyphCache {
    79  	var zeroDot fixed.Point26_6 // always use zero
    80  	dr, mask, maskp, adv, ok := face.Glyph(zeroDot, ru)
    81  
    82  	// avoid the truetype package cache (it's not giving the same mask everytime, probably needs cache parameter)
    83  	if ok {
    84  		mask = copyMask(mask)
    85  	}
    86  
    87  	return &GlyphCache{dr, mask, maskp, adv, ok}
    88  }
    89  
    90  //----------
    91  
    92  type GlyphAdvanceCache struct {
    93  	advance fixed.Int26_6
    94  	ok      bool
    95  }
    96  
    97  func NewGlyphAdvanceCache(face font.Face, ru rune) *GlyphAdvanceCache {
    98  	adv, ok := face.GlyphAdvance(ru) // only one can run at a time
    99  	return &GlyphAdvanceCache{adv, ok}
   100  }
   101  
   102  //----------
   103  
   104  type GlyphBoundsCache struct {
   105  	bounds  fixed.Rectangle26_6
   106  	advance fixed.Int26_6
   107  	ok      bool
   108  }
   109  
   110  func NewGlyphBoundsCache(face font.Face, ru rune) *GlyphBoundsCache {
   111  	bounds, adv, ok := face.GlyphBounds(ru) // only one can run at a time
   112  	return &GlyphBoundsCache{bounds, adv, ok}
   113  }
   114  
   115  //----------
   116  
   117  func kernIndex(r0, r1 rune) string {
   118  	return string([]rune{r0, ',', r1})
   119  }
   120  
   121  func NewKernCache(face font.Face, r0, r1 rune) fixed.Int26_6 {
   122  	return face.Kern(r0, r1) // only one can run at a time
   123  }
   124  
   125  //----------
   126  
   127  func copyMask(mask image.Image) image.Image {
   128  	alpha := *(mask.(*image.Alpha)) // copy structure
   129  	pix := make([]uint8, len(alpha.Pix))
   130  	copy(pix, alpha.Pix)
   131  	alpha.Pix = pix
   132  	return &alpha
   133  }
   134  
   135  //----------
   136  
   137  //func copyMask2(mask image.Image) (image.Image, []byte) {
   138  //	alpha := *(mask.(*image.Alpha)) // copy structure
   139  //	pix := make([]uint8, len(alpha.Pix))
   140  //	copy(pix, alpha.Pix)
   141  //	alpha.Pix = pix
   142  //	h := bytesHash(pix)
   143  //	return &alpha, h
   144  //}
   145  
   146  //func bytesHash(b []byte) []byte {
   147  //	h := sha1.New()
   148  //	h.Write(b)
   149  //	return h.Sum(nil)
   150  //}