mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-09-26 20:11:28 +08:00
text/v2, exp/textinput: bug fix: RuneLen could return -1 for errors
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
package textinput
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
@@ -65,27 +66,49 @@ func start(bounds image.Rectangle) (states <-chan textInputState, close func())
|
||||
}
|
||||
|
||||
func convertUTF16CountToByteCount(text string, c int) int {
|
||||
if !utf8.ValidString(text) {
|
||||
return -1
|
||||
}
|
||||
if c == 0 {
|
||||
return 0
|
||||
}
|
||||
var utf16Len int
|
||||
for idx, r := range text {
|
||||
utf16Len += utf16.RuneLen(r)
|
||||
l16 := utf16.RuneLen(r)
|
||||
if l16 < 0 {
|
||||
panic(fmt.Sprintf("textinput: invalid rune: %c", r))
|
||||
}
|
||||
utf16Len += l16
|
||||
if utf16Len >= c {
|
||||
return idx + utf8.RuneLen(r)
|
||||
l8 := utf8.RuneLen(r)
|
||||
if l8 < 0 {
|
||||
panic(fmt.Sprintf("textinput: invalid rune: %c", r))
|
||||
}
|
||||
return idx + l8
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func convertByteCountToUTF16Count(text string, c int) int {
|
||||
if !utf8.ValidString(text) {
|
||||
return -1
|
||||
}
|
||||
if c == 0 {
|
||||
return 0
|
||||
}
|
||||
var utf16Len int
|
||||
for idx, r := range text {
|
||||
utf16Len += utf16.RuneLen(r)
|
||||
if idx+utf8.RuneLen(r) >= c {
|
||||
l16 := utf16.RuneLen(r)
|
||||
if l16 < 0 {
|
||||
panic(fmt.Sprintf("textinput: invalid rune length for rune %c", r))
|
||||
}
|
||||
utf16Len += l16
|
||||
l8 := utf8.RuneLen(r)
|
||||
if l8 < 0 {
|
||||
panic(fmt.Sprintf("textinput: invalid rune length for rune %c", r))
|
||||
}
|
||||
if idx+l8 >= c {
|
||||
return utf16Len
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,10 @@ func TestConvertUTF16CountToByteCount(t *testing.T) {
|
||||
{"寿司🍣食べたい", 4, 10},
|
||||
{"寿司🍣食べたい", 5, 13},
|
||||
{"寿司🍣食べたい", 100, -1},
|
||||
{"\xff\xff\xff\xff", 0, -1},
|
||||
{"\xff\xff\xff\xff", 1, -1},
|
||||
{"\xff\xff\xff\xff", 2, -1},
|
||||
{"\xff\xff\xff\xff", 100, -1},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
if got := textinput.ConvertUTF16CountToByteCount(tc.text, tc.c); got != tc.want {
|
||||
@@ -72,6 +76,10 @@ func TestConvertByteCountToUTF16Count(t *testing.T) {
|
||||
{"寿司🍣食べたい", 10, 4},
|
||||
{"寿司🍣食べたい", 13, 5},
|
||||
{"寿司🍣食べたい", 100, -1},
|
||||
{"\xff\xff\xff\xff", 0, -1},
|
||||
{"\xff\xff\xff\xff", 3, -1},
|
||||
{"\xff\xff\xff\xff", 6, -1},
|
||||
{"\xff\xff\xff\xff", 100, -1},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
if got := textinput.ConvertByteCountToUTF16Count(tc.text, tc.c); got != tc.want {
|
||||
|
@@ -172,6 +172,10 @@ func (g *GoXFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset i
|
||||
// Adjust the position to the integers.
|
||||
// The current glyph images assume that they are rendered on integer positions so far.
|
||||
size := utf8.RuneLen(r)
|
||||
if size < 0 {
|
||||
// Treat an error as 1, following DecodeRuneInString.
|
||||
size = 1
|
||||
}
|
||||
|
||||
// Append a glyph even if img is nil.
|
||||
// This is necessary to return index information for control characters.
|
||||
|
@@ -168,7 +168,6 @@ func (m *MultiFace) splitText(text string) iter.Seq[textChunk] {
|
||||
var chunk textChunk
|
||||
for _, r := range text {
|
||||
fi := -1
|
||||
l := utf8.RuneLen(r)
|
||||
for i, f := range m.faces {
|
||||
if !f.hasGlyph(r) && i < len(m.faces)-1 {
|
||||
continue
|
||||
@@ -180,6 +179,12 @@ func (m *MultiFace) splitText(text string) iter.Seq[textChunk] {
|
||||
panic("text: a face was not selected correctly")
|
||||
}
|
||||
|
||||
l := utf8.RuneLen(r)
|
||||
if l < 0 {
|
||||
// Treat an error as 1, following DecodeRuneInString.
|
||||
l = 1
|
||||
}
|
||||
|
||||
var s int
|
||||
if chunk != (textChunk{}) {
|
||||
if chunk.faceIndex == fi {
|
||||
|
Reference in New Issue
Block a user