multi.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. "errors"
  17. "unicode/utf8"
  18. "github.com/hajimehoshi/ebiten/v2/vector"
  19. )
  20. var _ Face = (*MultiFace)(nil)
  21. // MultiFace is a Face that consists of multiple Face objects.
  22. // The face in the first index is used in the highest priority, and the last the lowest priority.
  23. //
  24. // There is a known issue: if the writing directions of the faces don't agree, the rendering result might be messed up.
  25. type MultiFace struct {
  26. faces []Face
  27. }
  28. // NewMultiFace creates a new MultiFace from the given faces.
  29. //
  30. // NewMultiFace returns an error when no faces are given, or the faces' directions don't agree.
  31. func NewMultiFace(faces ...Face) (*MultiFace, error) {
  32. if len(faces) == 0 {
  33. return nil, errors.New("text: no faces are given at NewMultiFace")
  34. }
  35. d := faces[0].direction()
  36. for _, f := range faces[1:] {
  37. if f.direction() != d {
  38. return nil, errors.New("text: all the faces' directions must agree at NewMultiFace")
  39. }
  40. }
  41. m := &MultiFace{}
  42. m.faces = make([]Face, len(faces))
  43. copy(m.faces, faces)
  44. return m, nil
  45. }
  46. // Metrics implements Face.
  47. func (m *MultiFace) Metrics() Metrics {
  48. var mt Metrics
  49. for _, f := range m.faces {
  50. mt1 := f.Metrics()
  51. if mt1.HLineGap > mt.HLineGap {
  52. mt.HLineGap = mt1.HLineGap
  53. }
  54. if mt1.HAscent > mt.HAscent {
  55. mt.HAscent = mt1.HAscent
  56. }
  57. if mt1.HDescent > mt.HDescent {
  58. mt.HDescent = mt1.HDescent
  59. }
  60. if mt1.VLineGap > mt.VLineGap {
  61. mt.VLineGap = mt1.VLineGap
  62. }
  63. if mt1.VAscent > mt.VAscent {
  64. mt.VAscent = mt1.VAscent
  65. }
  66. if mt1.VDescent > mt.VDescent {
  67. mt.VDescent = mt1.VDescent
  68. }
  69. if mt1.XHeight > mt.XHeight {
  70. mt.XHeight = mt1.XHeight
  71. }
  72. if mt1.CapHeight > mt.CapHeight {
  73. mt.CapHeight = mt1.CapHeight
  74. }
  75. }
  76. return mt
  77. }
  78. // advance implements Face.
  79. func (m *MultiFace) advance(text string) float64 {
  80. var a float64
  81. for _, c := range m.splitText(text) {
  82. if c.faceIndex == -1 {
  83. continue
  84. }
  85. f := m.faces[c.faceIndex]
  86. a += f.advance(text[c.textStartIndex:c.textEndIndex])
  87. }
  88. return a
  89. }
  90. // hasGlyph implements Face.
  91. func (m *MultiFace) hasGlyph(r rune) bool {
  92. for _, f := range m.faces {
  93. if f.hasGlyph(r) {
  94. return true
  95. }
  96. }
  97. return false
  98. }
  99. // appendGlyphsForLine implements Face.
  100. func (m *MultiFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
  101. for _, c := range m.splitText(line) {
  102. if c.faceIndex == -1 {
  103. continue
  104. }
  105. f := m.faces[c.faceIndex]
  106. t := line[c.textStartIndex:c.textEndIndex]
  107. glyphs = f.appendGlyphsForLine(glyphs, t, indexOffset, originX, originY)
  108. if a := f.advance(t); f.direction().isHorizontal() {
  109. originX += a
  110. } else {
  111. originY += a
  112. }
  113. indexOffset += len(t)
  114. }
  115. return glyphs
  116. }
  117. // appendVectorPathForLine implements Face.
  118. func (m *MultiFace) appendVectorPathForLine(path *vector.Path, line string, originX, originY float64) {
  119. for _, c := range m.splitText(line) {
  120. if c.faceIndex == -1 {
  121. continue
  122. }
  123. f := m.faces[c.faceIndex]
  124. t := line[c.textStartIndex:c.textEndIndex]
  125. f.appendVectorPathForLine(path, t, originX, originY)
  126. if a := f.advance(t); f.direction().isHorizontal() {
  127. originX += a
  128. } else {
  129. originY += a
  130. }
  131. }
  132. }
  133. // direction implements Face.
  134. func (m *MultiFace) direction() Direction {
  135. if len(m.faces) == 0 {
  136. return DirectionLeftToRight
  137. }
  138. return m.faces[0].direction()
  139. }
  140. // private implements Face.
  141. func (m *MultiFace) private() {
  142. }
  143. type textChunk struct {
  144. textStartIndex int
  145. textEndIndex int
  146. faceIndex int
  147. }
  148. func (m *MultiFace) splitText(text string) []textChunk {
  149. var chunks []textChunk
  150. for ri, r := range text {
  151. fi := -1
  152. _, l := utf8.DecodeRuneInString(text[ri:])
  153. for i, f := range m.faces {
  154. if !f.hasGlyph(r) && i < len(m.faces)-1 {
  155. continue
  156. }
  157. fi = i
  158. break
  159. }
  160. if fi == -1 {
  161. panic("text: a face was not selected correctly")
  162. }
  163. var s int
  164. if len(chunks) > 0 {
  165. if chunks[len(chunks)-1].faceIndex == fi {
  166. chunks[len(chunks)-1].textEndIndex += l
  167. continue
  168. }
  169. s = chunks[len(chunks)-1].textEndIndex
  170. }
  171. chunks = append(chunks, textChunk{
  172. textStartIndex: s,
  173. textEndIndex: s + l,
  174. faceIndex: fi,
  175. })
  176. }
  177. return chunks
  178. }