// Copyright 2017-2022 The MathJax Consortium // SPDX-License-Identifier: Apache-2.0 // Based on BaseMethods.Not and BaseItems.NotItem (MathJax 3.2.2).
package tex import ( ) // This is an explicit data-map consumer. It does not change executable-map // eligibility or route arbitrary names through a parser-less map. func notRemap( string) (string, bool) { for := len(mjSourceMaps) - 1; >= 0; -- { := mjSourceMaps[] if .Name != "not_remap" || .Kind != mjSourceCharacterMap { continue } for := len(.Entries) - 1; >= 0; -- { := .Entries[] if .Name == { , := .Value.(string) return , } } return "", false } return "", false } func notFallback() *mml.Node { // Primary NotItem uses the node factory, not the token factory. := node("mtext", mml.NewText("\u29F8")) := node("mpadded", ) .Attributes.Set("width", 0) return texAtom(, mml.TeXClassRel) } // A true result means the original eligible token was changed in place. // The caller delivers that same token and consumes the pending Not. func applyNotToken( *mml.Node) bool { if == nil || (.Kind != "mo" && .Kind != "mi" && .Kind != "mtext") || len(.Children) != 1 { return false } := textContent() , := .Property("movesupsub") if len(utf16.Encode([]rune())) != 1 || limitsTruthy() { return false } if , := notRemap(); { := mml.NewText() // NodeUtil.setChild overwrites only the slot and new parent. It does // not clear the removed text node's parent pointer. .Children[0] = .Parent = } else { .AppendChild(mml.NewText("\u0338")) } return true } // A NotItem belongs to one logical row, not the shared macro configuration. // Empty command results leave it pending until a real stack item arrives. type pendingNot bool func ( *pendingNot) () []*mml.Node { if !* { return nil } * = false return []*mml.Node{notFallback()} } func ( *pendingNot) () []*mml.Node { := .finish() * = true return } func ( *pendingNot) ( []*mml.Node) []*mml.Node { if !* || len() == 0 { return } * = false if applyNotToken([0]) { return } return append([]*mml.Node{notFallback()}, ...) }