math-core 0.5.3__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {math_core-0.5.3 → math_core-0.6.0}/Cargo.lock +52 -38
  2. {math_core-0.5.3 → math_core-0.6.0}/Cargo.toml +1 -1
  3. math_core-0.6.0/LICENSE +9 -0
  4. {math_core-0.5.3 → math_core-0.6.0}/PKG-INFO +1 -1
  5. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/Cargo.toml +3 -3
  6. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/README.md +30 -9
  7. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/examples/browser_test.rs +3 -1
  8. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/examples/equations.rs +2 -2
  9. math_core-0.6.0/crates/math-core/src/character_class.rs +194 -0
  10. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/commands.rs +82 -32
  11. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/environments.rs +37 -32
  12. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/lexer.rs +16 -1
  13. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/lib.rs +9 -7
  14. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/parser.rs +181 -94
  15. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/predefined.rs +2 -1
  16. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/token.rs +8 -11
  17. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/tests/conversion_test.rs +6 -0
  18. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core-python/Cargo.toml +1 -1
  19. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core-python/src/lib.rs +11 -1
  20. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/arena.rs +4 -4
  21. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/ast.rs +58 -105
  22. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/attribute.rs +6 -43
  23. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/length.rs +2 -2
  24. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/lib.rs +1 -0
  25. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/symbol.rs +41 -122
  26. {math_core-0.5.3 → math_core-0.6.0}/pyproject.toml +1 -1
  27. {math_core-0.5.3 → math_core-0.6.0}/python/math_core/_math_core_rust.pyi +1 -0
  28. math_core-0.5.3/crates/math-core/src/character_class.rs +0 -22
  29. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/examples/minijinja.rs +0 -0
  30. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/atof.rs +0 -0
  31. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/color_defs.rs +0 -0
  32. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/error.rs +0 -0
  33. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/html_utils.rs +0 -0
  34. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/specifications.rs +0 -0
  35. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/text_parser.rs +0 -0
  36. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/src/token_queue.rs +0 -0
  37. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/tests/custom_cmd_test.rs +0 -0
  38. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/tests/error_test.rs +0 -0
  39. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core/tests/wiki_test.rs +0 -0
  40. {math_core-0.5.3 → math_core-0.6.0}/crates/math-core-python/README.md +0 -0
  41. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/Cargo.toml +0 -0
  42. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/README.md +0 -0
  43. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/fmt.rs +0 -0
  44. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/itoa.rs +0 -0
  45. {math_core-0.5.3 → math_core-0.6.0}/crates/mathml-renderer/src/table.rs +0 -0
  46. {math_core-0.5.3 → math_core-0.6.0}/python/math_core/__init__.py +0 -0
  47. {math_core-0.5.3 → math_core-0.6.0}/python/math_core/py.typed +0 -0
@@ -13,9 +13,9 @@ dependencies = [
13
13
 
14
14
  [[package]]
15
15
  name = "anstream"
16
- version = "0.6.15"
16
+ version = "1.0.0"
17
17
  source = "registry+https://github.com/rust-lang/crates.io-index"
18
- checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
18
+ checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
19
19
  dependencies = [
20
20
  "anstyle",
21
21
  "anstyle-parse",
@@ -28,15 +28,15 @@ dependencies = [
28
28
 
29
29
  [[package]]
30
30
  name = "anstyle"
31
- version = "1.0.8"
31
+ version = "1.0.14"
32
32
  source = "registry+https://github.com/rust-lang/crates.io-index"
33
- checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
33
+ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
34
34
 
35
35
  [[package]]
36
36
  name = "anstyle-parse"
37
- version = "0.2.5"
37
+ version = "1.0.0"
38
38
  source = "registry+https://github.com/rust-lang/crates.io-index"
39
- checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
39
+ checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
40
40
  dependencies = [
41
41
  "utf8parse",
42
42
  ]
@@ -52,12 +52,13 @@ dependencies = [
52
52
 
53
53
  [[package]]
54
54
  name = "anstyle-wincon"
55
- version = "3.0.4"
55
+ version = "3.0.11"
56
56
  source = "registry+https://github.com/rust-lang/crates.io-index"
57
- checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
57
+ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
58
58
  dependencies = [
59
59
  "anstyle",
60
- "windows-sys 0.52.0",
60
+ "once_cell_polyfill",
61
+ "windows-sys 0.61.2",
61
62
  ]
62
63
 
63
64
  [[package]]
@@ -126,9 +127,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
126
127
 
127
128
  [[package]]
128
129
  name = "clap"
129
- version = "4.5.60"
130
+ version = "4.6.0"
130
131
  source = "registry+https://github.com/rust-lang/crates.io-index"
131
- checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
132
+ checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
132
133
  dependencies = [
133
134
  "clap_builder",
134
135
  "clap_derive",
@@ -136,9 +137,9 @@ dependencies = [
136
137
 
137
138
  [[package]]
138
139
  name = "clap_builder"
139
- version = "4.5.60"
140
+ version = "4.6.0"
140
141
  source = "registry+https://github.com/rust-lang/crates.io-index"
141
- checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
142
+ checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
142
143
  dependencies = [
143
144
  "anstream",
144
145
  "anstyle",
@@ -148,9 +149,9 @@ dependencies = [
148
149
 
149
150
  [[package]]
150
151
  name = "clap_derive"
151
- version = "4.5.55"
152
+ version = "4.6.0"
152
153
  source = "registry+https://github.com/rust-lang/crates.io-index"
153
- checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
154
+ checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
154
155
  dependencies = [
155
156
  "heck",
156
157
  "proc-macro2",
@@ -362,7 +363,7 @@ dependencies = [
362
363
 
363
364
  [[package]]
364
365
  name = "math-core"
365
- version = "0.5.3"
366
+ version = "0.6.0"
366
367
  dependencies = [
367
368
  "ariadne",
368
369
  "insta",
@@ -382,7 +383,7 @@ dependencies = [
382
383
 
383
384
  [[package]]
384
385
  name = "math-core-cli"
385
- version = "0.5.3"
386
+ version = "0.6.0"
386
387
  dependencies = [
387
388
  "ariadne",
388
389
  "clap",
@@ -395,7 +396,7 @@ dependencies = [
395
396
 
396
397
  [[package]]
397
398
  name = "math-core-python"
398
- version = "0.5.3"
399
+ version = "0.6.0"
399
400
  dependencies = [
400
401
  "ariadne",
401
402
  "math-core",
@@ -405,7 +406,7 @@ dependencies = [
405
406
 
406
407
  [[package]]
407
408
  name = "math-core-renderer-internal"
408
- version = "0.5.3"
409
+ version = "0.6.0"
409
410
  dependencies = [
410
411
  "bitflags",
411
412
  "dtoa",
@@ -418,7 +419,7 @@ dependencies = [
418
419
 
419
420
  [[package]]
420
421
  name = "math-core-wasm"
421
- version = "0.5.3"
422
+ version = "0.6.0"
422
423
  dependencies = [
423
424
  "ariadne",
424
425
  "js-sys",
@@ -435,6 +436,12 @@ version = "2.8.0"
435
436
  source = "registry+https://github.com/rust-lang/crates.io-index"
436
437
  checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
437
438
 
439
+ [[package]]
440
+ name = "memo-map"
441
+ version = "0.3.3"
442
+ source = "registry+https://github.com/rust-lang/crates.io-index"
443
+ checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b"
444
+
438
445
  [[package]]
439
446
  name = "minicov"
440
447
  version = "0.3.8"
@@ -447,10 +454,11 @@ dependencies = [
447
454
 
448
455
  [[package]]
449
456
  name = "minijinja"
450
- version = "2.17.1"
457
+ version = "2.18.0"
451
458
  source = "registry+https://github.com/rust-lang/crates.io-index"
452
- checksum = "5ea5ea1e90055f200af6b8e52a4a34e05e77e7fee953a9fb40c631efdc43cab1"
459
+ checksum = "328251e58ad8e415be6198888fc207502727dc77945806421ab34f35bf012e7d"
453
460
  dependencies = [
461
+ "memo-map",
454
462
  "serde",
455
463
  ]
456
464
 
@@ -479,6 +487,12 @@ version = "1.21.3"
479
487
  source = "registry+https://github.com/rust-lang/crates.io-index"
480
488
  checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
481
489
 
490
+ [[package]]
491
+ name = "once_cell_polyfill"
492
+ version = "1.70.2"
493
+ source = "registry+https://github.com/rust-lang/crates.io-index"
494
+ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
495
+
482
496
  [[package]]
483
497
  name = "oorandom"
484
498
  version = "11.1.5"
@@ -548,9 +562,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
548
562
 
549
563
  [[package]]
550
564
  name = "proc-macro2"
551
- version = "1.0.101"
565
+ version = "1.0.106"
552
566
  source = "registry+https://github.com/rust-lang/crates.io-index"
553
- checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
567
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
554
568
  dependencies = [
555
569
  "unicode-ident",
556
570
  ]
@@ -615,9 +629,9 @@ dependencies = [
615
629
 
616
630
  [[package]]
617
631
  name = "quote"
618
- version = "1.0.41"
632
+ version = "1.0.45"
619
633
  source = "registry+https://github.com/rust-lang/crates.io-index"
620
- checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
634
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
621
635
  dependencies = [
622
636
  "proc-macro2",
623
637
  ]
@@ -843,9 +857,9 @@ dependencies = [
843
857
 
844
858
  [[package]]
845
859
  name = "syn"
846
- version = "2.0.106"
860
+ version = "2.0.117"
847
861
  source = "registry+https://github.com/rust-lang/crates.io-index"
848
- checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
862
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
849
863
  dependencies = [
850
864
  "proc-macro2",
851
865
  "quote",
@@ -873,9 +887,9 @@ dependencies = [
873
887
 
874
888
  [[package]]
875
889
  name = "toml"
876
- version = "1.0.6+spec-1.1.0"
890
+ version = "1.0.7+spec-1.1.0"
877
891
  source = "registry+https://github.com/rust-lang/crates.io-index"
878
- checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc"
892
+ checksum = "dd28d57d8a6f6e458bc0b8784f8fdcc4b99a437936056fa122cb234f18656a96"
879
893
  dependencies = [
880
894
  "indexmap",
881
895
  "serde_core",
@@ -888,27 +902,27 @@ dependencies = [
888
902
 
889
903
  [[package]]
890
904
  name = "toml_datetime"
891
- version = "1.0.0+spec-1.1.0"
905
+ version = "1.0.1+spec-1.1.0"
892
906
  source = "registry+https://github.com/rust-lang/crates.io-index"
893
- checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e"
907
+ checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9"
894
908
  dependencies = [
895
909
  "serde_core",
896
910
  ]
897
911
 
898
912
  [[package]]
899
913
  name = "toml_parser"
900
- version = "1.0.9+spec-1.1.0"
914
+ version = "1.0.10+spec-1.1.0"
901
915
  source = "registry+https://github.com/rust-lang/crates.io-index"
902
- checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
916
+ checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420"
903
917
  dependencies = [
904
918
  "winnow",
905
919
  ]
906
920
 
907
921
  [[package]]
908
922
  name = "toml_writer"
909
- version = "1.0.6+spec-1.1.0"
923
+ version = "1.0.7+spec-1.1.0"
910
924
  source = "registry+https://github.com/rust-lang/crates.io-index"
911
- checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
925
+ checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d"
912
926
 
913
927
  [[package]]
914
928
  name = "typeid"
@@ -1160,9 +1174,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1160
1174
 
1161
1175
  [[package]]
1162
1176
  name = "winnow"
1163
- version = "0.7.13"
1177
+ version = "1.0.0"
1164
1178
  source = "registry+https://github.com/rust-lang/crates.io-index"
1165
- checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
1179
+ checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
1166
1180
 
1167
1181
  [[package]]
1168
1182
  name = "wit-bindgen"
@@ -7,7 +7,7 @@ resolver = "2"
7
7
  edition = "2024"
8
8
  rust-version = "1.91"
9
9
  license = "MIT"
10
- version = "0.5.3"
10
+ version = "0.6.0"
11
11
  repository = "https://github.com/tmke8/math-core"
12
12
 
13
13
  [workspace.dependencies]
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright 2020 Hiromu Sugiura
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: math-core
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -19,7 +19,7 @@ categories = ["science"]
19
19
  exclude = ["/src/snapshots", "/tests/snapshots"]
20
20
 
21
21
  [dependencies]
22
- mathml-renderer = { path = "../mathml-renderer", package = "math-core-renderer-internal", version = "0.5.3" }
22
+ mathml-renderer = { path = "../mathml-renderer", package = "math-core-renderer-internal", version = "0.6.0" }
23
23
  serde = { workspace = true, optional = true }
24
24
  serde-tuple-vec-map = { version = "1.0.1", optional = true }
25
25
  phf = { version = "0.13.1", features = ["macros"] }
@@ -32,10 +32,10 @@ ariadne = { workspace = true, optional = true }
32
32
 
33
33
  [dev-dependencies]
34
34
  math-core = { path = ".", features = ["serde", "ariadne"] }
35
- mathml-renderer = { path = "../mathml-renderer", package = "math-core-renderer-internal", version = "0.5.3", features = ["serde"] }
35
+ mathml-renderer = { path = "../mathml-renderer", package = "math-core-renderer-internal", version = "0.6.0", features = ["serde"] }
36
36
  insta = { version = "1.46.3", features = ["default", "ron"] }
37
37
  regex = "1.12.3"
38
- minijinja = "2.17.1"
38
+ minijinja = "2.18.0"
39
39
 
40
40
  [features]
41
41
  serde = ["dep:serde", "dep:serde-tuple-vec-map"]
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Convert LaTeX to MathML Core
4
4
 
5
- [Try it out on the playground!](https://tmke8.github.io/math-core/)
5
+ [Try it out on the playground](https://tmke8.github.io/math-core/) or [take a look at the comparison table with KaTeX](https://tmke8.github.io/math-core/comparison.html).
6
6
 
7
7
  `math-core` allows you to convert LaTeX math to [MathML Core](https://www.w3.org/TR/mathml-core/), the MathML specification that is being implemented by web browsers. For example, this LaTeX code:
8
8
 
@@ -51,13 +51,13 @@ There are 4 ways to use the code in this project:
51
51
  1. As a CLI binary
52
52
  2. As a Python package
53
53
  3. As a Rust library
54
- 4. As a WebAssembly module
54
+ 4. As a Node.js package
55
55
 
56
56
  ### CLI
57
57
  You can download precompiled binaries from the GitHub Release page. Alternatively, you can build the CLI binary from source:
58
58
 
59
59
  ```sh
60
- cargo build --bin mathcore --release
60
+ cargo install math-core-cli
61
61
  ```
62
62
 
63
63
  You can see an explanation of the CLI interface with
@@ -86,12 +86,16 @@ cargo add math-core
86
86
 
87
87
  The documentation for the library can be found on docs.rs: https://docs.rs/math-core/latest/math_core/
88
88
 
89
- ### WebAssembly module
90
- The WebAssembly frontend is currently only used for the [playground](https://tmke8.github.io/math-core/). In the future, a package for this may be published to npm.
89
+ ### Node.js package
90
+ Install the package with
91
+
92
+ ```
93
+ npm i math-core
94
+ ```
91
95
 
92
96
  ## Required CSS
93
97
  ### CSS for math font
94
- The MathML code generated by this project is intended to be very portable and work *almost* without a CSS style sheet. However, in order to really get LaTeX-like rendering of the MathML, one unfortunately needs custom math fonts.
98
+ The MathML markup generated by this project is intended to be very portable and work *almost* without a CSS style sheet. However, in order to really get LaTeX-like rendering, one unfortunately needs custom math fonts.
95
99
 
96
100
  To specify the font, include something like this in your CSS:
97
101
 
@@ -106,15 +110,17 @@ math {
106
110
  }
107
111
  ```
108
112
 
109
- Some day, perhaps, any font with a MATH table will be supported, but right now fonts require some tweaks.
113
+ Some day, perhaps, any font with a MATH table will be supported, but right now fonts require some tweaks due to browser shortcomings.
110
114
 
111
- The main problem is that Chromium does not look at `ssty` variants when deciding on a glyph for super- and subscript (resulting in incorrectly rendered primes) and the fact that Chromium does not horizontally center accents. These problems have been manually fixed for the three fonts included in this project:
115
+ One problem is that Chromium does not look at `ssty` variants when deciding on a glyph for super- and subscript (resulting in incorrectly rendered primes). Another problem is that Safari displays accents with incorrect vertical space. Additionally, both Chromium and Safari do not horizontally center certain accents. These problems have been manually fixed for the three fonts selectable on the playground:
112
116
 
113
117
  - *New Computer Modern Math Book* ([original repo](https://git.gnu.org.ua/newcm.git/about/)): a maintained continuation of LaTeX’s classic *Computer Modern Math*
114
118
  - *Libertinus Math* ([original repo](https://github.com/alerque/libertinus)): a maintained continuation of *Linux Libertine*
115
119
  - *Noto Sans Math* ([original repo](https://github.com/notofonts/math)): a sans-serif math font
116
120
 
117
- The fixes applied to the font files do not change the shape of any glyphs; they merely rearrange some glyphs or center them. The font files can be found in the `playground/` directory in this repository. To use them in your website, download them here and load them on the page from your server. No guarantees will be made that the fonts on the playground will remain available on the current URLs.
121
+ The fixes applied to the font files do not change the shape of any glyphs; they merely rearrange some glyphs or position them differently within glyph space.
122
+
123
+ The patching of these fonts is tracked in a separate repository: [math-core-fonts](https://github.com/tmke8/math-core-fonts). To use them on your website, download them from there.
118
124
 
119
125
  #### Font subsetting
120
126
  The math fonts all have quite large font files. Especially *New Computer Modern Math Book* is enormous with an almost 700kB `.woff2` file. Therefore, if possible, you should use *font subsetting* where the font file only includes those glyphs that are actually used on your website. Existing tools should work fine for this.
@@ -184,6 +190,20 @@ Chromium does not support the `<menclose>` element, which is used for `\sout{...
184
190
  }
185
191
  ```
186
192
 
193
+ ### Accent gap
194
+ We also recommend (though it is not necessary) to add the following CSS:
195
+
196
+ ```css
197
+ /* Styles for Chromium and Safari */
198
+ @supports (not (-moz-appearance: none)) {
199
+ mover[accent="true" i] > mo:nth-child(2) {
200
+ margin-bottom: 0.15ex;
201
+ }
202
+ }
203
+ ```
204
+
205
+ This slightly increases the gap between letter and accent on Chromium and Safari. One risk with such a CSS rule is that if Chromium or Safari ever increases that gap to match Firefox, then this CSS will produce an overlarge gap. However, it's not clear that this will ever happen and we think the present-day benefits of this CSS rule outweigh the future risks.
206
+
187
207
  #### Dealing with other rendering problems
188
208
  The above CSS unfortunately does not fix all rendering bugs found in the current versions of browsers. There is a tracking issue for other known rendering bugs: https://github.com/tmke8/math-core/issues/209
189
209
 
@@ -218,6 +238,7 @@ There is no Unicode range for this, so the only way to implement this would be w
218
238
  - This also applies to things like `:=`. Consider using `\coloneqq` instead, which will result in the semantically correct Unicode symbol.
219
239
  - Don’t worry about having unnecessary curly braces, like, say, `x_{2}` vs `x_2`. Both result in the same MathML because unnecessary groups are stripped away by this library.
220
240
  - Try to avoid using absolute length units like `\hspace{1cm}`. It’s difficult to render them correctly. Instead, use relative length units like `\hspace{2.8em}`.
241
+ - Use `\text{...}` only for prose and not for, e.g., subscripted textual labels as in `D_\text{test}`. In the latter case, use `\mathrm{...}` instead.
221
242
 
222
243
  ## Alternatives to this library
223
244
 
@@ -4,9 +4,10 @@ fn main() {
4
4
  let inputs = vec![
5
5
  // Safari bugs:
6
6
  r#"\bar x, \hat x, \check x, \grave x, \breve x, \acute x"#,
7
- r#"\vec x, \dot x, \ddot x, \dddot x, \ddddot x"#,
7
+ r#"\vec x, \mathring x, \tilde x, \dot x, \ddot x, \dddot x, \ddddot x"#,
8
8
  r#"x^*"#,
9
9
  // Chrome bugs:
10
+ r#"\widehat x, \widehat{xxxx}"#,
10
11
  r#"\widetilde x, \widetilde{xxxx}"#,
11
12
  r#"\widecheck x, \widecheck{xxxx}"#,
12
13
  r#"\overline x, \overline{xxxx}"#,
@@ -21,6 +22,7 @@ fn main() {
21
22
 
22
23
  let converter = LatexToMathML::new(MathCoreConfig {
23
24
  pretty_print: PrettyPrint::Always,
25
+ allow_unreliable_rendering: true,
24
26
  ..Default::default()
25
27
  })
26
28
  .unwrap();
@@ -18,7 +18,7 @@ fn main() {
18
18
  r#"\overparen{x\times\cdots\times x}, \overparen{x\times\cdots\times x}^{n}, \underparen{x\times\cdots\times x}, \underparen{x\times\cdots\times x}_{n} ,
19
19
  \overbracket{x\times\cdots\times x}, \overbracket{x\times\cdots\times x}^{n}, \underbracket{x\times\cdots\times x}, \underbracket{x\times\cdots\times x}_{n}"#,
20
20
  r#"X \overset{f}{\rightarrow} Y \underset{g}{\rightarrow} Z , \ h \eqdef g \circ f"#,
21
- r#"\overline{x + y} , \underline{x + y}, \widehat{x + y}, \widetilde{x + y} , \overrightarrow{A + B} , \overleftarrow{A + B}"#,
21
+ r#"\overline{x + y} , \underline{x + y}, \widehat{x + y}, \overrightarrow{A + B} , \overleftarrow{A + B}"#,
22
22
  r#"\left. \frac{\pi}{2} \right\} \, \left( x \right) \, \left\{ \frac12 \right."#,
23
23
  r#"\Biggl( \biggl( \Bigl( \bigl( ( ) \bigr) \Bigr) \biggr) \Biggr)"#,
24
24
  r#"\mu \left( \bigcup_i E_i \right) = \sum_i \mu ( E_i )"#,
@@ -60,7 +60,7 @@ fn main() {
60
60
  r#"\mathcal{C} \times \mathcal{Y}\times\mathcal{P}"#,
61
61
  r"a := 2 \land b :\equiv 3 \land f : X\to Y",
62
62
  r"f(x):=\begin{cases}0 &\text{if }x\geq 0\\1 &\text{otherwise}\end{cases}",
63
- r"\oint_C \vec{B}\circ \mathrm{d}\vec{l} = \mu_0 \left( I_{\mathrm{enc}} + \varepsilon_0 \frac{\mathrm{d}}{\mathrm{d}t} \int_S {\vec{E} \circ \hat{n}}\; \mathrm{d}a \right)",
63
+ r"\oint_C \vec{B}\circ \mathrm{d}\vec{\ell} = \mu_0 \left( I_{\mathrm{enc}} + \varepsilon_0 \frac{\mathrm{d}}{\mathrm{d}t} \int_S {\vec{E} \circ \hat{n}}\; \mathrm{d}a \right)",
64
64
  ];
65
65
 
66
66
  let converter = LatexToMathML::new(MathCoreConfig {
@@ -0,0 +1,194 @@
1
+ use mathml_renderer::{
2
+ arena::Arena,
3
+ ast::Node,
4
+ attribute::{MathSpacing, OpAttrs, RowAttr, Style, TextTransform},
5
+ symbol::{self, MathMLOperator, OrdCategory, OrdLike, Rel, RelCategory},
6
+ };
7
+
8
+ #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
9
+ pub enum Class {
10
+ /// `mathord`
11
+ #[default]
12
+ Default = 0,
13
+ /// `mathop`
14
+ Operator,
15
+ /// `mathbin`
16
+ BinaryOp,
17
+ /// `mathrel`
18
+ Relation,
19
+ /// `mathopen`
20
+ Open,
21
+ /// `mathclose`
22
+ Close,
23
+ /// `mathpunct`
24
+ Punctuation,
25
+ /// `mathinner`
26
+ Inner,
27
+ /// A class indicating the end of the current formula.
28
+ End,
29
+ }
30
+
31
+ #[derive(Debug, Clone, Copy)]
32
+ pub enum ParenType {
33
+ Left = 1,
34
+ Right,
35
+ Middle,
36
+ }
37
+
38
+ /// <mi> mathvariant attribute
39
+ #[derive(Debug, Clone, Copy)]
40
+ pub enum MathVariant {
41
+ /// This is enforced by setting `mathvariant="normal"`.
42
+ Normal,
43
+ /// This is enforced by transforming the characters themselves.
44
+ Transform(TextTransform),
45
+ }
46
+
47
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
48
+ pub enum Stretchy {
49
+ /// The operator is always stretchy (e.g. `(`, `)`).
50
+ Always = 1,
51
+ /// The operator is only stretchy as a pre- or postfix operator (e.g. `|`).
52
+ PrePostfix,
53
+ /// The operator is never stretchy (e.g. `/`).
54
+ Never,
55
+ /// The operator is always stretchy but isn't symmetric (e.g. `↑`).
56
+ AlwaysAsymmetric,
57
+ }
58
+
59
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
60
+ pub enum DelimiterSpacing {
61
+ /// Never has any spacing, even when used as an infix operator (e.g. `(`, `)`).
62
+ Zero,
63
+ /// Has relation spacing when used as an infix operator, but not when used as a prefix or
64
+ /// postfix operator (e.g. `|`).
65
+ InfixRelation,
66
+ /// Always has relation spacing, even when used as a prefix or postfix operator (e.g. `↑`).
67
+ Relation,
68
+ /// Always has some spacing, even when used as a prefix or postfix operator (e.g. `/`).
69
+ Other,
70
+ }
71
+
72
+ /// A stretchable operator.
73
+ ///
74
+ /// It can be created from an `OrdLike` or a `Rel` if the operator is stretchable. This struct
75
+ /// carries all the information needed to know how to make the operator stretchy and how to set
76
+ /// spacing around it.
77
+ #[derive(Debug, Clone, PartialEq, Eq, Copy)]
78
+ pub struct StretchableOp {
79
+ op: MathMLOperator,
80
+ pub stretchy: Stretchy,
81
+ pub spacing: DelimiterSpacing,
82
+ }
83
+
84
+ impl StretchableOp {
85
+ #[inline]
86
+ pub const fn as_op(self) -> MathMLOperator {
87
+ self.op
88
+ }
89
+
90
+ /// Creates a `StretchableOp` from an `OrdLike` if it's stretchable. Returns `None` if the
91
+ /// operator isn't stretchable.
92
+ pub const fn from_ord(ord: OrdLike) -> Option<Self> {
93
+ let (stretchy, spacing) = match ord.category() {
94
+ OrdCategory::F | OrdCategory::G => (Stretchy::Always, DelimiterSpacing::Zero),
95
+ OrdCategory::FGandForceDefault => {
96
+ (Stretchy::PrePostfix, DelimiterSpacing::InfixRelation)
97
+ }
98
+ OrdCategory::K => (Stretchy::Never, DelimiterSpacing::Zero),
99
+ OrdCategory::KButUsedToBeB => (Stretchy::Never, DelimiterSpacing::Other),
100
+ OrdCategory::D | OrdCategory::E | OrdCategory::I | OrdCategory::IK => {
101
+ return None;
102
+ }
103
+ };
104
+ Some(StretchableOp {
105
+ op: ord.as_op(),
106
+ stretchy,
107
+ spacing,
108
+ })
109
+ }
110
+
111
+ /// Creates a `StretchableOp` from a `Rel` if it's stretchable. Returns `None` if the operator
112
+ /// isn't stretchable.
113
+ pub const fn from_rel(rel: Rel) -> Option<Self> {
114
+ match rel.category() {
115
+ RelCategory::A => Some(StretchableOp {
116
+ op: rel.as_op(),
117
+ stretchy: Stretchy::AlwaysAsymmetric,
118
+ spacing: DelimiterSpacing::Relation,
119
+ }),
120
+ RelCategory::Default => None,
121
+ }
122
+ }
123
+ }
124
+
125
+ /// Creates a fenced expression where opening and closing delimiters are stretched to fit the height
126
+ /// of the content. If `open` or `close` is `None`, no delimiter will be rendered on that side.
127
+ pub fn fenced<'arena>(
128
+ arena: &'arena Arena,
129
+ mut content: Vec<&'arena Node<'arena>>,
130
+ open: Option<StretchableOp>,
131
+ close: Option<StretchableOp>,
132
+ style: Option<Style>,
133
+ ) -> Node<'arena> {
134
+ fn to_operator(delim: Option<StretchableOp>) -> Node<'static> {
135
+ if let Some(op) = delim {
136
+ let attrs = if matches!(op.stretchy, Stretchy::Never) {
137
+ OpAttrs::STRETCHY_TRUE
138
+ } else {
139
+ OpAttrs::empty()
140
+ };
141
+ let (left, right) = if matches!(
142
+ op.spacing,
143
+ DelimiterSpacing::Relation | DelimiterSpacing::Other
144
+ ) {
145
+ (Some(MathSpacing::Zero), Some(MathSpacing::Zero))
146
+ } else {
147
+ (None, None)
148
+ };
149
+ Node::Operator {
150
+ op: op.as_op(),
151
+ attrs,
152
+ size: None,
153
+ left,
154
+ right,
155
+ }
156
+ } else {
157
+ // An empty `<mo></mo>` produces weird spacing in some browsers.
158
+ // Use U+2063 (INVISIBLE SEPARATOR) to work around this. It's in Category K in MathML Core.
159
+ Node::Operator {
160
+ op: const { symbol::INVISIBLE_SEPARATOR.as_op() },
161
+ attrs: OpAttrs::empty(),
162
+ size: None,
163
+ left: None,
164
+ right: None,
165
+ }
166
+ }
167
+ }
168
+ let open = arena.push(to_operator(open));
169
+ let close = arena.push(to_operator(close));
170
+ content.insert(0, open);
171
+ content.push(close);
172
+ let nodes = arena.push_slice(&content);
173
+ Node::Row {
174
+ nodes,
175
+ attr: style.map(RowAttr::Style),
176
+ }
177
+ }
178
+
179
+ #[cfg(test)]
180
+ mod tests {
181
+ use super::{MathVariant, TextTransform};
182
+
183
+ #[test]
184
+ fn size_test() {
185
+ assert_eq!(
186
+ std::mem::size_of::<MathVariant>(),
187
+ std::mem::size_of::<TextTransform>()
188
+ );
189
+ assert_eq!(
190
+ std::mem::size_of::<Option<MathVariant>>(),
191
+ std::mem::size_of::<TextTransform>()
192
+ );
193
+ }
194
+ }