goxcache.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2023 The Ebitengine Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package text
  15. import (
  16. "image"
  17. "sync"
  18. "golang.org/x/image/font"
  19. "golang.org/x/image/math/fixed"
  20. )
  21. type glyphBoundsCacheValue struct {
  22. bounds fixed.Rectangle26_6
  23. advance fixed.Int26_6
  24. ok bool
  25. }
  26. type glyphAdvanceCacheValue struct {
  27. advance fixed.Int26_6
  28. ok bool
  29. }
  30. type kernCacheKey struct {
  31. r0 rune
  32. r1 rune
  33. }
  34. type faceWithCache struct {
  35. f font.Face
  36. glyphBoundsCache map[rune]glyphBoundsCacheValue
  37. glyphAdvanceCache map[rune]glyphAdvanceCacheValue
  38. kernCache map[kernCacheKey]fixed.Int26_6
  39. m sync.Mutex
  40. }
  41. func (f *faceWithCache) Close() error {
  42. if err := f.f.Close(); err != nil {
  43. return err
  44. }
  45. f.m.Lock()
  46. defer f.m.Unlock()
  47. f.glyphBoundsCache = nil
  48. f.glyphAdvanceCache = nil
  49. f.kernCache = nil
  50. return nil
  51. }
  52. func (f *faceWithCache) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
  53. return f.f.Glyph(dot, r)
  54. }
  55. func (f *faceWithCache) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
  56. f.m.Lock()
  57. defer f.m.Unlock()
  58. if v, ok := f.glyphBoundsCache[r]; ok {
  59. return v.bounds, v.advance, v.ok
  60. }
  61. bounds, advance, ok = f.f.GlyphBounds(r)
  62. if f.glyphBoundsCache == nil {
  63. f.glyphBoundsCache = map[rune]glyphBoundsCacheValue{}
  64. }
  65. f.glyphBoundsCache[r] = glyphBoundsCacheValue{
  66. bounds: bounds,
  67. advance: advance,
  68. ok: ok,
  69. }
  70. return
  71. }
  72. func (f *faceWithCache) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
  73. f.m.Lock()
  74. defer f.m.Unlock()
  75. if v, ok := f.glyphAdvanceCache[r]; ok {
  76. return v.advance, v.ok
  77. }
  78. advance, ok = f.f.GlyphAdvance(r)
  79. if f.glyphAdvanceCache == nil {
  80. f.glyphAdvanceCache = map[rune]glyphAdvanceCacheValue{}
  81. }
  82. f.glyphAdvanceCache[r] = glyphAdvanceCacheValue{
  83. advance: advance,
  84. ok: ok,
  85. }
  86. return
  87. }
  88. func (f *faceWithCache) Kern(r0, r1 rune) fixed.Int26_6 {
  89. f.m.Lock()
  90. defer f.m.Unlock()
  91. key := kernCacheKey{r0: r0, r1: r1}
  92. if v, ok := f.kernCache[key]; ok {
  93. return v
  94. }
  95. v := f.f.Kern(r0, r1)
  96. if f.kernCache == nil {
  97. f.kernCache = map[kernCacheKey]fixed.Int26_6{}
  98. }
  99. f.kernCache[key] = v
  100. return v
  101. }
  102. func (f *faceWithCache) Metrics() font.Metrics {
  103. return f.f.Metrics()
  104. }