mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-04 07:33:44 +09:00
fix(markup): don't escape ambiguous characters in MathML (#39493)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -8,11 +8,13 @@ import (
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/translation"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
type htmlChunkReader struct {
|
||||
@@ -30,6 +32,10 @@ type escapeStreamer struct {
|
||||
ambiguousTables []*AmbiguousTable
|
||||
allowed map[rune]bool
|
||||
|
||||
tagPartial []byte // partial tag content, used to detect if we are in some tags
|
||||
|
||||
inTagMath bool // MathML operators like U+2212 are intended and wrapping them breaks the math layout
|
||||
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
@@ -62,6 +68,7 @@ func escapeStream(locale translation.Locale, in io.Reader, out io.Writer, opts .
|
||||
for i, part := range parts {
|
||||
if partInTag[i] {
|
||||
lastIsTag = true
|
||||
es.trackHtmlTag(part)
|
||||
if _, err := out.Write(part); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -75,7 +82,11 @@ func escapeStream(locale translation.Locale, in io.Reader, out io.Writer, opts .
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = es.detectAndWriteRunes(part); err != nil {
|
||||
if es.inTagMath {
|
||||
if _, err := out.Write(part); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err = es.detectAndWriteRunes(part); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -83,6 +94,34 @@ func escapeStream(locale translation.Locale, in io.Reader, out io.Writer, opts .
|
||||
}
|
||||
}
|
||||
|
||||
// trackHtmlTag receives tag parts, a tag might be split into multiple parts
|
||||
func (e *escapeStreamer) trackHtmlTag(part []byte) {
|
||||
const maxHeadLen = 100 // only read the first N bytes of the tag for detection purpose
|
||||
if part[0] == '<' {
|
||||
// start a new tag
|
||||
e.tagPartial = e.tagPartial[:0]
|
||||
}
|
||||
if len(e.tagPartial) >= maxHeadLen {
|
||||
return
|
||||
}
|
||||
e.tagPartial = append(e.tagPartial, part[:min(len(part), maxHeadLen-len(e.tagPartial))]...)
|
||||
|
||||
isTag := func(prefix string) bool {
|
||||
if len(e.tagPartial) < len(prefix)+1 {
|
||||
return false
|
||||
}
|
||||
if !util.AsciiEqualFold(e.tagPartial[:len(prefix)], []byte(prefix)) {
|
||||
return false
|
||||
}
|
||||
return strings.IndexByte(" \t\n\r\f>", e.tagPartial[len(prefix)]) != -1
|
||||
}
|
||||
if isTag("<math") {
|
||||
e.inTagMath = true
|
||||
} else if isTag("</math") {
|
||||
e.inTagMath = false
|
||||
}
|
||||
}
|
||||
|
||||
func (e *escapeStreamer) trimAndWriteBom(part []byte) ([]byte, error) {
|
||||
remaining, ok := bytes.CutPrefix(part, globalVars().utf8Bom)
|
||||
if ok {
|
||||
|
||||
Reference in New Issue
Block a user