Spaces:
Sleeping
Sleeping
Upload 47 files
Browse files- Dockerfile +40 -0
- LICENSE.md +202 -0
- README.md +103 -10
- app.py +351 -0
- assets/demo/cases.png +0 -0
- assets/demo/demo.png +0 -0
- assets/example/input_example.json +17 -0
- assets/example/table_example.json +10 -0
- evaluation.py +290 -0
- modules/latex2bbox_color.py +215 -0
- modules/latex_processor.py +536 -0
- modules/latex_render_percentage.py +116 -0
- modules/tokenize_latex/preprocess_formula.js +387 -0
- modules/tokenize_latex/preprocess_tabular.js +395 -0
- modules/tokenize_latex/third_party/README.md +1 -0
- modules/tokenize_latex/third_party/katex/LICENSE.txt +27 -0
- modules/tokenize_latex/third_party/katex/README.md +68 -0
- modules/tokenize_latex/third_party/katex/cli.js +32 -0
- modules/tokenize_latex/third_party/katex/katex.js +74 -0
- modules/tokenize_latex/third_party/katex/package.json +108 -0
- modules/tokenize_latex/third_party/katex/src/Lexer.js +162 -0
- modules/tokenize_latex/third_party/katex/src/Options.js +189 -0
- modules/tokenize_latex/third_party/katex/src/ParseError.js +40 -0
- modules/tokenize_latex/third_party/katex/src/Parser.js +798 -0
- modules/tokenize_latex/third_party/katex/src/Settings.js +28 -0
- modules/tokenize_latex/third_party/katex/src/Style.js +126 -0
- modules/tokenize_latex/third_party/katex/src/buildCommon.js +450 -0
- modules/tokenize_latex/third_party/katex/src/buildHTML.js +1402 -0
- modules/tokenize_latex/third_party/katex/src/buildMathML.js +533 -0
- modules/tokenize_latex/third_party/katex/src/buildTree.js +40 -0
- modules/tokenize_latex/third_party/katex/src/delimiter.js +542 -0
- modules/tokenize_latex/third_party/katex/src/domTree.js +269 -0
- modules/tokenize_latex/third_party/katex/src/environments.js +295 -0
- modules/tokenize_latex/third_party/katex/src/fontMetrics.js +147 -0
- modules/tokenize_latex/third_party/katex/src/fontMetricsData.js +1752 -0
- modules/tokenize_latex/third_party/katex/src/functions.js +585 -0
- modules/tokenize_latex/third_party/katex/src/mathMLTree.js +102 -0
- modules/tokenize_latex/third_party/katex/src/parseData.js +13 -0
- modules/tokenize_latex/third_party/katex/src/parseTree.js +17 -0
- modules/tokenize_latex/third_party/katex/src/symbols.js +687 -0
- modules/tokenize_latex/third_party/katex/src/utils.js +106 -0
- modules/tokenize_latex/third_party/match-at/README.md +1 -0
- modules/tokenize_latex/third_party/match-at/lib/matchAt.js +42 -0
- modules/tokenize_latex/third_party/match-at/package.json +54 -0
- modules/tokenize_latex/tokenize_latex.py +98 -0
- modules/visual_matcher.py +191 -0
- requriements.txt +5 -0
Dockerfile
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.8
|
2 |
+
|
3 |
+
WORKDIR /code
|
4 |
+
|
5 |
+
RUN wget https://registry.npmmirror.com/-/binary/node/latest-v16.x/node-v16.13.1-linux-x64.tar.gz \
|
6 |
+
&& tar -xvf node-v16.13.1-linux-x64.tar.gz \
|
7 |
+
&& mv node-v16.13.1-linux-x64 /usr/local/nodejs \
|
8 |
+
&& ln -s /usr/local/nodejs/bin/node /usr/local/bin \
|
9 |
+
&& ln -s /usr/local/nodejs/bin/npm /usr/local/bin \
|
10 |
+
&& node -v
|
11 |
+
|
12 |
+
RUN apt-get update \
|
13 |
+
&& apt-get install -y texlive-full \
|
14 |
+
&& pdflatex -v
|
15 |
+
|
16 |
+
RUN git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.1 \
|
17 |
+
&& cd ImageMagick-7.1.1 \
|
18 |
+
&& ./configure \
|
19 |
+
&& make \
|
20 |
+
&& make install \
|
21 |
+
&& ldconfig /usr/local/lib \
|
22 |
+
&& convert --version
|
23 |
+
|
24 |
+
COPY ./requriements.txt /code/requriements.txt
|
25 |
+
|
26 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requriements.txt
|
27 |
+
|
28 |
+
|
29 |
+
RUN useradd -m -u 1000 user
|
30 |
+
|
31 |
+
USER user
|
32 |
+
|
33 |
+
ENV HOME=/home/user \
|
34 |
+
PATH=/home/user/.local/bin:$PATH
|
35 |
+
|
36 |
+
WORKDIR $HOME/app
|
37 |
+
|
38 |
+
COPY --chown=user . $HOME/app
|
39 |
+
|
40 |
+
CMD ["python", "app.py"]
|
LICENSE.md
ADDED
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
Apache License
|
3 |
+
Version 2.0, January 2004
|
4 |
+
http://www.apache.org/licenses/
|
5 |
+
|
6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
7 |
+
|
8 |
+
1. Definitions.
|
9 |
+
|
10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
12 |
+
|
13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
14 |
+
the copyright owner that is granting the License.
|
15 |
+
|
16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
17 |
+
other entities that control, are controlled by, or are under common
|
18 |
+
control with that entity. For the purposes of this definition,
|
19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
20 |
+
direction or management of such entity, whether by contract or
|
21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
23 |
+
|
24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
25 |
+
exercising permissions granted by this License.
|
26 |
+
|
27 |
+
"Source" form shall mean the preferred form for making modifications,
|
28 |
+
including but not limited to software source code, documentation
|
29 |
+
source, and configuration files.
|
30 |
+
|
31 |
+
"Object" form shall mean any form resulting from mechanical
|
32 |
+
transformation or translation of a Source form, including but
|
33 |
+
not limited to compiled object code, generated documentation,
|
34 |
+
and conversions to other media types.
|
35 |
+
|
36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
37 |
+
Object form, made available under the License, as indicated by a
|
38 |
+
copyright notice that is included in or attached to the work
|
39 |
+
(an example is provided in the Appendix below).
|
40 |
+
|
41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
42 |
+
form, that is based on (or derived from) the Work and for which the
|
43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
45 |
+
of this License, Derivative Works shall not include works that remain
|
46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
47 |
+
the Work and Derivative Works thereof.
|
48 |
+
|
49 |
+
"Contribution" shall mean any work of authorship, including
|
50 |
+
the original version of the Work and any modifications or additions
|
51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
55 |
+
means any form of electronic, verbal, or written communication sent
|
56 |
+
to the Licensor or its representatives, including but not limited to
|
57 |
+
communication on electronic mailing lists, source code control systems,
|
58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
60 |
+
excluding communication that is conspicuously marked or otherwise
|
61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
62 |
+
|
63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
65 |
+
subsequently incorporated within the Work.
|
66 |
+
|
67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
72 |
+
Work and such Derivative Works in Source or Object form.
|
73 |
+
|
74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
77 |
+
(except as stated in this section) patent license to make, have made,
|
78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
79 |
+
where such license applies only to those patent claims licensable
|
80 |
+
by such Contributor that are necessarily infringed by their
|
81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
83 |
+
institute patent litigation against any entity (including a
|
84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
85 |
+
or a Contribution incorporated within the Work constitutes direct
|
86 |
+
or contributory patent infringement, then any patent licenses
|
87 |
+
granted to You under this License for that Work shall terminate
|
88 |
+
as of the date such litigation is filed.
|
89 |
+
|
90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
91 |
+
Work or Derivative Works thereof in any medium, with or without
|
92 |
+
modifications, and in Source or Object form, provided that You
|
93 |
+
meet the following conditions:
|
94 |
+
|
95 |
+
(a) You must give any other recipients of the Work or
|
96 |
+
Derivative Works a copy of this License; and
|
97 |
+
|
98 |
+
(b) You must cause any modified files to carry prominent notices
|
99 |
+
stating that You changed the files; and
|
100 |
+
|
101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
102 |
+
that You distribute, all copyright, patent, trademark, and
|
103 |
+
attribution notices from the Source form of the Work,
|
104 |
+
excluding those notices that do not pertain to any part of
|
105 |
+
the Derivative Works; and
|
106 |
+
|
107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
108 |
+
distribution, then any Derivative Works that You distribute must
|
109 |
+
include a readable copy of the attribution notices contained
|
110 |
+
within such NOTICE file, excluding those notices that do not
|
111 |
+
pertain to any part of the Derivative Works, in at least one
|
112 |
+
of the following places: within a NOTICE text file distributed
|
113 |
+
as part of the Derivative Works; within the Source form or
|
114 |
+
documentation, if provided along with the Derivative Works; or,
|
115 |
+
within a display generated by the Derivative Works, if and
|
116 |
+
wherever such third-party notices normally appear. The contents
|
117 |
+
of the NOTICE file are for informational purposes only and
|
118 |
+
do not modify the License. You may add Your own attribution
|
119 |
+
notices within Derivative Works that You distribute, alongside
|
120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
121 |
+
that such additional attribution notices cannot be construed
|
122 |
+
as modifying the License.
|
123 |
+
|
124 |
+
You may add Your own copyright statement to Your modifications and
|
125 |
+
may provide additional or different license terms and conditions
|
126 |
+
for use, reproduction, or distribution of Your modifications, or
|
127 |
+
for any such Derivative Works as a whole, provided Your use,
|
128 |
+
reproduction, and distribution of the Work otherwise complies with
|
129 |
+
the conditions stated in this License.
|
130 |
+
|
131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
133 |
+
by You to the Licensor shall be under the terms and conditions of
|
134 |
+
this License, without any additional terms or conditions.
|
135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
136 |
+
the terms of any separate license agreement you may have executed
|
137 |
+
with Licensor regarding such Contributions.
|
138 |
+
|
139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
141 |
+
except as required for reasonable and customary use in describing the
|
142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
143 |
+
|
144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
145 |
+
agreed to in writing, Licensor provides the Work (and each
|
146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
148 |
+
implied, including, without limitation, any warranties or conditions
|
149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
151 |
+
appropriateness of using or redistributing the Work and assume any
|
152 |
+
risks associated with Your exercise of permissions under this License.
|
153 |
+
|
154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
155 |
+
whether in tort (including negligence), contract, or otherwise,
|
156 |
+
unless required by applicable law (such as deliberate and grossly
|
157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
158 |
+
liable to You for damages, including any direct, indirect, special,
|
159 |
+
incidental, or consequential damages of any character arising as a
|
160 |
+
result of this License or out of the use or inability to use the
|
161 |
+
Work (including but not limited to damages for loss of goodwill,
|
162 |
+
work stoppage, computer failure or malfunction, or any and all
|
163 |
+
other commercial damages or losses), even if such Contributor
|
164 |
+
has been advised of the possibility of such damages.
|
165 |
+
|
166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
169 |
+
or other liability obligations and/or rights consistent with this
|
170 |
+
License. However, in accepting such obligations, You may act only
|
171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
172 |
+
of any other Contributor, and only if You agree to indemnify,
|
173 |
+
defend, and hold each Contributor harmless for any liability
|
174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
175 |
+
of your accepting any such warranty or additional liability.
|
176 |
+
|
177 |
+
END OF TERMS AND CONDITIONS
|
178 |
+
|
179 |
+
APPENDIX: How to apply the Apache License to your work.
|
180 |
+
|
181 |
+
To apply the Apache License to your work, attach the following
|
182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
183 |
+
replaced with your own identifying information. (Don't include
|
184 |
+
the brackets!) The text should be enclosed in the appropriate
|
185 |
+
comment syntax for the file format. We also recommend that a
|
186 |
+
file or class name and description of purpose be included on the
|
187 |
+
same "printed page" as the copyright notice for easier
|
188 |
+
identification within third-party archives.
|
189 |
+
|
190 |
+
Copyright [yyyy] [name of copyright owner]
|
191 |
+
|
192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
193 |
+
you may not use this file except in compliance with the License.
|
194 |
+
You may obtain a copy of the License at
|
195 |
+
|
196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
197 |
+
|
198 |
+
Unless required by applicable law or agreed to in writing, software
|
199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
201 |
+
See the License for the specific language governing permissions and
|
202 |
+
limitations under the License.
|
README.md
CHANGED
@@ -1,10 +1,103 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Character Detection Matching (CDM)
|
2 |
+
|
3 |
+
## Demo
|
4 |
+
|
5 |
+
CDM: A Reliable Metric for Fair and Accurate Formula Recognition
|
6 |
+
|
7 |
+
![demo](assets/demo/demo.png)
|
8 |
+
|
9 |
+
Compair with BLEU and ExpRate:
|
10 |
+
|
11 |
+
![demo](assets/demo/cases.png)
|
12 |
+
|
13 |
+
## Installation Guide
|
14 |
+
|
15 |
+
Nodejs, imagemagic, pdflatex are requried packages when render pdf files and convert them to images, here are installation guides.
|
16 |
+
|
17 |
+
### install nodejs
|
18 |
+
|
19 |
+
download the package from [offical website](https://registry.npmmirror.com/binary.html?path=node/latest-v16.x/), and then run these commands.
|
20 |
+
```
|
21 |
+
tar -xvf node-v16.13.1-linux-x64.tar.gz
|
22 |
+
|
23 |
+
mv node-v16.13.1-linux-x64/* /usr/local/nodejs/
|
24 |
+
|
25 |
+
ln -s /usr/local/nodejs/bin/node /usr/local/bin
|
26 |
+
|
27 |
+
ln -s /usr/local/nodejs/bin/npm /usr/local/bin
|
28 |
+
|
29 |
+
node -v
|
30 |
+
```
|
31 |
+
|
32 |
+
### install imagemagic
|
33 |
+
|
34 |
+
the version of imagemagic installed by `apt-gt` usually be 6.x, so we also install it from source code.
|
35 |
+
```
|
36 |
+
git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.1
|
37 |
+
|
38 |
+
cd ImageMagick-7.1.1
|
39 |
+
|
40 |
+
./configure
|
41 |
+
|
42 |
+
make
|
43 |
+
|
44 |
+
sudo make install
|
45 |
+
|
46 |
+
sudo ldconfig /usr/local/lib
|
47 |
+
|
48 |
+
convert --version
|
49 |
+
```
|
50 |
+
|
51 |
+
### install latexpdf
|
52 |
+
|
53 |
+
```
|
54 |
+
apt-get update
|
55 |
+
|
56 |
+
sudo apt-get install texlive-full
|
57 |
+
```
|
58 |
+
|
59 |
+
### install python requriements
|
60 |
+
|
61 |
+
```
|
62 |
+
conda create -n CDM python=3.10 # optional
|
63 |
+
|
64 |
+
git clone xxx
|
65 |
+
|
66 |
+
cd xxx
|
67 |
+
|
68 |
+
pip install -r requirements.txt
|
69 |
+
```
|
70 |
+
|
71 |
+
|
72 |
+
## Usage
|
73 |
+
|
74 |
+
Should the installation go well, you may now enjoy the evaluation pipeline.
|
75 |
+
|
76 |
+
### 1. batch evaluation
|
77 |
+
|
78 |
+
```
|
79 |
+
python evaluation.py -i {path_to_your_input_json}
|
80 |
+
```
|
81 |
+
|
82 |
+
the format of input json like this:
|
83 |
+
```
|
84 |
+
[
|
85 |
+
{
|
86 |
+
"img_id": "case_1", # optional key
|
87 |
+
"gt": "y = 2z + 3x",
|
88 |
+
"pred": "y = 2x + 3z"
|
89 |
+
},
|
90 |
+
{
|
91 |
+
"img_id": "case_2",
|
92 |
+
"gt": "y = x^2 + 1",
|
93 |
+
"pred": "y = x^2 + 1"
|
94 |
+
},
|
95 |
+
...
|
96 |
+
]
|
97 |
+
```
|
98 |
+
|
99 |
+
### 2. run a gradio demo
|
100 |
+
|
101 |
+
```
|
102 |
+
python app.py
|
103 |
+
```
|
app.py
ADDED
@@ -0,0 +1,351 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import os
|
3 |
+
import re
|
4 |
+
import json
|
5 |
+
import time
|
6 |
+
import shutil
|
7 |
+
import numpy as np
|
8 |
+
import gradio as gr
|
9 |
+
from datetime import datetime
|
10 |
+
from multiprocessing import Pool
|
11 |
+
from multiprocessing.dummy import Pool as ThreadPool
|
12 |
+
from PIL import Image, ImageDraw
|
13 |
+
from skimage.measure import ransac
|
14 |
+
import matplotlib.pyplot as plt
|
15 |
+
|
16 |
+
from modules.latex2bbox_color import latex2bbox_color
|
17 |
+
from modules.tokenize_latex.tokenize_latex import tokenize_latex
|
18 |
+
from modules.visual_matcher import HungarianMatcher, SimpleAffineTransform
|
19 |
+
|
20 |
+
|
21 |
+
DATA_ROOT = "output"
|
22 |
+
|
23 |
+
def gen_color_list(num=10, gap=15):
|
24 |
+
num += 1
|
25 |
+
single_num = 255 // gap + 1
|
26 |
+
max_num = single_num ** 3
|
27 |
+
num = min(num, max_num)
|
28 |
+
color_list = []
|
29 |
+
for idx in range(num):
|
30 |
+
R = idx // single_num**2
|
31 |
+
GB = idx % single_num**2
|
32 |
+
G = GB // single_num
|
33 |
+
B = GB % single_num
|
34 |
+
|
35 |
+
color_list.append((R*gap, G*gap, B*gap))
|
36 |
+
return color_list[1:]
|
37 |
+
|
38 |
+
def process_latex(groundtruths, predictions, user_id="test"):
|
39 |
+
data_root = DATA_ROOT
|
40 |
+
temp_dir = os.path.join(data_root, "temp_dir")
|
41 |
+
|
42 |
+
data_root = os.path.join(data_root, user_id)
|
43 |
+
output_dir_info = {}
|
44 |
+
input_args = []
|
45 |
+
for subset, latex_list in zip(['gt', 'pred'], [groundtruths, predictions]):
|
46 |
+
sub_temp_dir = os.path.join(temp_dir, f"{user_id}_{subset}")
|
47 |
+
os.makedirs(sub_temp_dir, exist_ok=True)
|
48 |
+
|
49 |
+
output_path = os.path.join(data_root, subset)
|
50 |
+
output_dir_info[output_path] = []
|
51 |
+
|
52 |
+
os.makedirs(os.path.join(output_path, 'bbox'), exist_ok=True)
|
53 |
+
os.makedirs(os.path.join(output_path, 'vis'), exist_ok=True)
|
54 |
+
|
55 |
+
total_color_list = gen_color_list(num=5800)
|
56 |
+
|
57 |
+
for idx, latex in enumerate(latex_list):
|
58 |
+
basename = f"sample_{idx}"
|
59 |
+
input_arg = latex, basename, output_path, sub_temp_dir, total_color_list
|
60 |
+
a = time.time()
|
61 |
+
latex2bbox_color(input_arg)
|
62 |
+
b = time.time()
|
63 |
+
|
64 |
+
for subset in ['gt', 'pred']:
|
65 |
+
shutil.rmtree(os.path.join(temp_dir, f"{user_id}_{subset}"))
|
66 |
+
|
67 |
+
|
68 |
+
def update_inliers(ori_inliers, sub_inliers):
|
69 |
+
inliers = np.copy(ori_inliers)
|
70 |
+
sub_idx = -1
|
71 |
+
for idx in range(len(ori_inliers)):
|
72 |
+
if ori_inliers[idx] == False:
|
73 |
+
sub_idx += 1
|
74 |
+
if sub_inliers[sub_idx] == True:
|
75 |
+
inliers[idx] = True
|
76 |
+
return inliers
|
77 |
+
|
78 |
+
def reshape_inliers(ori_inliers, sub_inliers):
|
79 |
+
inliers = np.copy(ori_inliers)
|
80 |
+
sub_idx = -1
|
81 |
+
for idx in range(len(ori_inliers)):
|
82 |
+
if ori_inliers[idx] == False:
|
83 |
+
sub_idx += 1
|
84 |
+
if sub_inliers[sub_idx] == True:
|
85 |
+
inliers[idx] = True
|
86 |
+
else:
|
87 |
+
inliers[idx] = False
|
88 |
+
return inliers
|
89 |
+
|
90 |
+
|
91 |
+
def evaluation(user_id="test"):
|
92 |
+
data_root = DATA_ROOT
|
93 |
+
data_root = os.path.join(data_root, user_id)
|
94 |
+
gt_box_dir = os.path.join(data_root, "gt")
|
95 |
+
pred_box_dir = os.path.join(data_root, "pred")
|
96 |
+
match_vis_dir = os.path.join(data_root, "vis_match")
|
97 |
+
os.makedirs(match_vis_dir, exist_ok=True)
|
98 |
+
|
99 |
+
max_iter = 3
|
100 |
+
min_samples = 3
|
101 |
+
residual_threshold = 25
|
102 |
+
max_trials = 50
|
103 |
+
|
104 |
+
metrics_per_img = {}
|
105 |
+
gt_basename_list = [item.split(".")[0] for item in os.listdir(os.path.join(gt_box_dir, 'bbox'))]
|
106 |
+
for basename in gt_basename_list:
|
107 |
+
gt_valid, pred_valid = True, True
|
108 |
+
if not os.path.exists(os.path.join(gt_box_dir, 'bbox', basename+".jsonl")):
|
109 |
+
gt_valid = False
|
110 |
+
else:
|
111 |
+
with open(os.path.join(gt_box_dir, 'bbox', basename+".jsonl"), 'r') as f:
|
112 |
+
box_gt = []
|
113 |
+
for line in f:
|
114 |
+
info = json.loads(line)
|
115 |
+
if info['bbox']:
|
116 |
+
box_gt.append(info)
|
117 |
+
if not box_gt:
|
118 |
+
gt_valid = False
|
119 |
+
if not gt_valid:
|
120 |
+
continue
|
121 |
+
|
122 |
+
if not os.path.exists(os.path.join(pred_box_dir, 'bbox', basename+".jsonl")):
|
123 |
+
pred_valid = False
|
124 |
+
else:
|
125 |
+
with open(os.path.join(pred_box_dir, 'bbox', basename+".jsonl"), 'r') as f:
|
126 |
+
box_pred = []
|
127 |
+
for line in f:
|
128 |
+
info = json.loads(line)
|
129 |
+
if info['bbox']:
|
130 |
+
box_pred.append(info)
|
131 |
+
if not box_pred:
|
132 |
+
pred_valid = False
|
133 |
+
if not pred_valid:
|
134 |
+
metrics_per_img[basename] = {
|
135 |
+
"recall": 0,
|
136 |
+
"precision": 0,
|
137 |
+
"F1_score": 0,
|
138 |
+
}
|
139 |
+
continue
|
140 |
+
gt_img_path = os.path.join(gt_box_dir, 'vis', basename+"_base.png")
|
141 |
+
pred_img_path = os.path.join(pred_box_dir, 'vis', basename+"_base.png")
|
142 |
+
|
143 |
+
img_gt = Image.open(gt_img_path)
|
144 |
+
img_pred = Image.open(pred_img_path)
|
145 |
+
|
146 |
+
matcher = HungarianMatcher()
|
147 |
+
matched_idxes = matcher(box_gt, box_pred, img_gt.size, img_pred.size)
|
148 |
+
src = []
|
149 |
+
dst = []
|
150 |
+
for (idx1, idx2) in matched_idxes:
|
151 |
+
x1min, y1min, x1max, y1max = box_gt[idx1]['bbox']
|
152 |
+
x2min, y2min, x2max, y2max = box_pred[idx2]['bbox']
|
153 |
+
x1_c, y1_c = float((x1min+x1max)/2), float((y1min+y1max)/2)
|
154 |
+
x2_c, y2_c = float((x2min+x2max)/2), float((y2min+y2max)/2)
|
155 |
+
src.append([y1_c, x1_c])
|
156 |
+
dst.append([y2_c, x2_c])
|
157 |
+
|
158 |
+
src = np.array(src)
|
159 |
+
dst = np.array(dst)
|
160 |
+
if src.shape[0] <= min_samples:
|
161 |
+
inliers = np.array([True for _ in matched_idxes])
|
162 |
+
else:
|
163 |
+
inliers = np.array([False for _ in matched_idxes])
|
164 |
+
for i in range(max_iter):
|
165 |
+
if src[inliers==False].shape[0] <= min_samples:
|
166 |
+
break
|
167 |
+
model, inliers_1 = ransac((src[inliers==False], dst[inliers==False]), SimpleAffineTransform, min_samples=min_samples, residual_threshold=residual_threshold, max_trials=max_trials)
|
168 |
+
if inliers_1 is not None and inliers_1.any():
|
169 |
+
inliers = update_inliers(inliers, inliers_1)
|
170 |
+
else:
|
171 |
+
break
|
172 |
+
if len(inliers[inliers==True]) >= len(matched_idxes):
|
173 |
+
break
|
174 |
+
|
175 |
+
for idx, (a,b) in enumerate(matched_idxes):
|
176 |
+
if inliers[idx] == True and matcher.cost['token'][a, b] == 1:
|
177 |
+
inliers[idx] = False
|
178 |
+
|
179 |
+
final_match_num = len(inliers[inliers==True])
|
180 |
+
recall = round(final_match_num/(len(box_gt)), 3)
|
181 |
+
precision = round(final_match_num/(len(box_pred)), 3)
|
182 |
+
F1_score = round(2*final_match_num/(len(box_gt)+len(box_pred)), 3)
|
183 |
+
metrics_per_img[basename] = {
|
184 |
+
"recall": recall,
|
185 |
+
"precision": precision,
|
186 |
+
"F1_score": F1_score,
|
187 |
+
}
|
188 |
+
|
189 |
+
if True:
|
190 |
+
gap = 5
|
191 |
+
W1, H1 = img_gt.size
|
192 |
+
W2, H2 = img_pred.size
|
193 |
+
H = H1 + H2 + gap
|
194 |
+
W = max(W1, W2)
|
195 |
+
|
196 |
+
vis_img = Image.new('RGB', (W, H), (255, 255, 255))
|
197 |
+
vis_img.paste(img_gt, (0, 0))
|
198 |
+
vis_img.paste(Image.new('RGB', (W, gap), (0, 150, 200)), (0, H1))
|
199 |
+
vis_img.paste(img_pred, (0, H1+gap))
|
200 |
+
|
201 |
+
match_img = vis_img.copy()
|
202 |
+
match_draw = ImageDraw.Draw(match_img)
|
203 |
+
|
204 |
+
gt_matched_idx = {
|
205 |
+
a: flag
|
206 |
+
for (a,b), flag in
|
207 |
+
zip(matched_idxes, inliers)
|
208 |
+
}
|
209 |
+
pred_matched_idx = {
|
210 |
+
b: flag
|
211 |
+
for (a,b), flag in
|
212 |
+
zip(matched_idxes, inliers)
|
213 |
+
}
|
214 |
+
|
215 |
+
for idx, box in enumerate(box_gt):
|
216 |
+
if idx in gt_matched_idx and gt_matched_idx[idx]==True:
|
217 |
+
color = "green"
|
218 |
+
else:
|
219 |
+
color = "red"
|
220 |
+
x_min, y_min, x_max, y_max = box['bbox']
|
221 |
+
match_draw.rectangle([x_min-1, y_min-1, x_max+1, y_max+1], fill=None, outline=color, width=2)
|
222 |
+
|
223 |
+
for idx, box in enumerate(box_pred):
|
224 |
+
if idx in pred_matched_idx and pred_matched_idx[idx]==True:
|
225 |
+
color = "green"
|
226 |
+
else:
|
227 |
+
color = "red"
|
228 |
+
x_min, y_min, x_max, y_max = box['bbox']
|
229 |
+
match_draw.rectangle([x_min-1, y_min-1+H1+gap, x_max+1, y_max+1+H1+gap], fill=None, outline=color, width=2)
|
230 |
+
|
231 |
+
vis_img.save(os.path.join(match_vis_dir, basename+"_base.png"))
|
232 |
+
if W < 500:
|
233 |
+
padding = (500 - W)//2 + 1
|
234 |
+
reshape_match_img = Image.new('RGB', (500, H), (255, 255, 255))
|
235 |
+
reshape_match_img.paste(match_img, (padding, 0))
|
236 |
+
reshape_match_img.paste(Image.new('RGB', (500, gap), (0, 150, 200)), (0, H1))
|
237 |
+
reshape_match_img.save(os.path.join(match_vis_dir, basename+".png"))
|
238 |
+
else:
|
239 |
+
match_img.save(os.path.join(match_vis_dir, basename+".png"))
|
240 |
+
|
241 |
+
acc_list = [val['F1_score'] for _, val in metrics_per_img.items()]
|
242 |
+
metrics_res = {
|
243 |
+
"mean_score": round(np.mean(acc_list), 3),
|
244 |
+
"details": metrics_per_img
|
245 |
+
}
|
246 |
+
metric_res_path = os.path.join(data_root, "metrics_res.json")
|
247 |
+
with open(metric_res_path, "w") as f:
|
248 |
+
f.write(json.dumps(metrics_res, indent=2))
|
249 |
+
return metrics_res, metric_res_path, match_vis_dir
|
250 |
+
|
251 |
+
def calculate_metric_single(groundtruth, prediction):
|
252 |
+
user_id = datetime.now().strftime('%Y%m%d-%H%M%S')
|
253 |
+
process_latex([groundtruth], [prediction], user_id)
|
254 |
+
metrics_res, metric_res_path, match_vis_dir = evaluation(user_id)
|
255 |
+
basename = "sample_0"
|
256 |
+
image_path = os.path.join(match_vis_dir, basename+".png")
|
257 |
+
sample = metrics_res["details"][basename]
|
258 |
+
score = sample['F1_score']
|
259 |
+
recall = sample['recall']
|
260 |
+
precision = sample['precision']
|
261 |
+
return score, recall, precision, gr.Image(image_path)
|
262 |
+
|
263 |
+
def calculate_metric_batch(json_input):
|
264 |
+
user_id = datetime.now().strftime('%Y%m%d-%H%M%S')
|
265 |
+
with open(json_input.name, "r") as f:
|
266 |
+
input_data = json.load(f)
|
267 |
+
groundtruths = []
|
268 |
+
predictions = []
|
269 |
+
for item in input_data:
|
270 |
+
groundtruths.append(item['gt'])
|
271 |
+
predictions.append(item['pred'])
|
272 |
+
process_latex(groundtruths, predictions, user_id)
|
273 |
+
metrics_res, metric_res_path, match_vis_dir = evaluation(user_id)
|
274 |
+
return metric_res_path
|
275 |
+
|
276 |
+
def gradio_reset_single():
|
277 |
+
return gr.update(value=None, placeholder='type gt latex code here'), gr.update(value=None, placeholder='type pred latex code here'), \
|
278 |
+
gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None)
|
279 |
+
|
280 |
+
def gradio_reset_batch():
|
281 |
+
return gr.update(value=None), gr.update(value=None)
|
282 |
+
|
283 |
+
def select_example1():
|
284 |
+
gt = "y = 2x + 3z"
|
285 |
+
pred = "y = 2z + 3x"
|
286 |
+
return gr.update(value=gt, placeholder='type gt latex code here'), gr.update(value=pred, placeholder='type pred latex code here')
|
287 |
+
|
288 |
+
def select_example2():
|
289 |
+
gt = "r = \\frac { \\alpha } { \\beta } \\vert \\sin \\beta \\left( \\sigma _ { 1 } \\pm \\sigma _ { 2 } \\right) \\vert"
|
290 |
+
pred = "r={\\frac{\\alpha}{\\beta}}|\\sin\\beta\\left(\\sigma_{2}+\\sigma_{1}\\right)|"
|
291 |
+
return gr.update(value=gt, placeholder='type gt latex code here'), gr.update(value=pred, placeholder='type pred latex code here')
|
292 |
+
|
293 |
+
def select_example3():
|
294 |
+
gt = "\\begin{array} { r l r } & { } & { \\mathbf { J } _ { L } = \\left( \\begin{array} { c c } { 0 } & { 0 } \\\\ { v _ { n } } & { 0 } \\end{array} \\right) , ~ \\mathbf { J } _ { R } = \\left( \\begin{array} { c c } { u _ { n - 1 } } & { 0 } \\\\ { 0 } & { 0 } \\end{array} \\right) , ~ } \\\\ & { } & {\\mathbf { K } = \\left( \\begin{array} { c c } { V _ { n - 1 } } & { u _ { n } } \\\\ { v _ { n - 1 } } & { V _ { n } } \\end{array} \\right) , } \\end{array}"
|
295 |
+
pred = "\\mathbf{J}_{U}={\\left(\\begin{array}{l l}{0}&{0}\\\\ {v_{n}}&{0}\\end{array}\\right)}\\,,\\ \\mathbf{J}_{R}={\\left(\\begin{array}{l l}{u_{n-1}}&{0}\\\\ {0}&{0}\\end{array}\\right)}\\,,\\mathbf{K}={\\left(\\begin{array}{l l}{V_{n-1}}&{u_{n}}\\\\ {v_{n-1}}&{V_{n}}\\end{array}\\right)}\\,,"
|
296 |
+
return gr.update(value=gt, placeholder='type gt latex code here'), gr.update(value=pred, placeholder='type pred latex code here')
|
297 |
+
|
298 |
+
|
299 |
+
|
300 |
+
if __name__ == "__main__":
|
301 |
+
title = """<h1 align="center">CDM: A Reliable Metric for Fair and Accurate Formula Recognition Evaluation</h1>"""
|
302 |
+
|
303 |
+
with gr.Blocks() as demo:
|
304 |
+
gr.Markdown(title)
|
305 |
+
|
306 |
+
# gr.Button(value="Quick Try: type latex code of gt and pred, get metrics and visualization.", interactive=False, variant="primary")
|
307 |
+
|
308 |
+
with gr.Row():
|
309 |
+
with gr.Column():
|
310 |
+
gt_input = gr.Textbox(label='gt', placeholder='type gt latex code here', interactive=True)
|
311 |
+
pred_input = gr.Textbox(label='pred', placeholder='type pred latex code here', interactive=True)
|
312 |
+
with gr.Row():
|
313 |
+
clear_single = gr.Button("Clear")
|
314 |
+
submit_single = gr.Button(value="Submit", interactive=True, variant="primary")
|
315 |
+
with gr.Accordion("Examples:"):
|
316 |
+
with gr.Row():
|
317 |
+
example1 = gr.Button("Example A(short)")
|
318 |
+
example2 = gr.Button("Example B(middle)")
|
319 |
+
example3 = gr.Button("Example C(long)")
|
320 |
+
with gr.Column():
|
321 |
+
with gr.Row():
|
322 |
+
score_output = gr.Number(label="F1 Score", interactive=False)
|
323 |
+
recall_output = gr.Number(label="Recall", interactive=False)
|
324 |
+
recision_output = gr.Number(label="Precision", interactive=False)
|
325 |
+
gr.Button(value="Visualization (green bbox means correcttlly matched, red bbox means missed or wrong.)", interactive=False)
|
326 |
+
vis_output = gr.Image(label=" ", interactive=False)
|
327 |
+
|
328 |
+
example1.click(select_example1, inputs=None, outputs=[gt_input, pred_input])
|
329 |
+
example2.click(select_example2, inputs=None, outputs=[gt_input, pred_input])
|
330 |
+
example3.click(select_example3, inputs=None, outputs=[gt_input, pred_input])
|
331 |
+
|
332 |
+
clear_single.click(gradio_reset_single, inputs=None, outputs=[gt_input, pred_input, score_output, recall_output, recision_output, vis_output])
|
333 |
+
submit_single.click(calculate_metric_single, inputs=[gt_input, pred_input], outputs=[score_output, recall_output, recision_output, vis_output])
|
334 |
+
|
335 |
+
|
336 |
+
# gr.Button(value="Batch Run: upload a json file and batch processing, this may take some times according to your latex amount and length.", interactive=False, variant="primary")
|
337 |
+
|
338 |
+
# with gr.Row():
|
339 |
+
# with gr.Column():
|
340 |
+
# json_input = gr.File(label="Input Json", file_types=[".json"])
|
341 |
+
# json_example = gr.File(label="Input Example", value="assets/example/input_example.json")
|
342 |
+
# with gr.Row():
|
343 |
+
# clear_batch = gr.Button("Clear")
|
344 |
+
# submit_batch = gr.Button(value="Submit", interactive=True, variant="primary")
|
345 |
+
|
346 |
+
# metric_output = gr.File(label="Output Metrics")
|
347 |
+
|
348 |
+
# clear_batch.click(gradio_reset_batch, inputs=None, outputs=[json_input, metric_output])
|
349 |
+
# submit_batch.click(calculate_metric_batch, inputs=[json_input], outputs=[metric_output])
|
350 |
+
|
351 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, debug=True)
|
assets/demo/cases.png
ADDED
assets/demo/demo.png
ADDED
assets/example/input_example.json
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"img_id": "case_1",
|
4 |
+
"gt": "r = \\frac { \\alpha } { \\beta } \\vert \\sin \\beta \\left( \\sigma _ { 1 } \\pm \\sigma _ { 2 } \\right) \\vert",
|
5 |
+
"pred": "r={\\frac{\\alpha}{\\beta}}|\\sin\\beta\\left(\\sigma_{2}+\\sigma_{1}\\right)|"
|
6 |
+
},
|
7 |
+
{
|
8 |
+
"img_id": "case_2",
|
9 |
+
"gt": "y = 2z + 3x",
|
10 |
+
"pred": "y = 2x + 3z"
|
11 |
+
},
|
12 |
+
{
|
13 |
+
"img_id": "case_3",
|
14 |
+
"gt": "\\begin{array} { r l r } & { } & { \\mathbf { J } _ { L } = \\left( \\begin{array} { c c } { 0 } & { 0 } \\\\ { v _ { n } } & { 0 } \\end{array} \\right) , ~ \\mathbf { J } _ { R } = \\left( \\begin{array} { c c } { u _ { n - 1 } } & { 0 } \\\\ { 0 } & { 0 } \\end{array} \\right) , ~ } \\\\ & { } & { ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ \\mathbf { K } = \\left( \\begin{array} { c c } { V _ { n - 1 } } & { u _ { n } } \\\\ { v _ { n - 1 } } & { V _ { n } } \\end{array} \\right) , } \\end{array}",
|
15 |
+
"pred": "\\mathbf{J}_{R}={\\left(\\begin{array}{l l}{0}&{0}\\\\ {v_{n}}&{0}\\end{array}\\right)}\\,,\\ \\mathbf{J}_{L}={\\left(\\begin{array}{l l}{u_{n-1}}&{0}\\\\ {0}&{0}\\end{array}\\right)}\\,,\\mathbf{K}={\\left(\\begin{array}{l l}{V_{n-1}}&{u_{n}}\\\\ {v_{n-1}}&{V_{n}}\\end{array}\\right)}\\,,"
|
16 |
+
}
|
17 |
+
]
|
assets/example/table_example.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"pred": "\\begin{tabular}{cccc}Property&Value\\\\ \\hline$e^{min}_c$&0.069\\\\ $e^{min}_d$&0.074\\\\ $e^{max}_c$&0.39\\\\ $e^{max}_d$&0.365\\\\ $\\epsilon$&0.17\\\\ $i^{min}_c$&$16.0^\\circ$\\\\ $i^{min}_d$&$11.6^\\circ$\\\\ $i^{max}_c$&$20.4^\\circ$\\\\ $i^{max}_d$&$16.7^\\circ$\\\\ $\\Psi^{min}$&$27.6^\\circ$\\\\ $\\Psi^{max}$&$37.1^\\circ$\\\\ $\\beta/\\beta_{crit}$&1.075\\\\ \\end{tabular} ",
|
4 |
+
"gt": "\\begin{tabular}{cc}Property&Value\\\\\\hline$e^{min}_c$&0.069\\\\$e^{min}_d$&0.074\\\\$e^{max}_c$&0.39\\\\$e^{max}_d$&0.365\\\\$\\epsilon$&0.17\\\\$i^{min}_c$&$16.0^\\circ$\\\\$i^{min}_d$&$11.6^\\circ$\\\\$i^{max}_c$&$20.4^\\circ$\\\\$i^{max}_d$&$16.7^\\circ$\\\\$\\Psi^{min}$&$27.6^\\circ$\\\\$\\Psi^{max}$&$37.1^\\circ$\\\\$\\beta/\\beta_{crit}$&1.075\\\\ \\end{tabular}\n"
|
5 |
+
},
|
6 |
+
{
|
7 |
+
"pred": "\\begin{tabular}{l r r r r}\\hline Element&\\multicolumn{2}{c}{fully convective}&\\multicolumn{2}{c}{convective at$\\tau_{\\rm R}=3.2$}\\\\ &$\\log\\tau_{\\rm diff}$[yrs]&$\\dot{m}$[g\\,s$^{-1}$]&$\\log\\tau_{\\rm diff}$[yrs]&$\\dot{m}$[g\\,s$^{-1}$]\\\\ \\hline$12$Mg&$-0.46$&$1.7\\times10^8$&$-2.2$&$7.3\\times10^7$\\\\ $14$Si&$-0.36$&$\\leq2.5\\times10^8$&$-2.5$&$\\leq2.9\\times10^8$\\\\ $20$Ca&$-0.37$&$7.2\\times10^6$&$-2.3$&$5.0\\times10^6$\\\\ \\hline\\end{tabular} ",
|
8 |
+
"gt": "\\begin{tabular}{lrrrr}\\hline\nElement&\\multicolumn{2}{c}{fully convective}&\\multicolumn{2}{c}{convective at$\\tau_\\mathrm{R}=3.2$}\\\\ &$\\log\\tau_\\mathrm{diff}$[yrs]&$\\dot m~[\\mathrm{g\\,s^{-1}}]$&$\\log\\tau_\\mathrm{diff}$[yrs]&$\\dot m~[\\mathrm{g\\,s^{-1}}]$\\\\\\hline12Mg&$-0.46$&$1.7\\times10^8$&$-2.2$&$7.3\\times10^7$\\\\14Si&$-0.36$&$\\leq2.5\\times10^8$&$-2.5$&$\\leq2.9\\times10^8$\\\\20Ca&$-0.37$&$7.2\\times10^6$&$-2.3$&$5.0\\times10^6$\\\\\\hline\\end{tabular}\n"
|
9 |
+
}
|
10 |
+
]
|
evaluation.py
ADDED
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import os
|
3 |
+
import re
|
4 |
+
import json
|
5 |
+
import time
|
6 |
+
import shutil
|
7 |
+
import argparse
|
8 |
+
import numpy as np
|
9 |
+
import matplotlib.pyplot as plt
|
10 |
+
|
11 |
+
from tqdm import tqdm
|
12 |
+
from datetime import datetime
|
13 |
+
from multiprocessing import Pool
|
14 |
+
from multiprocessing.dummy import Pool as ThreadPool
|
15 |
+
from PIL import Image, ImageDraw
|
16 |
+
from skimage.measure import ransac
|
17 |
+
|
18 |
+
from modules.latex2bbox_color import latex2bbox_color
|
19 |
+
from modules.tokenize_latex.tokenize_latex import tokenize_latex
|
20 |
+
from modules.visual_matcher import HungarianMatcher, SimpleAffineTransform
|
21 |
+
|
22 |
+
|
23 |
+
def gen_color_list(num=10, gap=15):
|
24 |
+
num += 1
|
25 |
+
single_num = 255 // gap + 1
|
26 |
+
max_num = single_num ** 3
|
27 |
+
num = min(num, max_num)
|
28 |
+
color_list = []
|
29 |
+
for idx in range(num):
|
30 |
+
R = idx // single_num**2
|
31 |
+
GB = idx % single_num**2
|
32 |
+
G = GB // single_num
|
33 |
+
B = GB % single_num
|
34 |
+
|
35 |
+
color_list.append((R*gap, G*gap, B*gap))
|
36 |
+
return color_list[1:]
|
37 |
+
|
38 |
+
def update_inliers(ori_inliers, sub_inliers):
|
39 |
+
inliers = np.copy(ori_inliers)
|
40 |
+
sub_idx = -1
|
41 |
+
for idx in range(len(ori_inliers)):
|
42 |
+
if ori_inliers[idx] == False:
|
43 |
+
sub_idx += 1
|
44 |
+
if sub_inliers[sub_idx] == True:
|
45 |
+
inliers[idx] = True
|
46 |
+
return inliers
|
47 |
+
|
48 |
+
def reshape_inliers(ori_inliers, sub_inliers):
|
49 |
+
inliers = np.copy(ori_inliers)
|
50 |
+
sub_idx = -1
|
51 |
+
for idx in range(len(ori_inliers)):
|
52 |
+
if ori_inliers[idx] == False:
|
53 |
+
sub_idx += 1
|
54 |
+
if sub_inliers[sub_idx] == True:
|
55 |
+
inliers[idx] = True
|
56 |
+
else:
|
57 |
+
inliers[idx] = False
|
58 |
+
return inliers
|
59 |
+
|
60 |
+
def gen_token_order(box_list):
|
61 |
+
new_box_list = copy.deepcopy(box_list)
|
62 |
+
for idx, box in enumerate(new_box_list):
|
63 |
+
new_box_list[idx]['order'] = idx / len(new_box_list)
|
64 |
+
return new_box_list
|
65 |
+
|
66 |
+
def evaluation(data_root, user_id="test"):
|
67 |
+
data_root = os.path.join(data_root, user_id)
|
68 |
+
gt_box_dir = os.path.join(data_root, "gt")
|
69 |
+
pred_box_dir = os.path.join(data_root, "pred")
|
70 |
+
match_vis_dir = os.path.join(data_root, "vis_match")
|
71 |
+
os.makedirs(match_vis_dir, exist_ok=True)
|
72 |
+
|
73 |
+
max_iter = 3
|
74 |
+
min_samples = 3
|
75 |
+
residual_threshold = 25
|
76 |
+
max_trials = 50
|
77 |
+
|
78 |
+
metrics_per_img = {}
|
79 |
+
gt_basename_list = [item.split(".")[0] for item in os.listdir(os.path.join(gt_box_dir, 'bbox'))]
|
80 |
+
for basename in tqdm(gt_basename_list):
|
81 |
+
gt_valid, pred_valid = True, True
|
82 |
+
if not os.path.exists(os.path.join(gt_box_dir, 'bbox', basename+".jsonl")):
|
83 |
+
gt_valid = False
|
84 |
+
else:
|
85 |
+
with open(os.path.join(gt_box_dir, 'bbox', basename+".jsonl"), 'r') as f:
|
86 |
+
box_gt = []
|
87 |
+
for line in f:
|
88 |
+
info = json.loads(line)
|
89 |
+
if info['bbox']:
|
90 |
+
box_gt.append(info)
|
91 |
+
if not box_gt:
|
92 |
+
gt_valid = False
|
93 |
+
if not gt_valid:
|
94 |
+
continue
|
95 |
+
|
96 |
+
if not os.path.exists(os.path.join(pred_box_dir, 'bbox', basename+".jsonl")):
|
97 |
+
pred_valid = False
|
98 |
+
else:
|
99 |
+
with open(os.path.join(pred_box_dir, 'bbox', basename+".jsonl"), 'r') as f:
|
100 |
+
box_pred = []
|
101 |
+
for line in f:
|
102 |
+
info = json.loads(line)
|
103 |
+
if info['bbox']:
|
104 |
+
box_pred.append(info)
|
105 |
+
if not box_pred:
|
106 |
+
pred_valid = False
|
107 |
+
if not pred_valid:
|
108 |
+
metrics_per_img[basename] = {
|
109 |
+
"recall": 0,
|
110 |
+
"precision": 0,
|
111 |
+
"F1_score": 0,
|
112 |
+
}
|
113 |
+
continue
|
114 |
+
gt_img_path = os.path.join(gt_box_dir, 'vis', basename+"_base.png")
|
115 |
+
pred_img_path = os.path.join(pred_box_dir, 'vis', basename+"_base.png")
|
116 |
+
|
117 |
+
img_gt = Image.open(gt_img_path)
|
118 |
+
img_pred = Image.open(pred_img_path)
|
119 |
+
|
120 |
+
matcher = HungarianMatcher()
|
121 |
+
matched_idxes = matcher(box_gt, box_pred, img_gt.size, img_pred.size)
|
122 |
+
src = []
|
123 |
+
dst = []
|
124 |
+
for (idx1, idx2) in matched_idxes:
|
125 |
+
x1min, y1min, x1max, y1max = box_gt[idx1]['bbox']
|
126 |
+
x2min, y2min, x2max, y2max = box_pred[idx2]['bbox']
|
127 |
+
x1_c, y1_c = float((x1min+x1max)/2), float((y1min+y1max)/2)
|
128 |
+
x2_c, y2_c = float((x2min+x2max)/2), float((y2min+y2max)/2)
|
129 |
+
src.append([y1_c, x1_c])
|
130 |
+
dst.append([y2_c, x2_c])
|
131 |
+
|
132 |
+
src = np.array(src)
|
133 |
+
dst = np.array(dst)
|
134 |
+
if src.shape[0] <= min_samples:
|
135 |
+
inliers = np.array([True for _ in matched_idxes])
|
136 |
+
else:
|
137 |
+
inliers = np.array([False for _ in matched_idxes])
|
138 |
+
for i in range(max_iter):
|
139 |
+
if src[inliers==False].shape[0] <= min_samples:
|
140 |
+
break
|
141 |
+
model, inliers_1 = ransac((src[inliers==False], dst[inliers==False]), SimpleAffineTransform, min_samples=min_samples, residual_threshold=residual_threshold, max_trials=max_trials, random_state=42)
|
142 |
+
if inliers_1 is not None and inliers_1.any():
|
143 |
+
inliers = update_inliers(inliers, inliers_1)
|
144 |
+
else:
|
145 |
+
break
|
146 |
+
if len(inliers[inliers==True]) >= len(matched_idxes):
|
147 |
+
break
|
148 |
+
|
149 |
+
for idx, (a,b) in enumerate(matched_idxes):
|
150 |
+
if inliers[idx] == True and matcher.cost['token'][a, b] == 1:
|
151 |
+
inliers[idx] = False
|
152 |
+
|
153 |
+
final_match_num = len(inliers[inliers==True])
|
154 |
+
recall = round(final_match_num/(len(box_gt)), 3)
|
155 |
+
precision = round(final_match_num/(len(box_pred)), 3)
|
156 |
+
F1_score = round(2*final_match_num/(len(box_gt)+len(box_pred)), 3)
|
157 |
+
metrics_per_img[basename] = {
|
158 |
+
"recall": recall,
|
159 |
+
"precision": precision,
|
160 |
+
"F1_score": F1_score,
|
161 |
+
}
|
162 |
+
|
163 |
+
if True:
|
164 |
+
gap = 5
|
165 |
+
W1, H1 = img_gt.size
|
166 |
+
W2, H2 = img_pred.size
|
167 |
+
H = H1 + H2 + gap
|
168 |
+
W = max(W1, W2)
|
169 |
+
|
170 |
+
vis_img = Image.new('RGB', (W, H), (255, 255, 255))
|
171 |
+
vis_img.paste(img_gt, (0, 0))
|
172 |
+
vis_img.paste(Image.new('RGB', (W, gap), (120, 120, 120)), (0, H1))
|
173 |
+
vis_img.paste(img_pred, (0, H1+gap))
|
174 |
+
|
175 |
+
match_img = vis_img.copy()
|
176 |
+
match_draw = ImageDraw.Draw(match_img)
|
177 |
+
|
178 |
+
gt_matched_idx = {
|
179 |
+
a: flag
|
180 |
+
for (a,b), flag in
|
181 |
+
zip(matched_idxes, inliers)
|
182 |
+
}
|
183 |
+
pred_matched_idx = {
|
184 |
+
b: flag
|
185 |
+
for (a,b), flag in
|
186 |
+
zip(matched_idxes, inliers)
|
187 |
+
}
|
188 |
+
|
189 |
+
for idx, box in enumerate(box_gt):
|
190 |
+
if idx in gt_matched_idx and gt_matched_idx[idx]==True:
|
191 |
+
color = "green"
|
192 |
+
else:
|
193 |
+
color = "red"
|
194 |
+
x_min, y_min, x_max, y_max = box['bbox']
|
195 |
+
match_draw.rectangle([x_min-1, y_min-1, x_max+1, y_max+1], fill=None, outline=color, width=2)
|
196 |
+
|
197 |
+
for idx, box in enumerate(box_pred):
|
198 |
+
if idx in pred_matched_idx and pred_matched_idx[idx]==True:
|
199 |
+
color = "green"
|
200 |
+
else:
|
201 |
+
color = "red"
|
202 |
+
x_min, y_min, x_max, y_max = box['bbox']
|
203 |
+
match_draw.rectangle([x_min-1, y_min-1+H1+gap, x_max+1, y_max+1+H1+gap], fill=None, outline=color, width=2)
|
204 |
+
|
205 |
+
vis_img.save(os.path.join(match_vis_dir, basename+"_base.png"))
|
206 |
+
match_img.save(os.path.join(match_vis_dir, basename+".png"))
|
207 |
+
|
208 |
+
score_list = [val['F1_score'] for _, val in metrics_per_img.items()]
|
209 |
+
exp_list = [1 if score==1 else 0 for score in score_list]
|
210 |
+
metrics_res = {
|
211 |
+
"mean_score": round(np.mean(score_list), 3),
|
212 |
+
"exp_rate": round(np.mean(exp_list), 3),
|
213 |
+
"details": metrics_per_img
|
214 |
+
}
|
215 |
+
metric_res_path = os.path.join(data_root, "metrics_res.json")
|
216 |
+
with open(metric_res_path, "w") as f:
|
217 |
+
f.write(json.dumps(metrics_res, indent=2))
|
218 |
+
return metrics_res, metric_res_path, match_vis_dir
|
219 |
+
|
220 |
+
|
221 |
+
if __name__ == '__main__':
|
222 |
+
parser = argparse.ArgumentParser()
|
223 |
+
parser.add_argument('--input', '-i', type=str, default="assets/example/input_example.json")
|
224 |
+
parser.add_argument('--output', '-o', type=str, default="output")
|
225 |
+
parser.add_argument('--pools', '-p', type=int, default=240)
|
226 |
+
args = parser.parse_args()
|
227 |
+
print(args)
|
228 |
+
|
229 |
+
json_input, data_root, pool_num = args.input, args.output, args.pools
|
230 |
+
temp_dir = os.path.join(data_root, "temp_dir")
|
231 |
+
exp_name = os.path.basename(json_input).split('.')[0]
|
232 |
+
with open(json_input, "r") as f:
|
233 |
+
input_data = json.load(f)
|
234 |
+
img_ids = []
|
235 |
+
groundtruths = []
|
236 |
+
predictions = []
|
237 |
+
for idx, item in enumerate(input_data):
|
238 |
+
if "img_id" in item:
|
239 |
+
img_ids.append(item["img_id"])
|
240 |
+
else:
|
241 |
+
img_ids.append(f"sample_{idx}")
|
242 |
+
groundtruths.append(item['gt'])
|
243 |
+
predictions.append(item['pred'])
|
244 |
+
|
245 |
+
a = time.time()
|
246 |
+
user_id = exp_name
|
247 |
+
|
248 |
+
total_color_list = gen_color_list(num=5800)
|
249 |
+
|
250 |
+
data_root = os.path.join(data_root, user_id)
|
251 |
+
output_dir_info = {}
|
252 |
+
input_args = []
|
253 |
+
for subset, latex_list in zip(['gt', 'pred'], [groundtruths, predictions]):
|
254 |
+
sub_temp_dir = os.path.join(temp_dir, f"{exp_name}_{subset}")
|
255 |
+
os.makedirs(sub_temp_dir, exist_ok=True)
|
256 |
+
output_path = os.path.join(data_root, subset)
|
257 |
+
output_dir_info[output_path] = []
|
258 |
+
|
259 |
+
os.makedirs(os.path.join(output_path, 'bbox'), exist_ok=True)
|
260 |
+
os.makedirs(os.path.join(output_path, 'vis'), exist_ok=True)
|
261 |
+
|
262 |
+
for idx, latex in tqdm(enumerate(latex_list), desc=f"collect {subset} latex ..."):
|
263 |
+
basename = img_ids[idx]
|
264 |
+
input_arg = latex, basename, output_path, sub_temp_dir, total_color_list
|
265 |
+
input_args.append(input_arg)
|
266 |
+
|
267 |
+
if pool_num > 1:
|
268 |
+
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "using processpool, pool num:", pool_num, ", job num:", len(input_args))
|
269 |
+
myP = Pool(args.pools)
|
270 |
+
for input_arg in input_args:
|
271 |
+
myP.apply_async(latex2bbox_color, args=(input_arg,))
|
272 |
+
myP.close()
|
273 |
+
myP.join()
|
274 |
+
else:
|
275 |
+
for input_arg in input_args:
|
276 |
+
latex2bbox_color(input_arg)
|
277 |
+
b = time.time()
|
278 |
+
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "extract bbox done, time cost:", round(b-a, 3), "s")
|
279 |
+
|
280 |
+
for subset in ['gt', 'pred']:
|
281 |
+
shutil.rmtree(os.path.join(temp_dir, f"{exp_name}_{subset}"))
|
282 |
+
|
283 |
+
c = time.time()
|
284 |
+
metrics_res, metric_res_path, match_vis_dir = evaluation(args.output, exp_name)
|
285 |
+
d = time.time()
|
286 |
+
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "calculate metrics done, time cost:", round(d-c, 3), "s")
|
287 |
+
|
288 |
+
print(f"=> process done, mean f1 score: {metrics_res['mean_score']}.")
|
289 |
+
print(f"=> more details of metrics are saved in `{metric_res_path}`")
|
290 |
+
print(f"=> visulization images are saved under `{match_vis_dir}`")
|
modules/latex2bbox_color.py
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import re
|
3 |
+
import json
|
4 |
+
import shutil
|
5 |
+
import logging
|
6 |
+
import subprocess
|
7 |
+
import numpy as np
|
8 |
+
|
9 |
+
from threading import Timer
|
10 |
+
from PIL import Image, ImageDraw
|
11 |
+
from modules.latex_processor import (
|
12 |
+
normalize_latex,
|
13 |
+
token_add_color_RGB,
|
14 |
+
clean_latex
|
15 |
+
)
|
16 |
+
from modules.tokenize_latex.tokenize_latex import tokenize_latex
|
17 |
+
|
18 |
+
|
19 |
+
tabular_template = r"""
|
20 |
+
\documentclass[12pt]{article}
|
21 |
+
\usepackage[landscape]{geometry}
|
22 |
+
\usepackage{geometry}
|
23 |
+
\geometry{a<PaperSize>paper,scale=0.98}
|
24 |
+
\pagestyle{empty}
|
25 |
+
\usepackage{booktabs}
|
26 |
+
\usepackage{multirow}
|
27 |
+
\usepackage{amssymb}
|
28 |
+
\usepackage{upgreek}
|
29 |
+
\usepackage{amsmath}
|
30 |
+
\usepackage{xcolor}
|
31 |
+
\begin{document}
|
32 |
+
\makeatletter
|
33 |
+
\renewcommand*{\@textcolor}[3]{%%
|
34 |
+
\protect\leavevmode
|
35 |
+
\begingroup
|
36 |
+
\color#1{#2}#3%%
|
37 |
+
\endgroup
|
38 |
+
}
|
39 |
+
\makeatother
|
40 |
+
\begin{displaymath}
|
41 |
+
%s
|
42 |
+
\end{displaymath}
|
43 |
+
\end{document}
|
44 |
+
"""
|
45 |
+
|
46 |
+
formular_template = r"""
|
47 |
+
\documentclass[12pt]{article}
|
48 |
+
\usepackage[landscape]{geometry}
|
49 |
+
\usepackage{geometry}
|
50 |
+
\geometry{a<PaperSize>paper,scale=0.98}
|
51 |
+
\pagestyle{empty}
|
52 |
+
\usepackage{booktabs}
|
53 |
+
\usepackage{amsmath}
|
54 |
+
\usepackage{upgreek}
|
55 |
+
\usepackage{amssymb}
|
56 |
+
\usepackage{xcolor}
|
57 |
+
\begin{document}
|
58 |
+
\makeatletter
|
59 |
+
\renewcommand*{\@textcolor}[3]{%%
|
60 |
+
\protect\leavevmode
|
61 |
+
\begingroup
|
62 |
+
\color#1{#2}#3%%
|
63 |
+
\endgroup
|
64 |
+
}
|
65 |
+
\makeatother
|
66 |
+
\begin{displaymath}
|
67 |
+
%s
|
68 |
+
\end{displaymath}
|
69 |
+
\end{document}
|
70 |
+
"""
|
71 |
+
|
72 |
+
|
73 |
+
def run_cmd(cmd, timeout_sec=30):
|
74 |
+
proc = subprocess.Popen(cmd, shell=True)
|
75 |
+
kill_proc = lambda p: p.kill()
|
76 |
+
timer = Timer(timeout_sec, kill_proc, [proc])
|
77 |
+
try:
|
78 |
+
timer.start()
|
79 |
+
stdout,stderr = proc.communicate()
|
80 |
+
finally:
|
81 |
+
timer.cancel()
|
82 |
+
|
83 |
+
def convert_pdf2img(pdf_filename, png_filename):
|
84 |
+
cmd = "magick -density 200 -quality 100 %s %s"%(pdf_filename, png_filename)
|
85 |
+
os.system(cmd)
|
86 |
+
|
87 |
+
def crop_image(image_path, pad=8):
|
88 |
+
img = Image.open(image_path).convert("L")
|
89 |
+
img_data = np.asarray(img, dtype=np.uint8)
|
90 |
+
nnz_inds = np.where(img_data!=255)
|
91 |
+
if len(nnz_inds[0]) == 0:
|
92 |
+
y_min = 0
|
93 |
+
y_max = 10
|
94 |
+
x_min = 0
|
95 |
+
x_max = 10
|
96 |
+
else:
|
97 |
+
y_min = np.min(nnz_inds[0])
|
98 |
+
y_max = np.max(nnz_inds[0])
|
99 |
+
x_min = np.min(nnz_inds[1])
|
100 |
+
x_max = np.max(nnz_inds[1])
|
101 |
+
|
102 |
+
img = Image.open(image_path).convert("RGB").crop((x_min-pad, y_min-pad, x_max+pad, y_max+pad))
|
103 |
+
img.save(image_path)
|
104 |
+
|
105 |
+
def extrac_bbox_from_color_image(image_path, color_list):
|
106 |
+
img = Image.open(image_path).convert("RGB")
|
107 |
+
W, H = img.size
|
108 |
+
pixels = list(img.getdata())
|
109 |
+
|
110 |
+
bbox_list = []
|
111 |
+
for target_color in color_list:
|
112 |
+
target_pixels = [ i for i, pixel in enumerate(pixels)if pixel == target_color ]
|
113 |
+
x_list = []
|
114 |
+
y_list = []
|
115 |
+
for idx in target_pixels:
|
116 |
+
x_list.append(idx % W)
|
117 |
+
y_list.append(idx // W)
|
118 |
+
try:
|
119 |
+
y_min, y_max, x_min, x_max = min(y_list), max(y_list), min(x_list), max(x_list)
|
120 |
+
bbox_list.append([x_min-1, y_min-1, x_max+1, y_max+1])
|
121 |
+
|
122 |
+
except:
|
123 |
+
bbox_list.append([])
|
124 |
+
continue
|
125 |
+
|
126 |
+
img = img.convert("L")
|
127 |
+
img_bw = img.point(lambda x: 255 if x == 255 else 0, '1')
|
128 |
+
img_bw.convert("RGB").save(image_path)
|
129 |
+
return bbox_list
|
130 |
+
|
131 |
+
|
132 |
+
def latex2bbox_color(input_arg):
|
133 |
+
latex, basename, output_path, temp_dir, total_color_list = input_arg
|
134 |
+
template = tabular_template if "tabular" in latex else formular_template
|
135 |
+
output_bbox_path = os.path.join(output_path, 'bbox', basename+'.jsonl')
|
136 |
+
output_vis_path = os.path.join(output_path, 'vis', basename+'.png')
|
137 |
+
output_base_path = os.path.join(output_path, 'vis', basename+'_base.png')
|
138 |
+
|
139 |
+
if os.path.exists(output_bbox_path) and os.path.exists(output_vis_path) and os.path.exists(output_base_path):
|
140 |
+
return
|
141 |
+
|
142 |
+
try:
|
143 |
+
ret, new_latex = tokenize_latex(latex, middle_file=os.path.join(temp_dir, basename+'.txt'))
|
144 |
+
if not(ret and new_latex):
|
145 |
+
log = f"ERROR, Tokenize latex failed: {basename}."
|
146 |
+
logging.info(log)
|
147 |
+
new_latex = latex
|
148 |
+
latex = normalize_latex(new_latex)
|
149 |
+
token_list = []
|
150 |
+
l_split = latex.strip().split(' ')
|
151 |
+
color_list = total_color_list[0:len(l_split)]
|
152 |
+
idx = 0
|
153 |
+
while idx < len(l_split):
|
154 |
+
l_split, idx, token_list = token_add_color_RGB(l_split, idx, token_list)
|
155 |
+
|
156 |
+
rgb_latex = " ".join(l_split)
|
157 |
+
for idx, color in enumerate(color_list):
|
158 |
+
R, G, B = color
|
159 |
+
rgb_latex = rgb_latex.replace(f"<color_{idx}>", f"{R},{G},{B}")
|
160 |
+
|
161 |
+
if len(token_list) > 1300:
|
162 |
+
paper_size = 3
|
163 |
+
elif len(token_list) > 600:
|
164 |
+
paper_size = 4
|
165 |
+
else:
|
166 |
+
paper_size = 5
|
167 |
+
final_latex = formular_template.replace("<PaperSize>", str(paper_size)) % rgb_latex
|
168 |
+
|
169 |
+
except Exception as e:
|
170 |
+
log = f"ERROR, Preprocess latex failed: {basename}; {e}."
|
171 |
+
logging.info(log)
|
172 |
+
return
|
173 |
+
|
174 |
+
pre_name = output_path.replace('/', '_').replace('.','_') + '_' + basename
|
175 |
+
tex_filename = os.path.join(temp_dir, pre_name+'.tex')
|
176 |
+
log_filename = os.path.join(temp_dir, pre_name+'.log')
|
177 |
+
aux_filename = os.path.join(temp_dir, pre_name+'.aux')
|
178 |
+
|
179 |
+
with open(tex_filename, "w") as w:
|
180 |
+
print(final_latex, file=w)
|
181 |
+
run_cmd(f"pdflatex -interaction=nonstopmode -output-directory={temp_dir} {tex_filename} >/dev/null")
|
182 |
+
try:
|
183 |
+
os.remove(tex_filename)
|
184 |
+
os.remove(log_filename)
|
185 |
+
os.remove(aux_filename)
|
186 |
+
except:
|
187 |
+
pass
|
188 |
+
pdf_filename = tex_filename[:-4]+'.pdf'
|
189 |
+
if not os.path.exists(pdf_filename):
|
190 |
+
log = f"ERROR, Compile pdf failed: {pdf_filename}"
|
191 |
+
logging.info(log)
|
192 |
+
else:
|
193 |
+
convert_pdf2img(pdf_filename, output_base_path)
|
194 |
+
os.remove(pdf_filename)
|
195 |
+
|
196 |
+
crop_image(output_base_path)
|
197 |
+
bbox_list = extrac_bbox_from_color_image(output_base_path, color_list)
|
198 |
+
vis = Image.open(output_base_path)
|
199 |
+
draw = ImageDraw.Draw(vis)
|
200 |
+
|
201 |
+
with open(output_bbox_path, 'w') as f:
|
202 |
+
for token, box in zip(token_list, bbox_list):
|
203 |
+
item = {
|
204 |
+
"bbox": box,
|
205 |
+
"token": token
|
206 |
+
}
|
207 |
+
f.write(json.dumps(item)+'\n')
|
208 |
+
|
209 |
+
if not box:
|
210 |
+
continue
|
211 |
+
x_min, y_min, x_max, y_max = box
|
212 |
+
draw.rectangle([x_min, y_min, x_max, y_max], fill=None, outline=(0,250,0), width=1)
|
213 |
+
draw.text((x_min, y_min), token, (250,0,0))
|
214 |
+
|
215 |
+
vis.save(output_vis_path)
|
modules/latex_processor.py
ADDED
@@ -0,0 +1,536 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import re
|
3 |
+
import json
|
4 |
+
import shutil
|
5 |
+
import logging
|
6 |
+
import numpy as np
|
7 |
+
from PIL import Image
|
8 |
+
|
9 |
+
|
10 |
+
SKIP_PATTERNS = [r'\{', r'\}', r'[\[\]]', r'\\begin\{.*?\}', r'\\end\{.*?\}', r'\^', r'\_', r'\\.*rule.*', r'\\.*line.*', r'\[[\-.0-9]+[epm][xtm]\]']
|
11 |
+
SKIP_Tokens = ['\\', '\\\\', '\\index', '\\a', '&', '$', '\\multirow', '\\def', '\\raggedright', '\\url', '\\cr', '\\ensuremath', '\\left', '\\right',
|
12 |
+
'\\mathchoice', '\\scriptstyle', '\\displaystyle', '\\qquad', '\\quad', '\\,', '\\!', '~', '\\boldmath']
|
13 |
+
PHANTOM_Tokens = ['\\fontfamily', '\\vphantom', '\\phantom', '\\rowcolor', '\\ref']
|
14 |
+
TWO_Tail_Tokens = ['\\frac', '\\binom']
|
15 |
+
AB_Tail_Tokens = ['\\xrightarrow', '\\xleftarrow', '\\sqrt'] # special token \xxx [] {}
|
16 |
+
TWO_Tail_Invisb_Tokens = ['\\overset', '\\underset', '\\stackrel']
|
17 |
+
ONE_Tail_Tokens = ['\\widetilde', '\\overline', '\\hat', '\\widehat', '\\tilde', '\\Tilde', '\\dot', '\\bar', '\\vec', '\\underline', '\\underbrace', '\\check',
|
18 |
+
'\\breve', '\\Bar', '\\Vec', '\\mathring', '\\ddot']
|
19 |
+
ONE_Tail_Invisb_Tokens = ['\\boldsymbol', '\\pmb', '\\textbf', '\\mathrm', '\\mathbf', '\\mathbb', '\\mathcal', '\\textmd', '\\texttt', '\\textnormal',
|
20 |
+
'\\text', '\\textit', '\\textup', '\\mathop', '\\mathbin', '\\smash', '\\operatorname', '\\textrm', '\\mathfrak', '\\emph',
|
21 |
+
'\\textsf', '\\textsc']
|
22 |
+
|
23 |
+
|
24 |
+
def flatten_multiline(latex):
|
25 |
+
brace_map = {
|
26 |
+
"\\left(": "\\right)",
|
27 |
+
"\\left[": "\\right]",
|
28 |
+
"\\left{": "\\right}",
|
29 |
+
}
|
30 |
+
l_split = latex.split(' ')
|
31 |
+
if l_split[0] == "\\begin{array}":
|
32 |
+
if l_split[-1] == "\\end{array}":
|
33 |
+
l_split = l_split[2:-1]
|
34 |
+
else:
|
35 |
+
l_split = l_split[2:]
|
36 |
+
|
37 |
+
idx = 0
|
38 |
+
while idx < len(l_split):
|
39 |
+
token = l_split[idx]
|
40 |
+
if token.startswith("\\left") and token in brace_map.keys():
|
41 |
+
end_idx = find_matching_brace(l_split, idx, brace=[token, brace_map[token]])
|
42 |
+
if end_idx != -1:
|
43 |
+
idx = end_idx
|
44 |
+
elif token in ["\\\\", "~", "\\qquad"]:
|
45 |
+
l_split = l_split[0:idx] + l_split[idx+1:]
|
46 |
+
idx -= 1
|
47 |
+
idx += 1
|
48 |
+
latex = ' '.join(l_split)
|
49 |
+
return "$ "+latex+" $"
|
50 |
+
|
51 |
+
|
52 |
+
def clean_latex(text):
|
53 |
+
# TODO 让GPT写的去空格函数, 初步测了是没问题的, 不确定是否完全没有bug
|
54 |
+
cleaned_text = re.sub(r'(?<=[^\\])\s+(?=[^\\])', '', text)
|
55 |
+
# TODO 有一些不能去掉的空格给补充回来
|
56 |
+
for item in ["\\hline", "\\midrule", "\\times", "\\bf", "\\footnotesize", "\\cr", '\\log']:
|
57 |
+
cleaned_text = cleaned_text.replace(item, item+" ")
|
58 |
+
cleaned_text = cleaned_text.replace(" \\mathcolor{black}", "\\mathcolor{black}")
|
59 |
+
return cleaned_text
|
60 |
+
|
61 |
+
def remove_trailing_latex(formula):
|
62 |
+
pattern = r'(\\(hspace\*?\{[^{}]*?\}|vspace\*?\{[^{}]*?\}|smallskip|medskip|quad|qquad|bigskip|[;,])|\~|\.)*$'
|
63 |
+
# Replace the matched pattern with an empty string
|
64 |
+
cleaned_formula = re.sub(pattern, '', formula, count=1)
|
65 |
+
return cleaned_formula
|
66 |
+
|
67 |
+
def find_matching_brace(sequence, start_index, brace=['{', '}']):
|
68 |
+
# Finds the index of the matching brace for the one at start_index
|
69 |
+
left_brace, right_brace = brace
|
70 |
+
depth = 0
|
71 |
+
for i, char in enumerate(sequence[start_index:], start=start_index):
|
72 |
+
if char == left_brace:
|
73 |
+
depth += 1
|
74 |
+
elif char == right_brace:
|
75 |
+
depth -= 1
|
76 |
+
if depth == 0:
|
77 |
+
return i
|
78 |
+
if depth > 0:
|
79 |
+
error_info = "Warning! found no matching brace in sequence !"
|
80 |
+
raise ValueError(error_info)
|
81 |
+
return -1
|
82 |
+
|
83 |
+
def normalize_latex(l, rm_trail=False):
|
84 |
+
if "tabular" in l:
|
85 |
+
latex_type = "tabular"
|
86 |
+
else:
|
87 |
+
latex_type = "formula"
|
88 |
+
|
89 |
+
if rm_trail:
|
90 |
+
l = remove_trailing_latex(l)
|
91 |
+
l = l.strip().replace(r'\pmatrix', r'\mypmatrix').replace(r'\matrix', r'\mymatrix')
|
92 |
+
|
93 |
+
# TODO \raggedright \arraybackslash, these align method, difficult to handle, remove it.
|
94 |
+
for item in ['\\raggedright', '\\arraybackslash']:
|
95 |
+
l = l.replace(item, "")
|
96 |
+
|
97 |
+
for item in ['\\lowercase', '\\uppercase']:
|
98 |
+
l = l.replace(item, "")
|
99 |
+
|
100 |
+
# TODO \hspace {1 . 5 cm}, for formula, change to \hspace{1.5cm}, for table, remove it.
|
101 |
+
pattern = r'\\[hv]space { [.0-9a-z ]+ }'
|
102 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
103 |
+
if latex_type == "tabular":
|
104 |
+
new_token = ["" for item in old_token]
|
105 |
+
else:
|
106 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
107 |
+
for bef, aft in zip(old_token, new_token):
|
108 |
+
l = l.replace(bef, aft)
|
109 |
+
|
110 |
+
# TODO take \begin {tabular} {} as one token
|
111 |
+
# TODO there are \begin{array} in table too,so the process should run in both formula and table.
|
112 |
+
if latex_type == "tabular":
|
113 |
+
l = l.replace("\\begin {tabular}", "\\begin{tabular}")
|
114 |
+
l = l.replace("\\end {tabular}", "\\end{tabular}")
|
115 |
+
l = l.replace("\\begin {array}", "\\begin{array}")
|
116 |
+
l = l.replace("\\end {array}", "\\end{array}")
|
117 |
+
l_split = l.split(' ')
|
118 |
+
idx = 0
|
119 |
+
while idx < len(l_split):
|
120 |
+
token = l_split[idx]
|
121 |
+
if token == "\\begin{tabular}":
|
122 |
+
sub_idx = idx + 1
|
123 |
+
end_idx = find_matching_brace(l_split, sub_idx)
|
124 |
+
new_token = "".join(l_split[idx: end_idx+1])
|
125 |
+
l_split = l_split[0:idx] + [new_token] + l_split[end_idx+1:]
|
126 |
+
break
|
127 |
+
idx += 1
|
128 |
+
l = ' '.join(l_split)
|
129 |
+
|
130 |
+
# TODO some complex format, hart to deal with re.match, so using brace match, such as:\cmidrule ( l { 3 p t } r { 3 p t } ) { 1 - 1 }
|
131 |
+
l_split = l.split(' ')
|
132 |
+
idx = 0
|
133 |
+
while idx < len(l_split):
|
134 |
+
token = l_split[idx]
|
135 |
+
if token in ["\\cmidrule", "\\cline"]:
|
136 |
+
sub_idx = idx + 1
|
137 |
+
if l_split[sub_idx] == "(":
|
138 |
+
mid_end = find_matching_brace(l_split, sub_idx, brace=['(', ')'])
|
139 |
+
end_idx = find_matching_brace(l_split, mid_end+1)
|
140 |
+
else:
|
141 |
+
end_idx = find_matching_brace(l_split, sub_idx)
|
142 |
+
new_token = "".join(l_split[idx: end_idx+1])
|
143 |
+
l_split = l_split[0:idx] + [new_token] + l_split[end_idx+1:]
|
144 |
+
idx += 1
|
145 |
+
l = ' '.join(l_split)
|
146 |
+
|
147 |
+
pattern = r'\\begin{array} { [lrc ]+ }'
|
148 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
149 |
+
new_token = [item.replace("\\begin{array} ", "<s>").replace(" ", "").replace("<s>", "\\begin{array} ") for item in old_token]
|
150 |
+
for bef, aft in zip(old_token, new_token):
|
151 |
+
l = l.replace(bef, aft)
|
152 |
+
|
153 |
+
# TODO token such \not= should be one token
|
154 |
+
pattern = r'\\not [<>+=\-]'
|
155 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
156 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
157 |
+
for bef, aft in zip(old_token, new_token):
|
158 |
+
l = l.replace(bef, aft)
|
159 |
+
|
160 |
+
# TODO tokens such as \dots \exp \sinh, split them to parts, so the bbox match will be easier.
|
161 |
+
|
162 |
+
l = " "+l+" "
|
163 |
+
l = l.replace(" \\ldots ", " . . . ")
|
164 |
+
l = l.replace(" \\cdots ", " . . . ")
|
165 |
+
l = l.replace(" \\dots ", " . . . ")
|
166 |
+
l = l.replace(" \\dotsb ", " . . . ")
|
167 |
+
l = l.replace(" \\log ", " \\mathrm { l o g } ")
|
168 |
+
l = l.replace(" \\exp ", " \\mathrm { e x p } ")
|
169 |
+
l = l.replace(" \\sin ", " \\mathrm { s i n } ")
|
170 |
+
l = l.replace(" \\cos ", " \\mathrm { c o s } ")
|
171 |
+
l = l.replace(" \\tan ", " \\mathrm { t a n } ")
|
172 |
+
l = l.replace(" \\tanh ", " \\mathrm { t a n h } ")
|
173 |
+
l = l.replace(" \\cosh ", " \\mathrm { c o s h } ")
|
174 |
+
l = l.replace(" \\sinh ", " \\mathrm { s i n h } ")
|
175 |
+
|
176 |
+
# ** token such as \big( should be one token
|
177 |
+
pattern = r'\\[Bb]ig[g]?[glrm]? [(){}|\[\]] '
|
178 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
179 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
180 |
+
for bef, aft in zip(old_token, new_token):
|
181 |
+
l = l.replace(bef, aft+" ")
|
182 |
+
|
183 |
+
pattern = r'\\[Bb]ig[g]?[glrm]? \\.*? '
|
184 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
185 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
186 |
+
for bef, aft in zip(old_token, new_token):
|
187 |
+
l = l.replace(bef, aft+" ")
|
188 |
+
|
189 |
+
# TODO when \operatorname * meets mathcolor it comes error, yet the * is useless, so we simply remove it bynow.
|
190 |
+
pattern = r'\\operatorname \*'
|
191 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
192 |
+
new_token = ["\\operatorname" for item in old_token]
|
193 |
+
for bef, aft in zip(old_token, new_token):
|
194 |
+
l = l.replace(bef, aft)
|
195 |
+
|
196 |
+
# TODO \lefteqn will lead to letter overlap, it's harmfull for render, so simply remove it.
|
197 |
+
l = l.replace("\\lefteqn", "")
|
198 |
+
|
199 |
+
# TODO \footnote can not seem as ONE_Tail_Invisb_Tokens(usually this type token add color by \mathrm {\color(x)}, yet \footnode should be \color{\footnote{x}}), so we simple change it to "^".
|
200 |
+
l = l.replace("\\footnote ", "^ ")
|
201 |
+
|
202 |
+
# TODO \' can not be rendered separately(cause to different visulize performence), so we take these tokens as one token such as \' e -> \'e, on the other hand, if { after \' then render them separately.
|
203 |
+
pattern = r'\\\' [^{] '
|
204 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
205 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
206 |
+
for bef, aft in zip(old_token, new_token):
|
207 |
+
l = l.replace(bef, aft+" ")
|
208 |
+
|
209 |
+
# TODO [ -1.5ex ] [ 1.5pt ] [ 3 mm ] some layout adjustment, no need to render. combine them as one token.
|
210 |
+
if latex_type == "tabular":
|
211 |
+
pattern = r'\[ [\-.0-9 ]+[exptcm ]+ \]'
|
212 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
213 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
214 |
+
for bef, aft in zip(old_token, new_token):
|
215 |
+
l = l.replace(bef, aft)
|
216 |
+
|
217 |
+
# ** \parbox { 3cm } {} shoudle be combined as one token
|
218 |
+
pattern = r'\\parbox {[^{]+}'
|
219 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
220 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
221 |
+
for bef, aft in zip(old_token, new_token):
|
222 |
+
l = l.replace(bef, aft)
|
223 |
+
|
224 |
+
# ** \raisebox{<lift>}[<height>][<depth>] {} shoudle be combined as one token, \raisebox{-1.5ex}[0pt]
|
225 |
+
pattern = r'\\raisebox {[^{]+} [\[\]0-9 exptcm]+{'
|
226 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
227 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
228 |
+
for bef, aft in zip(old_token, new_token):
|
229 |
+
l = l.replace(bef, aft[0:-1]+" {")
|
230 |
+
|
231 |
+
# ** \char shoudle be combined as one token
|
232 |
+
pattern = r'{ \\char[0-9\' ]+}'
|
233 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
234 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
235 |
+
for bef, aft in zip(old_token, new_token):
|
236 |
+
l = l.replace(bef, "{ "+aft[1:-1]+" }")
|
237 |
+
|
238 |
+
# ** \not xx shoudle be combined as one token
|
239 |
+
pattern = r'\\not [\\=\<\>][^ ]+ '
|
240 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
241 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
242 |
+
for bef, aft in zip(old_token, new_token):
|
243 |
+
l = l.replace(bef, aft+" ")
|
244 |
+
|
245 |
+
# ** \specialrule{1pt}{2pt}{2pt}, special lines, shoudle be combined as one token
|
246 |
+
pattern = r'\\specialrule {[ .0-9a-z]+} {[ .0-9a-z]+} {[ .0-9a-z]+}'
|
247 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
248 |
+
new_token = [item.replace(" ", "") for item in old_token]
|
249 |
+
for bef, aft in zip(old_token, new_token):
|
250 |
+
l = l.replace(bef, aft)
|
251 |
+
|
252 |
+
# ** for easier add color, the original color should be removed, there are two type of color for now: \color[rgb]{0, 1, 0} and \color{red}
|
253 |
+
pattern = r'\\colorbox[ \[\]RGBrgb]+{ [A-Za-z 0-9,!]+ } |\\color[ \[\]RGBrgb]+{ [A-Za-z 0-9,!]+ } |\\textcolor[ \[\]RGBrgb]+{ [A-Za-z 0-9,!]+ } |\\cellcolor[ \[\]RGBrgb]+{ [A-Za-z 0-9,!]+ } '
|
254 |
+
old_token = re.findall(pattern, l, re.DOTALL)
|
255 |
+
for bef in old_token:
|
256 |
+
l = l.replace(bef, "")
|
257 |
+
|
258 |
+
# ** filling the missing brace [] and {} according to token.
|
259 |
+
l_split = l.split(' ')
|
260 |
+
idx = 0
|
261 |
+
while idx < len(l_split):
|
262 |
+
token = l_split[idx]
|
263 |
+
if token in ONE_Tail_Tokens + ONE_Tail_Invisb_Tokens:
|
264 |
+
# ** normalize tokens such as \hat, fill missing the {}, such as \hat \lambda -> \hat {\lambda}
|
265 |
+
sub_idx = idx + 1
|
266 |
+
while sub_idx < len(l_split) and l_split[sub_idx] in ONE_Tail_Tokens+ONE_Tail_Invisb_Tokens:
|
267 |
+
sub_idx += 1
|
268 |
+
new_split = l_split[0:idx]
|
269 |
+
for ii in range(idx, sub_idx):
|
270 |
+
new_split = new_split + [l_split[ii], "{"]
|
271 |
+
if l_split[sub_idx] != "{":
|
272 |
+
new_split = new_split + [l_split[sub_idx]] + ["}"]*(sub_idx-idx)
|
273 |
+
l_split = new_split + l_split[sub_idx+1:]
|
274 |
+
else:
|
275 |
+
end_idx = find_matching_brace(l_split, sub_idx)
|
276 |
+
new_split = new_split + l_split[sub_idx+1:end_idx] + ["}"]*(sub_idx-idx)
|
277 |
+
l_split = new_split + l_split[end_idx+1:]
|
278 |
+
elif token in AB_Tail_Tokens:
|
279 |
+
# ** normalize special tokens such as \sqrt, fill the missing [] {} in \sqrt [] {}, yet the [] is optional, for example: \sqrt A B -> \sqrt {A} B and \sqrt [A] B -> \sqrt [A] {B}
|
280 |
+
if l_split[idx + 1] != "[" and l_split[idx + 1] != "{":
|
281 |
+
l_split = l_split[0:idx+1] + ["{"] + [l_split[idx+1]] + ["}"] + l_split[idx+2:]
|
282 |
+
else:
|
283 |
+
if l_split[idx + 1] == "[":
|
284 |
+
end1 = find_matching_brace(l_split, idx+1, brace=['[', ']'])
|
285 |
+
else:
|
286 |
+
end1 = idx
|
287 |
+
if l_split[end1 + 1] != "{":
|
288 |
+
l_split = l_split[0:end1+1] + ["{"] + [l_split[end1+1]] + ["}"] + l_split[end1+2:]
|
289 |
+
elif token in TWO_Tail_Tokens + TWO_Tail_Invisb_Tokens:
|
290 |
+
# ** normalize special tokens such as \frac, add missing brace in \frac {A} {B} for example: \frac {\lambda} 2 -> \frac {\lambda} {2}
|
291 |
+
if l_split[idx + 1] != "{":
|
292 |
+
l_split = l_split[0:idx+1] + ["{"] + [l_split[idx+1]] + ["}"] + l_split[idx+2:]
|
293 |
+
end1 = find_matching_brace(l_split, idx+1)
|
294 |
+
if l_split[end1 + 1] != "{":
|
295 |
+
l_split = l_split[0:end1+1] + ["{"] + [l_split[end1+1]] + ["}"] + l_split[end1+2:]
|
296 |
+
|
297 |
+
idx += 1
|
298 |
+
l = ' '.join(l_split)
|
299 |
+
|
300 |
+
return l
|
301 |
+
|
302 |
+
def token_add_color(l_split, idx, render_dict):
|
303 |
+
token = l_split[idx]
|
304 |
+
if token in PHANTOM_Tokens:
|
305 |
+
# ** special tokens that do not need render, skip it
|
306 |
+
if l_split[idx + 1] == '{':
|
307 |
+
brace_end = find_matching_brace(l_split, idx + 1)
|
308 |
+
else:
|
309 |
+
brace_end = idx + 1
|
310 |
+
next_idx = brace_end + 1
|
311 |
+
elif token in TWO_Tail_Tokens:
|
312 |
+
# ** tokens such as \frac A B, and the token needs render too.
|
313 |
+
num_start = idx + 1
|
314 |
+
num_end = find_matching_brace(l_split, num_start)
|
315 |
+
den_start = num_end + 1
|
316 |
+
den_end = find_matching_brace(l_split, den_start)
|
317 |
+
l_split_copy = l_split[:idx] + [r'\mathcolor{black}{'+token+'{'] + \
|
318 |
+
[r'\mathcolor{gray}{'] + l_split[num_start + 1:num_end] + \
|
319 |
+
['}'] + [r'}{'] + [r'\mathcolor{gray}{'] + l_split[den_start + 1:den_end] + \
|
320 |
+
['}'] + ['}'] + ['}'] + l_split[den_end + 1:]
|
321 |
+
|
322 |
+
l_new = ' '.join(l_split_copy)
|
323 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
324 |
+
render_dict[str(idx)] = l_new, token
|
325 |
+
next_idx = idx + 1
|
326 |
+
elif token in ONE_Tail_Tokens:
|
327 |
+
# ** tokens such as \hat A, and the token needs render too.
|
328 |
+
num_start = idx + 1
|
329 |
+
num_end = find_matching_brace(l_split, num_start)
|
330 |
+
l_split_copy = l_split[:idx] + [r'\mathcolor{black}{'] + l_split[idx: num_start+1] + \
|
331 |
+
[r'\mathcolor{gray}{'] + l_split[num_start+1: num_end] + \
|
332 |
+
['}'] + l_split[num_end: num_end+1] + ['}'] + l_split[num_end+1:]
|
333 |
+
l_new = ' '.join(l_split_copy)
|
334 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
335 |
+
render_dict[str(idx)] = l_new, token
|
336 |
+
next_idx = idx + 1
|
337 |
+
elif token in ONE_Tail_Invisb_Tokens:
|
338 |
+
# ** tokens such as \text A B, and the token does not need render.
|
339 |
+
num_start = idx + 1
|
340 |
+
num_end = find_matching_brace(l_split, num_start)
|
341 |
+
sub_idx = num_start+1
|
342 |
+
if num_end-num_start == 2:
|
343 |
+
l_split_copy = l_split.copy()
|
344 |
+
l_split_copy[sub_idx] = r'{\mathcolor{black}{' + l_split_copy[sub_idx] + '}}'
|
345 |
+
l_new = ' '.join(l_split_copy)
|
346 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
347 |
+
render_dict[str(idx)] = l_new, l_split[sub_idx]
|
348 |
+
next_idx = num_end
|
349 |
+
else:
|
350 |
+
while sub_idx < num_end:
|
351 |
+
l_split, sub_idx, render_dict = token_add_color(l_split, sub_idx, render_dict)
|
352 |
+
next_idx = num_end + 1
|
353 |
+
elif token in AB_Tail_Tokens:
|
354 |
+
# ** special token \xrightarrow, could be \xrightarrow [] {} or \xrightarrow {}, process method are different.
|
355 |
+
if l_split[idx+1] == '{':
|
356 |
+
num_start = idx + 1
|
357 |
+
num_end = find_matching_brace(l_split, num_start)
|
358 |
+
l_split_copy = l_split[:idx] + [r'\mathcolor{black}{'] + l_split[idx: idx+2] \
|
359 |
+
+ [r'\mathcolor{gray}{'] + l_split[num_start+1: num_end] + ['}}'] + l_split[num_end:]
|
360 |
+
l_new = ' '.join(l_split_copy)
|
361 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
362 |
+
render_dict[str(idx)] = l_new, token
|
363 |
+
sub_idx = num_start+1
|
364 |
+
while sub_idx < num_end:
|
365 |
+
l_split, sub_idx, render_dict = token_add_color(l_split, sub_idx, render_dict)
|
366 |
+
next_idx = num_end + 1
|
367 |
+
elif l_split[idx+1] == '[':
|
368 |
+
num_start = idx + 1
|
369 |
+
num_end = find_matching_brace(l_split, num_start, brace=['[', ']'])
|
370 |
+
den_start = num_end + 1
|
371 |
+
den_end = find_matching_brace(l_split, den_start)
|
372 |
+
l_split_copy = l_split[:idx] + [r'{\mathcolor{black}{'] + l_split[idx: idx+2] \
|
373 |
+
+ [r'\mathcolor{gray}{'] + l_split[idx+2: num_end] + ['}'] + l_split[num_end:den_start+1] \
|
374 |
+
+ [r'\mathcolor{gray}{'] + l_split[den_start+1: den_end] + ['}'] + l_split[den_end: den_end+1] \
|
375 |
+
+ ['}}'] + l_split[den_end+1:]
|
376 |
+
l_new = ' '.join(l_split_copy)
|
377 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
378 |
+
render_dict[str(idx)] = l_new, token
|
379 |
+
sub_idx = num_start + 1
|
380 |
+
while sub_idx < num_end:
|
381 |
+
l_split, sub_idx, render_dict = token_add_color(l_split, sub_idx, render_dict)
|
382 |
+
sub_idx = den_start + 1
|
383 |
+
while sub_idx < den_end:
|
384 |
+
l_split, sub_idx, render_dict = token_add_color(l_split, sub_idx, render_dict)
|
385 |
+
next_idx = den_end + 1
|
386 |
+
elif token in ["\\multicolumn", "\\multirow"]:
|
387 |
+
# ** tokens with three {}, such as \multicolumn {} {} {}, the text in third {} need be rendered.
|
388 |
+
first_start = idx + 1
|
389 |
+
first_end = find_matching_brace(l_split, first_start)
|
390 |
+
second_start = first_end + 1
|
391 |
+
second_end = find_matching_brace(l_split, second_start)
|
392 |
+
third_start = second_end + 1
|
393 |
+
third_end = find_matching_brace(l_split, third_start)
|
394 |
+
|
395 |
+
sub_idx = third_start+1
|
396 |
+
while sub_idx < third_end:
|
397 |
+
l_split, sub_idx, render_dict = token_add_color(l_split, sub_idx, render_dict)
|
398 |
+
next_idx = third_end + 1
|
399 |
+
elif token in SKIP_Tokens+TWO_Tail_Invisb_Tokens or any(re.match(pattern, token) for pattern in SKIP_PATTERNS):
|
400 |
+
# ** tokens no need render, just skip
|
401 |
+
# print('skip', idx, token)
|
402 |
+
# TODO special case :[], could be single, or in \sqrt[]{}.
|
403 |
+
if (token == "[" and l_split[idx-1]!="\\sqrt") or (token == "]" and idx>=3 and l_split[idx-3]!="\\sqrt"):
|
404 |
+
l_split_copy = l_split.copy()
|
405 |
+
l_split_copy[idx] = r'\mathcolor{black}{ ' + l_split_copy[idx] + ' }'
|
406 |
+
l_new = ' '.join(l_split_copy)
|
407 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
408 |
+
render_dict[str(idx)] = l_new, token
|
409 |
+
next_idx = idx + 1
|
410 |
+
else:
|
411 |
+
next_idx = idx + 1
|
412 |
+
else:
|
413 |
+
# ** nomal token
|
414 |
+
l_split_copy = l_split.copy()
|
415 |
+
# TODO sometimes there is translation after add color, the exp prove that \mathcolor{black}{ A } is better than \mathcolor{black}{A}
|
416 |
+
l_split_copy[idx] = r'\mathcolor{black}{ ' + l_split_copy[idx] + ' }'
|
417 |
+
|
418 |
+
l_new = ' '.join(l_split_copy)
|
419 |
+
l_new = r'\mathcolor{gray}{ ' + l_new + ' }'
|
420 |
+
render_dict[str(idx)] = l_new, token
|
421 |
+
next_idx = idx + 1
|
422 |
+
|
423 |
+
return l_split, next_idx, render_dict
|
424 |
+
|
425 |
+
|
426 |
+
def token_add_color_RGB(l_split, idx, token_list, brace_color=False):
|
427 |
+
"""using \mathcolor[RGB]{r,g,b} to render latex.
|
428 |
+
"""
|
429 |
+
token = l_split[idx]
|
430 |
+
if not token:
|
431 |
+
next_idx = idx + 1
|
432 |
+
elif token in PHANTOM_Tokens:
|
433 |
+
# ** special tokens that do not need render, skip it
|
434 |
+
if l_split[idx + 1] == '{':
|
435 |
+
brace_end = find_matching_brace(l_split, idx + 1)
|
436 |
+
else:
|
437 |
+
brace_end = idx + 1
|
438 |
+
next_idx = brace_end + 1
|
439 |
+
elif token in TWO_Tail_Tokens:
|
440 |
+
# ** tokens such as \frac A B, and the token needs render too.
|
441 |
+
num_start = idx + 1
|
442 |
+
num_end = find_matching_brace(l_split, num_start)
|
443 |
+
den_start = num_end + 1
|
444 |
+
den_end = find_matching_brace(l_split, den_start)
|
445 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
446 |
+
l_split = l_split[:idx] + [color_token+token] + l_split[idx+1: den_end+1] + ["}"] + l_split[den_end+1:]
|
447 |
+
token_list.append(token)
|
448 |
+
next_idx = idx + 1
|
449 |
+
elif token in ONE_Tail_Tokens:
|
450 |
+
# ** tokens such as \hat A, and the token needs render too.
|
451 |
+
num_start = idx + 1
|
452 |
+
num_end = find_matching_brace(l_split, num_start)
|
453 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
454 |
+
if token != "\\underbrace" and num_end+1 < len(l_split) and l_split[num_end+1] == "_":
|
455 |
+
l_split = l_split[:idx] + ["{"+color_token+token] + l_split[idx+1: num_end+1] + ["}}"] + l_split[num_end+1:]
|
456 |
+
else:
|
457 |
+
l_split = l_split[:idx] + [color_token+token] + l_split[idx+1: num_end+1] + ["}"] + l_split[num_end+1:]
|
458 |
+
token_list.append(token)
|
459 |
+
next_idx = idx + 1
|
460 |
+
elif token in ONE_Tail_Invisb_Tokens:
|
461 |
+
# ** tokens such as \text A B, and the token does not need render.
|
462 |
+
num_start = idx + 1
|
463 |
+
num_end = find_matching_brace(l_split, num_start)
|
464 |
+
sub_idx = num_start+1
|
465 |
+
if num_end-num_start == 2:
|
466 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
467 |
+
token_list.append(l_split[num_start+1])
|
468 |
+
l_split = l_split[:num_start+1] + [color_token+l_split[num_start+1]+"}"] + l_split[num_end:]
|
469 |
+
else:
|
470 |
+
while sub_idx < num_end:
|
471 |
+
l_split, sub_idx, token_list = token_add_color_RGB(l_split, sub_idx, token_list)
|
472 |
+
next_idx = num_end + 1
|
473 |
+
elif token in AB_Tail_Tokens:
|
474 |
+
# ** special token \xrightarrow, could be \xrightarrow [] {} or \xrightarrow {}, process method are different.
|
475 |
+
if l_split[idx+1] == '{':
|
476 |
+
num_start = idx + 1
|
477 |
+
num_end = find_matching_brace(l_split, num_start)
|
478 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
479 |
+
l_split = l_split[:idx] + [color_token+token] + l_split[idx+1: num_end+1] + ["}"] + l_split[num_end+1:]
|
480 |
+
token_list.append(token)
|
481 |
+
sub_idx = num_start+1
|
482 |
+
while sub_idx < num_end:
|
483 |
+
l_split, sub_idx, token_list = token_add_color_RGB(l_split, sub_idx, token_list)
|
484 |
+
next_idx = num_end + 1
|
485 |
+
elif l_split[idx+1] == '[':
|
486 |
+
num_start = idx + 1
|
487 |
+
num_end = find_matching_brace(l_split, num_start, brace=['[', ']'])
|
488 |
+
den_start = num_end + 1
|
489 |
+
den_end = find_matching_brace(l_split, den_start)
|
490 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
491 |
+
l_split = l_split[:idx] + [color_token+token] + l_split[idx+1: den_end+1] + ["}"] + l_split[den_end+1:]
|
492 |
+
token_list.append(token)
|
493 |
+
sub_idx = num_start + 1
|
494 |
+
while sub_idx < num_end:
|
495 |
+
l_split, sub_idx, token_list = token_add_color_RGB(l_split, sub_idx, token_list, brace_color=True)
|
496 |
+
sub_idx = den_start + 1
|
497 |
+
while sub_idx < den_end:
|
498 |
+
l_split, sub_idx, token_list = token_add_color_RGB(l_split, sub_idx, token_list)
|
499 |
+
next_idx = den_end + 1
|
500 |
+
elif token in ["\\multicolumn", "\\multirow"]:
|
501 |
+
# ** tokens with three {}, such as \multicolumn {} {} {}, the text in third {} need be rendered.
|
502 |
+
first_start = idx + 1
|
503 |
+
first_end = find_matching_brace(l_split, first_start)
|
504 |
+
second_start = first_end + 1
|
505 |
+
second_end = find_matching_brace(l_split, second_start)
|
506 |
+
third_start = second_end + 1
|
507 |
+
third_end = find_matching_brace(l_split, third_start)
|
508 |
+
|
509 |
+
sub_idx = third_start+1
|
510 |
+
while sub_idx < third_end:
|
511 |
+
l_split, sub_idx, token_list = token_add_color_RGB(l_split, sub_idx, token_list)
|
512 |
+
next_idx = third_end + 1
|
513 |
+
elif token in SKIP_Tokens+TWO_Tail_Invisb_Tokens or any(re.match(pattern, token) for pattern in SKIP_PATTERNS):
|
514 |
+
# ** tokens no need render, just skip
|
515 |
+
# print('skip', idx, token)
|
516 |
+
# TODO special case :[], could be single, or in \sqrt[]{}.
|
517 |
+
if (token == "[" and l_split[idx-1]!="\\sqrt") or (token == "]" and idx>=3 and l_split[idx-3]!="\\sqrt"):
|
518 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
519 |
+
l_split = l_split[:idx] + [color_token + l_split[idx] + "}"] + l_split[idx+1:]
|
520 |
+
token_list.append(token)
|
521 |
+
next_idx = idx + 1
|
522 |
+
else:
|
523 |
+
next_idx = idx + 1
|
524 |
+
else:
|
525 |
+
# ** nomal token
|
526 |
+
if brace_color or (idx > 1 and l_split[idx-1] == "_"):
|
527 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
528 |
+
l_split = l_split[:idx] + ["{" + color_token + l_split[idx] + "}}"] + l_split[idx+1:]
|
529 |
+
token_list.append(token)
|
530 |
+
next_idx = idx + 1
|
531 |
+
else:
|
532 |
+
color_token = "\\mathcolor[RGB]{<color_<idx>>}{".replace("<idx>", str(len(token_list)))
|
533 |
+
l_split = l_split[:idx] + [color_token + l_split[idx] + "}"] + l_split[idx+1:]
|
534 |
+
token_list.append(token)
|
535 |
+
next_idx = idx + 1
|
536 |
+
return l_split, next_idx, token_list
|
modules/latex_render_percentage.py
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
import os
|
3 |
+
import json
|
4 |
+
import time
|
5 |
+
import shutil
|
6 |
+
import random
|
7 |
+
import argparse
|
8 |
+
import subprocess
|
9 |
+
import numpy as np
|
10 |
+
|
11 |
+
from tqdm import tqdm
|
12 |
+
from multiprocessing import Pool
|
13 |
+
|
14 |
+
|
15 |
+
formular_template = r"""
|
16 |
+
\documentclass[12pt]{article}
|
17 |
+
\usepackage[landscape]{geometry}
|
18 |
+
\usepackage{geometry}
|
19 |
+
\geometry{a5paper,scale=0.98}
|
20 |
+
\pagestyle{empty}
|
21 |
+
\usepackage{booktabs}
|
22 |
+
\usepackage{amsmath}
|
23 |
+
\usepackage{amssymb}
|
24 |
+
\usepackage{xcolor}
|
25 |
+
\begin{document}
|
26 |
+
\makeatletter
|
27 |
+
\renewcommand*{\@textcolor}[3]{%%
|
28 |
+
\protect\leavevmode
|
29 |
+
\begingroup
|
30 |
+
\color#1{#2}#3%%
|
31 |
+
\endgroup
|
32 |
+
}
|
33 |
+
\makeatother
|
34 |
+
\begin{displaymath}
|
35 |
+
%s
|
36 |
+
\end{displaymath}
|
37 |
+
\end{document}
|
38 |
+
"""
|
39 |
+
|
40 |
+
def run_shell_cmd(cmd, max_time=15):
|
41 |
+
child = subprocess.Popen(cmd, shell=True)
|
42 |
+
for i in range(max_time):
|
43 |
+
if child.poll():
|
44 |
+
return True
|
45 |
+
if i == max_time-1:
|
46 |
+
child.kill()
|
47 |
+
return False
|
48 |
+
time.sleep(1)
|
49 |
+
return False
|
50 |
+
|
51 |
+
def render_latex(latex_code, basename, latex_dir, pdf_dir):
|
52 |
+
latex_path = os.path.join(latex_dir, basename + ".tex")
|
53 |
+
pdf_path = os.path.join(pdf_dir, basename + ".pdf")
|
54 |
+
with open(latex_path, "w") as f:
|
55 |
+
f.write(formular_template % latex_code)
|
56 |
+
cmd = f"pdflatex -interaction=nonstopmode -output-directory={pdf_dir} -output-format=pdf {latex_path} >/dev/null"
|
57 |
+
run_shell_cmd(cmd)
|
58 |
+
return pdf_path
|
59 |
+
|
60 |
+
|
61 |
+
if __name__ == "__main__":
|
62 |
+
parser = argparse.ArgumentParser()
|
63 |
+
parser.add_argument('--input', '-i', type=str, default='data/pred_results/test.json')
|
64 |
+
parser.add_argument('--clean', action='store_true', default=False)
|
65 |
+
parser.add_argument('--gt', action='store_true', default=False)
|
66 |
+
args = parser.parse_args()
|
67 |
+
|
68 |
+
if args.gt:
|
69 |
+
output_path = os.path.join("output", 'gt.json')
|
70 |
+
load_key = 'gt'
|
71 |
+
else:
|
72 |
+
load_key = 'pred'
|
73 |
+
output_path = os.path.join("output", os.path.basename(args.input))
|
74 |
+
|
75 |
+
|
76 |
+
temp_dir=f"render_temp_dir"
|
77 |
+
try:
|
78 |
+
shutil.rmtree(temp_dir)
|
79 |
+
except:
|
80 |
+
pass
|
81 |
+
latex_dir = os.path.join(temp_dir, "texes")
|
82 |
+
pdf_dir = os.path.join(temp_dir, "pdfs")
|
83 |
+
os.makedirs(latex_dir, exist_ok=True)
|
84 |
+
os.makedirs(pdf_dir, exist_ok=True)
|
85 |
+
|
86 |
+
with open(args.input, "r") as f:
|
87 |
+
input_data = json.load(f)
|
88 |
+
|
89 |
+
myP = Pool(200)
|
90 |
+
for idx, item in enumerate(input_data):
|
91 |
+
basename = f"sample_{idx}"
|
92 |
+
myP.apply_async(render_latex, args=(item[load_key], basename, latex_dir, pdf_dir))
|
93 |
+
myP.close()
|
94 |
+
print("processing, may take some times.")
|
95 |
+
myP.join()
|
96 |
+
|
97 |
+
success_num = 0
|
98 |
+
total_num = 0
|
99 |
+
for idx, item in enumerate(input_data):
|
100 |
+
basename = f"sample_{idx}"
|
101 |
+
total_num += 1
|
102 |
+
pdf_path = os.path.join(pdf_dir, basename + ".pdf")
|
103 |
+
if os.path.exists(pdf_path):
|
104 |
+
success_num += 1
|
105 |
+
item['renderable'] = 1
|
106 |
+
else:
|
107 |
+
item['renderable'] = 0
|
108 |
+
|
109 |
+
print("total num:", total_num, "render success num:", success_num)
|
110 |
+
with open(output_path, "w") as f:
|
111 |
+
f.write(json.dumps(input_data, indent=2))
|
112 |
+
if args.clean:
|
113 |
+
try:
|
114 |
+
shutil.rmtree(temp_dir)
|
115 |
+
except:
|
116 |
+
pass
|
modules/tokenize_latex/preprocess_formula.js
ADDED
@@ -0,0 +1,387 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const path = require('path');
|
2 |
+
var katex = require(path.join(__dirname,"third_party/katex/katex.js"))
|
3 |
+
options = require(path.join(__dirname,"third_party/katex/src/Options.js"))
|
4 |
+
var readline = require('readline');
|
5 |
+
var rl = readline.createInterface({
|
6 |
+
input: process.stdin,
|
7 |
+
output: process.stdout,
|
8 |
+
terminal: false
|
9 |
+
});
|
10 |
+
|
11 |
+
|
12 |
+
rl.on('line', function(line){
|
13 |
+
a = line
|
14 |
+
if (line[0] == "%") {
|
15 |
+
line = line.substr(1, line.length - 1);
|
16 |
+
}
|
17 |
+
line = line.split('%')[0];
|
18 |
+
|
19 |
+
line = line.split('\\~').join(' ');
|
20 |
+
|
21 |
+
for (var i = 0; i < 300; i++) {
|
22 |
+
line = line.replace(/\\>/, " ");
|
23 |
+
line = line.replace('$', ' ');
|
24 |
+
line = line.replace(/\\label{.*?}/, "");
|
25 |
+
}
|
26 |
+
|
27 |
+
if (line.indexOf("matrix") == -1 && line.indexOf("cases")==-1 &&
|
28 |
+
line.indexOf("array")==-1 && line.indexOf("begin")==-1) {
|
29 |
+
for (var i = 0; i < 300; i++) {
|
30 |
+
line = line.replace(/\\\\/, "\\,");
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
line = line + " "
|
36 |
+
// global_str is tokenized version (build in parser.js)
|
37 |
+
// norm_str is normalized version build by renderer below.
|
38 |
+
try {
|
39 |
+
|
40 |
+
|
41 |
+
if (process.argv[2] == "tokenize") {
|
42 |
+
var tree = katex.__parse(line, {});
|
43 |
+
console.log(global_str.replace(/\\label { .*? }/, ""));
|
44 |
+
} else {
|
45 |
+
for (var i = 0; i < 300; ++i) {
|
46 |
+
line = line.replace(/{\\rm/, "\\mathrm{");
|
47 |
+
line = line.replace(/{ \\rm/, "\\mathrm{");
|
48 |
+
line = line.replace(/\\rm{/, "\\mathrm{");
|
49 |
+
}
|
50 |
+
|
51 |
+
var tree = katex.__parse(line, {});
|
52 |
+
buildExpression(tree, new options({}));
|
53 |
+
for (var i = 0; i < 300; ++i) {
|
54 |
+
norm_str = norm_str.replace('SSSSSS', '$');
|
55 |
+
norm_str = norm_str.replace(' S S S S S S', '$');
|
56 |
+
}
|
57 |
+
console.log(norm_str.replace(/\\label { .*? }/, ""));
|
58 |
+
}
|
59 |
+
} catch (e) {
|
60 |
+
console.error(line);
|
61 |
+
console.error(norm_str);
|
62 |
+
console.error(e);
|
63 |
+
console.log();
|
64 |
+
}
|
65 |
+
global_str = ""
|
66 |
+
norm_str = ""
|
67 |
+
})
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
// This is a LaTeX AST to LaTeX Renderer (modified version of KaTeX AST-> MathML).
|
72 |
+
norm_str = ""
|
73 |
+
|
74 |
+
var groupTypes = {};
|
75 |
+
|
76 |
+
groupTypes.mathord = function(group, options) {
|
77 |
+
if (options.font == "mathrm"){
|
78 |
+
for (i = 0; i < group.value.length; ++i ) {
|
79 |
+
if (group.value[i] == " ") {
|
80 |
+
norm_str = norm_str + group.value[i] + "\; ";
|
81 |
+
} else {
|
82 |
+
norm_str = norm_str + group.value[i] + " ";
|
83 |
+
}
|
84 |
+
}
|
85 |
+
} else {
|
86 |
+
norm_str = norm_str + group.value + " ";
|
87 |
+
}
|
88 |
+
};
|
89 |
+
|
90 |
+
groupTypes.textord = function(group, options) {
|
91 |
+
norm_str = norm_str + group.value + " ";
|
92 |
+
};
|
93 |
+
|
94 |
+
groupTypes.bin = function(group) {
|
95 |
+
norm_str = norm_str + group.value + " ";
|
96 |
+
};
|
97 |
+
|
98 |
+
groupTypes.rel = function(group) {
|
99 |
+
norm_str = norm_str + group.value + " ";
|
100 |
+
};
|
101 |
+
|
102 |
+
groupTypes.open = function(group) {
|
103 |
+
norm_str = norm_str + group.value + " ";
|
104 |
+
};
|
105 |
+
|
106 |
+
groupTypes.close = function(group) {
|
107 |
+
norm_str = norm_str + group.value + " ";
|
108 |
+
};
|
109 |
+
|
110 |
+
groupTypes.inner = function(group) {
|
111 |
+
norm_str = norm_str + group.value + " ";
|
112 |
+
};
|
113 |
+
|
114 |
+
groupTypes.punct = function(group) {
|
115 |
+
norm_str = norm_str + group.value + " ";
|
116 |
+
};
|
117 |
+
|
118 |
+
groupTypes.ordgroup = function(group, options) {
|
119 |
+
norm_str = norm_str + "{ ";
|
120 |
+
|
121 |
+
buildExpression(group.value, options);
|
122 |
+
|
123 |
+
norm_str = norm_str + "} ";
|
124 |
+
};
|
125 |
+
|
126 |
+
groupTypes.text = function(group, options) {
|
127 |
+
|
128 |
+
norm_str = norm_str + "\\mathrm { ";
|
129 |
+
|
130 |
+
buildExpression(group.value.body, options);
|
131 |
+
norm_str = norm_str + "} ";
|
132 |
+
};
|
133 |
+
|
134 |
+
groupTypes.color = function(group, options) {
|
135 |
+
var inner = buildExpression(group.value.value, options);
|
136 |
+
|
137 |
+
var node = new mathMLTree.MathNode("mstyle", inner);
|
138 |
+
|
139 |
+
node.setAttribute("mathcolor", group.value.color);
|
140 |
+
|
141 |
+
return node;
|
142 |
+
};
|
143 |
+
|
144 |
+
groupTypes.supsub = function(group, options) {
|
145 |
+
buildGroup(group.value.base, options);
|
146 |
+
|
147 |
+
if (group.value.sub) {
|
148 |
+
norm_str = norm_str + "_ ";
|
149 |
+
if (group.value.sub.type != 'ordgroup') {
|
150 |
+
norm_str = norm_str + " { ";
|
151 |
+
buildGroup(group.value.sub, options);
|
152 |
+
norm_str = norm_str + "} ";
|
153 |
+
} else {
|
154 |
+
buildGroup(group.value.sub, options);
|
155 |
+
}
|
156 |
+
|
157 |
+
}
|
158 |
+
|
159 |
+
if (group.value.sup) {
|
160 |
+
norm_str = norm_str + "^ ";
|
161 |
+
if (group.value.sup.type != 'ordgroup') {
|
162 |
+
norm_str = norm_str + " { ";
|
163 |
+
buildGroup(group.value.sup, options);
|
164 |
+
norm_str = norm_str + "} ";
|
165 |
+
} else {
|
166 |
+
buildGroup(group.value.sup, options);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
};
|
171 |
+
|
172 |
+
groupTypes.genfrac = function(group, options) {
|
173 |
+
if (!group.value.hasBarLine) {
|
174 |
+
norm_str = norm_str + "\\binom ";
|
175 |
+
} else {
|
176 |
+
norm_str = norm_str + "\\frac ";
|
177 |
+
}
|
178 |
+
buildGroup(group.value.numer, options);
|
179 |
+
buildGroup(group.value.denom, options);
|
180 |
+
|
181 |
+
};
|
182 |
+
|
183 |
+
groupTypes.array = function(group, options) {
|
184 |
+
norm_str = norm_str + "\\begin{array} { ";
|
185 |
+
if (group.value.cols) {
|
186 |
+
group.value.cols.map(function(start) {
|
187 |
+
if (start && start.align) {
|
188 |
+
norm_str = norm_str + start.align + " ";}});
|
189 |
+
} else {
|
190 |
+
group.value.body[0].map(function(start) {
|
191 |
+
norm_str = norm_str + "l ";
|
192 |
+
} );
|
193 |
+
}
|
194 |
+
norm_str = norm_str + "} ";
|
195 |
+
group.value.body.map(function(row) {
|
196 |
+
if (row.some(cell => cell.value.length > 0)) { // orginal code: if (row[0].value.length > 0)
|
197 |
+
out = row.map(function(cell) {
|
198 |
+
buildGroup(cell, options);
|
199 |
+
if (norm_str.length > 4
|
200 |
+
&& norm_str.substring(norm_str.length-4, norm_str.length) == "{ } ") {
|
201 |
+
norm_str = norm_str.substring(0, norm_str.length-4) ;
|
202 |
+
}
|
203 |
+
norm_str = norm_str + "& ";
|
204 |
+
});
|
205 |
+
norm_str = norm_str.substring(0, norm_str.length-2) + "\\\\ ";
|
206 |
+
}
|
207 |
+
});
|
208 |
+
norm_str = norm_str + "\\end{array} ";
|
209 |
+
};
|
210 |
+
|
211 |
+
groupTypes.sqrt = function(group, options) {
|
212 |
+
var node;
|
213 |
+
if (group.value.index) {
|
214 |
+
norm_str = norm_str + "\\sqrt [ ";
|
215 |
+
buildExpression(group.value.index.value, options);
|
216 |
+
norm_str = norm_str + "] ";
|
217 |
+
buildGroup(group.value.body, options);
|
218 |
+
} else {
|
219 |
+
norm_str = norm_str + "\\sqrt ";
|
220 |
+
buildGroup(group.value.body, options);
|
221 |
+
}
|
222 |
+
};
|
223 |
+
|
224 |
+
groupTypes.leftright = function(group, options) {
|
225 |
+
|
226 |
+
|
227 |
+
|
228 |
+
norm_str = norm_str + "\\left" + group.value.left + " ";
|
229 |
+
buildExpression(group.value.body, options);
|
230 |
+
norm_str = norm_str + "\\right" + group.value.right + " ";
|
231 |
+
};
|
232 |
+
|
233 |
+
groupTypes.accent = function(group, options) {
|
234 |
+
if (group.value.base.type != 'ordgroup') {
|
235 |
+
norm_str = norm_str + group.value.accent + " { ";
|
236 |
+
buildGroup(group.value.base, options);
|
237 |
+
norm_str = norm_str + "} ";
|
238 |
+
} else {
|
239 |
+
norm_str = norm_str + group.value.accent + " ";
|
240 |
+
buildGroup(group.value.base, options);
|
241 |
+
}
|
242 |
+
};
|
243 |
+
|
244 |
+
groupTypes.spacing = function(group) {
|
245 |
+
var node;
|
246 |
+
if (group.value == " ") {
|
247 |
+
norm_str = norm_str + "~ ";
|
248 |
+
} else {
|
249 |
+
norm_str = norm_str + group.value + " ";
|
250 |
+
}
|
251 |
+
return node;
|
252 |
+
};
|
253 |
+
|
254 |
+
groupTypes.op = function(group) {
|
255 |
+
var node;
|
256 |
+
|
257 |
+
// TODO(emily): handle big operators using the `largeop` attribute
|
258 |
+
|
259 |
+
|
260 |
+
if (group.value.symbol) {
|
261 |
+
// This is a symbol. Just add the symbol.
|
262 |
+
norm_str = norm_str + group.value.body + " ";
|
263 |
+
|
264 |
+
} else {
|
265 |
+
if (group.value.limits == false) {
|
266 |
+
norm_str = norm_str + "\\\operatorname { ";
|
267 |
+
} else {
|
268 |
+
norm_str = norm_str + "\\\operatorname* { ";
|
269 |
+
}
|
270 |
+
for (i = 1; i < group.value.body.length; ++i ) {
|
271 |
+
norm_str = norm_str + group.value.body[i] + " ";
|
272 |
+
}
|
273 |
+
norm_str = norm_str + "} ";
|
274 |
+
}
|
275 |
+
};
|
276 |
+
|
277 |
+
groupTypes.katex = function(group) {
|
278 |
+
var node = new mathMLTree.MathNode(
|
279 |
+
"mtext", [new mathMLTree.TextNode("KaTeX")]);
|
280 |
+
|
281 |
+
return node;
|
282 |
+
};
|
283 |
+
|
284 |
+
|
285 |
+
|
286 |
+
groupTypes.font = function(group, options) {
|
287 |
+
var font = group.value.font;
|
288 |
+
if (font == "mbox" || font == "hbox") {
|
289 |
+
font = "mathrm";
|
290 |
+
}
|
291 |
+
norm_str = norm_str + "\\" + font + " ";
|
292 |
+
buildGroup(group.value.body, options.withFont(font));
|
293 |
+
};
|
294 |
+
|
295 |
+
groupTypes.delimsizing = function(group) {
|
296 |
+
var children = [];
|
297 |
+
norm_str = norm_str + group.value.funcName + " " + group.value.value + " ";
|
298 |
+
};
|
299 |
+
|
300 |
+
groupTypes.styling = function(group, options) {
|
301 |
+
norm_str = norm_str + " " + group.value.original + " ";
|
302 |
+
buildExpression(group.value.value, options);
|
303 |
+
|
304 |
+
};
|
305 |
+
|
306 |
+
groupTypes.sizing = function(group, options) {
|
307 |
+
|
308 |
+
if (group.value.original == "\\rm") {
|
309 |
+
norm_str = norm_str + "\\mathrm { ";
|
310 |
+
buildExpression(group.value.value, options.withFont("mathrm"));
|
311 |
+
norm_str = norm_str + "} ";
|
312 |
+
} else {
|
313 |
+
norm_str = norm_str + " " + group.value.original + " ";
|
314 |
+
buildExpression(group.value.value, options);
|
315 |
+
}
|
316 |
+
};
|
317 |
+
|
318 |
+
groupTypes.overline = function(group, options) {
|
319 |
+
norm_str = norm_str + "\\overline { ";
|
320 |
+
|
321 |
+
buildGroup(group.value.body, options);
|
322 |
+
norm_str = norm_str + "} ";
|
323 |
+
norm_str = norm_str;
|
324 |
+
|
325 |
+
};
|
326 |
+
|
327 |
+
groupTypes.underline = function(group, options) {
|
328 |
+
norm_str = norm_str + "\\underline { ";
|
329 |
+
buildGroup(group.value.body, options);
|
330 |
+
norm_str = norm_str + "} ";
|
331 |
+
|
332 |
+
norm_str = norm_str;
|
333 |
+
|
334 |
+
};
|
335 |
+
|
336 |
+
groupTypes.rule = function(group) {
|
337 |
+
norm_str = norm_str + "\\rule { "+group.value.width.number+" "+group.value.width.unit+" } { "+group.value.height.number+" "+group.value.height.unit+ " } ";
|
338 |
+
|
339 |
+
};
|
340 |
+
|
341 |
+
groupTypes.llap = function(group, options) {
|
342 |
+
norm_str = norm_str + "\\llap ";
|
343 |
+
buildGroup(group.value.body, options);
|
344 |
+
};
|
345 |
+
|
346 |
+
groupTypes.rlap = function(group, options) {
|
347 |
+
norm_str = norm_str + "\\rlap ";
|
348 |
+
buildGroup(group.value.body, options);
|
349 |
+
|
350 |
+
};
|
351 |
+
|
352 |
+
groupTypes.phantom = function(group, options, prev) {
|
353 |
+
norm_str = norm_str + "\\phantom { ";
|
354 |
+
buildExpression(group.value.value, options);
|
355 |
+
norm_str = norm_str + "} ";
|
356 |
+
|
357 |
+
};
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Takes a list of nodes, builds them, and returns a list of the generated
|
361 |
+
* MathML nodes. A little simpler than the HTML version because we don't do any
|
362 |
+
* previous-node handling.
|
363 |
+
*/
|
364 |
+
var buildExpression = function(expression, options) {
|
365 |
+
var groups = [];
|
366 |
+
for (var i = 0; i < expression.length; i++) {
|
367 |
+
var group = expression[i];
|
368 |
+
buildGroup(group, options);
|
369 |
+
}
|
370 |
+
// console.log(norm_str);
|
371 |
+
// return groups;
|
372 |
+
};
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Takes a group from the parser and calls the appropriate groupTypes function
|
376 |
+
* on it to produce a MathML node.
|
377 |
+
*/
|
378 |
+
var buildGroup = function(group, options) {
|
379 |
+
if (groupTypes[group.type]) {
|
380 |
+
groupTypes[group.type](group, options);
|
381 |
+
} else {
|
382 |
+
throw new ParseError(
|
383 |
+
"Got group of unknown type: '" + group.type + "'");
|
384 |
+
}
|
385 |
+
};
|
386 |
+
|
387 |
+
|
modules/tokenize_latex/preprocess_tabular.js
ADDED
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const path = require('path');
|
2 |
+
var katex = require(path.join(__dirname,"third_party/katex/katex.js"))
|
3 |
+
options = require(path.join(__dirname,"third_party/katex/src/Options.js"))
|
4 |
+
var readline = require('readline');
|
5 |
+
var rl = readline.createInterface({
|
6 |
+
input: process.stdin,
|
7 |
+
output: process.stdout,
|
8 |
+
terminal: false
|
9 |
+
});
|
10 |
+
|
11 |
+
|
12 |
+
rl.on('line', function(line){
|
13 |
+
a = line
|
14 |
+
if (line[0] == "%") {
|
15 |
+
line = line.substr(1, line.length - 1);
|
16 |
+
}
|
17 |
+
// line = line.split('%')[0];
|
18 |
+
|
19 |
+
line = line.split('\\~').join(' ');
|
20 |
+
|
21 |
+
for (var i = 0; i < 300; i++) {
|
22 |
+
line = line.replace(/\\>/, " ");
|
23 |
+
// line = line.replace('$', ' ');
|
24 |
+
line = line.replace(/\\label{.*?}/, "");
|
25 |
+
}
|
26 |
+
|
27 |
+
if (line.indexOf("matrix") == -1 && line.indexOf("cases")==-1 &&
|
28 |
+
line.indexOf("array")==-1 && line.indexOf("begin")==-1) {
|
29 |
+
for (var i = 0; i < 300; i++) {
|
30 |
+
line = line.replace(/\\\\/, "\\,");
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
line = line + " "
|
36 |
+
// global_str is tokenized version (build in parser.js)
|
37 |
+
// norm_str is normalized version build by renderer below.
|
38 |
+
try {
|
39 |
+
|
40 |
+
|
41 |
+
if (process.argv[2] == "tokenize") {
|
42 |
+
var tree = katex.__parse(line, {});
|
43 |
+
console.log(global_str.replace(/\\label { .*? }/, ""));
|
44 |
+
} else {
|
45 |
+
for (var i = 0; i < 300; ++i) {
|
46 |
+
line = line.replace(/{\\rm/, "\\mathrm{");
|
47 |
+
line = line.replace(/{ \\rm/, "\\mathrm{");
|
48 |
+
line = line.replace(/\\rm{/, "\\mathrm{");
|
49 |
+
}
|
50 |
+
|
51 |
+
var tree = katex.__parse(line, {});
|
52 |
+
buildExpression(tree, new options({}));
|
53 |
+
for (var i = 0; i < 300; ++i) {
|
54 |
+
norm_str = norm_str.replace('SSSSSS', '$');
|
55 |
+
norm_str = norm_str.replace(' S S S S S S', '$');
|
56 |
+
}
|
57 |
+
console.log(norm_str.replace(/\\label { .*? }/, ""));
|
58 |
+
}
|
59 |
+
} catch (e) {
|
60 |
+
console.error(line);
|
61 |
+
console.error(norm_str);
|
62 |
+
console.error(e);
|
63 |
+
console.log("");
|
64 |
+
}
|
65 |
+
global_str = ""
|
66 |
+
norm_str = ""
|
67 |
+
})
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
// This is a LaTeX AST to LaTeX Renderer (modified version of KaTeX AST-> MathML).
|
72 |
+
norm_str = ""
|
73 |
+
|
74 |
+
var groupTypes = {};
|
75 |
+
|
76 |
+
groupTypes.mathord = function(group, options) {
|
77 |
+
if (options.font == "mathrm"){
|
78 |
+
for (i = 0; i < group.value.length; ++i ) {
|
79 |
+
if (group.value[i] == " ") {
|
80 |
+
norm_str = norm_str + group.value[i] + "\; ";
|
81 |
+
} else {
|
82 |
+
norm_str = norm_str + group.value[i] + " ";
|
83 |
+
}
|
84 |
+
}
|
85 |
+
} else {
|
86 |
+
norm_str = norm_str + group.value + " ";
|
87 |
+
}
|
88 |
+
};
|
89 |
+
|
90 |
+
groupTypes.textord = function(group, options) {
|
91 |
+
norm_str = norm_str + group.value + " ";
|
92 |
+
};
|
93 |
+
|
94 |
+
groupTypes.bin = function(group) {
|
95 |
+
norm_str = norm_str + group.value + " ";
|
96 |
+
};
|
97 |
+
|
98 |
+
groupTypes.rel = function(group) {
|
99 |
+
norm_str = norm_str + group.value + " ";
|
100 |
+
};
|
101 |
+
|
102 |
+
groupTypes.open = function(group) {
|
103 |
+
norm_str = norm_str + group.value + " ";
|
104 |
+
};
|
105 |
+
|
106 |
+
groupTypes.close = function(group) {
|
107 |
+
norm_str = norm_str + group.value + " ";
|
108 |
+
};
|
109 |
+
|
110 |
+
groupTypes.inner = function(group) {
|
111 |
+
norm_str = norm_str + group.value + " ";
|
112 |
+
};
|
113 |
+
|
114 |
+
groupTypes.punct = function(group) {
|
115 |
+
norm_str = norm_str + group.value + " ";
|
116 |
+
};
|
117 |
+
|
118 |
+
groupTypes.ordgroup = function(group, options) {
|
119 |
+
norm_str = norm_str + "{ ";
|
120 |
+
|
121 |
+
buildExpression(group.value, options);
|
122 |
+
|
123 |
+
norm_str = norm_str + "} ";
|
124 |
+
};
|
125 |
+
|
126 |
+
groupTypes.text = function(group, options) {
|
127 |
+
|
128 |
+
norm_str = norm_str + "\\mathrm { ";
|
129 |
+
|
130 |
+
buildExpression(group.value.body, options);
|
131 |
+
norm_str = norm_str + "} ";
|
132 |
+
};
|
133 |
+
|
134 |
+
groupTypes.color = function(group, options) {
|
135 |
+
var inner = buildExpression(group.value.value, options);
|
136 |
+
|
137 |
+
var node = new mathMLTree.MathNode("mstyle", inner);
|
138 |
+
|
139 |
+
node.setAttribute("mathcolor", group.value.color);
|
140 |
+
|
141 |
+
return node;
|
142 |
+
};
|
143 |
+
|
144 |
+
groupTypes.supsub = function(group, options) {
|
145 |
+
buildGroup(group.value.base, options);
|
146 |
+
|
147 |
+
if (group.value.sub) {
|
148 |
+
norm_str = norm_str + "_ ";
|
149 |
+
if (group.value.sub.type != 'ordgroup') {
|
150 |
+
norm_str = norm_str + " { ";
|
151 |
+
buildGroup(group.value.sub, options);
|
152 |
+
norm_str = norm_str + "} ";
|
153 |
+
} else {
|
154 |
+
buildGroup(group.value.sub, options);
|
155 |
+
}
|
156 |
+
|
157 |
+
}
|
158 |
+
|
159 |
+
if (group.value.sup) {
|
160 |
+
norm_str = norm_str + "^ ";
|
161 |
+
if (group.value.sup.type != 'ordgroup') {
|
162 |
+
norm_str = norm_str + " { ";
|
163 |
+
buildGroup(group.value.sup, options);
|
164 |
+
norm_str = norm_str + "} ";
|
165 |
+
} else {
|
166 |
+
buildGroup(group.value.sup, options);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
};
|
171 |
+
|
172 |
+
groupTypes.genfrac = function(group, options) {
|
173 |
+
if (!group.value.hasBarLine) {
|
174 |
+
norm_str = norm_str + "\\binom ";
|
175 |
+
} else {
|
176 |
+
norm_str = norm_str + "\\frac ";
|
177 |
+
}
|
178 |
+
buildGroup(group.value.numer, options);
|
179 |
+
buildGroup(group.value.denom, options);
|
180 |
+
|
181 |
+
};
|
182 |
+
|
183 |
+
groupTypes.array = function(group, options) {
|
184 |
+
norm_str = norm_str + "\\begin{" + group.value.style + "} ";
|
185 |
+
|
186 |
+
if (group.value.style == "array" || group.value.style == "tabular" || group.value.style == "tabularx") {
|
187 |
+
norm_str = norm_str + "{ ";
|
188 |
+
if (group.value.cols) {
|
189 |
+
group.value.cols.map(function(start) {
|
190 |
+
if (start) {
|
191 |
+
if (start.type == "align") {
|
192 |
+
norm_str = norm_str + start.align + " ";
|
193 |
+
} else if (start.type == "separator") {
|
194 |
+
norm_str = norm_str + start.separator + " ";
|
195 |
+
}
|
196 |
+
}
|
197 |
+
});
|
198 |
+
} else {
|
199 |
+
group.value.body[0].map(function(start) {
|
200 |
+
norm_str = norm_str + "c ";
|
201 |
+
} );
|
202 |
+
}
|
203 |
+
norm_str = norm_str + "} ";
|
204 |
+
}
|
205 |
+
group.value.body.map(function(row) {
|
206 |
+
if (row.length > 1 || row[0].value.length > 0) {
|
207 |
+
if (row[0].value[0] && row[0].value[0].value == "\\hline") {
|
208 |
+
norm_str = norm_str + "\\hline ";
|
209 |
+
row[0].value = row[0].value.slice(1);
|
210 |
+
}
|
211 |
+
out = row.map(function(cell) {
|
212 |
+
buildGroup(cell, options);
|
213 |
+
norm_str = norm_str + "& ";
|
214 |
+
});
|
215 |
+
norm_str = norm_str.substring(0, norm_str.length-2) + "\\\\ ";
|
216 |
+
}
|
217 |
+
});
|
218 |
+
norm_str = norm_str + "\\end{" + group.value.style + "} ";
|
219 |
+
};
|
220 |
+
|
221 |
+
groupTypes.sqrt = function(group, options) {
|
222 |
+
var node;
|
223 |
+
if (group.value.index) {
|
224 |
+
norm_str = norm_str + "\\sqrt [ " + group.value.index + " ] ";
|
225 |
+
buildGroup(group.value.body, options);
|
226 |
+
} else {
|
227 |
+
norm_str = norm_str + "\\sqrt ";
|
228 |
+
buildGroup(group.value.body, options);
|
229 |
+
}
|
230 |
+
};
|
231 |
+
|
232 |
+
groupTypes.leftright = function(group, options) {
|
233 |
+
|
234 |
+
|
235 |
+
|
236 |
+
norm_str = norm_str + "\\left" + group.value.left + " ";
|
237 |
+
buildExpression(group.value.body, options);
|
238 |
+
norm_str = norm_str + "\\right" + group.value.right + " ";
|
239 |
+
};
|
240 |
+
|
241 |
+
groupTypes.accent = function(group, options) {
|
242 |
+
if (group.value.base.type != 'ordgroup') {
|
243 |
+
norm_str = norm_str + group.value.accent + " { ";
|
244 |
+
buildGroup(group.value.base, options);
|
245 |
+
norm_str = norm_str + "} ";
|
246 |
+
} else {
|
247 |
+
norm_str = norm_str + group.value.accent + " ";
|
248 |
+
buildGroup(group.value.base, options);
|
249 |
+
}
|
250 |
+
};
|
251 |
+
|
252 |
+
groupTypes.spacing = function(group) {
|
253 |
+
var node;
|
254 |
+
if (group.value == " ") {
|
255 |
+
norm_str = norm_str + "~ ";
|
256 |
+
} else {
|
257 |
+
norm_str = norm_str + group.value + " ";
|
258 |
+
}
|
259 |
+
return node;
|
260 |
+
};
|
261 |
+
|
262 |
+
groupTypes.op = function(group) {
|
263 |
+
var node;
|
264 |
+
|
265 |
+
// TODO(emily): handle big operators using the `largeop` attribute
|
266 |
+
|
267 |
+
|
268 |
+
if (group.value.symbol) {
|
269 |
+
// This is a symbol. Just add the symbol.
|
270 |
+
norm_str = norm_str + group.value.body + " ";
|
271 |
+
|
272 |
+
} else {
|
273 |
+
if (group.value.limits == false) {
|
274 |
+
norm_str = norm_str + "\\\operatorname { ";
|
275 |
+
} else {
|
276 |
+
norm_str = norm_str + "\\\operatorname* { ";
|
277 |
+
}
|
278 |
+
for (i = 1; i < group.value.body.length; ++i ) {
|
279 |
+
norm_str = norm_str + group.value.body[i] + " ";
|
280 |
+
}
|
281 |
+
norm_str = norm_str + "} ";
|
282 |
+
}
|
283 |
+
};
|
284 |
+
|
285 |
+
groupTypes.katex = function(group) {
|
286 |
+
var node = new mathMLTree.MathNode(
|
287 |
+
"mtext", [new mathMLTree.TextNode("KaTeX")]);
|
288 |
+
|
289 |
+
return node;
|
290 |
+
};
|
291 |
+
|
292 |
+
|
293 |
+
|
294 |
+
groupTypes.font = function(group, options) {
|
295 |
+
var font = group.value.font;
|
296 |
+
if (font == "mbox" || font == "hbox") {
|
297 |
+
font = "mathrm";
|
298 |
+
}
|
299 |
+
norm_str = norm_str + "\\" + font + " ";
|
300 |
+
buildGroup(group.value.body, options.withFont(font));
|
301 |
+
};
|
302 |
+
|
303 |
+
groupTypes.delimsizing = function(group) {
|
304 |
+
var children = [];
|
305 |
+
norm_str = norm_str + group.value.funcName + " " + group.value.value + " ";
|
306 |
+
};
|
307 |
+
|
308 |
+
groupTypes.styling = function(group, options) {
|
309 |
+
norm_str = norm_str + " " + group.value.original + " ";
|
310 |
+
buildExpression(group.value.value, options);
|
311 |
+
|
312 |
+
};
|
313 |
+
|
314 |
+
groupTypes.sizing = function(group, options) {
|
315 |
+
|
316 |
+
if (group.value.original == "\\rm") {
|
317 |
+
norm_str = norm_str + "\\mathrm { ";
|
318 |
+
buildExpression(group.value.value, options.withFont("mathrm"));
|
319 |
+
norm_str = norm_str + "} ";
|
320 |
+
} else {
|
321 |
+
norm_str = norm_str + " " + group.value.original + " ";
|
322 |
+
buildExpression(group.value.value, options);
|
323 |
+
}
|
324 |
+
};
|
325 |
+
|
326 |
+
groupTypes.overline = function(group, options) {
|
327 |
+
norm_str = norm_str + "\\overline { ";
|
328 |
+
|
329 |
+
buildGroup(group.value.body, options);
|
330 |
+
norm_str = norm_str + "} ";
|
331 |
+
norm_str = norm_str;
|
332 |
+
|
333 |
+
};
|
334 |
+
|
335 |
+
groupTypes.underline = function(group, options) {
|
336 |
+
norm_str = norm_str + "\\underline { ";
|
337 |
+
buildGroup(group.value.body, options);
|
338 |
+
norm_str = norm_str + "} ";
|
339 |
+
|
340 |
+
norm_str = norm_str;
|
341 |
+
|
342 |
+
};
|
343 |
+
|
344 |
+
groupTypes.rule = function(group) {
|
345 |
+
norm_str = norm_str + "\\rule { "+group.value.width.number+" "+group.value.width.unit+" } { "+group.value.height.number+" "+group.value.height.unit+ " } ";
|
346 |
+
|
347 |
+
};
|
348 |
+
|
349 |
+
groupTypes.llap = function(group, options) {
|
350 |
+
norm_str = norm_str + "\\llap ";
|
351 |
+
buildGroup(group.value.body, options);
|
352 |
+
};
|
353 |
+
|
354 |
+
groupTypes.rlap = function(group, options) {
|
355 |
+
norm_str = norm_str + "\\rlap ";
|
356 |
+
buildGroup(group.value.body, options);
|
357 |
+
|
358 |
+
};
|
359 |
+
|
360 |
+
groupTypes.phantom = function(group, options, prev) {
|
361 |
+
norm_str = norm_str + "\\phantom { ";
|
362 |
+
buildExpression(group.value.value, options);
|
363 |
+
norm_str = norm_str + "} ";
|
364 |
+
|
365 |
+
};
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Takes a list of nodes, builds them, and returns a list of the generated
|
369 |
+
* MathML nodes. A little simpler than the HTML version because we don't do any
|
370 |
+
* previous-node handling.
|
371 |
+
*/
|
372 |
+
var buildExpression = function(expression, options) {
|
373 |
+
var groups = [];
|
374 |
+
for (var i = 0; i < expression.length; i++) {
|
375 |
+
var group = expression[i];
|
376 |
+
buildGroup(group, options);
|
377 |
+
}
|
378 |
+
// console.log(norm_str);
|
379 |
+
// return groups;
|
380 |
+
};
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Takes a group from the parser and calls the appropriate groupTypes function
|
384 |
+
* on it to produce a MathML node.
|
385 |
+
*/
|
386 |
+
var buildGroup = function(group, options) {
|
387 |
+
if (groupTypes[group.type]) {
|
388 |
+
groupTypes[group.type](group, options);
|
389 |
+
} else {
|
390 |
+
throw new ParseError(
|
391 |
+
"Got group of unknown type: '" + group.type + "'");
|
392 |
+
}
|
393 |
+
};
|
394 |
+
|
395 |
+
|
modules/tokenize_latex/third_party/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
Directly taken from https://github.com/harvardnlp/im2markup
|
modules/tokenize_latex/third_party/katex/LICENSE.txt
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The MIT License (MIT)
|
2 |
+
|
3 |
+
Copyright (c) 2015 Khan Academy
|
4 |
+
|
5 |
+
This software also uses portions of the underscore.js project, which is
|
6 |
+
MIT licensed with the following copyright:
|
7 |
+
|
8 |
+
Copyright (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative
|
9 |
+
Reporters & Editors
|
10 |
+
|
11 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
12 |
+
of this software and associated documentation files (the "Software"), to deal
|
13 |
+
in the Software without restriction, including without limitation the rights
|
14 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
15 |
+
copies of the Software, and to permit persons to whom the Software is
|
16 |
+
furnished to do so, subject to the following conditions:
|
17 |
+
|
18 |
+
The above copyright notice and this permission notice shall be included in all
|
19 |
+
copies or substantial portions of the Software.
|
20 |
+
|
21 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27 |
+
SOFTWARE.
|
modules/tokenize_latex/third_party/katex/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX)
|
2 |
+
|
3 |
+
[![Join the chat at https://gitter.im/Khan/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4 |
+
|
5 |
+
KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
|
6 |
+
|
7 |
+
* **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://jsperf.com/katex-vs-mathjax/).
|
8 |
+
* **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
|
9 |
+
* **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
|
10 |
+
* **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
|
11 |
+
|
12 |
+
KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, and IE 8 - IE 11. A list of supported commands can be on the [wiki](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX).
|
13 |
+
|
14 |
+
## Usage
|
15 |
+
|
16 |
+
You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
|
17 |
+
|
18 |
+
```html
|
19 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css">
|
20 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.js"></script>
|
21 |
+
```
|
22 |
+
|
23 |
+
#### In-browser rendering
|
24 |
+
|
25 |
+
Call `katex.render` with a TeX expression and a DOM element to render into:
|
26 |
+
|
27 |
+
```js
|
28 |
+
katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
|
29 |
+
```
|
30 |
+
|
31 |
+
If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
|
32 |
+
|
33 |
+
#### Server side rendering or rendering to a string
|
34 |
+
|
35 |
+
To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
|
36 |
+
|
37 |
+
```js
|
38 |
+
var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
|
39 |
+
// '<span class="katex">...</span>'
|
40 |
+
```
|
41 |
+
|
42 |
+
Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
|
43 |
+
|
44 |
+
#### Rendering options
|
45 |
+
|
46 |
+
You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
|
47 |
+
|
48 |
+
- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
|
49 |
+
- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
|
50 |
+
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
|
51 |
+
|
52 |
+
For example:
|
53 |
+
|
54 |
+
```js
|
55 |
+
katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true });
|
56 |
+
```
|
57 |
+
|
58 |
+
#### Automatic rendering of math on a page
|
59 |
+
|
60 |
+
Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
|
61 |
+
|
62 |
+
## Contributing
|
63 |
+
|
64 |
+
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
65 |
+
|
66 |
+
## License
|
67 |
+
|
68 |
+
KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
modules/tokenize_latex/third_party/katex/cli.js
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env node
|
2 |
+
// Simple CLI for KaTeX.
|
3 |
+
// Reads TeX from stdin, outputs HTML to stdout.
|
4 |
+
/* eslint no-console:0 */
|
5 |
+
|
6 |
+
var katex = require("./");
|
7 |
+
var input = "";
|
8 |
+
|
9 |
+
// Skip the first two args, which are just "node" and "cli.js"
|
10 |
+
var args = process.argv.slice(2);
|
11 |
+
|
12 |
+
if (args.indexOf("--help") !== -1) {
|
13 |
+
console.log(process.argv[0] + " " + process.argv[1] +
|
14 |
+
" [ --help ]" +
|
15 |
+
" [ --display-mode ]");
|
16 |
+
|
17 |
+
console.log("\n" +
|
18 |
+
"Options:");
|
19 |
+
console.log(" --help Display this help message");
|
20 |
+
console.log(" --display-mode Render in display mode (not inline mode)");
|
21 |
+
process.exit();
|
22 |
+
}
|
23 |
+
|
24 |
+
process.stdin.on("data", function(chunk) {
|
25 |
+
input += chunk.toString();
|
26 |
+
});
|
27 |
+
|
28 |
+
process.stdin.on("end", function() {
|
29 |
+
var options = { displayMode: args.indexOf("--display-mode") !== -1 };
|
30 |
+
var output = katex.renderToString(input, options);
|
31 |
+
console.log(output);
|
32 |
+
});
|
modules/tokenize_latex/third_party/katex/katex.js
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-console:0 */
|
2 |
+
/**
|
3 |
+
* This is the main entry point for KaTeX. Here, we expose functions for
|
4 |
+
* rendering expressions either to DOM nodes or to markup strings.
|
5 |
+
*
|
6 |
+
* We also expose the ParseError class to check if errors thrown from KaTeX are
|
7 |
+
* errors in the expression, or errors in javascript handling.
|
8 |
+
*/
|
9 |
+
|
10 |
+
var ParseError = require("./src/ParseError");
|
11 |
+
var Settings = require("./src/Settings");
|
12 |
+
|
13 |
+
var buildTree = require("./src/buildTree");
|
14 |
+
var parseTree = require("./src/parseTree");
|
15 |
+
var utils = require("./src/utils");
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Parse and build an expression, and place that expression in the DOM node
|
19 |
+
* given.
|
20 |
+
*/
|
21 |
+
var render = function(expression, baseNode, options) {
|
22 |
+
utils.clearNode(baseNode);
|
23 |
+
|
24 |
+
var settings = new Settings(options);
|
25 |
+
|
26 |
+
var tree = parseTree(expression, settings);
|
27 |
+
var node = buildTree(tree, expression, settings).toNode();
|
28 |
+
|
29 |
+
baseNode.appendChild(node);
|
30 |
+
};
|
31 |
+
|
32 |
+
// KaTeX's styles don't work properly in quirks mode. Print out an error, and
|
33 |
+
// disable rendering.
|
34 |
+
if (typeof document !== "undefined") {
|
35 |
+
if (document.compatMode !== "CSS1Compat") {
|
36 |
+
typeof console !== "undefined" && console.warn(
|
37 |
+
"Warning: KaTeX doesn't work in quirks mode. Make sure your " +
|
38 |
+
"website has a suitable doctype.");
|
39 |
+
|
40 |
+
render = function() {
|
41 |
+
throw new ParseError("KaTeX doesn't work in quirks mode.");
|
42 |
+
};
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Parse and build an expression, and return the markup for that.
|
48 |
+
*/
|
49 |
+
var renderToString = function(expression, options) {
|
50 |
+
var settings = new Settings(options);
|
51 |
+
|
52 |
+
var tree = parseTree(expression, settings);
|
53 |
+
return buildTree(tree, expression, settings).toMarkup();
|
54 |
+
};
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Parse an expression and return the parse tree.
|
58 |
+
*/
|
59 |
+
var generateParseTree = function(expression, options) {
|
60 |
+
var settings = new Settings(options);
|
61 |
+
return parseTree(expression, settings);
|
62 |
+
};
|
63 |
+
|
64 |
+
module.exports = {
|
65 |
+
render: render,
|
66 |
+
renderToString: renderToString,
|
67 |
+
/**
|
68 |
+
* NOTE: This method is not currently recommended for public use.
|
69 |
+
* The internal tree representation is unstable and is very likely
|
70 |
+
* to change. Use at your own risk.
|
71 |
+
*/
|
72 |
+
__parse: generateParseTree,
|
73 |
+
ParseError: ParseError,
|
74 |
+
};
|
modules/tokenize_latex/third_party/katex/package.json
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_args": [
|
3 |
+
[
|
4 |
+
"katex",
|
5 |
+
"/home/srush/Projects/im2latex"
|
6 |
+
]
|
7 |
+
],
|
8 |
+
"_from": "katex@latest",
|
9 |
+
"_id": "[email protected]",
|
10 |
+
"_inCache": true,
|
11 |
+
"_installable": true,
|
12 |
+
"_location": "/katex",
|
13 |
+
"_nodeVersion": "4.2.1",
|
14 |
+
"_npmOperationalInternal": {
|
15 |
+
"host": "packages-12-west.internal.npmjs.com",
|
16 |
+
"tmp": "tmp/katex-0.6.0.tgz_1460769444991_0.38667152682319283"
|
17 |
+
},
|
18 |
+
"_npmUser": {
|
19 |
+
"email": "[email protected]",
|
20 |
+
"name": "kevinbarabash"
|
21 |
+
},
|
22 |
+
"_npmVersion": "2.15.2",
|
23 |
+
"_phantomChildren": {},
|
24 |
+
"_requested": {
|
25 |
+
"name": "katex",
|
26 |
+
"raw": "katex",
|
27 |
+
"rawSpec": "",
|
28 |
+
"scope": null,
|
29 |
+
"spec": "latest",
|
30 |
+
"type": "tag"
|
31 |
+
},
|
32 |
+
"_requiredBy": [
|
33 |
+
"#USER"
|
34 |
+
],
|
35 |
+
"_resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz",
|
36 |
+
"_shasum": "12418e09121c05c92041b6b3b9fb6bab213cb6f3",
|
37 |
+
"_shrinkwrap": null,
|
38 |
+
"_spec": "katex",
|
39 |
+
"_where": "/home/srush/Projects/im2latex",
|
40 |
+
"bin": {
|
41 |
+
"katex": "cli.js"
|
42 |
+
},
|
43 |
+
"bugs": {
|
44 |
+
"url": "https://github.com/Khan/KaTeX/issues"
|
45 |
+
},
|
46 |
+
"dependencies": {
|
47 |
+
"match-at": "^0.1.0"
|
48 |
+
},
|
49 |
+
"description": "Fast math typesetting for the web.",
|
50 |
+
"devDependencies": {
|
51 |
+
"browserify": "^10.2.4",
|
52 |
+
"clean-css": "~2.2.15",
|
53 |
+
"eslint": "^1.10.2",
|
54 |
+
"express": "~3.3.3",
|
55 |
+
"glob": "^5.0.15",
|
56 |
+
"jasmine": "^2.3.2",
|
57 |
+
"jasmine-core": "^2.3.4",
|
58 |
+
"js-yaml": "^3.3.1",
|
59 |
+
"jspngopt": "^0.1.0",
|
60 |
+
"less": "~1.7.5",
|
61 |
+
"nomnom": "^1.8.1",
|
62 |
+
"pako": "0.2.7",
|
63 |
+
"selenium-webdriver": "^2.46.1",
|
64 |
+
"uglify-js": "~2.4.15"
|
65 |
+
},
|
66 |
+
"directories": {},
|
67 |
+
"dist": {
|
68 |
+
"shasum": "12418e09121c05c92041b6b3b9fb6bab213cb6f3",
|
69 |
+
"tarball": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz"
|
70 |
+
},
|
71 |
+
"files": [
|
72 |
+
"cli.js",
|
73 |
+
"dist/",
|
74 |
+
"katex.js",
|
75 |
+
"src/"
|
76 |
+
],
|
77 |
+
"gitHead": "b94fc6534d5c23f944906a52a592bee4e0090665",
|
78 |
+
"homepage": "https://github.com/Khan/KaTeX#readme",
|
79 |
+
"license": "MIT",
|
80 |
+
"main": "katex.js",
|
81 |
+
"maintainers": [
|
82 |
+
{
|
83 |
+
"name": "kevinbarabash",
|
84 |
+
"email": "[email protected]"
|
85 |
+
},
|
86 |
+
{
|
87 |
+
"name": "spicyj",
|
88 |
+
"email": "[email protected]"
|
89 |
+
},
|
90 |
+
{
|
91 |
+
"name": "xymostech",
|
92 |
+
"email": "[email protected]"
|
93 |
+
}
|
94 |
+
],
|
95 |
+
"name": "katex",
|
96 |
+
"optionalDependencies": {},
|
97 |
+
"readme": "ERROR: No README data found!",
|
98 |
+
"repository": {
|
99 |
+
"type": "git",
|
100 |
+
"url": "git://github.com/Khan/KaTeX.git"
|
101 |
+
},
|
102 |
+
"scripts": {
|
103 |
+
"prepublish": "make dist",
|
104 |
+
"start": "node server.js",
|
105 |
+
"test": "make lint test"
|
106 |
+
},
|
107 |
+
"version": "0.6.0"
|
108 |
+
}
|
modules/tokenize_latex/third_party/katex/src/Lexer.js
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* The Lexer class handles tokenizing the input in various ways. Since our
|
3 |
+
* parser expects us to be able to backtrack, the lexer allows lexing from any
|
4 |
+
* given starting point.
|
5 |
+
*
|
6 |
+
* Its main exposed function is the `lex` function, which takes a position to
|
7 |
+
* lex from and a type of token to lex. It defers to the appropriate `_innerLex`
|
8 |
+
* function.
|
9 |
+
*
|
10 |
+
* The various `_innerLex` functions perform the actual lexing of different
|
11 |
+
* kinds.
|
12 |
+
*/
|
13 |
+
|
14 |
+
var matchAt = require("../../match-at");
|
15 |
+
|
16 |
+
var ParseError = require("./ParseError");
|
17 |
+
|
18 |
+
// The main lexer class
|
19 |
+
function Lexer(input) {
|
20 |
+
this._input = input;
|
21 |
+
}
|
22 |
+
|
23 |
+
// The resulting token returned from `lex`.
|
24 |
+
function Token(text, data, position) {
|
25 |
+
this.text = text;
|
26 |
+
this.data = data;
|
27 |
+
this.position = position;
|
28 |
+
}
|
29 |
+
|
30 |
+
/* The following tokenRegex
|
31 |
+
* - matches typical whitespace (but not NBSP etc.) using its first group
|
32 |
+
* - matches symbol combinations which result in a single output character
|
33 |
+
* - does not match any control character \x00-\x1f except whitespace
|
34 |
+
* - does not match a bare backslash
|
35 |
+
* - matches any ASCII character except those just mentioned
|
36 |
+
* - does not match the BMP private use area \uE000-\uF8FF
|
37 |
+
* - does not match bare surrogate code units
|
38 |
+
* - matches any BMP character except for those just described
|
39 |
+
* - matches any valid Unicode surrogate pair
|
40 |
+
* - matches a backslash followed by one or more letters
|
41 |
+
* - matches a backslash followed by any BMP character, including newline
|
42 |
+
* Just because the Lexer matches something doesn't mean it's valid input:
|
43 |
+
* If there is no matching function or symbol definition, the Parser will
|
44 |
+
* still reject the input.
|
45 |
+
*/
|
46 |
+
var tokenRegex = new RegExp(
|
47 |
+
"([ \r\n\t]+)|(" + // whitespace
|
48 |
+
"---?" + // special combinations
|
49 |
+
"|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
50 |
+
"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
|
51 |
+
"|\\\\(?:[a-zA-Z]+|[^\uD800-\uDFFF])" + // function name
|
52 |
+
")"
|
53 |
+
);
|
54 |
+
|
55 |
+
var whitespaceRegex = /\s*/;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* This function lexes a single normal token. It takes a position and
|
59 |
+
* whether it should completely ignore whitespace or not.
|
60 |
+
*/
|
61 |
+
Lexer.prototype._innerLex = function(pos, ignoreWhitespace) {
|
62 |
+
var input = this._input;
|
63 |
+
if (pos === input.length) {
|
64 |
+
return new Token("EOF", null, pos);
|
65 |
+
}
|
66 |
+
var match = matchAt(tokenRegex, input, pos);
|
67 |
+
if (match === null) {
|
68 |
+
throw new ParseError(
|
69 |
+
"Unexpected character: '" + input[pos] + "'",
|
70 |
+
this, pos);
|
71 |
+
} else if (match[2]) { // matched non-whitespace
|
72 |
+
return new Token(match[2], null, pos + match[2].length);
|
73 |
+
} else if (ignoreWhitespace) {
|
74 |
+
return this._innerLex(pos + match[1].length, true);
|
75 |
+
} else { // concatenate whitespace to a single space
|
76 |
+
return new Token(" ", null, pos + match[1].length);
|
77 |
+
}
|
78 |
+
};
|
79 |
+
|
80 |
+
// A regex to match a CSS color (like #ffffff or BlueViolet)
|
81 |
+
var cssColor = /#[a-z0-9]+|[a-z]+/i;
|
82 |
+
|
83 |
+
/**
|
84 |
+
* This function lexes a CSS color.
|
85 |
+
*/
|
86 |
+
Lexer.prototype._innerLexColor = function(pos) {
|
87 |
+
var input = this._input;
|
88 |
+
|
89 |
+
// Ignore whitespace
|
90 |
+
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
|
91 |
+
pos += whitespace.length;
|
92 |
+
|
93 |
+
var match;
|
94 |
+
if ((match = matchAt(cssColor, input, pos))) {
|
95 |
+
// If we look like a color, return a color
|
96 |
+
return new Token(match[0], null, pos + match[0].length);
|
97 |
+
} else {
|
98 |
+
throw new ParseError("Invalid color", this, pos);
|
99 |
+
}
|
100 |
+
};
|
101 |
+
|
102 |
+
// A regex to match a dimension. Dimensions look like
|
103 |
+
// "1.2em" or ".4pt" or "1 ex"
|
104 |
+
var sizeRegex = /(-?)\s*(\d+(?:\.\d*)?|\.\d+)\s*([a-z]{2})/;
|
105 |
+
|
106 |
+
/**
|
107 |
+
* This function lexes a dimension.
|
108 |
+
*/
|
109 |
+
Lexer.prototype._innerLexSize = function(pos) {
|
110 |
+
var input = this._input;
|
111 |
+
|
112 |
+
// Ignore whitespace
|
113 |
+
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
|
114 |
+
pos += whitespace.length;
|
115 |
+
|
116 |
+
var match;
|
117 |
+
if ((match = matchAt(sizeRegex, input, pos))) {
|
118 |
+
var unit = match[3];
|
119 |
+
// We only currently handle "em" and "ex" units
|
120 |
+
// if (unit !== "em" && unit !== "ex") {
|
121 |
+
// throw new ParseError("Invalid unit: '" + unit + "'", this, pos);
|
122 |
+
// }
|
123 |
+
return new Token(match[0], {
|
124 |
+
number: +(match[1] + match[2]),
|
125 |
+
unit: unit,
|
126 |
+
}, pos + match[0].length);
|
127 |
+
}
|
128 |
+
|
129 |
+
throw new ParseError("Invalid size", this, pos);
|
130 |
+
};
|
131 |
+
|
132 |
+
/**
|
133 |
+
* This function lexes a string of whitespace.
|
134 |
+
*/
|
135 |
+
Lexer.prototype._innerLexWhitespace = function(pos) {
|
136 |
+
var input = this._input;
|
137 |
+
|
138 |
+
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
|
139 |
+
pos += whitespace.length;
|
140 |
+
|
141 |
+
return new Token(whitespace[0], null, pos);
|
142 |
+
};
|
143 |
+
|
144 |
+
/**
|
145 |
+
* This function lexes a single token starting at `pos` and of the given mode.
|
146 |
+
* Based on the mode, we defer to one of the `_innerLex` functions.
|
147 |
+
*/
|
148 |
+
Lexer.prototype.lex = function(pos, mode) {
|
149 |
+
if (mode === "math") {
|
150 |
+
return this._innerLex(pos, true);
|
151 |
+
} else if (mode === "text") {
|
152 |
+
return this._innerLex(pos, false);
|
153 |
+
} else if (mode === "color") {
|
154 |
+
return this._innerLexColor(pos);
|
155 |
+
} else if (mode === "size") {
|
156 |
+
return this._innerLexSize(pos);
|
157 |
+
} else if (mode === "whitespace") {
|
158 |
+
return this._innerLexWhitespace(pos);
|
159 |
+
}
|
160 |
+
};
|
161 |
+
|
162 |
+
module.exports = Lexer;
|
modules/tokenize_latex/third_party/katex/src/Options.js
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file contains information about the options that the Parser carries
|
3 |
+
* around with it while parsing. Data is held in an `Options` object, and when
|
4 |
+
* recursing, a new `Options` object can be created with the `.with*` and
|
5 |
+
* `.reset` functions.
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* This is the main options class. It contains the style, size, color, and font
|
10 |
+
* of the current parse level. It also contains the style and size of the parent
|
11 |
+
* parse level, so size changes can be handled efficiently.
|
12 |
+
*
|
13 |
+
* Each of the `.with*` and `.reset` functions passes its current style and size
|
14 |
+
* as the parentStyle and parentSize of the new options class, so parent
|
15 |
+
* handling is taken care of automatically.
|
16 |
+
*/
|
17 |
+
function Options(data) {
|
18 |
+
this.style = data.style;
|
19 |
+
this.color = data.color;
|
20 |
+
this.size = data.size;
|
21 |
+
this.phantom = data.phantom;
|
22 |
+
this.font = data.font;
|
23 |
+
|
24 |
+
if (data.parentStyle === undefined) {
|
25 |
+
this.parentStyle = data.style;
|
26 |
+
} else {
|
27 |
+
this.parentStyle = data.parentStyle;
|
28 |
+
}
|
29 |
+
|
30 |
+
if (data.parentSize === undefined) {
|
31 |
+
this.parentSize = data.size;
|
32 |
+
} else {
|
33 |
+
this.parentSize = data.parentSize;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns a new options object with the same properties as "this". Properties
|
39 |
+
* from "extension" will be copied to the new options object.
|
40 |
+
*/
|
41 |
+
Options.prototype.extend = function(extension) {
|
42 |
+
var data = {
|
43 |
+
style: this.style,
|
44 |
+
size: this.size,
|
45 |
+
color: this.color,
|
46 |
+
parentStyle: this.style,
|
47 |
+
parentSize: this.size,
|
48 |
+
phantom: this.phantom,
|
49 |
+
font: this.font,
|
50 |
+
};
|
51 |
+
|
52 |
+
for (var key in extension) {
|
53 |
+
if (extension.hasOwnProperty(key)) {
|
54 |
+
data[key] = extension[key];
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
return new Options(data);
|
59 |
+
};
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Create a new options object with the given style.
|
63 |
+
*/
|
64 |
+
Options.prototype.withStyle = function(style) {
|
65 |
+
return this.extend({
|
66 |
+
style: style,
|
67 |
+
});
|
68 |
+
};
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Create a new options object with the given size.
|
72 |
+
*/
|
73 |
+
Options.prototype.withSize = function(size) {
|
74 |
+
return this.extend({
|
75 |
+
size: size,
|
76 |
+
});
|
77 |
+
};
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Create a new options object with the given color.
|
81 |
+
*/
|
82 |
+
Options.prototype.withColor = function(color) {
|
83 |
+
return this.extend({
|
84 |
+
color: color,
|
85 |
+
});
|
86 |
+
};
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Create a new options object with "phantom" set to true.
|
90 |
+
*/
|
91 |
+
Options.prototype.withPhantom = function() {
|
92 |
+
return this.extend({
|
93 |
+
phantom: true,
|
94 |
+
});
|
95 |
+
};
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Create a new options objects with the give font.
|
99 |
+
*/
|
100 |
+
Options.prototype.withFont = function(font) {
|
101 |
+
return this.extend({
|
102 |
+
font: font,
|
103 |
+
});
|
104 |
+
};
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Create a new options object with the same style, size, and color. This is
|
108 |
+
* used so that parent style and size changes are handled correctly.
|
109 |
+
*/
|
110 |
+
Options.prototype.reset = function() {
|
111 |
+
return this.extend({});
|
112 |
+
};
|
113 |
+
|
114 |
+
/**
|
115 |
+
* A map of color names to CSS colors.
|
116 |
+
* TODO(emily): Remove this when we have real macros
|
117 |
+
*/
|
118 |
+
var colorMap = {
|
119 |
+
"katex-blue": "#6495ed",
|
120 |
+
"katex-orange": "#ffa500",
|
121 |
+
"katex-pink": "#ff00af",
|
122 |
+
"katex-red": "#df0030",
|
123 |
+
"katex-green": "#28ae7b",
|
124 |
+
"katex-gray": "gray",
|
125 |
+
"katex-purple": "#9d38bd",
|
126 |
+
"katex-blueA": "#c7e9f1",
|
127 |
+
"katex-blueB": "#9cdceb",
|
128 |
+
"katex-blueC": "#58c4dd",
|
129 |
+
"katex-blueD": "#29abca",
|
130 |
+
"katex-blueE": "#1c758a",
|
131 |
+
"katex-tealA": "#acead7",
|
132 |
+
"katex-tealB": "#76ddc0",
|
133 |
+
"katex-tealC": "#5cd0b3",
|
134 |
+
"katex-tealD": "#55c1a7",
|
135 |
+
"katex-tealE": "#49a88f",
|
136 |
+
"katex-greenA": "#c9e2ae",
|
137 |
+
"katex-greenB": "#a6cf8c",
|
138 |
+
"katex-greenC": "#83c167",
|
139 |
+
"katex-greenD": "#77b05d",
|
140 |
+
"katex-greenE": "#699c52",
|
141 |
+
"katex-goldA": "#f7c797",
|
142 |
+
"katex-goldB": "#f9b775",
|
143 |
+
"katex-goldC": "#f0ac5f",
|
144 |
+
"katex-goldD": "#e1a158",
|
145 |
+
"katex-goldE": "#c78d46",
|
146 |
+
"katex-redA": "#f7a1a3",
|
147 |
+
"katex-redB": "#ff8080",
|
148 |
+
"katex-redC": "#fc6255",
|
149 |
+
"katex-redD": "#e65a4c",
|
150 |
+
"katex-redE": "#cf5044",
|
151 |
+
"katex-maroonA": "#ecabc1",
|
152 |
+
"katex-maroonB": "#ec92ab",
|
153 |
+
"katex-maroonC": "#c55f73",
|
154 |
+
"katex-maroonD": "#a24d61",
|
155 |
+
"katex-maroonE": "#94424f",
|
156 |
+
"katex-purpleA": "#caa3e8",
|
157 |
+
"katex-purpleB": "#b189c6",
|
158 |
+
"katex-purpleC": "#9a72ac",
|
159 |
+
"katex-purpleD": "#715582",
|
160 |
+
"katex-purpleE": "#644172",
|
161 |
+
"katex-mintA": "#f5f9e8",
|
162 |
+
"katex-mintB": "#edf2df",
|
163 |
+
"katex-mintC": "#e0e5cc",
|
164 |
+
"katex-grayA": "#fdfdfd",
|
165 |
+
"katex-grayB": "#f7f7f7",
|
166 |
+
"katex-grayC": "#eeeeee",
|
167 |
+
"katex-grayD": "#dddddd",
|
168 |
+
"katex-grayE": "#cccccc",
|
169 |
+
"katex-grayF": "#aaaaaa",
|
170 |
+
"katex-grayG": "#999999",
|
171 |
+
"katex-grayH": "#555555",
|
172 |
+
"katex-grayI": "#333333",
|
173 |
+
"katex-kaBlue": "#314453",
|
174 |
+
"katex-kaGreen": "#639b24",
|
175 |
+
};
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Gets the CSS color of the current options object, accounting for the
|
179 |
+
* `colorMap`.
|
180 |
+
*/
|
181 |
+
Options.prototype.getColor = function() {
|
182 |
+
if (this.phantom) {
|
183 |
+
return "transparent";
|
184 |
+
} else {
|
185 |
+
return colorMap[this.color] || this.color;
|
186 |
+
}
|
187 |
+
};
|
188 |
+
|
189 |
+
module.exports = Options;
|
modules/tokenize_latex/third_party/katex/src/ParseError.js
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This is the ParseError class, which is the main error thrown by KaTeX
|
3 |
+
* functions when something has gone wrong. This is used to distinguish internal
|
4 |
+
* errors from errors in the expression that the user provided.
|
5 |
+
*/
|
6 |
+
function ParseError(message, lexer, position) {
|
7 |
+
var error = "KaTeX parse error: " + message;
|
8 |
+
|
9 |
+
if (lexer !== undefined && position !== undefined) {
|
10 |
+
// If we have the input and a position, make the error a bit fancier
|
11 |
+
|
12 |
+
// Prepend some information
|
13 |
+
error += " at position " + position + ": ";
|
14 |
+
|
15 |
+
// Get the input
|
16 |
+
var input = lexer._input;
|
17 |
+
// Insert a combining underscore at the correct position
|
18 |
+
input = input.slice(0, position) + "\u0332" +
|
19 |
+
input.slice(position);
|
20 |
+
|
21 |
+
// Extract some context from the input and add it to the error
|
22 |
+
var begin = Math.max(0, position - 15);
|
23 |
+
var end = position + 15;
|
24 |
+
error += input.slice(begin, end);
|
25 |
+
}
|
26 |
+
|
27 |
+
// Some hackery to make ParseError a prototype of Error
|
28 |
+
// See http://stackoverflow.com/a/8460753
|
29 |
+
var self = new Error(error);
|
30 |
+
self.name = "ParseError";
|
31 |
+
self.__proto__ = ParseError.prototype;
|
32 |
+
|
33 |
+
self.position = position;
|
34 |
+
return self;
|
35 |
+
}
|
36 |
+
|
37 |
+
// More hackery
|
38 |
+
ParseError.prototype.__proto__ = Error.prototype;
|
39 |
+
|
40 |
+
module.exports = ParseError;
|
modules/tokenize_latex/third_party/katex/src/Parser.js
ADDED
@@ -0,0 +1,798 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-constant-condition:0 */
|
2 |
+
var functions = require("./functions");
|
3 |
+
var environments = require("./environments");
|
4 |
+
var Lexer = require("./Lexer");
|
5 |
+
var symbols = require("./symbols");
|
6 |
+
var utils = require("./utils");
|
7 |
+
|
8 |
+
var parseData = require("./parseData");
|
9 |
+
var ParseError = require("./ParseError");
|
10 |
+
|
11 |
+
global_str = ""
|
12 |
+
|
13 |
+
/**
|
14 |
+
* This file contains the parser used to parse out a TeX expression from the
|
15 |
+
* input. Since TeX isn't context-free, standard parsers don't work particularly
|
16 |
+
* well.
|
17 |
+
*
|
18 |
+
* The strategy of this parser is as such:
|
19 |
+
*
|
20 |
+
* The main functions (the `.parse...` ones) take a position in the current
|
21 |
+
* parse string to parse tokens from. The lexer (found in Lexer.js, stored at
|
22 |
+
* this.lexer) also supports pulling out tokens at arbitrary places. When
|
23 |
+
* individual tokens are needed at a position, the lexer is called to pull out a
|
24 |
+
* token, which is then used.
|
25 |
+
*
|
26 |
+
* The parser has a property called "mode" indicating the mode that
|
27 |
+
* the parser is currently in. Currently it has to be one of "math" or
|
28 |
+
* "text", which denotes whether the current environment is a math-y
|
29 |
+
* one or a text-y one (e.g. inside \text). Currently, this serves to
|
30 |
+
* limit the functions which can be used in text mode.
|
31 |
+
*
|
32 |
+
* The main functions then return an object which contains the useful data that
|
33 |
+
* was parsed at its given point, and a new position at the end of the parsed
|
34 |
+
* data. The main functions can call each other and continue the parsing by
|
35 |
+
* using the returned position as a new starting point.
|
36 |
+
*
|
37 |
+
* There are also extra `.handle...` functions, which pull out some reused
|
38 |
+
* functionality into self-contained functions.
|
39 |
+
*
|
40 |
+
* The earlier functions return ParseNodes.
|
41 |
+
* The later functions (which are called deeper in the parse) sometimes return
|
42 |
+
* ParseFuncOrArgument, which contain a ParseNode as well as some data about
|
43 |
+
* whether the parsed object is a function which is missing some arguments, or a
|
44 |
+
* standalone object which can be used as an argument to another function.
|
45 |
+
*/
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Main Parser class
|
49 |
+
*/
|
50 |
+
function Parser(input, settings) {
|
51 |
+
// Make a new lexer
|
52 |
+
this.lexer = new Lexer(input);
|
53 |
+
// Store the settings for use in parsing
|
54 |
+
this.settings = settings;
|
55 |
+
}
|
56 |
+
|
57 |
+
var ParseNode = parseData.ParseNode;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* An initial function (without its arguments), or an argument to a function.
|
61 |
+
* The `result` argument should be a ParseNode.
|
62 |
+
*/
|
63 |
+
function ParseFuncOrArgument(result, isFunction) {
|
64 |
+
this.result = result;
|
65 |
+
// Is this a function (i.e. is it something defined in functions.js)?
|
66 |
+
this.isFunction = isFunction;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Checks a result to make sure it has the right type, and throws an
|
71 |
+
* appropriate error otherwise.
|
72 |
+
*
|
73 |
+
* @param {boolean=} consume whether to consume the expected token,
|
74 |
+
* defaults to true
|
75 |
+
*/
|
76 |
+
Parser.prototype.expect = function(text, consume) {
|
77 |
+
if (this.nextToken.text !== text) {
|
78 |
+
throw new ParseError(
|
79 |
+
"Expected '" + text + "', got '" + this.nextToken.text + "'",
|
80 |
+
this.lexer, this.nextToken.position
|
81 |
+
);
|
82 |
+
}
|
83 |
+
if (consume !== false) {
|
84 |
+
this.consume();
|
85 |
+
}
|
86 |
+
};
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Considers the current look ahead token as consumed,
|
90 |
+
* and fetches the one after that as the new look ahead.
|
91 |
+
*/
|
92 |
+
Parser.prototype.consume = function() {
|
93 |
+
this.pos = this.nextToken.position;
|
94 |
+
|
95 |
+
global_str = global_str + " " + this.nextToken.text
|
96 |
+
this.nextToken = this.lexer.lex(this.pos, this.mode);
|
97 |
+
};
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Main parsing function, which parses an entire input.
|
101 |
+
*
|
102 |
+
* @return {?Array.<ParseNode>}
|
103 |
+
*/
|
104 |
+
Parser.prototype.parse = function() {
|
105 |
+
// Try to parse the input
|
106 |
+
this.mode = "math";
|
107 |
+
this.pos = 0;
|
108 |
+
this.nextToken = this.lexer.lex(this.pos, this.mode);
|
109 |
+
var parse = this.parseInput();
|
110 |
+
return parse;
|
111 |
+
};
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Parses an entire input tree.
|
115 |
+
*/
|
116 |
+
Parser.prototype.parseInput = function() {
|
117 |
+
// Parse an expression
|
118 |
+
var expression = this.parseExpression(false);
|
119 |
+
// If we succeeded, make sure there's an EOF at the end
|
120 |
+
this.expect("EOF", false);
|
121 |
+
return expression;
|
122 |
+
};
|
123 |
+
|
124 |
+
var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Parses an "expression", which is a list of atoms.
|
128 |
+
*
|
129 |
+
* @param {boolean} breakOnInfix Should the parsing stop when we hit infix
|
130 |
+
* nodes? This happens when functions have higher precendence
|
131 |
+
* than infix nodes in implicit parses.
|
132 |
+
*
|
133 |
+
* @param {?string} breakOnToken The token that the expression should end with,
|
134 |
+
* or `null` if something else should end the expression.
|
135 |
+
*
|
136 |
+
* @return {ParseNode}
|
137 |
+
*/
|
138 |
+
Parser.prototype.parseExpression = function(breakOnInfix, breakOnToken) {
|
139 |
+
var body = [];
|
140 |
+
// Keep adding atoms to the body until we can't parse any more atoms (either
|
141 |
+
// we reached the end, a }, or a \right)
|
142 |
+
while (true) {
|
143 |
+
var lex = this.nextToken;
|
144 |
+
var pos = this.pos;
|
145 |
+
if (endOfExpression.indexOf(lex.text) !== -1) {
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
if (breakOnToken && lex.text === breakOnToken) {
|
149 |
+
break;
|
150 |
+
}
|
151 |
+
var atom = this.parseAtom();
|
152 |
+
if (!atom) {
|
153 |
+
if (!this.settings.throwOnError && lex.text[0] === "\\") {
|
154 |
+
var errorNode = this.handleUnsupportedCmd();
|
155 |
+
body.push(errorNode);
|
156 |
+
|
157 |
+
pos = lex.position;
|
158 |
+
continue;
|
159 |
+
}
|
160 |
+
|
161 |
+
break;
|
162 |
+
}
|
163 |
+
if (breakOnInfix && atom.type === "infix") {
|
164 |
+
// rewind so we can parse the infix atom again
|
165 |
+
this.pos = pos;
|
166 |
+
this.nextToken = lex;
|
167 |
+
break;
|
168 |
+
}
|
169 |
+
body.push(atom);
|
170 |
+
}
|
171 |
+
return this.handleInfixNodes(body);
|
172 |
+
};
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Rewrites infix operators such as \over with corresponding commands such
|
176 |
+
* as \frac.
|
177 |
+
*
|
178 |
+
* There can only be one infix operator per group. If there's more than one
|
179 |
+
* then the expression is ambiguous. This can be resolved by adding {}.
|
180 |
+
*
|
181 |
+
* @returns {Array}
|
182 |
+
*/
|
183 |
+
Parser.prototype.handleInfixNodes = function(body) {
|
184 |
+
var overIndex = -1;
|
185 |
+
var funcName;
|
186 |
+
|
187 |
+
for (var i = 0; i < body.length; i++) {
|
188 |
+
var node = body[i];
|
189 |
+
if (node.type === "infix") {
|
190 |
+
if (overIndex !== -1) {
|
191 |
+
throw new ParseError("only one infix operator per group",
|
192 |
+
this.lexer, -1);
|
193 |
+
}
|
194 |
+
overIndex = i;
|
195 |
+
funcName = node.value.replaceWith;
|
196 |
+
}
|
197 |
+
}
|
198 |
+
|
199 |
+
if (overIndex !== -1) {
|
200 |
+
var numerNode;
|
201 |
+
var denomNode;
|
202 |
+
|
203 |
+
var numerBody = body.slice(0, overIndex);
|
204 |
+
var denomBody = body.slice(overIndex + 1);
|
205 |
+
|
206 |
+
if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
|
207 |
+
numerNode = numerBody[0];
|
208 |
+
} else {
|
209 |
+
numerNode = new ParseNode("ordgroup", numerBody, this.mode);
|
210 |
+
}
|
211 |
+
|
212 |
+
if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
|
213 |
+
denomNode = denomBody[0];
|
214 |
+
} else {
|
215 |
+
denomNode = new ParseNode("ordgroup", denomBody, this.mode);
|
216 |
+
}
|
217 |
+
|
218 |
+
var value = this.callFunction(
|
219 |
+
funcName, [numerNode, denomNode], null);
|
220 |
+
return [new ParseNode(value.type, value, this.mode)];
|
221 |
+
} else {
|
222 |
+
return body;
|
223 |
+
}
|
224 |
+
};
|
225 |
+
|
226 |
+
// The greediness of a superscript or subscript
|
227 |
+
var SUPSUB_GREEDINESS = 1;
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Handle a subscript or superscript with nice errors.
|
231 |
+
*/
|
232 |
+
Parser.prototype.handleSupSubscript = function(name) {
|
233 |
+
var symbol = this.nextToken.text;
|
234 |
+
var symPos = this.pos;
|
235 |
+
this.consume();
|
236 |
+
var group = this.parseGroup();
|
237 |
+
|
238 |
+
if (!group) {
|
239 |
+
if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") {
|
240 |
+
return this.handleUnsupportedCmd();
|
241 |
+
} else {
|
242 |
+
// throw new ParseError(
|
243 |
+
// "Expected group after '" + symbol + "'",
|
244 |
+
// this.lexer,
|
245 |
+
// symPos + 1
|
246 |
+
// );
|
247 |
+
}
|
248 |
+
} else if (group.isFunction) {
|
249 |
+
// ^ and _ have a greediness, so handle interactions with functions'
|
250 |
+
// greediness
|
251 |
+
var funcGreediness = functions[group.result].greediness;
|
252 |
+
if (funcGreediness > SUPSUB_GREEDINESS) {
|
253 |
+
return this.parseFunction(group);
|
254 |
+
} else {
|
255 |
+
throw new ParseError(
|
256 |
+
"Got function '" + group.result + "' with no arguments " +
|
257 |
+
"as " + name,
|
258 |
+
this.lexer, symPos + 1);
|
259 |
+
}
|
260 |
+
} else {
|
261 |
+
return group.result;
|
262 |
+
}
|
263 |
+
};
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Converts the textual input of an unsupported command into a text node
|
267 |
+
* contained within a color node whose color is determined by errorColor
|
268 |
+
*/
|
269 |
+
Parser.prototype.handleUnsupportedCmd = function() {
|
270 |
+
var text = this.nextToken.text;
|
271 |
+
var textordArray = [];
|
272 |
+
|
273 |
+
for (var i = 0; i < text.length; i++) {
|
274 |
+
textordArray.push(new ParseNode("textord", text[i], "text"));
|
275 |
+
}
|
276 |
+
|
277 |
+
var textNode = new ParseNode(
|
278 |
+
"text",
|
279 |
+
{
|
280 |
+
body: textordArray,
|
281 |
+
type: "text",
|
282 |
+
},
|
283 |
+
this.mode);
|
284 |
+
|
285 |
+
var colorNode = new ParseNode(
|
286 |
+
"color",
|
287 |
+
{
|
288 |
+
color: this.settings.errorColor,
|
289 |
+
value: [textNode],
|
290 |
+
type: "color",
|
291 |
+
},
|
292 |
+
this.mode);
|
293 |
+
|
294 |
+
this.consume();
|
295 |
+
return colorNode;
|
296 |
+
};
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Parses a group with optional super/subscripts.
|
300 |
+
*
|
301 |
+
* @return {?ParseNode}
|
302 |
+
*/
|
303 |
+
Parser.prototype.parseAtom = function() {
|
304 |
+
// The body of an atom is an implicit group, so that things like
|
305 |
+
// \left(x\right)^2 work correctly.
|
306 |
+
var base = this.parseImplicitGroup();
|
307 |
+
|
308 |
+
// In text mode, we don't have superscripts or subscripts
|
309 |
+
if (this.mode === "text") {
|
310 |
+
return base;
|
311 |
+
}
|
312 |
+
|
313 |
+
// Note that base may be empty (i.e. null) at this point.
|
314 |
+
|
315 |
+
var superscript;
|
316 |
+
var subscript;
|
317 |
+
while (true) {
|
318 |
+
// Lex the first token
|
319 |
+
var lex = this.nextToken;
|
320 |
+
|
321 |
+
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
322 |
+
// We got a limit control
|
323 |
+
if (!base || base.type !== "op") {
|
324 |
+
throw new ParseError(
|
325 |
+
"Limit controls must follow a math operator",
|
326 |
+
this.lexer, this.pos);
|
327 |
+
} else {
|
328 |
+
var limits = lex.text === "\\limits";
|
329 |
+
base.value.limits = limits;
|
330 |
+
base.value.alwaysHandleSupSub = true;
|
331 |
+
}
|
332 |
+
this.consume();
|
333 |
+
} else if (lex.text === "^") {
|
334 |
+
// We got a superscript start
|
335 |
+
// if (superscript) {
|
336 |
+
// throw new ParseError(
|
337 |
+
// "Double superscript", this.lexer, this.pos);
|
338 |
+
// }
|
339 |
+
superscript = this.handleSupSubscript("superscript");
|
340 |
+
} else if (lex.text === "_") {
|
341 |
+
// We got a subscript start
|
342 |
+
// if (subscript) {
|
343 |
+
// throw new ParseError(
|
344 |
+
// "Double subscript", this.lexer, this.pos);
|
345 |
+
// }
|
346 |
+
subscript = this.handleSupSubscript("subscript");
|
347 |
+
} else if (lex.text === "'") {
|
348 |
+
// We got a prime
|
349 |
+
var prime = new ParseNode("textord", "\\prime", this.mode);
|
350 |
+
|
351 |
+
// Many primes can be grouped together, so we handle this here
|
352 |
+
var primes = [prime];
|
353 |
+
this.consume();
|
354 |
+
// Keep lexing tokens until we get something that's not a prime
|
355 |
+
while (this.nextToken.text === "'") {
|
356 |
+
// For each one, add another prime to the list
|
357 |
+
primes.push(prime);
|
358 |
+
this.consume();
|
359 |
+
}
|
360 |
+
// Put them into an ordgroup as the superscript
|
361 |
+
superscript = new ParseNode("ordgroup", primes, this.mode);
|
362 |
+
} else {
|
363 |
+
// If it wasn't ^, _, or ', stop parsing super/subscripts
|
364 |
+
break;
|
365 |
+
}
|
366 |
+
}
|
367 |
+
|
368 |
+
if (superscript || subscript) {
|
369 |
+
// If we got either a superscript or subscript, create a supsub
|
370 |
+
return new ParseNode("supsub", {
|
371 |
+
base: base,
|
372 |
+
sup: superscript,
|
373 |
+
sub: subscript,
|
374 |
+
}, this.mode);
|
375 |
+
} else {
|
376 |
+
// Otherwise return the original body
|
377 |
+
return base;
|
378 |
+
}
|
379 |
+
};
|
380 |
+
|
381 |
+
// A list of the size-changing functions, for use in parseImplicitGroup
|
382 |
+
var sizeFuncs = [
|
383 |
+
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
|
384 |
+
"\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", "\\textrm", "\\rm", "\\cal",
|
385 |
+
"\\bf", "\\siptstyle", "\\boldmath", "\\it"
|
386 |
+
];
|
387 |
+
|
388 |
+
// A list of the style-changing functions, for use in parseImplicitGroup
|
389 |
+
var styleFuncs = [
|
390 |
+
"\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle",
|
391 |
+
];
|
392 |
+
|
393 |
+
/**
|
394 |
+
* Parses an implicit group, which is a group that starts at the end of a
|
395 |
+
* specified, and ends right before a higher explicit group ends, or at EOL. It
|
396 |
+
* is used for functions that appear to affect the current style, like \Large or
|
397 |
+
* \textrm, where instead of keeping a style we just pretend that there is an
|
398 |
+
* implicit grouping after it until the end of the group. E.g.
|
399 |
+
* small text {\Large large text} small text again
|
400 |
+
* It is also used for \left and \right to get the correct grouping.
|
401 |
+
*
|
402 |
+
* @return {?ParseNode}
|
403 |
+
*/
|
404 |
+
Parser.prototype.parseImplicitGroup = function() {
|
405 |
+
var start = this.parseSymbol();
|
406 |
+
|
407 |
+
if (start == null) {
|
408 |
+
// If we didn't get anything we handle, fall back to parseFunction
|
409 |
+
return this.parseFunction();
|
410 |
+
}
|
411 |
+
|
412 |
+
var func = start.result;
|
413 |
+
var body;
|
414 |
+
if (func === "\\left") {
|
415 |
+
// If we see a left:
|
416 |
+
// Parse the entire left function (including the delimiter)
|
417 |
+
var left = this.parseFunction(start);
|
418 |
+
// Parse out the implicit body
|
419 |
+
body = this.parseExpression(false);
|
420 |
+
// Check the next token
|
421 |
+
this.expect("\\right", false);
|
422 |
+
var right = this.parseFunction();
|
423 |
+
return new ParseNode("leftright", {
|
424 |
+
body: body,
|
425 |
+
left: left.value.value,
|
426 |
+
right: right.value.value,
|
427 |
+
}, this.mode);
|
428 |
+
} else if (func === "\\begin") {
|
429 |
+
// begin...end is similar to left...right
|
430 |
+
var begin = this.parseFunction(start);
|
431 |
+
var envName = begin.value.name;
|
432 |
+
var name = (begin.value.name + "")
|
433 |
+
|
434 |
+
global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
|
435 |
+
|
436 |
+
if (!environments.hasOwnProperty(envName)) {
|
437 |
+
throw new ParseError(
|
438 |
+
"No such environment: " + envName,
|
439 |
+
this.lexer, begin.value.namepos);
|
440 |
+
}
|
441 |
+
// Build the environment object. Arguments and other information will
|
442 |
+
// be made available to the begin and end methods using properties.
|
443 |
+
var env = environments[envName];
|
444 |
+
var args = this.parseArguments("\\begin{" + envName + "}", env);
|
445 |
+
var context = {
|
446 |
+
mode: this.mode,
|
447 |
+
envName: envName,
|
448 |
+
parser: this,
|
449 |
+
lexer: this.lexer,
|
450 |
+
positions: args.pop(),
|
451 |
+
};
|
452 |
+
var result = env.handler(context, args);
|
453 |
+
this.expect("\\end", false);
|
454 |
+
var end = this.parseFunction();
|
455 |
+
|
456 |
+
var name = (begin.value.name + "")
|
457 |
+
|
458 |
+
global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
|
459 |
+
if (end.value.name !== envName) {
|
460 |
+
throw new ParseError(
|
461 |
+
"Mismatch: \\begin{" + envName + "} matched " +
|
462 |
+
"by \\end{" + end.value.name + "}",
|
463 |
+
this.lexer /* , end.value.namepos */);
|
464 |
+
// TODO: Add position to the above line and adjust test case,
|
465 |
+
// requires #385 to get merged first
|
466 |
+
}
|
467 |
+
result.position = end.position;
|
468 |
+
|
469 |
+
return result;
|
470 |
+
|
471 |
+
} else if (func.value == "\\matrix" || func.value == "\\pmatrix" || func.value == "\\cases") {
|
472 |
+
// if (!environments.hasOwnProperty(envName)) {
|
473 |
+
// throw new ParseError(
|
474 |
+
// "No such environment: " + envName,
|
475 |
+
// this.lexer, begin.value.namepos);
|
476 |
+
// }
|
477 |
+
// Build the environment object. Arguments and other information will
|
478 |
+
// be made available to the begin and end methods using properties.
|
479 |
+
|
480 |
+
envName = func.value.slice(1);
|
481 |
+
var env = environments[envName];
|
482 |
+
// var args = this.parseArguments("\\matrix{", env);
|
483 |
+
this.expect("{", true);
|
484 |
+
var context = {
|
485 |
+
mode: this.mode,
|
486 |
+
envName: envName,
|
487 |
+
parser: this,
|
488 |
+
lexer: this.lexer
|
489 |
+
};
|
490 |
+
|
491 |
+
var result = env.handler(context, {} );
|
492 |
+
// exit();
|
493 |
+
this.expect("}", true);
|
494 |
+
// var end = this.parseFunction();
|
495 |
+
var next = this.nextToken.text;
|
496 |
+
// exit();
|
497 |
+
// console.log(next);
|
498 |
+
// var name = ( + "")
|
499 |
+
|
500 |
+
// global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
|
501 |
+
// result.position = end.position;
|
502 |
+
|
503 |
+
return result;
|
504 |
+
|
505 |
+
} else if (utils.contains(sizeFuncs, func)) {
|
506 |
+
// If we see a sizing function, parse out the implict body
|
507 |
+
body = this.parseExpression(false);
|
508 |
+
|
509 |
+
return new ParseNode("sizing", {
|
510 |
+
// Figure out what size to use based on the list of functions above
|
511 |
+
original: func,
|
512 |
+
size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
|
513 |
+
value: body,
|
514 |
+
}, this.mode);
|
515 |
+
} else if (utils.contains(styleFuncs, func)) {
|
516 |
+
// If we see a styling function, parse out the implict body
|
517 |
+
body = this.parseExpression(true);
|
518 |
+
return new ParseNode("styling", {
|
519 |
+
// Figure out what style to use by pulling out the style from
|
520 |
+
// the function name
|
521 |
+
original: func,
|
522 |
+
style: func.slice(1, func.length - 5),
|
523 |
+
value: body,
|
524 |
+
}, this.mode);
|
525 |
+
} else {
|
526 |
+
// Defer to parseFunction if it's not a function we handle
|
527 |
+
return this.parseFunction(start);
|
528 |
+
}
|
529 |
+
};
|
530 |
+
|
531 |
+
/**
|
532 |
+
* Parses an entire function, including its base and all of its arguments.
|
533 |
+
* The base might either have been parsed already, in which case
|
534 |
+
* it is provided as an argument, or it's the next group in the input.
|
535 |
+
*
|
536 |
+
* @param {ParseFuncOrArgument=} baseGroup optional as described above
|
537 |
+
* @return {?ParseNode}
|
538 |
+
*/
|
539 |
+
Parser.prototype.parseFunction = function(baseGroup) {
|
540 |
+
if (!baseGroup) {
|
541 |
+
baseGroup = this.parseGroup();
|
542 |
+
}
|
543 |
+
|
544 |
+
if (baseGroup) {
|
545 |
+
if (baseGroup.isFunction) {
|
546 |
+
var func = baseGroup.result;
|
547 |
+
var funcData = functions[func];
|
548 |
+
if (this.mode === "text" && !funcData.allowedInText) {
|
549 |
+
// throw new ParseError(
|
550 |
+
// "Can't use function '" + func + "' in text mode",
|
551 |
+
// this.lexer, baseGroup.position);
|
552 |
+
}
|
553 |
+
|
554 |
+
var args = this.parseArguments(func, funcData);
|
555 |
+
var result = this.callFunction(func, args, args.pop());
|
556 |
+
return new ParseNode(result.type, result, this.mode);
|
557 |
+
} else {
|
558 |
+
return baseGroup.result;
|
559 |
+
}
|
560 |
+
} else {
|
561 |
+
return null;
|
562 |
+
}
|
563 |
+
};
|
564 |
+
|
565 |
+
/**
|
566 |
+
* Call a function handler with a suitable context and arguments.
|
567 |
+
*/
|
568 |
+
Parser.prototype.callFunction = function(name, args, positions) {
|
569 |
+
var context = {
|
570 |
+
funcName: name,
|
571 |
+
parser: this,
|
572 |
+
lexer: this.lexer,
|
573 |
+
positions: positions,
|
574 |
+
};
|
575 |
+
return functions[name].handler(context, args);
|
576 |
+
};
|
577 |
+
|
578 |
+
/**
|
579 |
+
* Parses the arguments of a function or environment
|
580 |
+
*
|
581 |
+
* @param {string} func "\name" or "\begin{name}"
|
582 |
+
* @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData
|
583 |
+
* @return the array of arguments, with the list of positions as last element
|
584 |
+
*/
|
585 |
+
Parser.prototype.parseArguments = function(func, funcData) {
|
586 |
+
var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
587 |
+
if (totalArgs === 0) {
|
588 |
+
return [[this.pos]];
|
589 |
+
}
|
590 |
+
|
591 |
+
var baseGreediness = funcData.greediness;
|
592 |
+
var positions = [this.pos];
|
593 |
+
var args = [];
|
594 |
+
|
595 |
+
for (var i = 0; i < totalArgs; i++) {
|
596 |
+
var argType = funcData.argTypes && funcData.argTypes[i];
|
597 |
+
var arg;
|
598 |
+
if (i < funcData.numOptionalArgs) {
|
599 |
+
if (argType) {
|
600 |
+
arg = this.parseSpecialGroup(argType, true);
|
601 |
+
} else {
|
602 |
+
arg = this.parseOptionalGroup();
|
603 |
+
}
|
604 |
+
if (!arg) {
|
605 |
+
args.push(null);
|
606 |
+
positions.push(this.pos);
|
607 |
+
continue;
|
608 |
+
}
|
609 |
+
} else {
|
610 |
+
if (argType) {
|
611 |
+
arg = this.parseSpecialGroup(argType);
|
612 |
+
} else {
|
613 |
+
arg = this.parseGroup();
|
614 |
+
}
|
615 |
+
if (!arg) {
|
616 |
+
if (!this.settings.throwOnError &&
|
617 |
+
this.nextToken.text[0] === "\\") {
|
618 |
+
arg = new ParseFuncOrArgument(
|
619 |
+
this.handleUnsupportedCmd(this.nextToken.text),
|
620 |
+
false);
|
621 |
+
} else {
|
622 |
+
throw new ParseError(
|
623 |
+
"Expected group after '" + func + "'",
|
624 |
+
this.lexer, this.pos);
|
625 |
+
}
|
626 |
+
}
|
627 |
+
}
|
628 |
+
var argNode;
|
629 |
+
if (arg.isFunction) {
|
630 |
+
var argGreediness =
|
631 |
+
functions[arg.result].greediness;
|
632 |
+
if (argGreediness > baseGreediness) {
|
633 |
+
argNode = this.parseFunction(arg);
|
634 |
+
} else {
|
635 |
+
// throw new ParseError(
|
636 |
+
// "Got function '" + arg.result + "' as " +
|
637 |
+
// "argument to '" + func + "'",
|
638 |
+
// this.lexer, this.pos - 1);
|
639 |
+
}
|
640 |
+
} else {
|
641 |
+
argNode = arg.result;
|
642 |
+
}
|
643 |
+
args.push(argNode);
|
644 |
+
positions.push(this.pos);
|
645 |
+
}
|
646 |
+
|
647 |
+
args.push(positions);
|
648 |
+
|
649 |
+
return args;
|
650 |
+
};
|
651 |
+
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Parses a group when the mode is changing. Takes a position, a new mode, and
|
655 |
+
* an outer mode that is used to parse the outside.
|
656 |
+
*
|
657 |
+
* @return {?ParseFuncOrArgument}
|
658 |
+
*/
|
659 |
+
Parser.prototype.parseSpecialGroup = function(innerMode, optional) {
|
660 |
+
var outerMode = this.mode;
|
661 |
+
// Handle `original` argTypes
|
662 |
+
if (innerMode === "original") {
|
663 |
+
innerMode = outerMode;
|
664 |
+
}
|
665 |
+
|
666 |
+
if (innerMode === "color" || innerMode === "size") {
|
667 |
+
// color and size modes are special because they should have braces and
|
668 |
+
// should only lex a single symbol inside
|
669 |
+
var openBrace = this.nextToken;
|
670 |
+
if (optional && openBrace.text !== "[") {
|
671 |
+
// optional arguments should return null if they don't exist
|
672 |
+
return null;
|
673 |
+
}
|
674 |
+
// The call to expect will lex the token after the '{' in inner mode
|
675 |
+
this.mode = innerMode;
|
676 |
+
this.expect(optional ? "[" : "{");
|
677 |
+
var inner = this.nextToken;
|
678 |
+
this.mode = outerMode;
|
679 |
+
var data;
|
680 |
+
if (innerMode === "color") {
|
681 |
+
data = inner.text;
|
682 |
+
} else {
|
683 |
+
data = inner.data;
|
684 |
+
}
|
685 |
+
this.consume(); // consume the token stored in inner
|
686 |
+
this.expect(optional ? "]" : "}");
|
687 |
+
return new ParseFuncOrArgument(
|
688 |
+
new ParseNode(innerMode, data, outerMode),
|
689 |
+
false);
|
690 |
+
} else if (innerMode === "text") {
|
691 |
+
// text mode is special because it should ignore the whitespace before
|
692 |
+
// it
|
693 |
+
var whitespace = this.lexer.lex(this.pos, "whitespace");
|
694 |
+
this.pos = whitespace.position;
|
695 |
+
}
|
696 |
+
|
697 |
+
// By the time we get here, innerMode is one of "text" or "math".
|
698 |
+
// We switch the mode of the parser, recurse, then restore the old mode.
|
699 |
+
this.mode = innerMode;
|
700 |
+
this.nextToken = this.lexer.lex(this.pos, innerMode);
|
701 |
+
var res;
|
702 |
+
if (optional) {
|
703 |
+
res = this.parseOptionalGroup();
|
704 |
+
} else {
|
705 |
+
res = this.parseGroup();
|
706 |
+
}
|
707 |
+
this.mode = outerMode;
|
708 |
+
this.nextToken = this.lexer.lex(this.pos, outerMode);
|
709 |
+
return res;
|
710 |
+
};
|
711 |
+
|
712 |
+
/**
|
713 |
+
* Parses a group, which is either a single nucleus (like "x") or an expression
|
714 |
+
* in braces (like "{x+y}")
|
715 |
+
*
|
716 |
+
* @return {?ParseFuncOrArgument}
|
717 |
+
*/
|
718 |
+
Parser.prototype.parseGroup = function() {
|
719 |
+
// Try to parse an open brace
|
720 |
+
if (this.nextToken.text === "{") {
|
721 |
+
// If we get a brace, parse an expression
|
722 |
+
this.consume();
|
723 |
+
var expression = this.parseExpression(false);
|
724 |
+
// Make sure we get a close brace
|
725 |
+
this.expect("}");
|
726 |
+
return new ParseFuncOrArgument(
|
727 |
+
new ParseNode("ordgroup", expression, this.mode),
|
728 |
+
false);
|
729 |
+
} else {
|
730 |
+
// Otherwise, just return a nucleus
|
731 |
+
return this.parseSymbol();
|
732 |
+
}
|
733 |
+
};
|
734 |
+
|
735 |
+
/**
|
736 |
+
* Parses a group, which is an expression in brackets (like "[x+y]")
|
737 |
+
*
|
738 |
+
* @return {?ParseFuncOrArgument}
|
739 |
+
*/
|
740 |
+
Parser.prototype.parseOptionalGroup = function() {
|
741 |
+
// Try to parse an open bracket
|
742 |
+
if (this.nextToken.text === "[") {
|
743 |
+
// If we get a brace, parse an expression
|
744 |
+
this.consume();
|
745 |
+
var expression = this.parseExpression(false, "]");
|
746 |
+
// Make sure we get a close bracket
|
747 |
+
this.expect("]");
|
748 |
+
return new ParseFuncOrArgument(
|
749 |
+
new ParseNode("ordgroup", expression, this.mode),
|
750 |
+
false);
|
751 |
+
} else {
|
752 |
+
// Otherwise, return null,
|
753 |
+
return null;
|
754 |
+
}
|
755 |
+
};
|
756 |
+
|
757 |
+
/**
|
758 |
+
* Parse a single symbol out of the string. Here, we handle both the functions
|
759 |
+
* we have defined, as well as the single character symbols
|
760 |
+
*
|
761 |
+
* @return {?ParseFuncOrArgument}
|
762 |
+
*/
|
763 |
+
Parser.prototype.parseSymbol = function() {
|
764 |
+
var nucleus = this.nextToken;
|
765 |
+
|
766 |
+
if (functions[nucleus.text]) {
|
767 |
+
this.consume();
|
768 |
+
// If there exists a function with this name, we return the function and
|
769 |
+
// say that it is a function.
|
770 |
+
return new ParseFuncOrArgument(
|
771 |
+
nucleus.text,
|
772 |
+
true);
|
773 |
+
} else if (symbols[this.mode][nucleus.text]) {
|
774 |
+
this.consume();
|
775 |
+
// Otherwise if this is a no-argument function, find the type it
|
776 |
+
// corresponds to in the symbols map
|
777 |
+
return new ParseFuncOrArgument(
|
778 |
+
new ParseNode(symbols[this.mode][nucleus.text].group,
|
779 |
+
nucleus.text, this.mode),
|
780 |
+
false);
|
781 |
+
} else if (nucleus.text == "EOF" || nucleus.text == "{") {
|
782 |
+
return null;
|
783 |
+
|
784 |
+
} else {
|
785 |
+
this.consume();
|
786 |
+
// console.error(nucleus);
|
787 |
+
return new ParseFuncOrArgument(
|
788 |
+
new ParseNode(symbols["math"]["\\sigma"].group,
|
789 |
+
nucleus.text, this.mode),
|
790 |
+
false);
|
791 |
+
// console.log(nucleus.text);
|
792 |
+
// return null;
|
793 |
+
}
|
794 |
+
};
|
795 |
+
|
796 |
+
Parser.prototype.ParseNode = ParseNode;
|
797 |
+
|
798 |
+
module.exports = Parser;
|
modules/tokenize_latex/third_party/katex/src/Settings.js
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This is a module for storing settings passed into KaTeX. It correctly handles
|
3 |
+
* default settings.
|
4 |
+
*/
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Helper function for getting a default value if the value is undefined
|
8 |
+
*/
|
9 |
+
function get(option, defaultValue) {
|
10 |
+
return option === undefined ? defaultValue : option;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* The main Settings object
|
15 |
+
*
|
16 |
+
* The current options stored are:
|
17 |
+
* - displayMode: Whether the expression should be typeset by default in
|
18 |
+
* textstyle or displaystyle (default false)
|
19 |
+
*/
|
20 |
+
function Settings(options) {
|
21 |
+
// allow null options
|
22 |
+
options = options || {};
|
23 |
+
this.displayMode = get(options.displayMode, false);
|
24 |
+
this.throwOnError = get(options.throwOnError, true);
|
25 |
+
this.errorColor = get(options.errorColor, "#cc0000");
|
26 |
+
}
|
27 |
+
|
28 |
+
module.exports = Settings;
|
modules/tokenize_latex/third_party/katex/src/Style.js
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file contains information and classes for the various kinds of styles
|
3 |
+
* used in TeX. It provides a generic `Style` class, which holds information
|
4 |
+
* about a specific style. It then provides instances of all the different kinds
|
5 |
+
* of styles possible, and provides functions to move between them and get
|
6 |
+
* information about them.
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* The main style class. Contains a unique id for the style, a size (which is
|
11 |
+
* the same for cramped and uncramped version of a style), a cramped flag, and a
|
12 |
+
* size multiplier, which gives the size difference between a style and
|
13 |
+
* textstyle.
|
14 |
+
*/
|
15 |
+
function Style(id, size, multiplier, cramped) {
|
16 |
+
this.id = id;
|
17 |
+
this.size = size;
|
18 |
+
this.cramped = cramped;
|
19 |
+
this.sizeMultiplier = multiplier;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Get the style of a superscript given a base in the current style.
|
24 |
+
*/
|
25 |
+
Style.prototype.sup = function() {
|
26 |
+
return styles[sup[this.id]];
|
27 |
+
};
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Get the style of a subscript given a base in the current style.
|
31 |
+
*/
|
32 |
+
Style.prototype.sub = function() {
|
33 |
+
return styles[sub[this.id]];
|
34 |
+
};
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Get the style of a fraction numerator given the fraction in the current
|
38 |
+
* style.
|
39 |
+
*/
|
40 |
+
Style.prototype.fracNum = function() {
|
41 |
+
return styles[fracNum[this.id]];
|
42 |
+
};
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Get the style of a fraction denominator given the fraction in the current
|
46 |
+
* style.
|
47 |
+
*/
|
48 |
+
Style.prototype.fracDen = function() {
|
49 |
+
return styles[fracDen[this.id]];
|
50 |
+
};
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Get the cramped version of a style (in particular, cramping a cramped style
|
54 |
+
* doesn't change the style).
|
55 |
+
*/
|
56 |
+
Style.prototype.cramp = function() {
|
57 |
+
return styles[cramp[this.id]];
|
58 |
+
};
|
59 |
+
|
60 |
+
/**
|
61 |
+
* HTML class name, like "displaystyle cramped"
|
62 |
+
*/
|
63 |
+
Style.prototype.cls = function() {
|
64 |
+
return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped");
|
65 |
+
};
|
66 |
+
|
67 |
+
/**
|
68 |
+
* HTML Reset class name, like "reset-textstyle"
|
69 |
+
*/
|
70 |
+
Style.prototype.reset = function() {
|
71 |
+
return resetNames[this.size];
|
72 |
+
};
|
73 |
+
|
74 |
+
// IDs of the different styles
|
75 |
+
var D = 0;
|
76 |
+
var Dc = 1;
|
77 |
+
var T = 2;
|
78 |
+
var Tc = 3;
|
79 |
+
var S = 4;
|
80 |
+
var Sc = 5;
|
81 |
+
var SS = 6;
|
82 |
+
var SSc = 7;
|
83 |
+
|
84 |
+
// String names for the different sizes
|
85 |
+
var sizeNames = [
|
86 |
+
"displaystyle textstyle",
|
87 |
+
"textstyle",
|
88 |
+
"scriptstyle",
|
89 |
+
"scriptscriptstyle",
|
90 |
+
];
|
91 |
+
|
92 |
+
// Reset names for the different sizes
|
93 |
+
var resetNames = [
|
94 |
+
"reset-textstyle",
|
95 |
+
"reset-textstyle",
|
96 |
+
"reset-scriptstyle",
|
97 |
+
"reset-scriptscriptstyle",
|
98 |
+
];
|
99 |
+
|
100 |
+
// Instances of the different styles
|
101 |
+
var styles = [
|
102 |
+
new Style(D, 0, 1.0, false),
|
103 |
+
new Style(Dc, 0, 1.0, true),
|
104 |
+
new Style(T, 1, 1.0, false),
|
105 |
+
new Style(Tc, 1, 1.0, true),
|
106 |
+
new Style(S, 2, 0.7, false),
|
107 |
+
new Style(Sc, 2, 0.7, true),
|
108 |
+
new Style(SS, 3, 0.5, false),
|
109 |
+
new Style(SSc, 3, 0.5, true),
|
110 |
+
];
|
111 |
+
|
112 |
+
// Lookup tables for switching from one style to another
|
113 |
+
var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
|
114 |
+
var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
|
115 |
+
var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
|
116 |
+
var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
|
117 |
+
var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
|
118 |
+
|
119 |
+
// We only export some of the styles. Also, we don't export the `Style` class so
|
120 |
+
// no more styles can be generated.
|
121 |
+
module.exports = {
|
122 |
+
DISPLAY: styles[D],
|
123 |
+
TEXT: styles[T],
|
124 |
+
SCRIPT: styles[S],
|
125 |
+
SCRIPTSCRIPT: styles[SS],
|
126 |
+
};
|
modules/tokenize_latex/third_party/katex/src/buildCommon.js
ADDED
@@ -0,0 +1,450 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-console:0 */
|
2 |
+
/**
|
3 |
+
* This module contains general functions that can be used for building
|
4 |
+
* different kinds of domTree nodes in a consistent manner.
|
5 |
+
*/
|
6 |
+
|
7 |
+
var domTree = require("./domTree");
|
8 |
+
var fontMetrics = require("./fontMetrics");
|
9 |
+
var symbols = require("./symbols");
|
10 |
+
var utils = require("./utils");
|
11 |
+
|
12 |
+
var greekCapitals = [
|
13 |
+
"\\Gamma",
|
14 |
+
"\\Delta",
|
15 |
+
"\\Theta",
|
16 |
+
"\\Lambda",
|
17 |
+
"\\Xi",
|
18 |
+
"\\Pi",
|
19 |
+
"\\Sigma",
|
20 |
+
"\\Upsilon",
|
21 |
+
"\\Phi",
|
22 |
+
"\\Psi",
|
23 |
+
"\\Omega",
|
24 |
+
];
|
25 |
+
|
26 |
+
var dotlessLetters = [
|
27 |
+
"\u0131", // dotless i, \imath
|
28 |
+
"\u0237", // dotless j, \jmath
|
29 |
+
];
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Makes a symbolNode after translation via the list of symbols in symbols.js.
|
33 |
+
* Correctly pulls out metrics for the character, and optionally takes a list of
|
34 |
+
* classes to be attached to the node.
|
35 |
+
*/
|
36 |
+
var makeSymbol = function(value, style, mode, color, classes) {
|
37 |
+
// Replace the value with its replaced value from symbol.js
|
38 |
+
if (symbols[mode][value] && symbols[mode][value].replace) {
|
39 |
+
value = symbols[mode][value].replace;
|
40 |
+
}
|
41 |
+
|
42 |
+
var metrics = fontMetrics.getCharacterMetrics(value, style);
|
43 |
+
|
44 |
+
var symbolNode;
|
45 |
+
if (metrics) {
|
46 |
+
symbolNode = new domTree.symbolNode(
|
47 |
+
value, metrics.height, metrics.depth, metrics.italic, metrics.skew,
|
48 |
+
classes);
|
49 |
+
} else {
|
50 |
+
// TODO(emily): Figure out a good way to only print this in development
|
51 |
+
typeof console !== "undefined" && console.warn(
|
52 |
+
"No character metrics for '" + value + "' in style '" +
|
53 |
+
style + "'");
|
54 |
+
symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
|
55 |
+
}
|
56 |
+
|
57 |
+
if (color) {
|
58 |
+
symbolNode.style.color = color;
|
59 |
+
}
|
60 |
+
|
61 |
+
return symbolNode;
|
62 |
+
};
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Makes a symbol in Main-Regular or AMS-Regular.
|
66 |
+
* Used for rel, bin, open, close, inner, and punct.
|
67 |
+
*/
|
68 |
+
var mathsym = function(value, mode, color, classes) {
|
69 |
+
// Decide what font to render the symbol in by its entry in the symbols
|
70 |
+
// table.
|
71 |
+
// Have a special case for when the value = \ because the \ is used as a
|
72 |
+
// textord in unsupported command errors but cannot be parsed as a regular
|
73 |
+
// text ordinal and is therefore not present as a symbol in the symbols
|
74 |
+
// table for text
|
75 |
+
if (value === "\\" || symbols[mode][value].font === "main") {
|
76 |
+
return makeSymbol(value, "Main-Regular", mode, color, classes);
|
77 |
+
} else {
|
78 |
+
return makeSymbol(
|
79 |
+
value, "AMS-Regular", mode, color, classes.concat(["amsrm"]));
|
80 |
+
}
|
81 |
+
};
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Makes a symbol in the default font for mathords and textords.
|
85 |
+
*/
|
86 |
+
var mathDefault = function(value, mode, color, classes, type) {
|
87 |
+
if (type === "mathord") {
|
88 |
+
return mathit(value, mode, color, classes);
|
89 |
+
} else if (type === "textord") {
|
90 |
+
return makeSymbol(
|
91 |
+
value, "Main-Regular", mode, color, classes.concat(["mathrm"]));
|
92 |
+
} else {
|
93 |
+
throw new Error("unexpected type: " + type + " in mathDefault");
|
94 |
+
}
|
95 |
+
};
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Makes a symbol in the italic math font.
|
99 |
+
*/
|
100 |
+
var mathit = function(value, mode, color, classes) {
|
101 |
+
if (/[0-9]/.test(value.charAt(0)) ||
|
102 |
+
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
103 |
+
// need to use Main-Italic instead
|
104 |
+
utils.contains(dotlessLetters, value) ||
|
105 |
+
utils.contains(greekCapitals, value)) {
|
106 |
+
return makeSymbol(
|
107 |
+
value, "Main-Italic", mode, color, classes.concat(["mainit"]));
|
108 |
+
} else {
|
109 |
+
return makeSymbol(
|
110 |
+
value, "Math-Italic", mode, color, classes.concat(["mathit"]));
|
111 |
+
}
|
112 |
+
};
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Makes either a mathord or textord in the correct font and color.
|
116 |
+
*/
|
117 |
+
var makeOrd = function(group, options, type) {
|
118 |
+
var mode = group.mode;
|
119 |
+
var value = group.value;
|
120 |
+
if (symbols[mode][value] && symbols[mode][value].replace) {
|
121 |
+
value = symbols[mode][value].replace;
|
122 |
+
}
|
123 |
+
|
124 |
+
var classes = ["mord"];
|
125 |
+
var color = options.getColor();
|
126 |
+
|
127 |
+
var font = options.font;
|
128 |
+
if (font) {
|
129 |
+
if (font === "mathit" || utils.contains(dotlessLetters, value)) {
|
130 |
+
return mathit(value, mode, color, classes);
|
131 |
+
} else {
|
132 |
+
var fontName = fontMap[font].fontName;
|
133 |
+
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
134 |
+
return makeSymbol(
|
135 |
+
value, fontName, mode, color, classes.concat([font]));
|
136 |
+
} else {
|
137 |
+
return mathDefault(value, mode, color, classes, type);
|
138 |
+
}
|
139 |
+
}
|
140 |
+
} else {
|
141 |
+
return mathDefault(value, mode, color, classes, type);
|
142 |
+
}
|
143 |
+
};
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Calculate the height, depth, and maxFontSize of an element based on its
|
147 |
+
* children.
|
148 |
+
*/
|
149 |
+
var sizeElementFromChildren = function(elem) {
|
150 |
+
var height = 0;
|
151 |
+
var depth = 0;
|
152 |
+
var maxFontSize = 0;
|
153 |
+
|
154 |
+
if (elem.children) {
|
155 |
+
for (var i = 0; i < elem.children.length; i++) {
|
156 |
+
if (elem.children[i].height > height) {
|
157 |
+
height = elem.children[i].height;
|
158 |
+
}
|
159 |
+
if (elem.children[i].depth > depth) {
|
160 |
+
depth = elem.children[i].depth;
|
161 |
+
}
|
162 |
+
if (elem.children[i].maxFontSize > maxFontSize) {
|
163 |
+
maxFontSize = elem.children[i].maxFontSize;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
elem.height = height;
|
169 |
+
elem.depth = depth;
|
170 |
+
elem.maxFontSize = maxFontSize;
|
171 |
+
};
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Makes a span with the given list of classes, list of children, and color.
|
175 |
+
*/
|
176 |
+
var makeSpan = function(classes, children, color) {
|
177 |
+
var span = new domTree.span(classes, children);
|
178 |
+
|
179 |
+
sizeElementFromChildren(span);
|
180 |
+
|
181 |
+
if (color) {
|
182 |
+
span.style.color = color;
|
183 |
+
}
|
184 |
+
|
185 |
+
return span;
|
186 |
+
};
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Makes a document fragment with the given list of children.
|
190 |
+
*/
|
191 |
+
var makeFragment = function(children) {
|
192 |
+
var fragment = new domTree.documentFragment(children);
|
193 |
+
|
194 |
+
sizeElementFromChildren(fragment);
|
195 |
+
|
196 |
+
return fragment;
|
197 |
+
};
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Makes an element placed in each of the vlist elements to ensure that each
|
201 |
+
* element has the same max font size. To do this, we create a zero-width space
|
202 |
+
* with the correct font size.
|
203 |
+
*/
|
204 |
+
var makeFontSizer = function(options, fontSize) {
|
205 |
+
var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
|
206 |
+
fontSizeInner.style.fontSize =
|
207 |
+
(fontSize / options.style.sizeMultiplier) + "em";
|
208 |
+
|
209 |
+
var fontSizer = makeSpan(
|
210 |
+
["fontsize-ensurer", "reset-" + options.size, "size5"],
|
211 |
+
[fontSizeInner]);
|
212 |
+
|
213 |
+
return fontSizer;
|
214 |
+
};
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Makes a vertical list by stacking elements and kerns on top of each other.
|
218 |
+
* Allows for many different ways of specifying the positioning method.
|
219 |
+
*
|
220 |
+
* Arguments:
|
221 |
+
* - children: A list of child or kern nodes to be stacked on top of each other
|
222 |
+
* (i.e. the first element will be at the bottom, and the last at
|
223 |
+
* the top). Element nodes are specified as
|
224 |
+
* {type: "elem", elem: node}
|
225 |
+
* while kern nodes are specified as
|
226 |
+
* {type: "kern", size: size}
|
227 |
+
* - positionType: The method by which the vlist should be positioned. Valid
|
228 |
+
* values are:
|
229 |
+
* - "individualShift": The children list only contains elem
|
230 |
+
* nodes, and each node contains an extra
|
231 |
+
* "shift" value of how much it should be
|
232 |
+
* shifted (note that shifting is always
|
233 |
+
* moving downwards). positionData is
|
234 |
+
* ignored.
|
235 |
+
* - "top": The positionData specifies the topmost point of
|
236 |
+
* the vlist (note this is expected to be a height,
|
237 |
+
* so positive values move up)
|
238 |
+
* - "bottom": The positionData specifies the bottommost point
|
239 |
+
* of the vlist (note this is expected to be a
|
240 |
+
* depth, so positive values move down
|
241 |
+
* - "shift": The vlist will be positioned such that its
|
242 |
+
* baseline is positionData away from the baseline
|
243 |
+
* of the first child. Positive values move
|
244 |
+
* downwards.
|
245 |
+
* - "firstBaseline": The vlist will be positioned such that
|
246 |
+
* its baseline is aligned with the
|
247 |
+
* baseline of the first child.
|
248 |
+
* positionData is ignored. (this is
|
249 |
+
* equivalent to "shift" with
|
250 |
+
* positionData=0)
|
251 |
+
* - positionData: Data used in different ways depending on positionType
|
252 |
+
* - options: An Options object
|
253 |
+
*
|
254 |
+
*/
|
255 |
+
var makeVList = function(children, positionType, positionData, options) {
|
256 |
+
var depth;
|
257 |
+
var currPos;
|
258 |
+
var i;
|
259 |
+
if (positionType === "individualShift") {
|
260 |
+
var oldChildren = children;
|
261 |
+
children = [oldChildren[0]];
|
262 |
+
|
263 |
+
// Add in kerns to the list of children to get each element to be
|
264 |
+
// shifted to the correct specified shift
|
265 |
+
depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
|
266 |
+
currPos = depth;
|
267 |
+
for (i = 1; i < oldChildren.length; i++) {
|
268 |
+
var diff = -oldChildren[i].shift - currPos -
|
269 |
+
oldChildren[i].elem.depth;
|
270 |
+
var size = diff -
|
271 |
+
(oldChildren[i - 1].elem.height +
|
272 |
+
oldChildren[i - 1].elem.depth);
|
273 |
+
|
274 |
+
currPos = currPos + diff;
|
275 |
+
|
276 |
+
children.push({type: "kern", size: size});
|
277 |
+
children.push(oldChildren[i]);
|
278 |
+
}
|
279 |
+
} else if (positionType === "top") {
|
280 |
+
// We always start at the bottom, so calculate the bottom by adding up
|
281 |
+
// all the sizes
|
282 |
+
var bottom = positionData;
|
283 |
+
for (i = 0; i < children.length; i++) {
|
284 |
+
if (children[i].type === "kern") {
|
285 |
+
bottom -= children[i].size;
|
286 |
+
} else {
|
287 |
+
bottom -= children[i].elem.height + children[i].elem.depth;
|
288 |
+
}
|
289 |
+
}
|
290 |
+
depth = bottom;
|
291 |
+
} else if (positionType === "bottom") {
|
292 |
+
depth = -positionData;
|
293 |
+
} else if (positionType === "shift") {
|
294 |
+
depth = -children[0].elem.depth - positionData;
|
295 |
+
} else if (positionType === "firstBaseline") {
|
296 |
+
depth = -children[0].elem.depth;
|
297 |
+
} else {
|
298 |
+
depth = 0;
|
299 |
+
}
|
300 |
+
|
301 |
+
// Make the fontSizer
|
302 |
+
var maxFontSize = 0;
|
303 |
+
for (i = 0; i < children.length; i++) {
|
304 |
+
if (children[i].type === "elem") {
|
305 |
+
maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
|
306 |
+
}
|
307 |
+
}
|
308 |
+
var fontSizer = makeFontSizer(options, maxFontSize);
|
309 |
+
|
310 |
+
// Create a new list of actual children at the correct offsets
|
311 |
+
var realChildren = [];
|
312 |
+
currPos = depth;
|
313 |
+
for (i = 0; i < children.length; i++) {
|
314 |
+
if (children[i].type === "kern") {
|
315 |
+
currPos += children[i].size;
|
316 |
+
} else {
|
317 |
+
var child = children[i].elem;
|
318 |
+
|
319 |
+
var shift = -child.depth - currPos;
|
320 |
+
currPos += child.height + child.depth;
|
321 |
+
|
322 |
+
var childWrap = makeSpan([], [fontSizer, child]);
|
323 |
+
childWrap.height -= shift;
|
324 |
+
childWrap.depth += shift;
|
325 |
+
childWrap.style.top = shift + "em";
|
326 |
+
|
327 |
+
realChildren.push(childWrap);
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
// Add in an element at the end with no offset to fix the calculation of
|
332 |
+
// baselines in some browsers (namely IE, sometimes safari)
|
333 |
+
var baselineFix = makeSpan(
|
334 |
+
["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]);
|
335 |
+
realChildren.push(baselineFix);
|
336 |
+
|
337 |
+
var vlist = makeSpan(["vlist"], realChildren);
|
338 |
+
// Fix the final height and depth, in case there were kerns at the ends
|
339 |
+
// since the makeSpan calculation won't take that in to account.
|
340 |
+
vlist.height = Math.max(currPos, vlist.height);
|
341 |
+
vlist.depth = Math.max(-depth, vlist.depth);
|
342 |
+
return vlist;
|
343 |
+
};
|
344 |
+
|
345 |
+
// A table of size -> font size for the different sizing functions
|
346 |
+
var sizingMultiplier = {
|
347 |
+
size1: 0.5,
|
348 |
+
size2: 0.7,
|
349 |
+
size3: 0.8,
|
350 |
+
size4: 0.9,
|
351 |
+
size5: 1.0,
|
352 |
+
size6: 1.2,
|
353 |
+
size7: 1.44,
|
354 |
+
size8: 1.73,
|
355 |
+
size9: 2.07,
|
356 |
+
size10: 2.49,
|
357 |
+
};
|
358 |
+
|
359 |
+
// A map of spacing functions to their attributes, like size and corresponding
|
360 |
+
// CSS class
|
361 |
+
var spacingFunctions = {
|
362 |
+
"\\qquad": {
|
363 |
+
size: "2em",
|
364 |
+
className: "qquad",
|
365 |
+
},
|
366 |
+
"\\quad": {
|
367 |
+
size: "1em",
|
368 |
+
className: "quad",
|
369 |
+
},
|
370 |
+
"\\enspace": {
|
371 |
+
size: "0.5em",
|
372 |
+
className: "enspace",
|
373 |
+
},
|
374 |
+
"\\;": {
|
375 |
+
size: "0.277778em",
|
376 |
+
className: "thickspace",
|
377 |
+
},
|
378 |
+
"\\:": {
|
379 |
+
size: "0.22222em",
|
380 |
+
className: "mediumspace",
|
381 |
+
},
|
382 |
+
"\\,": {
|
383 |
+
size: "0.16667em",
|
384 |
+
className: "thinspace",
|
385 |
+
},
|
386 |
+
"\\!": {
|
387 |
+
size: "-0.16667em",
|
388 |
+
className: "negativethinspace",
|
389 |
+
},
|
390 |
+
};
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Maps TeX font commands to objects containing:
|
394 |
+
* - variant: string used for "mathvariant" attribute in buildMathML.js
|
395 |
+
* - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
|
396 |
+
*/
|
397 |
+
// A map between tex font commands an MathML mathvariant attribute values
|
398 |
+
var fontMap = {
|
399 |
+
// styles
|
400 |
+
"mathbf": {
|
401 |
+
variant: "bold",
|
402 |
+
fontName: "Main-Bold",
|
403 |
+
},
|
404 |
+
"mathrm": {
|
405 |
+
variant: "normal",
|
406 |
+
fontName: "Main-Regular",
|
407 |
+
},
|
408 |
+
|
409 |
+
// "mathit" is missing because it requires the use of two fonts: Main-Italic
|
410 |
+
// and Math-Italic. This is handled by a special case in makeOrd which ends
|
411 |
+
// up calling mathit.
|
412 |
+
|
413 |
+
// families
|
414 |
+
"mathbb": {
|
415 |
+
variant: "double-struck",
|
416 |
+
fontName: "AMS-Regular",
|
417 |
+
},
|
418 |
+
"mathcal": {
|
419 |
+
variant: "script",
|
420 |
+
fontName: "Caligraphic-Regular",
|
421 |
+
},
|
422 |
+
"mathfrak": {
|
423 |
+
variant: "fraktur",
|
424 |
+
fontName: "Fraktur-Regular",
|
425 |
+
},
|
426 |
+
"mathscr": {
|
427 |
+
variant: "script",
|
428 |
+
fontName: "Script-Regular",
|
429 |
+
},
|
430 |
+
"mathsf": {
|
431 |
+
variant: "sans-serif",
|
432 |
+
fontName: "SansSerif-Regular",
|
433 |
+
},
|
434 |
+
"mathtt": {
|
435 |
+
variant: "monospace",
|
436 |
+
fontName: "Typewriter-Regular",
|
437 |
+
},
|
438 |
+
};
|
439 |
+
|
440 |
+
module.exports = {
|
441 |
+
fontMap: fontMap,
|
442 |
+
makeSymbol: makeSymbol,
|
443 |
+
mathsym: mathsym,
|
444 |
+
makeSpan: makeSpan,
|
445 |
+
makeFragment: makeFragment,
|
446 |
+
makeVList: makeVList,
|
447 |
+
makeOrd: makeOrd,
|
448 |
+
sizingMultiplier: sizingMultiplier,
|
449 |
+
spacingFunctions: spacingFunctions,
|
450 |
+
};
|
modules/tokenize_latex/third_party/katex/src/buildHTML.js
ADDED
@@ -0,0 +1,1402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-console:0 */
|
2 |
+
/**
|
3 |
+
* This file does the main work of building a domTree structure from a parse
|
4 |
+
* tree. The entry point is the `buildHTML` function, which takes a parse tree.
|
5 |
+
* Then, the buildExpression, buildGroup, and various groupTypes functions are
|
6 |
+
* called, to produce a final HTML tree.
|
7 |
+
*/
|
8 |
+
|
9 |
+
var ParseError = require("./ParseError");
|
10 |
+
var Style = require("./Style");
|
11 |
+
|
12 |
+
var buildCommon = require("./buildCommon");
|
13 |
+
var delimiter = require("./delimiter");
|
14 |
+
var domTree = require("./domTree");
|
15 |
+
var fontMetrics = require("./fontMetrics");
|
16 |
+
var utils = require("./utils");
|
17 |
+
|
18 |
+
var makeSpan = buildCommon.makeSpan;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Take a list of nodes, build them in order, and return a list of the built
|
22 |
+
* nodes. This function handles the `prev` node correctly, and passes the
|
23 |
+
* previous element from the list as the prev of the next element.
|
24 |
+
*/
|
25 |
+
var buildExpression = function(expression, options, prev) {
|
26 |
+
var groups = [];
|
27 |
+
for (var i = 0; i < expression.length; i++) {
|
28 |
+
var group = expression[i];
|
29 |
+
groups.push(buildGroup(group, options, prev));
|
30 |
+
prev = group;
|
31 |
+
}
|
32 |
+
return groups;
|
33 |
+
};
|
34 |
+
|
35 |
+
// List of types used by getTypeOfGroup,
|
36 |
+
// see https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
|
37 |
+
var groupToType = {
|
38 |
+
mathord: "mord",
|
39 |
+
textord: "mord",
|
40 |
+
bin: "mbin",
|
41 |
+
rel: "mrel",
|
42 |
+
text: "mord",
|
43 |
+
open: "mopen",
|
44 |
+
close: "mclose",
|
45 |
+
inner: "minner",
|
46 |
+
genfrac: "mord",
|
47 |
+
array: "mord",
|
48 |
+
spacing: "mord",
|
49 |
+
punct: "mpunct",
|
50 |
+
ordgroup: "mord",
|
51 |
+
op: "mop",
|
52 |
+
katex: "mord",
|
53 |
+
overline: "mord",
|
54 |
+
underline: "mord",
|
55 |
+
rule: "mord",
|
56 |
+
leftright: "minner",
|
57 |
+
sqrt: "mord",
|
58 |
+
accent: "mord",
|
59 |
+
};
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Gets the final math type of an expression, given its group type. This type is
|
63 |
+
* used to determine spacing between elements, and affects bin elements by
|
64 |
+
* causing them to change depending on what types are around them. This type
|
65 |
+
* must be attached to the outermost node of an element as a CSS class so that
|
66 |
+
* spacing with its surrounding elements works correctly.
|
67 |
+
*
|
68 |
+
* Some elements can be mapped one-to-one from group type to math type, and
|
69 |
+
* those are listed in the `groupToType` table.
|
70 |
+
*
|
71 |
+
* Others (usually elements that wrap around other elements) often have
|
72 |
+
* recursive definitions, and thus call `getTypeOfGroup` on their inner
|
73 |
+
* elements.
|
74 |
+
*/
|
75 |
+
var getTypeOfGroup = function(group) {
|
76 |
+
if (group == null) {
|
77 |
+
// Like when typesetting $^3$
|
78 |
+
return groupToType.mathord;
|
79 |
+
} else if (group.type === "supsub") {
|
80 |
+
return getTypeOfGroup(group.value.base);
|
81 |
+
} else if (group.type === "llap" || group.type === "rlap") {
|
82 |
+
return getTypeOfGroup(group.value);
|
83 |
+
} else if (group.type === "color") {
|
84 |
+
return getTypeOfGroup(group.value.value);
|
85 |
+
} else if (group.type === "sizing") {
|
86 |
+
return getTypeOfGroup(group.value.value);
|
87 |
+
} else if (group.type === "styling") {
|
88 |
+
return getTypeOfGroup(group.value.value);
|
89 |
+
} else if (group.type === "delimsizing") {
|
90 |
+
return groupToType[group.value.delimType];
|
91 |
+
} else {
|
92 |
+
return groupToType[group.type];
|
93 |
+
}
|
94 |
+
};
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Sometimes, groups perform special rules when they have superscripts or
|
98 |
+
* subscripts attached to them. This function lets the `supsub` group know that
|
99 |
+
* its inner element should handle the superscripts and subscripts instead of
|
100 |
+
* handling them itself.
|
101 |
+
*/
|
102 |
+
var shouldHandleSupSub = function(group, options) {
|
103 |
+
if (!group) {
|
104 |
+
return false;
|
105 |
+
} else if (group.type === "op") {
|
106 |
+
// Operators handle supsubs differently when they have limits
|
107 |
+
// (e.g. `\displaystyle\sum_2^3`)
|
108 |
+
return group.value.limits &&
|
109 |
+
(options.style.size === Style.DISPLAY.size ||
|
110 |
+
group.value.alwaysHandleSupSub);
|
111 |
+
} else if (group.type === "accent") {
|
112 |
+
return isCharacterBox(group.value.base);
|
113 |
+
} else {
|
114 |
+
return null;
|
115 |
+
}
|
116 |
+
};
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Sometimes we want to pull out the innermost element of a group. In most
|
120 |
+
* cases, this will just be the group itself, but when ordgroups and colors have
|
121 |
+
* a single element, we want to pull that out.
|
122 |
+
*/
|
123 |
+
var getBaseElem = function(group) {
|
124 |
+
if (!group) {
|
125 |
+
return false;
|
126 |
+
} else if (group.type === "ordgroup") {
|
127 |
+
if (group.value.length === 1) {
|
128 |
+
return getBaseElem(group.value[0]);
|
129 |
+
} else {
|
130 |
+
return group;
|
131 |
+
}
|
132 |
+
} else if (group.type === "color") {
|
133 |
+
if (group.value.value.length === 1) {
|
134 |
+
return getBaseElem(group.value.value[0]);
|
135 |
+
} else {
|
136 |
+
return group;
|
137 |
+
}
|
138 |
+
} else {
|
139 |
+
return group;
|
140 |
+
}
|
141 |
+
};
|
142 |
+
|
143 |
+
/**
|
144 |
+
* TeXbook algorithms often reference "character boxes", which are simply groups
|
145 |
+
* with a single character in them. To decide if something is a character box,
|
146 |
+
* we find its innermost group, and see if it is a single character.
|
147 |
+
*/
|
148 |
+
var isCharacterBox = function(group) {
|
149 |
+
var baseElem = getBaseElem(group);
|
150 |
+
|
151 |
+
// These are all they types of groups which hold single characters
|
152 |
+
return baseElem.type === "mathord" ||
|
153 |
+
baseElem.type === "textord" ||
|
154 |
+
baseElem.type === "bin" ||
|
155 |
+
baseElem.type === "rel" ||
|
156 |
+
baseElem.type === "inner" ||
|
157 |
+
baseElem.type === "open" ||
|
158 |
+
baseElem.type === "close" ||
|
159 |
+
baseElem.type === "punct";
|
160 |
+
};
|
161 |
+
|
162 |
+
var makeNullDelimiter = function(options) {
|
163 |
+
return makeSpan([
|
164 |
+
"sizing", "reset-" + options.size, "size5",
|
165 |
+
options.style.reset(), Style.TEXT.cls(),
|
166 |
+
"nulldelimiter",
|
167 |
+
]);
|
168 |
+
};
|
169 |
+
|
170 |
+
/**
|
171 |
+
* This is a map of group types to the function used to handle that type.
|
172 |
+
* Simpler types come at the beginning, while complicated types come afterwards.
|
173 |
+
*/
|
174 |
+
var groupTypes = {};
|
175 |
+
|
176 |
+
groupTypes.mathord = function(group, options, prev) {
|
177 |
+
return buildCommon.makeOrd(group, options, "mathord");
|
178 |
+
};
|
179 |
+
|
180 |
+
groupTypes.textord = function(group, options, prev) {
|
181 |
+
return buildCommon.makeOrd(group, options, "textord");
|
182 |
+
};
|
183 |
+
|
184 |
+
groupTypes.bin = function(group, options, prev) {
|
185 |
+
var className = "mbin";
|
186 |
+
// Pull out the most recent element. Do some special handling to find
|
187 |
+
// things at the end of a \color group. Note that we don't use the same
|
188 |
+
// logic for ordgroups (which count as ords).
|
189 |
+
var prevAtom = prev;
|
190 |
+
while (prevAtom && prevAtom.type === "color") {
|
191 |
+
var atoms = prevAtom.value.value;
|
192 |
+
prevAtom = atoms[atoms.length - 1];
|
193 |
+
}
|
194 |
+
// See TeXbook pg. 442-446, Rules 5 and 6, and the text before Rule 19.
|
195 |
+
// Here, we determine whether the bin should turn into an ord. We
|
196 |
+
// currently only apply Rule 5.
|
197 |
+
if (!prev || utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"],
|
198 |
+
getTypeOfGroup(prevAtom))) {
|
199 |
+
group.type = "textord";
|
200 |
+
className = "mord";
|
201 |
+
}
|
202 |
+
|
203 |
+
return buildCommon.mathsym(
|
204 |
+
group.value, group.mode, options.getColor(), [className]);
|
205 |
+
};
|
206 |
+
|
207 |
+
groupTypes.rel = function(group, options, prev) {
|
208 |
+
return buildCommon.mathsym(
|
209 |
+
group.value, group.mode, options.getColor(), ["mrel"]);
|
210 |
+
};
|
211 |
+
|
212 |
+
groupTypes.open = function(group, options, prev) {
|
213 |
+
return buildCommon.mathsym(
|
214 |
+
group.value, group.mode, options.getColor(), ["mopen"]);
|
215 |
+
};
|
216 |
+
|
217 |
+
groupTypes.close = function(group, options, prev) {
|
218 |
+
return buildCommon.mathsym(
|
219 |
+
group.value, group.mode, options.getColor(), ["mclose"]);
|
220 |
+
};
|
221 |
+
|
222 |
+
groupTypes.inner = function(group, options, prev) {
|
223 |
+
return buildCommon.mathsym(
|
224 |
+
group.value, group.mode, options.getColor(), ["minner"]);
|
225 |
+
};
|
226 |
+
|
227 |
+
groupTypes.punct = function(group, options, prev) {
|
228 |
+
return buildCommon.mathsym(
|
229 |
+
group.value, group.mode, options.getColor(), ["mpunct"]);
|
230 |
+
};
|
231 |
+
|
232 |
+
groupTypes.ordgroup = function(group, options, prev) {
|
233 |
+
return makeSpan(
|
234 |
+
["mord", options.style.cls()],
|
235 |
+
buildExpression(group.value, options.reset())
|
236 |
+
);
|
237 |
+
};
|
238 |
+
|
239 |
+
groupTypes.text = function(group, options, prev) {
|
240 |
+
return makeSpan(["text", "mord", options.style.cls()],
|
241 |
+
buildExpression(group.value.body, options.reset()));
|
242 |
+
};
|
243 |
+
|
244 |
+
groupTypes.color = function(group, options, prev) {
|
245 |
+
var elements = buildExpression(
|
246 |
+
group.value.value,
|
247 |
+
options.withColor(group.value.color),
|
248 |
+
prev
|
249 |
+
);
|
250 |
+
|
251 |
+
// \color isn't supposed to affect the type of the elements it contains.
|
252 |
+
// To accomplish this, we wrap the results in a fragment, so the inner
|
253 |
+
// elements will be able to directly interact with their neighbors. For
|
254 |
+
// example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
|
255 |
+
return new buildCommon.makeFragment(elements);
|
256 |
+
};
|
257 |
+
|
258 |
+
groupTypes.supsub = function(group, options, prev) {
|
259 |
+
// Superscript and subscripts are handled in the TeXbook on page
|
260 |
+
// 445-446, rules 18(a-f).
|
261 |
+
|
262 |
+
// Here is where we defer to the inner group if it should handle
|
263 |
+
// superscripts and subscripts itself.
|
264 |
+
if (shouldHandleSupSub(group.value.base, options)) {
|
265 |
+
return groupTypes[group.value.base.type](group, options, prev);
|
266 |
+
}
|
267 |
+
|
268 |
+
var base = buildGroup(group.value.base, options.reset());
|
269 |
+
var supmid;
|
270 |
+
var submid;
|
271 |
+
var sup;
|
272 |
+
var sub;
|
273 |
+
|
274 |
+
if (group.value.sup) {
|
275 |
+
sup = buildGroup(group.value.sup,
|
276 |
+
options.withStyle(options.style.sup()));
|
277 |
+
supmid = makeSpan(
|
278 |
+
[options.style.reset(), options.style.sup().cls()], [sup]);
|
279 |
+
}
|
280 |
+
|
281 |
+
if (group.value.sub) {
|
282 |
+
sub = buildGroup(group.value.sub,
|
283 |
+
options.withStyle(options.style.sub()));
|
284 |
+
submid = makeSpan(
|
285 |
+
[options.style.reset(), options.style.sub().cls()], [sub]);
|
286 |
+
}
|
287 |
+
|
288 |
+
// Rule 18a
|
289 |
+
var supShift;
|
290 |
+
var subShift;
|
291 |
+
if (isCharacterBox(group.value.base)) {
|
292 |
+
supShift = 0;
|
293 |
+
subShift = 0;
|
294 |
+
} else {
|
295 |
+
supShift = base.height - fontMetrics.metrics.supDrop;
|
296 |
+
subShift = base.depth + fontMetrics.metrics.subDrop;
|
297 |
+
}
|
298 |
+
|
299 |
+
// Rule 18c
|
300 |
+
var minSupShift;
|
301 |
+
if (options.style === Style.DISPLAY) {
|
302 |
+
minSupShift = fontMetrics.metrics.sup1;
|
303 |
+
} else if (options.style.cramped) {
|
304 |
+
minSupShift = fontMetrics.metrics.sup3;
|
305 |
+
} else {
|
306 |
+
minSupShift = fontMetrics.metrics.sup2;
|
307 |
+
}
|
308 |
+
|
309 |
+
// scriptspace is a font-size-independent size, so scale it
|
310 |
+
// appropriately
|
311 |
+
var multiplier = Style.TEXT.sizeMultiplier *
|
312 |
+
options.style.sizeMultiplier;
|
313 |
+
var scriptspace =
|
314 |
+
(0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
|
315 |
+
|
316 |
+
var supsub;
|
317 |
+
if (!group.value.sup) {
|
318 |
+
// Rule 18b
|
319 |
+
subShift = Math.max(
|
320 |
+
subShift, fontMetrics.metrics.sub1,
|
321 |
+
sub.height - 0.8 * fontMetrics.metrics.xHeight);
|
322 |
+
|
323 |
+
supsub = buildCommon.makeVList([
|
324 |
+
{type: "elem", elem: submid},
|
325 |
+
], "shift", subShift, options);
|
326 |
+
|
327 |
+
supsub.children[0].style.marginRight = scriptspace;
|
328 |
+
|
329 |
+
// Subscripts shouldn't be shifted by the base's italic correction.
|
330 |
+
// Account for that by shifting the subscript back the appropriate
|
331 |
+
// amount. Note we only do this when the base is a single symbol.
|
332 |
+
if (base instanceof domTree.symbolNode) {
|
333 |
+
supsub.children[0].style.marginLeft = -base.italic + "em";
|
334 |
+
}
|
335 |
+
} else if (!group.value.sub) {
|
336 |
+
// Rule 18c, d
|
337 |
+
supShift = Math.max(supShift, minSupShift,
|
338 |
+
sup.depth + 0.25 * fontMetrics.metrics.xHeight);
|
339 |
+
|
340 |
+
supsub = buildCommon.makeVList([
|
341 |
+
{type: "elem", elem: supmid},
|
342 |
+
], "shift", -supShift, options);
|
343 |
+
|
344 |
+
supsub.children[0].style.marginRight = scriptspace;
|
345 |
+
} else {
|
346 |
+
supShift = Math.max(
|
347 |
+
supShift, minSupShift,
|
348 |
+
sup.depth + 0.25 * fontMetrics.metrics.xHeight);
|
349 |
+
subShift = Math.max(subShift, fontMetrics.metrics.sub2);
|
350 |
+
|
351 |
+
var ruleWidth = fontMetrics.metrics.defaultRuleThickness;
|
352 |
+
|
353 |
+
// Rule 18e
|
354 |
+
if ((supShift - sup.depth) - (sub.height - subShift) <
|
355 |
+
4 * ruleWidth) {
|
356 |
+
subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height;
|
357 |
+
var psi = 0.8 * fontMetrics.metrics.xHeight -
|
358 |
+
(supShift - sup.depth);
|
359 |
+
if (psi > 0) {
|
360 |
+
supShift += psi;
|
361 |
+
subShift -= psi;
|
362 |
+
}
|
363 |
+
}
|
364 |
+
|
365 |
+
supsub = buildCommon.makeVList([
|
366 |
+
{type: "elem", elem: submid, shift: subShift},
|
367 |
+
{type: "elem", elem: supmid, shift: -supShift},
|
368 |
+
], "individualShift", null, options);
|
369 |
+
|
370 |
+
// See comment above about subscripts not being shifted
|
371 |
+
if (base instanceof domTree.symbolNode) {
|
372 |
+
supsub.children[0].style.marginLeft = -base.italic + "em";
|
373 |
+
}
|
374 |
+
|
375 |
+
supsub.children[0].style.marginRight = scriptspace;
|
376 |
+
supsub.children[1].style.marginRight = scriptspace;
|
377 |
+
}
|
378 |
+
|
379 |
+
return makeSpan([getTypeOfGroup(group.value.base)],
|
380 |
+
[base, supsub]);
|
381 |
+
};
|
382 |
+
|
383 |
+
groupTypes.genfrac = function(group, options, prev) {
|
384 |
+
// Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
|
385 |
+
// Figure out what style this fraction should be in based on the
|
386 |
+
// function used
|
387 |
+
var fstyle = options.style;
|
388 |
+
if (group.value.size === "display") {
|
389 |
+
fstyle = Style.DISPLAY;
|
390 |
+
} else if (group.value.size === "text") {
|
391 |
+
fstyle = Style.TEXT;
|
392 |
+
}
|
393 |
+
|
394 |
+
var nstyle = fstyle.fracNum();
|
395 |
+
var dstyle = fstyle.fracDen();
|
396 |
+
|
397 |
+
var numer = buildGroup(group.value.numer, options.withStyle(nstyle));
|
398 |
+
var numerreset = makeSpan([fstyle.reset(), nstyle.cls()], [numer]);
|
399 |
+
|
400 |
+
var denom = buildGroup(group.value.denom, options.withStyle(dstyle));
|
401 |
+
var denomreset = makeSpan([fstyle.reset(), dstyle.cls()], [denom]);
|
402 |
+
|
403 |
+
var ruleWidth;
|
404 |
+
if (group.value.hasBarLine) {
|
405 |
+
ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
406 |
+
options.style.sizeMultiplier;
|
407 |
+
} else {
|
408 |
+
ruleWidth = 0;
|
409 |
+
}
|
410 |
+
|
411 |
+
// Rule 15b
|
412 |
+
var numShift;
|
413 |
+
var clearance;
|
414 |
+
var denomShift;
|
415 |
+
if (fstyle.size === Style.DISPLAY.size) {
|
416 |
+
numShift = fontMetrics.metrics.num1;
|
417 |
+
if (ruleWidth > 0) {
|
418 |
+
clearance = 3 * ruleWidth;
|
419 |
+
} else {
|
420 |
+
clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
|
421 |
+
}
|
422 |
+
denomShift = fontMetrics.metrics.denom1;
|
423 |
+
} else {
|
424 |
+
if (ruleWidth > 0) {
|
425 |
+
numShift = fontMetrics.metrics.num2;
|
426 |
+
clearance = ruleWidth;
|
427 |
+
} else {
|
428 |
+
numShift = fontMetrics.metrics.num3;
|
429 |
+
clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
|
430 |
+
}
|
431 |
+
denomShift = fontMetrics.metrics.denom2;
|
432 |
+
}
|
433 |
+
|
434 |
+
var frac;
|
435 |
+
if (ruleWidth === 0) {
|
436 |
+
// Rule 15c
|
437 |
+
var candiateClearance =
|
438 |
+
(numShift - numer.depth) - (denom.height - denomShift);
|
439 |
+
if (candiateClearance < clearance) {
|
440 |
+
numShift += 0.5 * (clearance - candiateClearance);
|
441 |
+
denomShift += 0.5 * (clearance - candiateClearance);
|
442 |
+
}
|
443 |
+
|
444 |
+
frac = buildCommon.makeVList([
|
445 |
+
{type: "elem", elem: denomreset, shift: denomShift},
|
446 |
+
{type: "elem", elem: numerreset, shift: -numShift},
|
447 |
+
], "individualShift", null, options);
|
448 |
+
} else {
|
449 |
+
// Rule 15d
|
450 |
+
var axisHeight = fontMetrics.metrics.axisHeight;
|
451 |
+
|
452 |
+
if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) <
|
453 |
+
clearance) {
|
454 |
+
numShift +=
|
455 |
+
clearance - ((numShift - numer.depth) -
|
456 |
+
(axisHeight + 0.5 * ruleWidth));
|
457 |
+
}
|
458 |
+
|
459 |
+
if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) <
|
460 |
+
clearance) {
|
461 |
+
denomShift +=
|
462 |
+
clearance - ((axisHeight - 0.5 * ruleWidth) -
|
463 |
+
(denom.height - denomShift));
|
464 |
+
}
|
465 |
+
|
466 |
+
var mid = makeSpan(
|
467 |
+
[options.style.reset(), Style.TEXT.cls(), "frac-line"]);
|
468 |
+
// Manually set the height of the line because its height is
|
469 |
+
// created in CSS
|
470 |
+
mid.height = ruleWidth;
|
471 |
+
|
472 |
+
var midShift = -(axisHeight - 0.5 * ruleWidth);
|
473 |
+
|
474 |
+
frac = buildCommon.makeVList([
|
475 |
+
{type: "elem", elem: denomreset, shift: denomShift},
|
476 |
+
{type: "elem", elem: mid, shift: midShift},
|
477 |
+
{type: "elem", elem: numerreset, shift: -numShift},
|
478 |
+
], "individualShift", null, options);
|
479 |
+
}
|
480 |
+
|
481 |
+
// Since we manually change the style sometimes (with \dfrac or \tfrac),
|
482 |
+
// account for the possible size change here.
|
483 |
+
frac.height *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
|
484 |
+
frac.depth *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
|
485 |
+
|
486 |
+
// Rule 15e
|
487 |
+
var delimSize;
|
488 |
+
if (fstyle.size === Style.DISPLAY.size) {
|
489 |
+
delimSize = fontMetrics.metrics.delim1;
|
490 |
+
} else {
|
491 |
+
delimSize = fontMetrics.metrics.getDelim2(fstyle);
|
492 |
+
}
|
493 |
+
|
494 |
+
var leftDelim;
|
495 |
+
var rightDelim;
|
496 |
+
if (group.value.leftDelim == null) {
|
497 |
+
leftDelim = makeNullDelimiter(options);
|
498 |
+
} else {
|
499 |
+
leftDelim = delimiter.customSizedDelim(
|
500 |
+
group.value.leftDelim, delimSize, true,
|
501 |
+
options.withStyle(fstyle), group.mode);
|
502 |
+
}
|
503 |
+
if (group.value.rightDelim == null) {
|
504 |
+
rightDelim = makeNullDelimiter(options);
|
505 |
+
} else {
|
506 |
+
rightDelim = delimiter.customSizedDelim(
|
507 |
+
group.value.rightDelim, delimSize, true,
|
508 |
+
options.withStyle(fstyle), group.mode);
|
509 |
+
}
|
510 |
+
|
511 |
+
return makeSpan(
|
512 |
+
["mord", options.style.reset(), fstyle.cls()],
|
513 |
+
[leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
|
514 |
+
options.getColor());
|
515 |
+
};
|
516 |
+
|
517 |
+
groupTypes.array = function(group, options, prev) {
|
518 |
+
var r;
|
519 |
+
var c;
|
520 |
+
var nr = group.value.body.length;
|
521 |
+
var nc = 0;
|
522 |
+
var body = new Array(nr);
|
523 |
+
|
524 |
+
// Horizontal spacing
|
525 |
+
var pt = 1 / fontMetrics.metrics.ptPerEm;
|
526 |
+
var arraycolsep = 5 * pt; // \arraycolsep in article.cls
|
527 |
+
|
528 |
+
// Vertical spacing
|
529 |
+
var baselineskip = 12 * pt; // see size10.clo
|
530 |
+
// Default \arraystretch from lttab.dtx
|
531 |
+
// TODO(gagern): may get redefined once we have user-defined macros
|
532 |
+
var arraystretch = utils.deflt(group.value.arraystretch, 1);
|
533 |
+
var arrayskip = arraystretch * baselineskip;
|
534 |
+
var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
|
535 |
+
var arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
536 |
+
|
537 |
+
var totalHeight = 0;
|
538 |
+
for (r = 0; r < group.value.body.length; ++r) {
|
539 |
+
var inrow = group.value.body[r];
|
540 |
+
var height = arstrutHeight; // \@array adds an \@arstrut
|
541 |
+
var depth = arstrutDepth; // to each tow (via the template)
|
542 |
+
|
543 |
+
if (nc < inrow.length) {
|
544 |
+
nc = inrow.length;
|
545 |
+
}
|
546 |
+
|
547 |
+
var outrow = new Array(inrow.length);
|
548 |
+
for (c = 0; c < inrow.length; ++c) {
|
549 |
+
var elt = buildGroup(inrow[c], options);
|
550 |
+
if (depth < elt.depth) {
|
551 |
+
depth = elt.depth;
|
552 |
+
}
|
553 |
+
if (height < elt.height) {
|
554 |
+
height = elt.height;
|
555 |
+
}
|
556 |
+
outrow[c] = elt;
|
557 |
+
}
|
558 |
+
|
559 |
+
var gap = 0;
|
560 |
+
if (group.value.rowGaps[r]) {
|
561 |
+
gap = group.value.rowGaps[r].value;
|
562 |
+
switch (gap.unit) {
|
563 |
+
case "em":
|
564 |
+
gap = gap.number;
|
565 |
+
break;
|
566 |
+
case "ex":
|
567 |
+
gap = gap.number * fontMetrics.metrics.emPerEx;
|
568 |
+
break;
|
569 |
+
default:
|
570 |
+
console.error("Can't handle unit " + gap.unit);
|
571 |
+
gap = 0;
|
572 |
+
}
|
573 |
+
if (gap > 0) { // \@argarraycr
|
574 |
+
gap += arstrutDepth;
|
575 |
+
if (depth < gap) {
|
576 |
+
depth = gap; // \@xargarraycr
|
577 |
+
}
|
578 |
+
gap = 0;
|
579 |
+
}
|
580 |
+
}
|
581 |
+
|
582 |
+
outrow.height = height;
|
583 |
+
outrow.depth = depth;
|
584 |
+
totalHeight += height;
|
585 |
+
outrow.pos = totalHeight;
|
586 |
+
totalHeight += depth + gap; // \@yargarraycr
|
587 |
+
body[r] = outrow;
|
588 |
+
}
|
589 |
+
|
590 |
+
var offset = totalHeight / 2 + fontMetrics.metrics.axisHeight;
|
591 |
+
var colDescriptions = group.value.cols || [];
|
592 |
+
var cols = [];
|
593 |
+
var colSep;
|
594 |
+
var colDescrNum;
|
595 |
+
for (c = 0, colDescrNum = 0;
|
596 |
+
// Continue while either there are more columns or more column
|
597 |
+
// descriptions, so trailing separators don't get lost.
|
598 |
+
c < nc || colDescrNum < colDescriptions.length;
|
599 |
+
++c, ++colDescrNum) {
|
600 |
+
|
601 |
+
var colDescr = colDescriptions[colDescrNum] || {};
|
602 |
+
|
603 |
+
var firstSeparator = true;
|
604 |
+
while (colDescr.type === "separator") {
|
605 |
+
// If there is more than one separator in a row, add a space
|
606 |
+
// between them.
|
607 |
+
if (!firstSeparator) {
|
608 |
+
colSep = makeSpan(["arraycolsep"], []);
|
609 |
+
colSep.style.width =
|
610 |
+
fontMetrics.metrics.doubleRuleSep + "em";
|
611 |
+
cols.push(colSep);
|
612 |
+
}
|
613 |
+
|
614 |
+
if (colDescr.separator === "|") {
|
615 |
+
var separator = makeSpan(
|
616 |
+
["vertical-separator"],
|
617 |
+
[]);
|
618 |
+
separator.style.height = totalHeight + "em";
|
619 |
+
separator.style.verticalAlign =
|
620 |
+
-(totalHeight - offset) + "em";
|
621 |
+
|
622 |
+
cols.push(separator);
|
623 |
+
} else {
|
624 |
+
throw new ParseError(
|
625 |
+
"Invalid separator type: " + colDescr.separator);
|
626 |
+
}
|
627 |
+
|
628 |
+
colDescrNum++;
|
629 |
+
colDescr = colDescriptions[colDescrNum] || {};
|
630 |
+
firstSeparator = false;
|
631 |
+
}
|
632 |
+
|
633 |
+
if (c >= nc) {
|
634 |
+
continue;
|
635 |
+
}
|
636 |
+
|
637 |
+
var sepwidth;
|
638 |
+
if (c > 0 || group.value.hskipBeforeAndAfter) {
|
639 |
+
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
640 |
+
if (sepwidth !== 0) {
|
641 |
+
colSep = makeSpan(["arraycolsep"], []);
|
642 |
+
colSep.style.width = sepwidth + "em";
|
643 |
+
cols.push(colSep);
|
644 |
+
}
|
645 |
+
}
|
646 |
+
|
647 |
+
var col = [];
|
648 |
+
for (r = 0; r < nr; ++r) {
|
649 |
+
var row = body[r];
|
650 |
+
var elem = row[c];
|
651 |
+
if (!elem) {
|
652 |
+
continue;
|
653 |
+
}
|
654 |
+
var shift = row.pos - offset;
|
655 |
+
elem.depth = row.depth;
|
656 |
+
elem.height = row.height;
|
657 |
+
col.push({type: "elem", elem: elem, shift: shift});
|
658 |
+
}
|
659 |
+
|
660 |
+
col = buildCommon.makeVList(col, "individualShift", null, options);
|
661 |
+
col = makeSpan(
|
662 |
+
["col-align-" + (colDescr.align || "c")],
|
663 |
+
[col]);
|
664 |
+
cols.push(col);
|
665 |
+
|
666 |
+
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
|
667 |
+
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
668 |
+
if (sepwidth !== 0) {
|
669 |
+
colSep = makeSpan(["arraycolsep"], []);
|
670 |
+
colSep.style.width = sepwidth + "em";
|
671 |
+
cols.push(colSep);
|
672 |
+
}
|
673 |
+
}
|
674 |
+
}
|
675 |
+
body = makeSpan(["mtable"], cols);
|
676 |
+
return makeSpan(["mord"], [body], options.getColor());
|
677 |
+
};
|
678 |
+
|
679 |
+
groupTypes.spacing = function(group, options, prev) {
|
680 |
+
if (group.value === "\\ " || group.value === "\\space" ||
|
681 |
+
group.value === " " || group.value === "~") {
|
682 |
+
// Spaces are generated by adding an actual space. Each of these
|
683 |
+
// things has an entry in the symbols table, so these will be turned
|
684 |
+
// into appropriate outputs.
|
685 |
+
return makeSpan(
|
686 |
+
["mord", "mspace"],
|
687 |
+
[buildCommon.mathsym(group.value, group.mode)]
|
688 |
+
);
|
689 |
+
} else {
|
690 |
+
// Other kinds of spaces are of arbitrary width. We use CSS to
|
691 |
+
// generate these.
|
692 |
+
return makeSpan(
|
693 |
+
["mord", "mspace",
|
694 |
+
buildCommon.spacingFunctions[group.value].className]);
|
695 |
+
}
|
696 |
+
};
|
697 |
+
|
698 |
+
groupTypes.llap = function(group, options, prev) {
|
699 |
+
var inner = makeSpan(
|
700 |
+
["inner"], [buildGroup(group.value.body, options.reset())]);
|
701 |
+
var fix = makeSpan(["fix"], []);
|
702 |
+
return makeSpan(
|
703 |
+
["llap", options.style.cls()], [inner, fix]);
|
704 |
+
};
|
705 |
+
|
706 |
+
groupTypes.rlap = function(group, options, prev) {
|
707 |
+
var inner = makeSpan(
|
708 |
+
["inner"], [buildGroup(group.value.body, options.reset())]);
|
709 |
+
var fix = makeSpan(["fix"], []);
|
710 |
+
return makeSpan(
|
711 |
+
["rlap", options.style.cls()], [inner, fix]);
|
712 |
+
};
|
713 |
+
|
714 |
+
groupTypes.op = function(group, options, prev) {
|
715 |
+
// Operators are handled in the TeXbook pg. 443-444, rule 13(a).
|
716 |
+
var supGroup;
|
717 |
+
var subGroup;
|
718 |
+
var hasLimits = false;
|
719 |
+
if (group.type === "supsub" ) {
|
720 |
+
// If we have limits, supsub will pass us its group to handle. Pull
|
721 |
+
// out the superscript and subscript and set the group to the op in
|
722 |
+
// its base.
|
723 |
+
supGroup = group.value.sup;
|
724 |
+
subGroup = group.value.sub;
|
725 |
+
group = group.value.base;
|
726 |
+
hasLimits = true;
|
727 |
+
}
|
728 |
+
|
729 |
+
// Most operators have a large successor symbol, but these don't.
|
730 |
+
var noSuccessor = [
|
731 |
+
"\\smallint",
|
732 |
+
];
|
733 |
+
|
734 |
+
var large = false;
|
735 |
+
if (options.style.size === Style.DISPLAY.size &&
|
736 |
+
group.value.symbol &&
|
737 |
+
!utils.contains(noSuccessor, group.value.body)) {
|
738 |
+
|
739 |
+
// Most symbol operators get larger in displaystyle (rule 13)
|
740 |
+
large = true;
|
741 |
+
}
|
742 |
+
|
743 |
+
var base;
|
744 |
+
var baseShift = 0;
|
745 |
+
var slant = 0;
|
746 |
+
if (group.value.symbol) {
|
747 |
+
// If this is a symbol, create the symbol.
|
748 |
+
var style = large ? "Size2-Regular" : "Size1-Regular";
|
749 |
+
base = buildCommon.makeSymbol(
|
750 |
+
group.value.body, style, "math", options.getColor(),
|
751 |
+
["op-symbol", large ? "large-op" : "small-op", "mop"]);
|
752 |
+
|
753 |
+
// Shift the symbol so its center lies on the axis (rule 13). It
|
754 |
+
// appears that our fonts have the centers of the symbols already
|
755 |
+
// almost on the axis, so these numbers are very small. Note we
|
756 |
+
// don't actually apply this here, but instead it is used either in
|
757 |
+
// the vlist creation or separately when there are no limits.
|
758 |
+
baseShift = (base.height - base.depth) / 2 -
|
759 |
+
fontMetrics.metrics.axisHeight *
|
760 |
+
options.style.sizeMultiplier;
|
761 |
+
|
762 |
+
// The slant of the symbol is just its italic correction.
|
763 |
+
slant = base.italic;
|
764 |
+
} else {
|
765 |
+
// Otherwise, this is a text operator. Build the text from the
|
766 |
+
// operator's name.
|
767 |
+
// TODO(emily): Add a space in the middle of some of these
|
768 |
+
// operators, like \limsup
|
769 |
+
var output = [];
|
770 |
+
for (var i = 1; i < group.value.body.length; i++) {
|
771 |
+
output.push(buildCommon.mathsym(group.value.body[i], group.mode));
|
772 |
+
}
|
773 |
+
base = makeSpan(["mop"], output, options.getColor());
|
774 |
+
}
|
775 |
+
|
776 |
+
if (hasLimits) {
|
777 |
+
// IE 8 clips \int if it is in a display: inline-block. We wrap it
|
778 |
+
// in a new span so it is an inline, and works.
|
779 |
+
base = makeSpan([], [base]);
|
780 |
+
|
781 |
+
var supmid;
|
782 |
+
var supKern;
|
783 |
+
var submid;
|
784 |
+
var subKern;
|
785 |
+
// We manually have to handle the superscripts and subscripts. This,
|
786 |
+
// aside from the kern calculations, is copied from supsub.
|
787 |
+
if (supGroup) {
|
788 |
+
var sup = buildGroup(
|
789 |
+
supGroup, options.withStyle(options.style.sup()));
|
790 |
+
supmid = makeSpan(
|
791 |
+
[options.style.reset(), options.style.sup().cls()], [sup]);
|
792 |
+
|
793 |
+
supKern = Math.max(
|
794 |
+
fontMetrics.metrics.bigOpSpacing1,
|
795 |
+
fontMetrics.metrics.bigOpSpacing3 - sup.depth);
|
796 |
+
}
|
797 |
+
|
798 |
+
if (subGroup) {
|
799 |
+
var sub = buildGroup(
|
800 |
+
subGroup, options.withStyle(options.style.sub()));
|
801 |
+
submid = makeSpan(
|
802 |
+
[options.style.reset(), options.style.sub().cls()],
|
803 |
+
[sub]);
|
804 |
+
|
805 |
+
subKern = Math.max(
|
806 |
+
fontMetrics.metrics.bigOpSpacing2,
|
807 |
+
fontMetrics.metrics.bigOpSpacing4 - sub.height);
|
808 |
+
}
|
809 |
+
|
810 |
+
// Build the final group as a vlist of the possible subscript, base,
|
811 |
+
// and possible superscript.
|
812 |
+
var finalGroup;
|
813 |
+
var top;
|
814 |
+
var bottom;
|
815 |
+
if (!supGroup) {
|
816 |
+
top = base.height - baseShift;
|
817 |
+
|
818 |
+
finalGroup = buildCommon.makeVList([
|
819 |
+
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
820 |
+
{type: "elem", elem: submid},
|
821 |
+
{type: "kern", size: subKern},
|
822 |
+
{type: "elem", elem: base},
|
823 |
+
], "top", top, options);
|
824 |
+
|
825 |
+
// Here, we shift the limits by the slant of the symbol. Note
|
826 |
+
// that we are supposed to shift the limits by 1/2 of the slant,
|
827 |
+
// but since we are centering the limits adding a full slant of
|
828 |
+
// margin will shift by 1/2 that.
|
829 |
+
finalGroup.children[0].style.marginLeft = -slant + "em";
|
830 |
+
} else if (!subGroup) {
|
831 |
+
bottom = base.depth + baseShift;
|
832 |
+
|
833 |
+
finalGroup = buildCommon.makeVList([
|
834 |
+
{type: "elem", elem: base},
|
835 |
+
{type: "kern", size: supKern},
|
836 |
+
{type: "elem", elem: supmid},
|
837 |
+
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
838 |
+
], "bottom", bottom, options);
|
839 |
+
|
840 |
+
// See comment above about slants
|
841 |
+
finalGroup.children[1].style.marginLeft = slant + "em";
|
842 |
+
} else if (!supGroup && !subGroup) {
|
843 |
+
// This case probably shouldn't occur (this would mean the
|
844 |
+
// supsub was sending us a group with no superscript or
|
845 |
+
// subscript) but be safe.
|
846 |
+
return base;
|
847 |
+
} else {
|
848 |
+
bottom = fontMetrics.metrics.bigOpSpacing5 +
|
849 |
+
submid.height + submid.depth +
|
850 |
+
subKern +
|
851 |
+
base.depth + baseShift;
|
852 |
+
|
853 |
+
finalGroup = buildCommon.makeVList([
|
854 |
+
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
855 |
+
{type: "elem", elem: submid},
|
856 |
+
{type: "kern", size: subKern},
|
857 |
+
{type: "elem", elem: base},
|
858 |
+
{type: "kern", size: supKern},
|
859 |
+
{type: "elem", elem: supmid},
|
860 |
+
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
861 |
+
], "bottom", bottom, options);
|
862 |
+
|
863 |
+
// See comment above about slants
|
864 |
+
finalGroup.children[0].style.marginLeft = -slant + "em";
|
865 |
+
finalGroup.children[2].style.marginLeft = slant + "em";
|
866 |
+
}
|
867 |
+
|
868 |
+
return makeSpan(["mop", "op-limits"], [finalGroup]);
|
869 |
+
} else {
|
870 |
+
if (group.value.symbol) {
|
871 |
+
base.style.top = baseShift + "em";
|
872 |
+
}
|
873 |
+
|
874 |
+
return base;
|
875 |
+
}
|
876 |
+
};
|
877 |
+
|
878 |
+
groupTypes.katex = function(group, options, prev) {
|
879 |
+
// The KaTeX logo. The offsets for the K and a were chosen to look
|
880 |
+
// good, but the offsets for the T, E, and X were taken from the
|
881 |
+
// definition of \TeX in TeX (see TeXbook pg. 356)
|
882 |
+
var k = makeSpan(
|
883 |
+
["k"], [buildCommon.mathsym("K", group.mode)]);
|
884 |
+
var a = makeSpan(
|
885 |
+
["a"], [buildCommon.mathsym("A", group.mode)]);
|
886 |
+
|
887 |
+
a.height = (a.height + 0.2) * 0.75;
|
888 |
+
a.depth = (a.height - 0.2) * 0.75;
|
889 |
+
|
890 |
+
var t = makeSpan(
|
891 |
+
["t"], [buildCommon.mathsym("T", group.mode)]);
|
892 |
+
var e = makeSpan(
|
893 |
+
["e"], [buildCommon.mathsym("E", group.mode)]);
|
894 |
+
|
895 |
+
e.height = (e.height - 0.2155);
|
896 |
+
e.depth = (e.depth + 0.2155);
|
897 |
+
|
898 |
+
var x = makeSpan(
|
899 |
+
["x"], [buildCommon.mathsym("X", group.mode)]);
|
900 |
+
|
901 |
+
return makeSpan(
|
902 |
+
["katex-logo", "mord"], [k, a, t, e, x], options.getColor());
|
903 |
+
};
|
904 |
+
|
905 |
+
groupTypes.overline = function(group, options, prev) {
|
906 |
+
// Overlines are handled in the TeXbook pg 443, Rule 9.
|
907 |
+
|
908 |
+
// Build the inner group in the cramped style.
|
909 |
+
var innerGroup = buildGroup(group.value.body,
|
910 |
+
options.withStyle(options.style.cramp()));
|
911 |
+
|
912 |
+
var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
913 |
+
options.style.sizeMultiplier;
|
914 |
+
|
915 |
+
// Create the line above the body
|
916 |
+
var line = makeSpan(
|
917 |
+
[options.style.reset(), Style.TEXT.cls(), "overline-line"]);
|
918 |
+
line.height = ruleWidth;
|
919 |
+
line.maxFontSize = 1.0;
|
920 |
+
|
921 |
+
// Generate the vlist, with the appropriate kerns
|
922 |
+
var vlist = buildCommon.makeVList([
|
923 |
+
{type: "elem", elem: innerGroup},
|
924 |
+
{type: "kern", size: 3 * ruleWidth},
|
925 |
+
{type: "elem", elem: line},
|
926 |
+
{type: "kern", size: ruleWidth},
|
927 |
+
], "firstBaseline", null, options);
|
928 |
+
|
929 |
+
return makeSpan(["overline", "mord"], [vlist], options.getColor());
|
930 |
+
};
|
931 |
+
|
932 |
+
groupTypes.underline = function(group, options, prev) {
|
933 |
+
// Underlines are handled in the TeXbook pg 443, Rule 10.
|
934 |
+
|
935 |
+
// Build the inner group.
|
936 |
+
var innerGroup = buildGroup(group.value.body, options);
|
937 |
+
|
938 |
+
var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
939 |
+
options.style.sizeMultiplier;
|
940 |
+
|
941 |
+
// Create the line above the body
|
942 |
+
var line = makeSpan(
|
943 |
+
[options.style.reset(), Style.TEXT.cls(), "underline-line"]);
|
944 |
+
line.height = ruleWidth;
|
945 |
+
line.maxFontSize = 1.0;
|
946 |
+
|
947 |
+
// Generate the vlist, with the appropriate kerns
|
948 |
+
var vlist = buildCommon.makeVList([
|
949 |
+
{type: "kern", size: ruleWidth},
|
950 |
+
{type: "elem", elem: line},
|
951 |
+
{type: "kern", size: 3 * ruleWidth},
|
952 |
+
{type: "elem", elem: innerGroup},
|
953 |
+
], "top", innerGroup.height, options);
|
954 |
+
|
955 |
+
return makeSpan(["underline", "mord"], [vlist], options.getColor());
|
956 |
+
};
|
957 |
+
|
958 |
+
groupTypes.sqrt = function(group, options, prev) {
|
959 |
+
// Square roots are handled in the TeXbook pg. 443, Rule 11.
|
960 |
+
|
961 |
+
// First, we do the same steps as in overline to build the inner group
|
962 |
+
// and line
|
963 |
+
var inner = buildGroup(group.value.body,
|
964 |
+
options.withStyle(options.style.cramp()));
|
965 |
+
|
966 |
+
var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
|
967 |
+
options.style.sizeMultiplier;
|
968 |
+
|
969 |
+
var line = makeSpan(
|
970 |
+
[options.style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
|
971 |
+
options.getColor());
|
972 |
+
line.height = ruleWidth;
|
973 |
+
line.maxFontSize = 1.0;
|
974 |
+
|
975 |
+
var phi = ruleWidth;
|
976 |
+
if (options.style.id < Style.TEXT.id) {
|
977 |
+
phi = fontMetrics.metrics.xHeight;
|
978 |
+
}
|
979 |
+
|
980 |
+
// Calculate the clearance between the body and line
|
981 |
+
var lineClearance = ruleWidth + phi / 4;
|
982 |
+
|
983 |
+
var innerHeight =
|
984 |
+
(inner.height + inner.depth) * options.style.sizeMultiplier;
|
985 |
+
var minDelimiterHeight = innerHeight + lineClearance + ruleWidth;
|
986 |
+
|
987 |
+
// Create a \surd delimiter of the required minimum size
|
988 |
+
var delim = makeSpan(["sqrt-sign"], [
|
989 |
+
delimiter.customSizedDelim("\\surd", minDelimiterHeight,
|
990 |
+
false, options, group.mode)],
|
991 |
+
options.getColor());
|
992 |
+
|
993 |
+
var delimDepth = (delim.height + delim.depth) - ruleWidth;
|
994 |
+
|
995 |
+
// Adjust the clearance based on the delimiter size
|
996 |
+
if (delimDepth > inner.height + inner.depth + lineClearance) {
|
997 |
+
lineClearance =
|
998 |
+
(lineClearance + delimDepth - inner.height - inner.depth) / 2;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
// Shift the delimiter so that its top lines up with the top of the line
|
1002 |
+
var delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height;
|
1003 |
+
delim.style.top = delimShift + "em";
|
1004 |
+
delim.height -= delimShift;
|
1005 |
+
delim.depth += delimShift;
|
1006 |
+
|
1007 |
+
// We add a special case here, because even when `inner` is empty, we
|
1008 |
+
// still get a line. So, we use a simple heuristic to decide if we
|
1009 |
+
// should omit the body entirely. (note this doesn't work for something
|
1010 |
+
// like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for
|
1011 |
+
// it not to work.
|
1012 |
+
var body;
|
1013 |
+
if (inner.height === 0 && inner.depth === 0) {
|
1014 |
+
body = makeSpan();
|
1015 |
+
} else {
|
1016 |
+
body = buildCommon.makeVList([
|
1017 |
+
{type: "elem", elem: inner},
|
1018 |
+
{type: "kern", size: lineClearance},
|
1019 |
+
{type: "elem", elem: line},
|
1020 |
+
{type: "kern", size: ruleWidth},
|
1021 |
+
], "firstBaseline", null, options);
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
if (!group.value.index) {
|
1025 |
+
return makeSpan(["sqrt", "mord"], [delim, body]);
|
1026 |
+
} else {
|
1027 |
+
// Handle the optional root index
|
1028 |
+
|
1029 |
+
// The index is always in scriptscript style
|
1030 |
+
var root = buildGroup(
|
1031 |
+
group.value.index,
|
1032 |
+
options.withStyle(Style.SCRIPTSCRIPT));
|
1033 |
+
var rootWrap = makeSpan(
|
1034 |
+
[options.style.reset(), Style.SCRIPTSCRIPT.cls()],
|
1035 |
+
[root]);
|
1036 |
+
|
1037 |
+
// Figure out the height and depth of the inner part
|
1038 |
+
var innerRootHeight = Math.max(delim.height, body.height);
|
1039 |
+
var innerRootDepth = Math.max(delim.depth, body.depth);
|
1040 |
+
|
1041 |
+
// The amount the index is shifted by. This is taken from the TeX
|
1042 |
+
// source, in the definition of `\r@@t`.
|
1043 |
+
var toShift = 0.6 * (innerRootHeight - innerRootDepth);
|
1044 |
+
|
1045 |
+
// Build a VList with the superscript shifted up correctly
|
1046 |
+
var rootVList = buildCommon.makeVList(
|
1047 |
+
[{type: "elem", elem: rootWrap}],
|
1048 |
+
"shift", -toShift, options);
|
1049 |
+
// Add a class surrounding it so we can add on the appropriate
|
1050 |
+
// kerning
|
1051 |
+
var rootVListWrap = makeSpan(["root"], [rootVList]);
|
1052 |
+
|
1053 |
+
return makeSpan(["sqrt", "mord"], [rootVListWrap, delim, body]);
|
1054 |
+
}
|
1055 |
+
};
|
1056 |
+
|
1057 |
+
groupTypes.sizing = function(group, options, prev) {
|
1058 |
+
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
|
1059 |
+
// these functions inside of math expressions, so we do some special
|
1060 |
+
// handling.
|
1061 |
+
var inner = buildExpression(group.value.value,
|
1062 |
+
options.withSize(group.value.size), prev);
|
1063 |
+
|
1064 |
+
var span = makeSpan(["mord"],
|
1065 |
+
[makeSpan(["sizing", "reset-" + options.size, group.value.size,
|
1066 |
+
options.style.cls()],
|
1067 |
+
inner)]);
|
1068 |
+
|
1069 |
+
// Calculate the correct maxFontSize manually
|
1070 |
+
var fontSize = buildCommon.sizingMultiplier[group.value.size];
|
1071 |
+
span.maxFontSize = fontSize * options.style.sizeMultiplier;
|
1072 |
+
|
1073 |
+
return span;
|
1074 |
+
};
|
1075 |
+
|
1076 |
+
groupTypes.styling = function(group, options, prev) {
|
1077 |
+
// Style changes are handled in the TeXbook on pg. 442, Rule 3.
|
1078 |
+
|
1079 |
+
// Figure out what style we're changing to.
|
1080 |
+
var style = {
|
1081 |
+
"display": Style.DISPLAY,
|
1082 |
+
"text": Style.TEXT,
|
1083 |
+
"script": Style.SCRIPT,
|
1084 |
+
"scriptscript": Style.SCRIPTSCRIPT,
|
1085 |
+
};
|
1086 |
+
|
1087 |
+
var newStyle = style[group.value.style];
|
1088 |
+
|
1089 |
+
// Build the inner expression in the new style.
|
1090 |
+
var inner = buildExpression(
|
1091 |
+
group.value.value, options.withStyle(newStyle), prev);
|
1092 |
+
|
1093 |
+
return makeSpan([options.style.reset(), newStyle.cls()], inner);
|
1094 |
+
};
|
1095 |
+
|
1096 |
+
groupTypes.font = function(group, options, prev) {
|
1097 |
+
var font = group.value.font;
|
1098 |
+
return buildGroup(group.value.body, options.withFont(font), prev);
|
1099 |
+
};
|
1100 |
+
|
1101 |
+
groupTypes.delimsizing = function(group, options, prev) {
|
1102 |
+
var delim = group.value.value;
|
1103 |
+
|
1104 |
+
if (delim === ".") {
|
1105 |
+
// Empty delimiters still count as elements, even though they don't
|
1106 |
+
// show anything.
|
1107 |
+
return makeSpan([groupToType[group.value.delimType]]);
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
// Use delimiter.sizedDelim to generate the delimiter.
|
1111 |
+
return makeSpan(
|
1112 |
+
[groupToType[group.value.delimType]],
|
1113 |
+
[delimiter.sizedDelim(
|
1114 |
+
delim, group.value.size, options, group.mode)]);
|
1115 |
+
};
|
1116 |
+
|
1117 |
+
groupTypes.leftright = function(group, options, prev) {
|
1118 |
+
// Build the inner expression
|
1119 |
+
var inner = buildExpression(group.value.body, options.reset());
|
1120 |
+
|
1121 |
+
var innerHeight = 0;
|
1122 |
+
var innerDepth = 0;
|
1123 |
+
|
1124 |
+
// Calculate its height and depth
|
1125 |
+
for (var i = 0; i < inner.length; i++) {
|
1126 |
+
innerHeight = Math.max(inner[i].height, innerHeight);
|
1127 |
+
innerDepth = Math.max(inner[i].depth, innerDepth);
|
1128 |
+
}
|
1129 |
+
|
1130 |
+
// The size of delimiters is the same, regardless of what style we are
|
1131 |
+
// in. Thus, to correctly calculate the size of delimiter we need around
|
1132 |
+
// a group, we scale down the inner size based on the size.
|
1133 |
+
innerHeight *= options.style.sizeMultiplier;
|
1134 |
+
innerDepth *= options.style.sizeMultiplier;
|
1135 |
+
|
1136 |
+
var leftDelim;
|
1137 |
+
if (group.value.left === ".") {
|
1138 |
+
// Empty delimiters in \left and \right make null delimiter spaces.
|
1139 |
+
leftDelim = makeNullDelimiter(options);
|
1140 |
+
} else {
|
1141 |
+
// Otherwise, use leftRightDelim to generate the correct sized
|
1142 |
+
// delimiter.
|
1143 |
+
leftDelim = delimiter.leftRightDelim(
|
1144 |
+
group.value.left, innerHeight, innerDepth, options,
|
1145 |
+
group.mode);
|
1146 |
+
}
|
1147 |
+
// Add it to the beginning of the expression
|
1148 |
+
inner.unshift(leftDelim);
|
1149 |
+
|
1150 |
+
var rightDelim;
|
1151 |
+
// Same for the right delimiter
|
1152 |
+
if (group.value.right === ".") {
|
1153 |
+
rightDelim = makeNullDelimiter(options);
|
1154 |
+
} else {
|
1155 |
+
rightDelim = delimiter.leftRightDelim(
|
1156 |
+
group.value.right, innerHeight, innerDepth, options,
|
1157 |
+
group.mode);
|
1158 |
+
}
|
1159 |
+
// Add it to the end of the expression.
|
1160 |
+
inner.push(rightDelim);
|
1161 |
+
|
1162 |
+
return makeSpan(
|
1163 |
+
["minner", options.style.cls()], inner, options.getColor());
|
1164 |
+
};
|
1165 |
+
|
1166 |
+
groupTypes.rule = function(group, options, prev) {
|
1167 |
+
// Make an empty span for the rule
|
1168 |
+
var rule = makeSpan(["mord", "rule"], [], options.getColor());
|
1169 |
+
|
1170 |
+
// Calculate the shift, width, and height of the rule, and account for units
|
1171 |
+
var shift = 0;
|
1172 |
+
if (group.value.shift) {
|
1173 |
+
shift = group.value.shift.number;
|
1174 |
+
if (group.value.shift.unit === "ex") {
|
1175 |
+
shift *= fontMetrics.metrics.xHeight;
|
1176 |
+
}
|
1177 |
+
}
|
1178 |
+
|
1179 |
+
var width = group.value.width.number;
|
1180 |
+
if (group.value.width.unit === "ex") {
|
1181 |
+
width *= fontMetrics.metrics.xHeight;
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
var height = group.value.height.number;
|
1185 |
+
if (group.value.height.unit === "ex") {
|
1186 |
+
height *= fontMetrics.metrics.xHeight;
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
// The sizes of rules are absolute, so make it larger if we are in a
|
1190 |
+
// smaller style.
|
1191 |
+
shift /= options.style.sizeMultiplier;
|
1192 |
+
width /= options.style.sizeMultiplier;
|
1193 |
+
height /= options.style.sizeMultiplier;
|
1194 |
+
|
1195 |
+
// Style the rule to the right size
|
1196 |
+
rule.style.borderRightWidth = width + "em";
|
1197 |
+
rule.style.borderTopWidth = height + "em";
|
1198 |
+
rule.style.bottom = shift + "em";
|
1199 |
+
|
1200 |
+
// Record the height and width
|
1201 |
+
rule.width = width;
|
1202 |
+
rule.height = height + shift;
|
1203 |
+
rule.depth = -shift;
|
1204 |
+
|
1205 |
+
return rule;
|
1206 |
+
};
|
1207 |
+
|
1208 |
+
groupTypes.accent = function(group, options, prev) {
|
1209 |
+
// Accents are handled in the TeXbook pg. 443, rule 12.
|
1210 |
+
var base = group.value.base;
|
1211 |
+
|
1212 |
+
var supsubGroup;
|
1213 |
+
if (group.type === "supsub") {
|
1214 |
+
// If our base is a character box, and we have superscripts and
|
1215 |
+
// subscripts, the supsub will defer to us. In particular, we want
|
1216 |
+
// to attach the superscripts and subscripts to the inner body (so
|
1217 |
+
// that the position of the superscripts and subscripts won't be
|
1218 |
+
// affected by the height of the accent). We accomplish this by
|
1219 |
+
// sticking the base of the accent into the base of the supsub, and
|
1220 |
+
// rendering that, while keeping track of where the accent is.
|
1221 |
+
|
1222 |
+
// The supsub group is the group that was passed in
|
1223 |
+
var supsub = group;
|
1224 |
+
// The real accent group is the base of the supsub group
|
1225 |
+
group = supsub.value.base;
|
1226 |
+
// The character box is the base of the accent group
|
1227 |
+
base = group.value.base;
|
1228 |
+
// Stick the character box into the base of the supsub group
|
1229 |
+
supsub.value.base = base;
|
1230 |
+
|
1231 |
+
// Rerender the supsub group with its new base, and store that
|
1232 |
+
// result.
|
1233 |
+
supsubGroup = buildGroup(
|
1234 |
+
supsub, options.reset(), prev);
|
1235 |
+
}
|
1236 |
+
|
1237 |
+
// Build the base group
|
1238 |
+
var body = buildGroup(
|
1239 |
+
base, options.withStyle(options.style.cramp()));
|
1240 |
+
|
1241 |
+
// Calculate the skew of the accent. This is based on the line "If the
|
1242 |
+
// nucleus is not a single character, let s = 0; otherwise set s to the
|
1243 |
+
// kern amount for the nucleus followed by the \skewchar of its font."
|
1244 |
+
// Note that our skew metrics are just the kern between each character
|
1245 |
+
// and the skewchar.
|
1246 |
+
var skew;
|
1247 |
+
if (isCharacterBox(base)) {
|
1248 |
+
// If the base is a character box, then we want the skew of the
|
1249 |
+
// innermost character. To do that, we find the innermost character:
|
1250 |
+
var baseChar = getBaseElem(base);
|
1251 |
+
// Then, we render its group to get the symbol inside it
|
1252 |
+
var baseGroup = buildGroup(
|
1253 |
+
baseChar, options.withStyle(options.style.cramp()));
|
1254 |
+
// Finally, we pull the skew off of the symbol.
|
1255 |
+
skew = baseGroup.skew;
|
1256 |
+
// Note that we now throw away baseGroup, because the layers we
|
1257 |
+
// removed with getBaseElem might contain things like \color which
|
1258 |
+
// we can't get rid of.
|
1259 |
+
// TODO(emily): Find a better way to get the skew
|
1260 |
+
} else {
|
1261 |
+
skew = 0;
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
// calculate the amount of space between the body and the accent
|
1265 |
+
var clearance = Math.min(body.height, fontMetrics.metrics.xHeight);
|
1266 |
+
|
1267 |
+
// Build the accent
|
1268 |
+
var accent = buildCommon.makeSymbol(
|
1269 |
+
group.value.accent, "Main-Regular", "math", options.getColor());
|
1270 |
+
// Remove the italic correction of the accent, because it only serves to
|
1271 |
+
// shift the accent over to a place we don't want.
|
1272 |
+
accent.italic = 0;
|
1273 |
+
|
1274 |
+
// The \vec character that the fonts use is a combining character, and
|
1275 |
+
// thus shows up much too far to the left. To account for this, we add a
|
1276 |
+
// specific class which shifts the accent over to where we want it.
|
1277 |
+
// TODO(emily): Fix this in a better way, like by changing the font
|
1278 |
+
var vecClass = group.value.accent === "\\vec" ? "accent-vec" : null;
|
1279 |
+
|
1280 |
+
var accentBody = makeSpan(["accent-body", vecClass], [
|
1281 |
+
makeSpan([], [accent])]);
|
1282 |
+
|
1283 |
+
accentBody = buildCommon.makeVList([
|
1284 |
+
{type: "elem", elem: body},
|
1285 |
+
{type: "kern", size: -clearance},
|
1286 |
+
{type: "elem", elem: accentBody},
|
1287 |
+
], "firstBaseline", null, options);
|
1288 |
+
|
1289 |
+
// Shift the accent over by the skew. Note we shift by twice the skew
|
1290 |
+
// because we are centering the accent, so by adding 2*skew to the left,
|
1291 |
+
// we shift it to the right by 1*skew.
|
1292 |
+
accentBody.children[1].style.marginLeft = 2 * skew + "em";
|
1293 |
+
|
1294 |
+
var accentWrap = makeSpan(["mord", "accent"], [accentBody]);
|
1295 |
+
|
1296 |
+
if (supsubGroup) {
|
1297 |
+
// Here, we replace the "base" child of the supsub with our newly
|
1298 |
+
// generated accent.
|
1299 |
+
supsubGroup.children[0] = accentWrap;
|
1300 |
+
|
1301 |
+
// Since we don't rerun the height calculation after replacing the
|
1302 |
+
// accent, we manually recalculate height.
|
1303 |
+
supsubGroup.height = Math.max(accentWrap.height, supsubGroup.height);
|
1304 |
+
|
1305 |
+
// Accents should always be ords, even when their innards are not.
|
1306 |
+
supsubGroup.classes[0] = "mord";
|
1307 |
+
|
1308 |
+
return supsubGroup;
|
1309 |
+
} else {
|
1310 |
+
return accentWrap;
|
1311 |
+
}
|
1312 |
+
};
|
1313 |
+
|
1314 |
+
groupTypes.phantom = function(group, options, prev) {
|
1315 |
+
var elements = buildExpression(
|
1316 |
+
group.value.value,
|
1317 |
+
options.withPhantom(),
|
1318 |
+
prev
|
1319 |
+
);
|
1320 |
+
|
1321 |
+
// \phantom isn't supposed to affect the elements it contains.
|
1322 |
+
// See "color" for more details.
|
1323 |
+
return new buildCommon.makeFragment(elements);
|
1324 |
+
};
|
1325 |
+
|
1326 |
+
/**
|
1327 |
+
* buildGroup is the function that takes a group and calls the correct groupType
|
1328 |
+
* function for it. It also handles the interaction of size and style changes
|
1329 |
+
* between parents and children.
|
1330 |
+
*/
|
1331 |
+
var buildGroup = function(group, options, prev) {
|
1332 |
+
if (!group) {
|
1333 |
+
return makeSpan();
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
if (groupTypes[group.type]) {
|
1337 |
+
// Call the groupTypes function
|
1338 |
+
var groupNode = groupTypes[group.type](group, options, prev);
|
1339 |
+
var multiplier;
|
1340 |
+
|
1341 |
+
// If the style changed between the parent and the current group,
|
1342 |
+
// account for the size difference
|
1343 |
+
if (options.style !== options.parentStyle) {
|
1344 |
+
multiplier = options.style.sizeMultiplier /
|
1345 |
+
options.parentStyle.sizeMultiplier;
|
1346 |
+
|
1347 |
+
groupNode.height *= multiplier;
|
1348 |
+
groupNode.depth *= multiplier;
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
// If the size changed between the parent and the current group, account
|
1352 |
+
// for that size difference.
|
1353 |
+
if (options.size !== options.parentSize) {
|
1354 |
+
multiplier = buildCommon.sizingMultiplier[options.size] /
|
1355 |
+
buildCommon.sizingMultiplier[options.parentSize];
|
1356 |
+
|
1357 |
+
groupNode.height *= multiplier;
|
1358 |
+
groupNode.depth *= multiplier;
|
1359 |
+
}
|
1360 |
+
|
1361 |
+
return groupNode;
|
1362 |
+
} else {
|
1363 |
+
throw new ParseError(
|
1364 |
+
"Got group of unknown type: '" + group.type + "'");
|
1365 |
+
}
|
1366 |
+
};
|
1367 |
+
|
1368 |
+
/**
|
1369 |
+
* Take an entire parse tree, and build it into an appropriate set of HTML
|
1370 |
+
* nodes.
|
1371 |
+
*/
|
1372 |
+
var buildHTML = function(tree, options) {
|
1373 |
+
// buildExpression is destructive, so we need to make a clone
|
1374 |
+
// of the incoming tree so that it isn't accidentally changed
|
1375 |
+
tree = JSON.parse(JSON.stringify(tree));
|
1376 |
+
|
1377 |
+
// Build the expression contained in the tree
|
1378 |
+
var expression = buildExpression(tree, options);
|
1379 |
+
var body = makeSpan(["base", options.style.cls()], expression);
|
1380 |
+
|
1381 |
+
// Add struts, which ensure that the top of the HTML element falls at the
|
1382 |
+
// height of the expression, and the bottom of the HTML element falls at the
|
1383 |
+
// depth of the expression.
|
1384 |
+
var topStrut = makeSpan(["strut"]);
|
1385 |
+
var bottomStrut = makeSpan(["strut", "bottom"]);
|
1386 |
+
|
1387 |
+
topStrut.style.height = body.height + "em";
|
1388 |
+
bottomStrut.style.height = (body.height + body.depth) + "em";
|
1389 |
+
// We'd like to use `vertical-align: top` but in IE 9 this lowers the
|
1390 |
+
// baseline of the box to the bottom of this strut (instead staying in the
|
1391 |
+
// normal place) so we use an absolute value for vertical-align instead
|
1392 |
+
bottomStrut.style.verticalAlign = -body.depth + "em";
|
1393 |
+
|
1394 |
+
// Wrap the struts and body together
|
1395 |
+
var htmlNode = makeSpan(["katex-html"], [topStrut, bottomStrut, body]);
|
1396 |
+
|
1397 |
+
htmlNode.setAttribute("aria-hidden", "true");
|
1398 |
+
|
1399 |
+
return htmlNode;
|
1400 |
+
};
|
1401 |
+
|
1402 |
+
module.exports = buildHTML;
|
modules/tokenize_latex/third_party/katex/src/buildMathML.js
ADDED
@@ -0,0 +1,533 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file converts a parse tree into a cooresponding MathML tree. The main
|
3 |
+
* entry point is the `buildMathML` function, which takes a parse tree from the
|
4 |
+
* parser.
|
5 |
+
*/
|
6 |
+
|
7 |
+
var buildCommon = require("./buildCommon");
|
8 |
+
var fontMetrics = require("./fontMetrics");
|
9 |
+
var mathMLTree = require("./mathMLTree");
|
10 |
+
var ParseError = require("./ParseError");
|
11 |
+
var symbols = require("./symbols");
|
12 |
+
var utils = require("./utils");
|
13 |
+
|
14 |
+
var makeSpan = buildCommon.makeSpan;
|
15 |
+
var fontMap = buildCommon.fontMap;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Takes a symbol and converts it into a MathML text node after performing
|
19 |
+
* optional replacement from symbols.js.
|
20 |
+
*/
|
21 |
+
var makeText = function(text, mode) {
|
22 |
+
if (symbols[mode][text] && symbols[mode][text].replace) {
|
23 |
+
text = symbols[mode][text].replace;
|
24 |
+
}
|
25 |
+
|
26 |
+
return new mathMLTree.TextNode(text);
|
27 |
+
};
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Returns the math variant as a string or null if none is required.
|
31 |
+
*/
|
32 |
+
var getVariant = function(group, options) {
|
33 |
+
var font = options.font;
|
34 |
+
if (!font) {
|
35 |
+
return null;
|
36 |
+
}
|
37 |
+
|
38 |
+
var mode = group.mode;
|
39 |
+
if (font === "mathit") {
|
40 |
+
return "italic";
|
41 |
+
}
|
42 |
+
|
43 |
+
var value = group.value;
|
44 |
+
if (utils.contains(["\\imath", "\\jmath"], value)) {
|
45 |
+
return null;
|
46 |
+
}
|
47 |
+
|
48 |
+
if (symbols[mode][value] && symbols[mode][value].replace) {
|
49 |
+
value = symbols[mode][value].replace;
|
50 |
+
}
|
51 |
+
|
52 |
+
var fontName = fontMap[font].fontName;
|
53 |
+
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
54 |
+
return fontMap[options.font].variant;
|
55 |
+
}
|
56 |
+
|
57 |
+
return null;
|
58 |
+
};
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Functions for handling the different types of groups found in the parse
|
62 |
+
* tree. Each function should take a parse group and return a MathML node.
|
63 |
+
*/
|
64 |
+
var groupTypes = {};
|
65 |
+
|
66 |
+
groupTypes.mathord = function(group, options) {
|
67 |
+
var node = new mathMLTree.MathNode(
|
68 |
+
"mi",
|
69 |
+
[makeText(group.value, group.mode)]);
|
70 |
+
|
71 |
+
var variant = getVariant(group, options);
|
72 |
+
if (variant) {
|
73 |
+
node.setAttribute("mathvariant", variant);
|
74 |
+
}
|
75 |
+
return node;
|
76 |
+
};
|
77 |
+
|
78 |
+
groupTypes.textord = function(group, options) {
|
79 |
+
var text = makeText(group.value, group.mode);
|
80 |
+
|
81 |
+
var variant = getVariant(group, options) || "normal";
|
82 |
+
|
83 |
+
var node;
|
84 |
+
if (/[0-9]/.test(group.value)) {
|
85 |
+
// TODO(kevinb) merge adjacent <mn> nodes
|
86 |
+
// do it as a post processing step
|
87 |
+
node = new mathMLTree.MathNode("mn", [text]);
|
88 |
+
if (options.font) {
|
89 |
+
node.setAttribute("mathvariant", variant);
|
90 |
+
}
|
91 |
+
} else {
|
92 |
+
node = new mathMLTree.MathNode("mi", [text]);
|
93 |
+
node.setAttribute("mathvariant", variant);
|
94 |
+
}
|
95 |
+
|
96 |
+
return node;
|
97 |
+
};
|
98 |
+
|
99 |
+
groupTypes.bin = function(group) {
|
100 |
+
var node = new mathMLTree.MathNode(
|
101 |
+
"mo", [makeText(group.value, group.mode)]);
|
102 |
+
|
103 |
+
return node;
|
104 |
+
};
|
105 |
+
|
106 |
+
groupTypes.rel = function(group) {
|
107 |
+
var node = new mathMLTree.MathNode(
|
108 |
+
"mo", [makeText(group.value, group.mode)]);
|
109 |
+
|
110 |
+
return node;
|
111 |
+
};
|
112 |
+
|
113 |
+
groupTypes.open = function(group) {
|
114 |
+
var node = new mathMLTree.MathNode(
|
115 |
+
"mo", [makeText(group.value, group.mode)]);
|
116 |
+
|
117 |
+
return node;
|
118 |
+
};
|
119 |
+
|
120 |
+
groupTypes.close = function(group) {
|
121 |
+
var node = new mathMLTree.MathNode(
|
122 |
+
"mo", [makeText(group.value, group.mode)]);
|
123 |
+
|
124 |
+
return node;
|
125 |
+
};
|
126 |
+
|
127 |
+
groupTypes.inner = function(group) {
|
128 |
+
var node = new mathMLTree.MathNode(
|
129 |
+
"mo", [makeText(group.value, group.mode)]);
|
130 |
+
|
131 |
+
return node;
|
132 |
+
};
|
133 |
+
|
134 |
+
groupTypes.punct = function(group) {
|
135 |
+
var node = new mathMLTree.MathNode(
|
136 |
+
"mo", [makeText(group.value, group.mode)]);
|
137 |
+
|
138 |
+
node.setAttribute("separator", "true");
|
139 |
+
|
140 |
+
return node;
|
141 |
+
};
|
142 |
+
|
143 |
+
groupTypes.ordgroup = function(group, options) {
|
144 |
+
var inner = buildExpression(group.value, options);
|
145 |
+
|
146 |
+
var node = new mathMLTree.MathNode("mrow", inner);
|
147 |
+
|
148 |
+
return node;
|
149 |
+
};
|
150 |
+
|
151 |
+
groupTypes.text = function(group, options) {
|
152 |
+
var inner = buildExpression(group.value.body, options);
|
153 |
+
|
154 |
+
var node = new mathMLTree.MathNode("mtext", inner);
|
155 |
+
|
156 |
+
return node;
|
157 |
+
};
|
158 |
+
|
159 |
+
groupTypes.color = function(group, options) {
|
160 |
+
var inner = buildExpression(group.value.value, options);
|
161 |
+
|
162 |
+
var node = new mathMLTree.MathNode("mstyle", inner);
|
163 |
+
|
164 |
+
node.setAttribute("mathcolor", group.value.color);
|
165 |
+
|
166 |
+
return node;
|
167 |
+
};
|
168 |
+
|
169 |
+
groupTypes.supsub = function(group, options) {
|
170 |
+
var children = [buildGroup(group.value.base, options)];
|
171 |
+
|
172 |
+
if (group.value.sub) {
|
173 |
+
children.push(buildGroup(group.value.sub, options));
|
174 |
+
}
|
175 |
+
|
176 |
+
if (group.value.sup) {
|
177 |
+
children.push(buildGroup(group.value.sup, options));
|
178 |
+
}
|
179 |
+
|
180 |
+
var nodeType;
|
181 |
+
if (!group.value.sub) {
|
182 |
+
nodeType = "msup";
|
183 |
+
} else if (!group.value.sup) {
|
184 |
+
nodeType = "msub";
|
185 |
+
} else {
|
186 |
+
nodeType = "msubsup";
|
187 |
+
}
|
188 |
+
|
189 |
+
var node = new mathMLTree.MathNode(nodeType, children);
|
190 |
+
|
191 |
+
return node;
|
192 |
+
};
|
193 |
+
|
194 |
+
groupTypes.genfrac = function(group, options) {
|
195 |
+
var node = new mathMLTree.MathNode(
|
196 |
+
"mfrac",
|
197 |
+
[buildGroup(group.value.numer, options),
|
198 |
+
buildGroup(group.value.denom, options)]);
|
199 |
+
|
200 |
+
if (!group.value.hasBarLine) {
|
201 |
+
node.setAttribute("linethickness", "0px");
|
202 |
+
}
|
203 |
+
|
204 |
+
if (group.value.leftDelim != null || group.value.rightDelim != null) {
|
205 |
+
var withDelims = [];
|
206 |
+
|
207 |
+
if (group.value.leftDelim != null) {
|
208 |
+
var leftOp = new mathMLTree.MathNode(
|
209 |
+
"mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
|
210 |
+
|
211 |
+
leftOp.setAttribute("fence", "true");
|
212 |
+
|
213 |
+
withDelims.push(leftOp);
|
214 |
+
}
|
215 |
+
|
216 |
+
withDelims.push(node);
|
217 |
+
|
218 |
+
if (group.value.rightDelim != null) {
|
219 |
+
var rightOp = new mathMLTree.MathNode(
|
220 |
+
"mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
|
221 |
+
|
222 |
+
rightOp.setAttribute("fence", "true");
|
223 |
+
|
224 |
+
withDelims.push(rightOp);
|
225 |
+
}
|
226 |
+
|
227 |
+
var outerNode = new mathMLTree.MathNode("mrow", withDelims);
|
228 |
+
|
229 |
+
return outerNode;
|
230 |
+
}
|
231 |
+
|
232 |
+
return node;
|
233 |
+
};
|
234 |
+
|
235 |
+
groupTypes.array = function(group, options) {
|
236 |
+
return new mathMLTree.MathNode(
|
237 |
+
"mtable", group.value.body.map(function(row) {
|
238 |
+
return new mathMLTree.MathNode(
|
239 |
+
"mtr", row.map(function(cell) {
|
240 |
+
return new mathMLTree.MathNode(
|
241 |
+
"mtd", [buildGroup(cell, options)]);
|
242 |
+
}));
|
243 |
+
}));
|
244 |
+
};
|
245 |
+
|
246 |
+
groupTypes.sqrt = function(group, options) {
|
247 |
+
var node;
|
248 |
+
if (group.value.index) {
|
249 |
+
node = new mathMLTree.MathNode(
|
250 |
+
"mroot", [
|
251 |
+
buildGroup(group.value.body, options),
|
252 |
+
buildGroup(group.value.index, options),
|
253 |
+
]);
|
254 |
+
} else {
|
255 |
+
node = new mathMLTree.MathNode(
|
256 |
+
"msqrt", [buildGroup(group.value.body, options)]);
|
257 |
+
}
|
258 |
+
|
259 |
+
return node;
|
260 |
+
};
|
261 |
+
|
262 |
+
groupTypes.leftright = function(group, options) {
|
263 |
+
var inner = buildExpression(group.value.body, options);
|
264 |
+
|
265 |
+
if (group.value.left !== ".") {
|
266 |
+
var leftNode = new mathMLTree.MathNode(
|
267 |
+
"mo", [makeText(group.value.left, group.mode)]);
|
268 |
+
|
269 |
+
leftNode.setAttribute("fence", "true");
|
270 |
+
|
271 |
+
inner.unshift(leftNode);
|
272 |
+
}
|
273 |
+
|
274 |
+
if (group.value.right !== ".") {
|
275 |
+
var rightNode = new mathMLTree.MathNode(
|
276 |
+
"mo", [makeText(group.value.right, group.mode)]);
|
277 |
+
|
278 |
+
rightNode.setAttribute("fence", "true");
|
279 |
+
|
280 |
+
inner.push(rightNode);
|
281 |
+
}
|
282 |
+
|
283 |
+
var outerNode = new mathMLTree.MathNode("mrow", inner);
|
284 |
+
|
285 |
+
return outerNode;
|
286 |
+
};
|
287 |
+
|
288 |
+
groupTypes.accent = function(group, options) {
|
289 |
+
var accentNode = new mathMLTree.MathNode(
|
290 |
+
"mo", [makeText(group.value.accent, group.mode)]);
|
291 |
+
|
292 |
+
var node = new mathMLTree.MathNode(
|
293 |
+
"mover",
|
294 |
+
[buildGroup(group.value.base, options),
|
295 |
+
accentNode]);
|
296 |
+
|
297 |
+
node.setAttribute("accent", "true");
|
298 |
+
|
299 |
+
return node;
|
300 |
+
};
|
301 |
+
|
302 |
+
groupTypes.spacing = function(group) {
|
303 |
+
var node;
|
304 |
+
|
305 |
+
if (group.value === "\\ " || group.value === "\\space" ||
|
306 |
+
group.value === " " || group.value === "~") {
|
307 |
+
node = new mathMLTree.MathNode(
|
308 |
+
"mtext", [new mathMLTree.TextNode("\u00a0")]);
|
309 |
+
} else {
|
310 |
+
node = new mathMLTree.MathNode("mspace");
|
311 |
+
|
312 |
+
node.setAttribute(
|
313 |
+
"width", buildCommon.spacingFunctions[group.value].size);
|
314 |
+
}
|
315 |
+
|
316 |
+
return node;
|
317 |
+
};
|
318 |
+
|
319 |
+
groupTypes.op = function(group) {
|
320 |
+
var node;
|
321 |
+
|
322 |
+
// TODO(emily): handle big operators using the `largeop` attribute
|
323 |
+
|
324 |
+
if (group.value.symbol) {
|
325 |
+
// This is a symbol. Just add the symbol.
|
326 |
+
node = new mathMLTree.MathNode(
|
327 |
+
"mo", [makeText(group.value.body, group.mode)]);
|
328 |
+
} else {
|
329 |
+
// This is a text operator. Add all of the characters from the
|
330 |
+
// operator's name.
|
331 |
+
// TODO(emily): Add a space in the middle of some of these
|
332 |
+
// operators, like \limsup.
|
333 |
+
node = new mathMLTree.MathNode(
|
334 |
+
"mi", [new mathMLTree.TextNode(group.value.body.slice(1))]);
|
335 |
+
}
|
336 |
+
|
337 |
+
return node;
|
338 |
+
};
|
339 |
+
|
340 |
+
groupTypes.katex = function(group) {
|
341 |
+
var node = new mathMLTree.MathNode(
|
342 |
+
"mtext", [new mathMLTree.TextNode("KaTeX")]);
|
343 |
+
|
344 |
+
return node;
|
345 |
+
};
|
346 |
+
|
347 |
+
groupTypes.font = function(group, options) {
|
348 |
+
var font = group.value.font;
|
349 |
+
return buildGroup(group.value.body, options.withFont(font));
|
350 |
+
};
|
351 |
+
|
352 |
+
groupTypes.delimsizing = function(group) {
|
353 |
+
var children = [];
|
354 |
+
|
355 |
+
if (group.value.value !== ".") {
|
356 |
+
children.push(makeText(group.value.value, group.mode));
|
357 |
+
}
|
358 |
+
|
359 |
+
var node = new mathMLTree.MathNode("mo", children);
|
360 |
+
|
361 |
+
if (group.value.delimType === "open" ||
|
362 |
+
group.value.delimType === "close") {
|
363 |
+
// Only some of the delimsizing functions act as fences, and they
|
364 |
+
// return "open" or "close" delimTypes.
|
365 |
+
node.setAttribute("fence", "true");
|
366 |
+
} else {
|
367 |
+
// Explicitly disable fencing if it's not a fence, to override the
|
368 |
+
// defaults.
|
369 |
+
node.setAttribute("fence", "false");
|
370 |
+
}
|
371 |
+
|
372 |
+
return node;
|
373 |
+
};
|
374 |
+
|
375 |
+
groupTypes.styling = function(group, options) {
|
376 |
+
var inner = buildExpression(group.value.value, options);
|
377 |
+
|
378 |
+
var node = new mathMLTree.MathNode("mstyle", inner);
|
379 |
+
|
380 |
+
var styleAttributes = {
|
381 |
+
"display": ["0", "true"],
|
382 |
+
"text": ["0", "false"],
|
383 |
+
"script": ["1", "false"],
|
384 |
+
"scriptscript": ["2", "false"],
|
385 |
+
};
|
386 |
+
|
387 |
+
var attr = styleAttributes[group.value.style];
|
388 |
+
|
389 |
+
node.setAttribute("scriptlevel", attr[0]);
|
390 |
+
node.setAttribute("displaystyle", attr[1]);
|
391 |
+
|
392 |
+
return node;
|
393 |
+
};
|
394 |
+
|
395 |
+
groupTypes.sizing = function(group, options) {
|
396 |
+
var inner = buildExpression(group.value.value, options);
|
397 |
+
|
398 |
+
var node = new mathMLTree.MathNode("mstyle", inner);
|
399 |
+
|
400 |
+
// TODO(emily): This doesn't produce the correct size for nested size
|
401 |
+
// changes, because we don't keep state of what style we're currently
|
402 |
+
// in, so we can't reset the size to normal before changing it. Now
|
403 |
+
// that we're passing an options parameter we should be able to fix
|
404 |
+
// this.
|
405 |
+
node.setAttribute(
|
406 |
+
"mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
|
407 |
+
|
408 |
+
return node;
|
409 |
+
};
|
410 |
+
|
411 |
+
groupTypes.overline = function(group, options) {
|
412 |
+
var operator = new mathMLTree.MathNode(
|
413 |
+
"mo", [new mathMLTree.TextNode("\u203e")]);
|
414 |
+
operator.setAttribute("stretchy", "true");
|
415 |
+
|
416 |
+
var node = new mathMLTree.MathNode(
|
417 |
+
"mover",
|
418 |
+
[buildGroup(group.value.body, options),
|
419 |
+
operator]);
|
420 |
+
node.setAttribute("accent", "true");
|
421 |
+
|
422 |
+
return node;
|
423 |
+
};
|
424 |
+
|
425 |
+
groupTypes.underline = function(group, options) {
|
426 |
+
var operator = new mathMLTree.MathNode(
|
427 |
+
"mo", [new mathMLTree.TextNode("\u203e")]);
|
428 |
+
operator.setAttribute("stretchy", "true");
|
429 |
+
|
430 |
+
var node = new mathMLTree.MathNode(
|
431 |
+
"munder",
|
432 |
+
[buildGroup(group.value.body, options),
|
433 |
+
operator]);
|
434 |
+
node.setAttribute("accentunder", "true");
|
435 |
+
|
436 |
+
return node;
|
437 |
+
};
|
438 |
+
|
439 |
+
groupTypes.rule = function(group) {
|
440 |
+
// TODO(emily): Figure out if there's an actual way to draw black boxes
|
441 |
+
// in MathML.
|
442 |
+
var node = new mathMLTree.MathNode("mrow");
|
443 |
+
|
444 |
+
return node;
|
445 |
+
};
|
446 |
+
|
447 |
+
groupTypes.llap = function(group, options) {
|
448 |
+
var node = new mathMLTree.MathNode(
|
449 |
+
"mpadded", [buildGroup(group.value.body, options)]);
|
450 |
+
|
451 |
+
node.setAttribute("lspace", "-1width");
|
452 |
+
node.setAttribute("width", "0px");
|
453 |
+
|
454 |
+
return node;
|
455 |
+
};
|
456 |
+
|
457 |
+
groupTypes.rlap = function(group, options) {
|
458 |
+
var node = new mathMLTree.MathNode(
|
459 |
+
"mpadded", [buildGroup(group.value.body, options)]);
|
460 |
+
|
461 |
+
node.setAttribute("width", "0px");
|
462 |
+
|
463 |
+
return node;
|
464 |
+
};
|
465 |
+
|
466 |
+
groupTypes.phantom = function(group, options, prev) {
|
467 |
+
var inner = buildExpression(group.value.value, options);
|
468 |
+
return new mathMLTree.MathNode("mphantom", inner);
|
469 |
+
};
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Takes a list of nodes, builds them, and returns a list of the generated
|
473 |
+
* MathML nodes. A little simpler than the HTML version because we don't do any
|
474 |
+
* previous-node handling.
|
475 |
+
*/
|
476 |
+
var buildExpression = function(expression, options) {
|
477 |
+
var groups = [];
|
478 |
+
for (var i = 0; i < expression.length; i++) {
|
479 |
+
var group = expression[i];
|
480 |
+
groups.push(buildGroup(group, options));
|
481 |
+
}
|
482 |
+
return groups;
|
483 |
+
};
|
484 |
+
|
485 |
+
/**
|
486 |
+
* Takes a group from the parser and calls the appropriate groupTypes function
|
487 |
+
* on it to produce a MathML node.
|
488 |
+
*/
|
489 |
+
var buildGroup = function(group, options) {
|
490 |
+
if (!group) {
|
491 |
+
return new mathMLTree.MathNode("mrow");
|
492 |
+
}
|
493 |
+
|
494 |
+
if (groupTypes[group.type]) {
|
495 |
+
// Call the groupTypes function
|
496 |
+
return groupTypes[group.type](group, options);
|
497 |
+
} else {
|
498 |
+
throw new ParseError(
|
499 |
+
"Got group of unknown type: '" + group.type + "'");
|
500 |
+
}
|
501 |
+
};
|
502 |
+
|
503 |
+
/**
|
504 |
+
* Takes a full parse tree and settings and builds a MathML representation of
|
505 |
+
* it. In particular, we put the elements from building the parse tree into a
|
506 |
+
* <semantics> tag so we can also include that TeX source as an annotation.
|
507 |
+
*
|
508 |
+
* Note that we actually return a domTree element with a `<math>` inside it so
|
509 |
+
* we can do appropriate styling.
|
510 |
+
*/
|
511 |
+
var buildMathML = function(tree, texExpression, options) {
|
512 |
+
var expression = buildExpression(tree, options);
|
513 |
+
|
514 |
+
// Wrap up the expression in an mrow so it is presented in the semantics
|
515 |
+
// tag correctly.
|
516 |
+
var wrapper = new mathMLTree.MathNode("mrow", expression);
|
517 |
+
|
518 |
+
// Build a TeX annotation of the source
|
519 |
+
var annotation = new mathMLTree.MathNode(
|
520 |
+
"annotation", [new mathMLTree.TextNode(texExpression)]);
|
521 |
+
|
522 |
+
annotation.setAttribute("encoding", "application/x-tex");
|
523 |
+
|
524 |
+
var semantics = new mathMLTree.MathNode(
|
525 |
+
"semantics", [wrapper, annotation]);
|
526 |
+
|
527 |
+
var math = new mathMLTree.MathNode("math", [semantics]);
|
528 |
+
|
529 |
+
// You can't style <math> nodes, so we wrap the node in a span.
|
530 |
+
return makeSpan(["katex-mathml"], [math]);
|
531 |
+
};
|
532 |
+
|
533 |
+
module.exports = buildMathML;
|
modules/tokenize_latex/third_party/katex/src/buildTree.js
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var buildHTML = require("./buildHTML");
|
2 |
+
var buildMathML = require("./buildMathML");
|
3 |
+
var buildCommon = require("./buildCommon");
|
4 |
+
var Options = require("./Options");
|
5 |
+
var Settings = require("./Settings");
|
6 |
+
var Style = require("./Style");
|
7 |
+
|
8 |
+
var makeSpan = buildCommon.makeSpan;
|
9 |
+
|
10 |
+
var buildTree = function(tree, expression, settings) {
|
11 |
+
settings = settings || new Settings({});
|
12 |
+
|
13 |
+
var startStyle = Style.TEXT;
|
14 |
+
if (settings.displayMode) {
|
15 |
+
startStyle = Style.DISPLAY;
|
16 |
+
}
|
17 |
+
|
18 |
+
// Setup the default options
|
19 |
+
var options = new Options({
|
20 |
+
style: startStyle,
|
21 |
+
size: "size5",
|
22 |
+
});
|
23 |
+
|
24 |
+
// `buildHTML` sometimes messes with the parse tree (like turning bins ->
|
25 |
+
// ords), so we build the MathML version first.
|
26 |
+
var mathMLNode = buildMathML(tree, expression, options);
|
27 |
+
var htmlNode = buildHTML(tree, options);
|
28 |
+
|
29 |
+
var katexNode = makeSpan(["katex"], [
|
30 |
+
mathMLNode, htmlNode,
|
31 |
+
]);
|
32 |
+
|
33 |
+
if (settings.displayMode) {
|
34 |
+
return makeSpan(["katex-display"], [katexNode]);
|
35 |
+
} else {
|
36 |
+
return katexNode;
|
37 |
+
}
|
38 |
+
};
|
39 |
+
|
40 |
+
module.exports = buildTree;
|
modules/tokenize_latex/third_party/katex/src/delimiter.js
ADDED
@@ -0,0 +1,542 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file deals with creating delimiters of various sizes. The TeXbook
|
3 |
+
* discusses these routines on page 441-442, in the "Another subroutine sets box
|
4 |
+
* x to a specified variable delimiter" paragraph.
|
5 |
+
*
|
6 |
+
* There are three main routines here. `makeSmallDelim` makes a delimiter in the
|
7 |
+
* normal font, but in either text, script, or scriptscript style.
|
8 |
+
* `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1,
|
9 |
+
* Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of
|
10 |
+
* smaller pieces that are stacked on top of one another.
|
11 |
+
*
|
12 |
+
* The functions take a parameter `center`, which determines if the delimiter
|
13 |
+
* should be centered around the axis.
|
14 |
+
*
|
15 |
+
* Then, there are three exposed functions. `sizedDelim` makes a delimiter in
|
16 |
+
* one of the given sizes. This is used for things like `\bigl`.
|
17 |
+
* `customSizedDelim` makes a delimiter with a given total height+depth. It is
|
18 |
+
* called in places like `\sqrt`. `leftRightDelim` makes an appropriate
|
19 |
+
* delimiter which surrounds an expression of a given height an depth. It is
|
20 |
+
* used in `\left` and `\right`.
|
21 |
+
*/
|
22 |
+
|
23 |
+
var ParseError = require("./ParseError");
|
24 |
+
var Style = require("./Style");
|
25 |
+
|
26 |
+
var buildCommon = require("./buildCommon");
|
27 |
+
var fontMetrics = require("./fontMetrics");
|
28 |
+
var symbols = require("./symbols");
|
29 |
+
var utils = require("./utils");
|
30 |
+
|
31 |
+
var makeSpan = buildCommon.makeSpan;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Get the metrics for a given symbol and font, after transformation (i.e.
|
35 |
+
* after following replacement from symbols.js)
|
36 |
+
*/
|
37 |
+
var getMetrics = function(symbol, font) {
|
38 |
+
if (symbols.math[symbol] && symbols.math[symbol].replace) {
|
39 |
+
return fontMetrics.getCharacterMetrics(
|
40 |
+
symbols.math[symbol].replace, font);
|
41 |
+
} else {
|
42 |
+
return fontMetrics.getCharacterMetrics(
|
43 |
+
symbol, font);
|
44 |
+
}
|
45 |
+
};
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Builds a symbol in the given font size (note size is an integer)
|
49 |
+
*/
|
50 |
+
var mathrmSize = function(value, size, mode) {
|
51 |
+
return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode);
|
52 |
+
};
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Puts a delimiter span in a given style, and adds appropriate height, depth,
|
56 |
+
* and maxFontSizes.
|
57 |
+
*/
|
58 |
+
var styleWrap = function(delim, toStyle, options) {
|
59 |
+
var span = makeSpan(
|
60 |
+
["style-wrap", options.style.reset(), toStyle.cls()], [delim]);
|
61 |
+
|
62 |
+
var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
|
63 |
+
|
64 |
+
span.height *= multiplier;
|
65 |
+
span.depth *= multiplier;
|
66 |
+
span.maxFontSize = toStyle.sizeMultiplier;
|
67 |
+
|
68 |
+
return span;
|
69 |
+
};
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Makes a small delimiter. This is a delimiter that comes in the Main-Regular
|
73 |
+
* font, but is restyled to either be in textstyle, scriptstyle, or
|
74 |
+
* scriptscriptstyle.
|
75 |
+
*/
|
76 |
+
var makeSmallDelim = function(delim, style, center, options, mode) {
|
77 |
+
var text = buildCommon.makeSymbol(delim, "Main-Regular", mode);
|
78 |
+
|
79 |
+
var span = styleWrap(text, style, options);
|
80 |
+
|
81 |
+
if (center) {
|
82 |
+
var shift =
|
83 |
+
(1 - options.style.sizeMultiplier / style.sizeMultiplier) *
|
84 |
+
fontMetrics.metrics.axisHeight;
|
85 |
+
|
86 |
+
span.style.top = shift + "em";
|
87 |
+
span.height -= shift;
|
88 |
+
span.depth += shift;
|
89 |
+
}
|
90 |
+
|
91 |
+
return span;
|
92 |
+
};
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
|
96 |
+
* Size3, or Size4 fonts. It is always rendered in textstyle.
|
97 |
+
*/
|
98 |
+
var makeLargeDelim = function(delim, size, center, options, mode) {
|
99 |
+
var inner = mathrmSize(delim, size, mode);
|
100 |
+
|
101 |
+
var span = styleWrap(
|
102 |
+
makeSpan(["delimsizing", "size" + size],
|
103 |
+
[inner], options.getColor()),
|
104 |
+
Style.TEXT, options);
|
105 |
+
|
106 |
+
if (center) {
|
107 |
+
var shift = (1 - options.style.sizeMultiplier) *
|
108 |
+
fontMetrics.metrics.axisHeight;
|
109 |
+
|
110 |
+
span.style.top = shift + "em";
|
111 |
+
span.height -= shift;
|
112 |
+
span.depth += shift;
|
113 |
+
}
|
114 |
+
|
115 |
+
return span;
|
116 |
+
};
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Make an inner span with the given offset and in the given font. This is used
|
120 |
+
* in `makeStackedDelim` to make the stacking pieces for the delimiter.
|
121 |
+
*/
|
122 |
+
var makeInner = function(symbol, font, mode) {
|
123 |
+
var sizeClass;
|
124 |
+
// Apply the correct CSS class to choose the right font.
|
125 |
+
if (font === "Size1-Regular") {
|
126 |
+
sizeClass = "delim-size1";
|
127 |
+
} else if (font === "Size4-Regular") {
|
128 |
+
sizeClass = "delim-size4";
|
129 |
+
}
|
130 |
+
|
131 |
+
var inner = makeSpan(
|
132 |
+
["delimsizinginner", sizeClass],
|
133 |
+
[makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]);
|
134 |
+
|
135 |
+
// Since this will be passed into `makeVList` in the end, wrap the element
|
136 |
+
// in the appropriate tag that VList uses.
|
137 |
+
return {type: "elem", elem: inner};
|
138 |
+
};
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Make a stacked delimiter out of a given delimiter, with the total height at
|
142 |
+
* least `heightTotal`. This routine is mentioned on page 442 of the TeXbook.
|
143 |
+
*/
|
144 |
+
var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
|
145 |
+
// There are four parts, the top, an optional middle, a repeated part, and a
|
146 |
+
// bottom.
|
147 |
+
var top;
|
148 |
+
var middle;
|
149 |
+
var repeat;
|
150 |
+
var bottom;
|
151 |
+
top = repeat = bottom = delim;
|
152 |
+
middle = null;
|
153 |
+
// Also keep track of what font the delimiters are in
|
154 |
+
var font = "Size1-Regular";
|
155 |
+
|
156 |
+
// We set the parts and font based on the symbol. Note that we use
|
157 |
+
// '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
|
158 |
+
// repeats of the arrows
|
159 |
+
if (delim === "\\uparrow") {
|
160 |
+
repeat = bottom = "\u23d0";
|
161 |
+
} else if (delim === "\\Uparrow") {
|
162 |
+
repeat = bottom = "\u2016";
|
163 |
+
} else if (delim === "\\downarrow") {
|
164 |
+
top = repeat = "\u23d0";
|
165 |
+
} else if (delim === "\\Downarrow") {
|
166 |
+
top = repeat = "\u2016";
|
167 |
+
} else if (delim === "\\updownarrow") {
|
168 |
+
top = "\\uparrow";
|
169 |
+
repeat = "\u23d0";
|
170 |
+
bottom = "\\downarrow";
|
171 |
+
} else if (delim === "\\Updownarrow") {
|
172 |
+
top = "\\Uparrow";
|
173 |
+
repeat = "\u2016";
|
174 |
+
bottom = "\\Downarrow";
|
175 |
+
} else if (delim === "[" || delim === "\\lbrack") {
|
176 |
+
top = "\u23a1";
|
177 |
+
repeat = "\u23a2";
|
178 |
+
bottom = "\u23a3";
|
179 |
+
font = "Size4-Regular";
|
180 |
+
} else if (delim === "]" || delim === "\\rbrack") {
|
181 |
+
top = "\u23a4";
|
182 |
+
repeat = "\u23a5";
|
183 |
+
bottom = "\u23a6";
|
184 |
+
font = "Size4-Regular";
|
185 |
+
} else if (delim === "\\lfloor") {
|
186 |
+
repeat = top = "\u23a2";
|
187 |
+
bottom = "\u23a3";
|
188 |
+
font = "Size4-Regular";
|
189 |
+
} else if (delim === "\\lceil") {
|
190 |
+
top = "\u23a1";
|
191 |
+
repeat = bottom = "\u23a2";
|
192 |
+
font = "Size4-Regular";
|
193 |
+
} else if (delim === "\\rfloor") {
|
194 |
+
repeat = top = "\u23a5";
|
195 |
+
bottom = "\u23a6";
|
196 |
+
font = "Size4-Regular";
|
197 |
+
} else if (delim === "\\rceil") {
|
198 |
+
top = "\u23a4";
|
199 |
+
repeat = bottom = "\u23a5";
|
200 |
+
font = "Size4-Regular";
|
201 |
+
} else if (delim === "(") {
|
202 |
+
top = "\u239b";
|
203 |
+
repeat = "\u239c";
|
204 |
+
bottom = "\u239d";
|
205 |
+
font = "Size4-Regular";
|
206 |
+
} else if (delim === ")") {
|
207 |
+
top = "\u239e";
|
208 |
+
repeat = "\u239f";
|
209 |
+
bottom = "\u23a0";
|
210 |
+
font = "Size4-Regular";
|
211 |
+
} else if (delim === "\\{" || delim === "\\lbrace") {
|
212 |
+
top = "\u23a7";
|
213 |
+
middle = "\u23a8";
|
214 |
+
bottom = "\u23a9";
|
215 |
+
repeat = "\u23aa";
|
216 |
+
font = "Size4-Regular";
|
217 |
+
} else if (delim === "\\}" || delim === "\\rbrace") {
|
218 |
+
top = "\u23ab";
|
219 |
+
middle = "\u23ac";
|
220 |
+
bottom = "\u23ad";
|
221 |
+
repeat = "\u23aa";
|
222 |
+
font = "Size4-Regular";
|
223 |
+
} else if (delim === "\\lgroup") {
|
224 |
+
top = "\u23a7";
|
225 |
+
bottom = "\u23a9";
|
226 |
+
repeat = "\u23aa";
|
227 |
+
font = "Size4-Regular";
|
228 |
+
} else if (delim === "\\rgroup") {
|
229 |
+
top = "\u23ab";
|
230 |
+
bottom = "\u23ad";
|
231 |
+
repeat = "\u23aa";
|
232 |
+
font = "Size4-Regular";
|
233 |
+
} else if (delim === "\\lmoustache") {
|
234 |
+
top = "\u23a7";
|
235 |
+
bottom = "\u23ad";
|
236 |
+
repeat = "\u23aa";
|
237 |
+
font = "Size4-Regular";
|
238 |
+
} else if (delim === "\\rmoustache") {
|
239 |
+
top = "\u23ab";
|
240 |
+
bottom = "\u23a9";
|
241 |
+
repeat = "\u23aa";
|
242 |
+
font = "Size4-Regular";
|
243 |
+
} else if (delim === "\\surd") {
|
244 |
+
top = "\ue001";
|
245 |
+
bottom = "\u23b7";
|
246 |
+
repeat = "\ue000";
|
247 |
+
font = "Size4-Regular";
|
248 |
+
}
|
249 |
+
|
250 |
+
// Get the metrics of the four sections
|
251 |
+
var topMetrics = getMetrics(top, font);
|
252 |
+
var topHeightTotal = topMetrics.height + topMetrics.depth;
|
253 |
+
var repeatMetrics = getMetrics(repeat, font);
|
254 |
+
var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
|
255 |
+
var bottomMetrics = getMetrics(bottom, font);
|
256 |
+
var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
|
257 |
+
var middleHeightTotal = 0;
|
258 |
+
var middleFactor = 1;
|
259 |
+
if (middle !== null) {
|
260 |
+
var middleMetrics = getMetrics(middle, font);
|
261 |
+
middleHeightTotal = middleMetrics.height + middleMetrics.depth;
|
262 |
+
middleFactor = 2; // repeat symmetrically above and below middle
|
263 |
+
}
|
264 |
+
|
265 |
+
// Calcuate the minimal height that the delimiter can have.
|
266 |
+
// It is at least the size of the top, bottom, and optional middle combined.
|
267 |
+
var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
|
268 |
+
|
269 |
+
// Compute the number of copies of the repeat symbol we will need
|
270 |
+
var repeatCount = Math.ceil(
|
271 |
+
(heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
|
272 |
+
|
273 |
+
// Compute the total height of the delimiter including all the symbols
|
274 |
+
var realHeightTotal =
|
275 |
+
minHeight + repeatCount * middleFactor * repeatHeightTotal;
|
276 |
+
|
277 |
+
// The center of the delimiter is placed at the center of the axis. Note
|
278 |
+
// that in this context, "center" means that the delimiter should be
|
279 |
+
// centered around the axis in the current style, while normally it is
|
280 |
+
// centered around the axis in textstyle.
|
281 |
+
var axisHeight = fontMetrics.metrics.axisHeight;
|
282 |
+
if (center) {
|
283 |
+
axisHeight *= options.style.sizeMultiplier;
|
284 |
+
}
|
285 |
+
// Calculate the depth
|
286 |
+
var depth = realHeightTotal / 2 - axisHeight;
|
287 |
+
|
288 |
+
// Now, we start building the pieces that will go into the vlist
|
289 |
+
|
290 |
+
// Keep a list of the inner pieces
|
291 |
+
var inners = [];
|
292 |
+
|
293 |
+
// Add the bottom symbol
|
294 |
+
inners.push(makeInner(bottom, font, mode));
|
295 |
+
|
296 |
+
var i;
|
297 |
+
if (middle === null) {
|
298 |
+
// Add that many symbols
|
299 |
+
for (i = 0; i < repeatCount; i++) {
|
300 |
+
inners.push(makeInner(repeat, font, mode));
|
301 |
+
}
|
302 |
+
} else {
|
303 |
+
// When there is a middle bit, we need the middle part and two repeated
|
304 |
+
// sections
|
305 |
+
for (i = 0; i < repeatCount; i++) {
|
306 |
+
inners.push(makeInner(repeat, font, mode));
|
307 |
+
}
|
308 |
+
inners.push(makeInner(middle, font, mode));
|
309 |
+
for (i = 0; i < repeatCount; i++) {
|
310 |
+
inners.push(makeInner(repeat, font, mode));
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
// Add the top symbol
|
315 |
+
inners.push(makeInner(top, font, mode));
|
316 |
+
|
317 |
+
// Finally, build the vlist
|
318 |
+
var inner = buildCommon.makeVList(inners, "bottom", depth, options);
|
319 |
+
|
320 |
+
return styleWrap(
|
321 |
+
makeSpan(["delimsizing", "mult"], [inner], options.getColor()),
|
322 |
+
Style.TEXT, options);
|
323 |
+
};
|
324 |
+
|
325 |
+
// There are three kinds of delimiters, delimiters that stack when they become
|
326 |
+
// too large
|
327 |
+
var stackLargeDelimiters = [
|
328 |
+
"(", ")", "[", "\\lbrack", "]", "\\rbrack",
|
329 |
+
"\\{", "\\lbrace", "\\}", "\\rbrace",
|
330 |
+
"\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
|
331 |
+
"\\surd",
|
332 |
+
];
|
333 |
+
|
334 |
+
// delimiters that always stack
|
335 |
+
var stackAlwaysDelimiters = [
|
336 |
+
"\\uparrow", "\\downarrow", "\\updownarrow",
|
337 |
+
"\\Uparrow", "\\Downarrow", "\\Updownarrow",
|
338 |
+
"|", "\\|", "\\vert", "\\Vert",
|
339 |
+
"\\lvert", "\\rvert", "\\lVert", "\\rVert",
|
340 |
+
"\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
|
341 |
+
];
|
342 |
+
|
343 |
+
// and delimiters that never stack
|
344 |
+
var stackNeverDelimiters = [
|
345 |
+
"<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt",
|
346 |
+
];
|
347 |
+
|
348 |
+
// Metrics of the different sizes. Found by looking at TeX's output of
|
349 |
+
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
350 |
+
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|
351 |
+
var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
352 |
+
|
353 |
+
/**
|
354 |
+
* Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4.
|
355 |
+
*/
|
356 |
+
var makeSizedDelim = function(delim, size, options, mode) {
|
357 |
+
// < and > turn into \langle and \rangle in delimiters
|
358 |
+
if (delim === "<" || delim === "\\lt") {
|
359 |
+
delim = "\\langle";
|
360 |
+
} else if (delim === ">" || delim === "\\gt") {
|
361 |
+
delim = "\\rangle";
|
362 |
+
}
|
363 |
+
|
364 |
+
// Sized delimiters are never centered.
|
365 |
+
if (utils.contains(stackLargeDelimiters, delim) ||
|
366 |
+
utils.contains(stackNeverDelimiters, delim)) {
|
367 |
+
return makeLargeDelim(delim, size, false, options, mode);
|
368 |
+
} else if (utils.contains(stackAlwaysDelimiters, delim)) {
|
369 |
+
return makeStackedDelim(
|
370 |
+
delim, sizeToMaxHeight[size], false, options, mode);
|
371 |
+
} else {
|
372 |
+
throw new ParseError("Illegal delimiter: '" + delim + "'");
|
373 |
+
}
|
374 |
+
};
|
375 |
+
|
376 |
+
/**
|
377 |
+
* There are three different sequences of delimiter sizes that the delimiters
|
378 |
+
* follow depending on the kind of delimiter. This is used when creating custom
|
379 |
+
* sized delimiters to decide whether to create a small, large, or stacked
|
380 |
+
* delimiter.
|
381 |
+
*
|
382 |
+
* In real TeX, these sequences aren't explicitly defined, but are instead
|
383 |
+
* defined inside the font metrics. Since there are only three sequences that
|
384 |
+
* are possible for the delimiters that TeX defines, it is easier to just encode
|
385 |
+
* them explicitly here.
|
386 |
+
*/
|
387 |
+
|
388 |
+
// Delimiters that never stack try small delimiters and large delimiters only
|
389 |
+
var stackNeverDelimiterSequence = [
|
390 |
+
{type: "small", style: Style.SCRIPTSCRIPT},
|
391 |
+
{type: "small", style: Style.SCRIPT},
|
392 |
+
{type: "small", style: Style.TEXT},
|
393 |
+
{type: "large", size: 1},
|
394 |
+
{type: "large", size: 2},
|
395 |
+
{type: "large", size: 3},
|
396 |
+
{type: "large", size: 4},
|
397 |
+
];
|
398 |
+
|
399 |
+
// Delimiters that always stack try the small delimiters first, then stack
|
400 |
+
var stackAlwaysDelimiterSequence = [
|
401 |
+
{type: "small", style: Style.SCRIPTSCRIPT},
|
402 |
+
{type: "small", style: Style.SCRIPT},
|
403 |
+
{type: "small", style: Style.TEXT},
|
404 |
+
{type: "stack"},
|
405 |
+
];
|
406 |
+
|
407 |
+
// Delimiters that stack when large try the small and then large delimiters, and
|
408 |
+
// stack afterwards
|
409 |
+
var stackLargeDelimiterSequence = [
|
410 |
+
{type: "small", style: Style.SCRIPTSCRIPT},
|
411 |
+
{type: "small", style: Style.SCRIPT},
|
412 |
+
{type: "small", style: Style.TEXT},
|
413 |
+
{type: "large", size: 1},
|
414 |
+
{type: "large", size: 2},
|
415 |
+
{type: "large", size: 3},
|
416 |
+
{type: "large", size: 4},
|
417 |
+
{type: "stack"},
|
418 |
+
];
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Get the font used in a delimiter based on what kind of delimiter it is.
|
422 |
+
*/
|
423 |
+
var delimTypeToFont = function(type) {
|
424 |
+
if (type.type === "small") {
|
425 |
+
return "Main-Regular";
|
426 |
+
} else if (type.type === "large") {
|
427 |
+
return "Size" + type.size + "-Regular";
|
428 |
+
} else if (type.type === "stack") {
|
429 |
+
return "Size4-Regular";
|
430 |
+
}
|
431 |
+
};
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Traverse a sequence of types of delimiters to decide what kind of delimiter
|
435 |
+
* should be used to create a delimiter of the given height+depth.
|
436 |
+
*/
|
437 |
+
var traverseSequence = function(delim, height, sequence, options) {
|
438 |
+
// Here, we choose the index we should start at in the sequences. In smaller
|
439 |
+
// sizes (which correspond to larger numbers in style.size) we start earlier
|
440 |
+
// in the sequence. Thus, scriptscript starts at index 3-3=0, script starts
|
441 |
+
// at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2
|
442 |
+
var start = Math.min(2, 3 - options.style.size);
|
443 |
+
for (var i = start; i < sequence.length; i++) {
|
444 |
+
if (sequence[i].type === "stack") {
|
445 |
+
// This is always the last delimiter, so we just break the loop now.
|
446 |
+
break;
|
447 |
+
}
|
448 |
+
|
449 |
+
var metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
|
450 |
+
var heightDepth = metrics.height + metrics.depth;
|
451 |
+
|
452 |
+
// Small delimiters are scaled down versions of the same font, so we
|
453 |
+
// account for the style change size.
|
454 |
+
|
455 |
+
if (sequence[i].type === "small") {
|
456 |
+
heightDepth *= sequence[i].style.sizeMultiplier;
|
457 |
+
}
|
458 |
+
|
459 |
+
// Check if the delimiter at this size works for the given height.
|
460 |
+
if (heightDepth > height) {
|
461 |
+
return sequence[i];
|
462 |
+
}
|
463 |
+
}
|
464 |
+
|
465 |
+
// If we reached the end of the sequence, return the last sequence element.
|
466 |
+
return sequence[sequence.length - 1];
|
467 |
+
};
|
468 |
+
|
469 |
+
/**
|
470 |
+
* Make a delimiter of a given height+depth, with optional centering. Here, we
|
471 |
+
* traverse the sequences, and create a delimiter that the sequence tells us to.
|
472 |
+
*/
|
473 |
+
var makeCustomSizedDelim = function(delim, height, center, options, mode) {
|
474 |
+
if (delim === "<" || delim === "\\lt") {
|
475 |
+
delim = "\\langle";
|
476 |
+
} else if (delim === ">" || delim === "\\gt") {
|
477 |
+
delim = "\\rangle";
|
478 |
+
}
|
479 |
+
|
480 |
+
// Decide what sequence to use
|
481 |
+
var sequence;
|
482 |
+
if (utils.contains(stackNeverDelimiters, delim)) {
|
483 |
+
sequence = stackNeverDelimiterSequence;
|
484 |
+
} else if (utils.contains(stackLargeDelimiters, delim)) {
|
485 |
+
sequence = stackLargeDelimiterSequence;
|
486 |
+
} else {
|
487 |
+
sequence = stackAlwaysDelimiterSequence;
|
488 |
+
}
|
489 |
+
|
490 |
+
// Look through the sequence
|
491 |
+
var delimType = traverseSequence(delim, height, sequence, options);
|
492 |
+
|
493 |
+
// Depending on the sequence element we decided on, call the appropriate
|
494 |
+
// function.
|
495 |
+
if (delimType.type === "small") {
|
496 |
+
return makeSmallDelim(delim, delimType.style, center, options, mode);
|
497 |
+
} else if (delimType.type === "large") {
|
498 |
+
return makeLargeDelim(delim, delimType.size, center, options, mode);
|
499 |
+
} else if (delimType.type === "stack") {
|
500 |
+
return makeStackedDelim(delim, height, center, options, mode);
|
501 |
+
}
|
502 |
+
};
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Make a delimiter for use with `\left` and `\right`, given a height and depth
|
506 |
+
* of an expression that the delimiters surround.
|
507 |
+
*/
|
508 |
+
var makeLeftRightDelim = function(delim, height, depth, options, mode) {
|
509 |
+
// We always center \left/\right delimiters, so the axis is always shifted
|
510 |
+
var axisHeight =
|
511 |
+
fontMetrics.metrics.axisHeight * options.style.sizeMultiplier;
|
512 |
+
|
513 |
+
// Taken from TeX source, tex.web, function make_left_right
|
514 |
+
var delimiterFactor = 901;
|
515 |
+
var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
|
516 |
+
|
517 |
+
var maxDistFromAxis = Math.max(
|
518 |
+
height - axisHeight, depth + axisHeight);
|
519 |
+
|
520 |
+
var totalHeight = Math.max(
|
521 |
+
// In real TeX, calculations are done using integral values which are
|
522 |
+
// 65536 per pt, or 655360 per em. So, the division here truncates in
|
523 |
+
// TeX but doesn't here, producing different results. If we wanted to
|
524 |
+
// exactly match TeX's calculation, we could do
|
525 |
+
// Math.floor(655360 * maxDistFromAxis / 500) *
|
526 |
+
// delimiterFactor / 655360
|
527 |
+
// (To see the difference, compare
|
528 |
+
// x^{x^{\left(\rule{0.1em}{0.68em}\right)}}
|
529 |
+
// in TeX and KaTeX)
|
530 |
+
maxDistFromAxis / 500 * delimiterFactor,
|
531 |
+
2 * maxDistFromAxis - delimiterExtend);
|
532 |
+
|
533 |
+
// Finally, we defer to `makeCustomSizedDelim` with our calculated total
|
534 |
+
// height
|
535 |
+
return makeCustomSizedDelim(delim, totalHeight, true, options, mode);
|
536 |
+
};
|
537 |
+
|
538 |
+
module.exports = {
|
539 |
+
sizedDelim: makeSizedDelim,
|
540 |
+
customSizedDelim: makeCustomSizedDelim,
|
541 |
+
leftRightDelim: makeLeftRightDelim,
|
542 |
+
};
|
modules/tokenize_latex/third_party/katex/src/domTree.js
ADDED
@@ -0,0 +1,269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* These objects store the data about the DOM nodes we create, as well as some
|
3 |
+
* extra data. They can then be transformed into real DOM nodes with the
|
4 |
+
* `toNode` function or HTML markup using `toMarkup`. They are useful for both
|
5 |
+
* storing extra properties on the nodes, as well as providing a way to easily
|
6 |
+
* work with the DOM.
|
7 |
+
*
|
8 |
+
* Similar functions for working with MathML nodes exist in mathMLTree.js.
|
9 |
+
*/
|
10 |
+
|
11 |
+
var utils = require("./utils");
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Create an HTML className based on a list of classes. In addition to joining
|
15 |
+
* with spaces, we also remove null or empty classes.
|
16 |
+
*/
|
17 |
+
var createClass = function(classes) {
|
18 |
+
classes = classes.slice();
|
19 |
+
for (var i = classes.length - 1; i >= 0; i--) {
|
20 |
+
if (!classes[i]) {
|
21 |
+
classes.splice(i, 1);
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
return classes.join(" ");
|
26 |
+
};
|
27 |
+
|
28 |
+
/**
|
29 |
+
* This node represents a span node, with a className, a list of children, and
|
30 |
+
* an inline style. It also contains information about its height, depth, and
|
31 |
+
* maxFontSize.
|
32 |
+
*/
|
33 |
+
function span(classes, children, height, depth, maxFontSize, style) {
|
34 |
+
this.classes = classes || [];
|
35 |
+
this.children = children || [];
|
36 |
+
this.height = height || 0;
|
37 |
+
this.depth = depth || 0;
|
38 |
+
this.maxFontSize = maxFontSize || 0;
|
39 |
+
this.style = style || {};
|
40 |
+
this.attributes = {};
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Sets an arbitrary attribute on the span. Warning: use this wisely. Not all
|
45 |
+
* browsers support attributes the same, and having too many custom attributes
|
46 |
+
* is probably bad.
|
47 |
+
*/
|
48 |
+
span.prototype.setAttribute = function(attribute, value) {
|
49 |
+
this.attributes[attribute] = value;
|
50 |
+
};
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Convert the span into an HTML node
|
54 |
+
*/
|
55 |
+
span.prototype.toNode = function() {
|
56 |
+
var span = document.createElement("span");
|
57 |
+
|
58 |
+
// Apply the class
|
59 |
+
span.className = createClass(this.classes);
|
60 |
+
|
61 |
+
// Apply inline styles
|
62 |
+
for (var style in this.style) {
|
63 |
+
if (Object.prototype.hasOwnProperty.call(this.style, style)) {
|
64 |
+
span.style[style] = this.style[style];
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
// Apply attributes
|
69 |
+
for (var attr in this.attributes) {
|
70 |
+
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
71 |
+
span.setAttribute(attr, this.attributes[attr]);
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
// Append the children, also as HTML nodes
|
76 |
+
for (var i = 0; i < this.children.length; i++) {
|
77 |
+
span.appendChild(this.children[i].toNode());
|
78 |
+
}
|
79 |
+
|
80 |
+
return span;
|
81 |
+
};
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Convert the span into an HTML markup string
|
85 |
+
*/
|
86 |
+
span.prototype.toMarkup = function() {
|
87 |
+
var markup = "<span";
|
88 |
+
|
89 |
+
// Add the class
|
90 |
+
if (this.classes.length) {
|
91 |
+
markup += " class=\"";
|
92 |
+
markup += utils.escape(createClass(this.classes));
|
93 |
+
markup += "\"";
|
94 |
+
}
|
95 |
+
|
96 |
+
var styles = "";
|
97 |
+
|
98 |
+
// Add the styles, after hyphenation
|
99 |
+
for (var style in this.style) {
|
100 |
+
if (this.style.hasOwnProperty(style)) {
|
101 |
+
styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
if (styles) {
|
106 |
+
markup += " style=\"" + utils.escape(styles) + "\"";
|
107 |
+
}
|
108 |
+
|
109 |
+
// Add the attributes
|
110 |
+
for (var attr in this.attributes) {
|
111 |
+
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
112 |
+
markup += " " + attr + "=\"";
|
113 |
+
markup += utils.escape(this.attributes[attr]);
|
114 |
+
markup += "\"";
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
markup += ">";
|
119 |
+
|
120 |
+
// Add the markup of the children, also as markup
|
121 |
+
for (var i = 0; i < this.children.length; i++) {
|
122 |
+
markup += this.children[i].toMarkup();
|
123 |
+
}
|
124 |
+
|
125 |
+
markup += "</span>";
|
126 |
+
|
127 |
+
return markup;
|
128 |
+
};
|
129 |
+
|
130 |
+
/**
|
131 |
+
* This node represents a document fragment, which contains elements, but when
|
132 |
+
* placed into the DOM doesn't have any representation itself. Thus, it only
|
133 |
+
* contains children and doesn't have any HTML properties. It also keeps track
|
134 |
+
* of a height, depth, and maxFontSize.
|
135 |
+
*/
|
136 |
+
function documentFragment(children, height, depth, maxFontSize) {
|
137 |
+
this.children = children || [];
|
138 |
+
this.height = height || 0;
|
139 |
+
this.depth = depth || 0;
|
140 |
+
this.maxFontSize = maxFontSize || 0;
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Convert the fragment into a node
|
145 |
+
*/
|
146 |
+
documentFragment.prototype.toNode = function() {
|
147 |
+
// Create a fragment
|
148 |
+
var frag = document.createDocumentFragment();
|
149 |
+
|
150 |
+
// Append the children
|
151 |
+
for (var i = 0; i < this.children.length; i++) {
|
152 |
+
frag.appendChild(this.children[i].toNode());
|
153 |
+
}
|
154 |
+
|
155 |
+
return frag;
|
156 |
+
};
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Convert the fragment into HTML markup
|
160 |
+
*/
|
161 |
+
documentFragment.prototype.toMarkup = function() {
|
162 |
+
var markup = "";
|
163 |
+
|
164 |
+
// Simply concatenate the markup for the children together
|
165 |
+
for (var i = 0; i < this.children.length; i++) {
|
166 |
+
markup += this.children[i].toMarkup();
|
167 |
+
}
|
168 |
+
|
169 |
+
return markup;
|
170 |
+
};
|
171 |
+
|
172 |
+
/**
|
173 |
+
* A symbol node contains information about a single symbol. It either renders
|
174 |
+
* to a single text node, or a span with a single text node in it, depending on
|
175 |
+
* whether it has CSS classes, styles, or needs italic correction.
|
176 |
+
*/
|
177 |
+
function symbolNode(value, height, depth, italic, skew, classes, style) {
|
178 |
+
this.value = value || "";
|
179 |
+
this.height = height || 0;
|
180 |
+
this.depth = depth || 0;
|
181 |
+
this.italic = italic || 0;
|
182 |
+
this.skew = skew || 0;
|
183 |
+
this.classes = classes || [];
|
184 |
+
this.style = style || {};
|
185 |
+
this.maxFontSize = 0;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Creates a text node or span from a symbol node. Note that a span is only
|
190 |
+
* created if it is needed.
|
191 |
+
*/
|
192 |
+
symbolNode.prototype.toNode = function() {
|
193 |
+
var node = document.createTextNode(this.value);
|
194 |
+
var span = null;
|
195 |
+
|
196 |
+
if (this.italic > 0) {
|
197 |
+
span = document.createElement("span");
|
198 |
+
span.style.marginRight = this.italic + "em";
|
199 |
+
}
|
200 |
+
|
201 |
+
if (this.classes.length > 0) {
|
202 |
+
span = span || document.createElement("span");
|
203 |
+
span.className = createClass(this.classes);
|
204 |
+
}
|
205 |
+
|
206 |
+
for (var style in this.style) {
|
207 |
+
if (this.style.hasOwnProperty(style)) {
|
208 |
+
span = span || document.createElement("span");
|
209 |
+
span.style[style] = this.style[style];
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
if (span) {
|
214 |
+
span.appendChild(node);
|
215 |
+
return span;
|
216 |
+
} else {
|
217 |
+
return node;
|
218 |
+
}
|
219 |
+
};
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Creates markup for a symbol node.
|
223 |
+
*/
|
224 |
+
symbolNode.prototype.toMarkup = function() {
|
225 |
+
// TODO(alpert): More duplication than I'd like from
|
226 |
+
// span.prototype.toMarkup and symbolNode.prototype.toNode...
|
227 |
+
var needsSpan = false;
|
228 |
+
|
229 |
+
var markup = "<span";
|
230 |
+
|
231 |
+
if (this.classes.length) {
|
232 |
+
needsSpan = true;
|
233 |
+
markup += " class=\"";
|
234 |
+
markup += utils.escape(createClass(this.classes));
|
235 |
+
markup += "\"";
|
236 |
+
}
|
237 |
+
|
238 |
+
var styles = "";
|
239 |
+
|
240 |
+
if (this.italic > 0) {
|
241 |
+
styles += "margin-right:" + this.italic + "em;";
|
242 |
+
}
|
243 |
+
for (var style in this.style) {
|
244 |
+
if (this.style.hasOwnProperty(style)) {
|
245 |
+
styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
if (styles) {
|
250 |
+
needsSpan = true;
|
251 |
+
markup += " style=\"" + utils.escape(styles) + "\"";
|
252 |
+
}
|
253 |
+
|
254 |
+
var escaped = utils.escape(this.value);
|
255 |
+
if (needsSpan) {
|
256 |
+
markup += ">";
|
257 |
+
markup += escaped;
|
258 |
+
markup += "</span>";
|
259 |
+
return markup;
|
260 |
+
} else {
|
261 |
+
return escaped;
|
262 |
+
}
|
263 |
+
};
|
264 |
+
|
265 |
+
module.exports = {
|
266 |
+
span: span,
|
267 |
+
documentFragment: documentFragment,
|
268 |
+
symbolNode: symbolNode,
|
269 |
+
};
|
modules/tokenize_latex/third_party/katex/src/environments.js
ADDED
@@ -0,0 +1,295 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-constant-condition:0 */
|
2 |
+
var fontMetrics = require("./fontMetrics");
|
3 |
+
var parseData = require("./parseData");
|
4 |
+
var ParseError = require("./ParseError");
|
5 |
+
|
6 |
+
var ParseNode = parseData.ParseNode;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Parse the body of the environment, with rows delimited by \\ and
|
10 |
+
* columns delimited by &, and create a nested list in row-major order
|
11 |
+
* with one group per cell.
|
12 |
+
*/
|
13 |
+
var q = 0 ;
|
14 |
+
function parseArray(parser, result) {
|
15 |
+
var row = [];
|
16 |
+
var body = [row];
|
17 |
+
var rowGaps = [];
|
18 |
+
|
19 |
+
while (true) {
|
20 |
+
|
21 |
+
// if (q == 1) console.error(parser.nextToken.text);
|
22 |
+
try {
|
23 |
+
var cell = parser.parseExpression(false, null);
|
24 |
+
} catch (e) {
|
25 |
+
// console.error(e);
|
26 |
+
exit();
|
27 |
+
}
|
28 |
+
// if (q == 1) exit();
|
29 |
+
row.push(new ParseNode("ordgroup", cell, parser.mode));
|
30 |
+
var next = parser.nextToken.text;
|
31 |
+
if (next === "&") {
|
32 |
+
parser.consume();
|
33 |
+
} else if (next === "\\end" || next == "}") {
|
34 |
+
break;
|
35 |
+
} else if (next === "\\\\" || next === "\\cr") {
|
36 |
+
|
37 |
+
var cr = parser.parseFunction();
|
38 |
+
|
39 |
+
rowGaps.push(cr.value.size);
|
40 |
+
row = [];
|
41 |
+
body.push(row);
|
42 |
+
} else {
|
43 |
+
// TODO: Clean up the following hack once #385 got merged
|
44 |
+
var pos = Math.min(parser.pos + 1, parser.lexer._input.length);
|
45 |
+
throw new ParseError("Expected & or \\\\ or \\end",
|
46 |
+
parser.lexer, pos);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
result.body = body;
|
50 |
+
result.rowGaps = rowGaps;
|
51 |
+
// if (q == 1) exit();
|
52 |
+
var node = new ParseNode(result.type, result, parser.mode);
|
53 |
+
return node;
|
54 |
+
}
|
55 |
+
|
56 |
+
/*
|
57 |
+
* An environment definition is very similar to a function definition:
|
58 |
+
* it is declared with a name or a list of names, a set of properties
|
59 |
+
* and a handler containing the actual implementation.
|
60 |
+
*
|
61 |
+
* The properties include:
|
62 |
+
* - numArgs: The number of arguments after the \begin{name} function.
|
63 |
+
* - argTypes: (optional) Just like for a function
|
64 |
+
* - allowedInText: (optional) Whether or not the environment is allowed inside
|
65 |
+
* text mode (default false) (not enforced yet)
|
66 |
+
* - numOptionalArgs: (optional) Just like for a function
|
67 |
+
* A bare number instead of that object indicates the numArgs value.
|
68 |
+
*
|
69 |
+
* The handler function will receive two arguments
|
70 |
+
* - context: information and references provided by the parser
|
71 |
+
* - args: an array of arguments passed to \begin{name}
|
72 |
+
* The context contains the following properties:
|
73 |
+
* - envName: the name of the environment, one of the listed names.
|
74 |
+
* - parser: the parser object
|
75 |
+
* - lexer: the lexer object
|
76 |
+
* - positions: the positions associated with these arguments from args.
|
77 |
+
* The handler must return a ParseResult.
|
78 |
+
*/
|
79 |
+
|
80 |
+
function defineEnvironment(names, props, handler) {
|
81 |
+
if (typeof names === "string") {
|
82 |
+
names = [names];
|
83 |
+
}
|
84 |
+
if (typeof props === "number") {
|
85 |
+
props = { numArgs: props };
|
86 |
+
}
|
87 |
+
// Set default values of environments
|
88 |
+
var data = {
|
89 |
+
numArgs: props.numArgs || 0,
|
90 |
+
argTypes: props.argTypes,
|
91 |
+
greediness: 1,
|
92 |
+
allowedInText: !!props.allowedInText,
|
93 |
+
numOptionalArgs: props.numOptionalArgs || 0,
|
94 |
+
handler: handler,
|
95 |
+
};
|
96 |
+
for (var i = 0; i < names.length; ++i) {
|
97 |
+
module.exports[names[i]] = data;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
// Arrays are part of LaTeX, defined in lttab.dtx so its documentation
|
102 |
+
// is part of the source2e.pdf file of LaTeX2e source documentation.
|
103 |
+
defineEnvironment("array", {
|
104 |
+
numArgs: 1,
|
105 |
+
}, function(context, args) {
|
106 |
+
var colalign = args[0];
|
107 |
+
colalign = colalign.value.map ? colalign.value : [colalign];
|
108 |
+
var cols = colalign.map(function(node) {
|
109 |
+
var ca = node.value;
|
110 |
+
if ("lcr".indexOf(ca) !== -1) {
|
111 |
+
return {
|
112 |
+
type: "align",
|
113 |
+
align: ca,
|
114 |
+
};
|
115 |
+
} else if (ca === "|") {
|
116 |
+
return {
|
117 |
+
type: "separator",
|
118 |
+
separator: "|",
|
119 |
+
};
|
120 |
+
}
|
121 |
+
// throw new ParseError(
|
122 |
+
// "Unknown column alignment: " + node.value,
|
123 |
+
// context.lexer, context.positions[1]);
|
124 |
+
});
|
125 |
+
var res = {
|
126 |
+
type: "array",
|
127 |
+
cols: cols,
|
128 |
+
hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
|
129 |
+
};
|
130 |
+
res = parseArray(context.parser, res);
|
131 |
+
return res;
|
132 |
+
});
|
133 |
+
|
134 |
+
defineEnvironment("tabular", {
|
135 |
+
numArgs: 1,
|
136 |
+
}, function(context, args) {
|
137 |
+
var colalign = args[0];
|
138 |
+
colalign = colalign.value.map ? colalign.value : [colalign];
|
139 |
+
var cols = colalign.map(function(node) {
|
140 |
+
var ca = node.value;
|
141 |
+
if ("lcr".indexOf(ca) !== -1) {
|
142 |
+
return {
|
143 |
+
type: "align",
|
144 |
+
align: ca,
|
145 |
+
};
|
146 |
+
} else if (ca === "|") {
|
147 |
+
return {
|
148 |
+
type: "separator",
|
149 |
+
separator: "|",
|
150 |
+
};
|
151 |
+
}
|
152 |
+
// throw new ParseError(
|
153 |
+
// "Unknown column alignment: " + node.value,
|
154 |
+
// context.lexer, context.positions[1]);
|
155 |
+
});
|
156 |
+
var res = {
|
157 |
+
type: "array",
|
158 |
+
style: "tabular",
|
159 |
+
cols: cols,
|
160 |
+
hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
|
161 |
+
};
|
162 |
+
res = parseArray(context.parser, res);
|
163 |
+
return res;
|
164 |
+
});
|
165 |
+
|
166 |
+
// The matrix environments of amsmath builds on the array environment
|
167 |
+
// of LaTeX, which is discussed above.
|
168 |
+
defineEnvironment([
|
169 |
+
"matrix",
|
170 |
+
"pmatrix",
|
171 |
+
"bmatrix",
|
172 |
+
"Bmatrix",
|
173 |
+
"vmatrix",
|
174 |
+
"Vmatrix",
|
175 |
+
], {
|
176 |
+
}, function(context) {
|
177 |
+
var delimiters = {
|
178 |
+
"matrix": null,
|
179 |
+
"pmatrix": ["(", ")"],
|
180 |
+
"bmatrix": ["[", "]"],
|
181 |
+
"Bmatrix": ["\\{", "\\}"],
|
182 |
+
"vmatrix": ["|", "|"],
|
183 |
+
"Vmatrix": ["\\Vert", "\\Vert"],
|
184 |
+
}[context.envName];
|
185 |
+
var res = {
|
186 |
+
type: "array",
|
187 |
+
hskipBeforeAndAfter: false, // \hskip -\arraycolsep in amsmath
|
188 |
+
};
|
189 |
+
q = 1;
|
190 |
+
res = parseArray(context.parser, res);
|
191 |
+
|
192 |
+
if (delimiters) {
|
193 |
+
res = new ParseNode("leftright", {
|
194 |
+
body: [res],
|
195 |
+
left: delimiters[0],
|
196 |
+
right: delimiters[1],
|
197 |
+
}, context.mode);
|
198 |
+
}
|
199 |
+
return res;
|
200 |
+
});
|
201 |
+
|
202 |
+
// A cases environment (in amsmath.sty) is almost equivalent to
|
203 |
+
// \def\arraystretch{1.2}%
|
204 |
+
// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
|
205 |
+
defineEnvironment("picture", {
|
206 |
+
}, function(context) {
|
207 |
+
var res = {
|
208 |
+
type: "array",
|
209 |
+
arraystretch: 1.2,
|
210 |
+
cols: [{
|
211 |
+
type: "align",
|
212 |
+
align: "l",
|
213 |
+
pregap: 0,
|
214 |
+
postgap: fontMetrics.metrics.quad,
|
215 |
+
}, {
|
216 |
+
type: "align",
|
217 |
+
align: "l",
|
218 |
+
pregap: 0,
|
219 |
+
postgap: 0,
|
220 |
+
}],
|
221 |
+
};
|
222 |
+
res = parseArray(context.parser, res);
|
223 |
+
res = new ParseNode("leftright", {
|
224 |
+
body: [res],
|
225 |
+
left: "\\{",
|
226 |
+
right: ".",
|
227 |
+
}, context.mode);
|
228 |
+
return res;
|
229 |
+
});
|
230 |
+
|
231 |
+
defineEnvironment("cases", {
|
232 |
+
}, function(context) {
|
233 |
+
var res = {
|
234 |
+
type: "array",
|
235 |
+
arraystretch: 1.2,
|
236 |
+
cols: [{
|
237 |
+
type: "align",
|
238 |
+
align: "l",
|
239 |
+
pregap: 0,
|
240 |
+
postgap: fontMetrics.metrics.quad,
|
241 |
+
}, {
|
242 |
+
type: "align",
|
243 |
+
align: "l",
|
244 |
+
pregap: 0,
|
245 |
+
postgap: 0,
|
246 |
+
}],
|
247 |
+
};
|
248 |
+
res = parseArray(context.parser, res);
|
249 |
+
res = new ParseNode("leftright", {
|
250 |
+
body: [res],
|
251 |
+
left: "\\{",
|
252 |
+
right: ".",
|
253 |
+
}, context.mode);
|
254 |
+
return res;
|
255 |
+
});
|
256 |
+
|
257 |
+
// An aligned environment is like the align* environment
|
258 |
+
// except it operates within math mode.
|
259 |
+
// Note that we assume \nomallineskiplimit to be zero,
|
260 |
+
// so that \strut@ is the same as \strut.
|
261 |
+
defineEnvironment("aligned", {
|
262 |
+
}, function(context) {
|
263 |
+
var res = {
|
264 |
+
type: "array",
|
265 |
+
cols: [],
|
266 |
+
};
|
267 |
+
res = parseArray(context.parser, res);
|
268 |
+
var emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
269 |
+
var numCols = 0;
|
270 |
+
res.value.body.forEach(function(row) {
|
271 |
+
var i;
|
272 |
+
for (i = 1; i < row.length; i += 2) {
|
273 |
+
row[i].value.unshift(emptyGroup);
|
274 |
+
}
|
275 |
+
if (numCols < row.length) {
|
276 |
+
numCols = row.length;
|
277 |
+
}
|
278 |
+
});
|
279 |
+
for (var i = 0; i < numCols; ++i) {
|
280 |
+
var align = "r";
|
281 |
+
var pregap = 0;
|
282 |
+
if (i % 2 === 1) {
|
283 |
+
align = "l";
|
284 |
+
} else if (i > 0) {
|
285 |
+
pregap = 2; // one \qquad between columns
|
286 |
+
}
|
287 |
+
res.value.cols[i] = {
|
288 |
+
type: "align",
|
289 |
+
align: align,
|
290 |
+
pregap: pregap,
|
291 |
+
postgap: 0,
|
292 |
+
};
|
293 |
+
}
|
294 |
+
return res;
|
295 |
+
});
|
modules/tokenize_latex/third_party/katex/src/fontMetrics.js
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint no-unused-vars:0 */
|
2 |
+
|
3 |
+
var Style = require("./Style");
|
4 |
+
|
5 |
+
/**
|
6 |
+
* This file contains metrics regarding fonts and individual symbols. The sigma
|
7 |
+
* and xi variables, as well as the metricMap map contain data extracted from
|
8 |
+
* TeX, TeX font metrics, and the TTF files. These data are then exposed via the
|
9 |
+
* `metrics` variable and the getCharacterMetrics function.
|
10 |
+
*/
|
11 |
+
|
12 |
+
// These font metrics are extracted from TeX by using
|
13 |
+
// \font\a=cmmi10
|
14 |
+
// \showthe\fontdimenX\a
|
15 |
+
// where X is the corresponding variable number. These correspond to the font
|
16 |
+
// parameters of the symbol fonts. In TeX, there are actually three sets of
|
17 |
+
// dimensions, one for each of textstyle, scriptstyle, and scriptscriptstyle,
|
18 |
+
// but we only use the textstyle ones, and scale certain dimensions accordingly.
|
19 |
+
// See the TeXbook, page 441.
|
20 |
+
var sigma1 = 0.025;
|
21 |
+
var sigma2 = 0;
|
22 |
+
var sigma3 = 0;
|
23 |
+
var sigma4 = 0;
|
24 |
+
var sigma5 = 0.431;
|
25 |
+
var sigma6 = 1;
|
26 |
+
var sigma7 = 0;
|
27 |
+
var sigma8 = 0.677;
|
28 |
+
var sigma9 = 0.394;
|
29 |
+
var sigma10 = 0.444;
|
30 |
+
var sigma11 = 0.686;
|
31 |
+
var sigma12 = 0.345;
|
32 |
+
var sigma13 = 0.413;
|
33 |
+
var sigma14 = 0.363;
|
34 |
+
var sigma15 = 0.289;
|
35 |
+
var sigma16 = 0.150;
|
36 |
+
var sigma17 = 0.247;
|
37 |
+
var sigma18 = 0.386;
|
38 |
+
var sigma19 = 0.050;
|
39 |
+
var sigma20 = 2.390;
|
40 |
+
var sigma21 = 1.01;
|
41 |
+
var sigma21Script = 0.81;
|
42 |
+
var sigma21ScriptScript = 0.71;
|
43 |
+
var sigma22 = 0.250;
|
44 |
+
|
45 |
+
// These font metrics are extracted from TeX by using
|
46 |
+
// \font\a=cmex10
|
47 |
+
// \showthe\fontdimenX\a
|
48 |
+
// where X is the corresponding variable number. These correspond to the font
|
49 |
+
// parameters of the extension fonts (family 3). See the TeXbook, page 441.
|
50 |
+
var xi1 = 0;
|
51 |
+
var xi2 = 0;
|
52 |
+
var xi3 = 0;
|
53 |
+
var xi4 = 0;
|
54 |
+
var xi5 = 0.431;
|
55 |
+
var xi6 = 1;
|
56 |
+
var xi7 = 0;
|
57 |
+
var xi8 = 0.04;
|
58 |
+
var xi9 = 0.111;
|
59 |
+
var xi10 = 0.166;
|
60 |
+
var xi11 = 0.2;
|
61 |
+
var xi12 = 0.6;
|
62 |
+
var xi13 = 0.1;
|
63 |
+
|
64 |
+
// This value determines how large a pt is, for metrics which are defined in
|
65 |
+
// terms of pts.
|
66 |
+
// This value is also used in katex.less; if you change it make sure the values
|
67 |
+
// match.
|
68 |
+
var ptPerEm = 10.0;
|
69 |
+
|
70 |
+
// The space between adjacent `|` columns in an array definition. From
|
71 |
+
// `\showthe\doublerulesep` in LaTeX.
|
72 |
+
var doubleRuleSep = 2.0 / ptPerEm;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* This is just a mapping from common names to real metrics
|
76 |
+
*/
|
77 |
+
var metrics = {
|
78 |
+
xHeight: sigma5,
|
79 |
+
quad: sigma6,
|
80 |
+
num1: sigma8,
|
81 |
+
num2: sigma9,
|
82 |
+
num3: sigma10,
|
83 |
+
denom1: sigma11,
|
84 |
+
denom2: sigma12,
|
85 |
+
sup1: sigma13,
|
86 |
+
sup2: sigma14,
|
87 |
+
sup3: sigma15,
|
88 |
+
sub1: sigma16,
|
89 |
+
sub2: sigma17,
|
90 |
+
supDrop: sigma18,
|
91 |
+
subDrop: sigma19,
|
92 |
+
axisHeight: sigma22,
|
93 |
+
defaultRuleThickness: xi8,
|
94 |
+
bigOpSpacing1: xi9,
|
95 |
+
bigOpSpacing2: xi10,
|
96 |
+
bigOpSpacing3: xi11,
|
97 |
+
bigOpSpacing4: xi12,
|
98 |
+
bigOpSpacing5: xi13,
|
99 |
+
ptPerEm: ptPerEm,
|
100 |
+
emPerEx: sigma5 / sigma6,
|
101 |
+
doubleRuleSep: doubleRuleSep,
|
102 |
+
|
103 |
+
// TODO(alpert): Missing parallel structure here. We should probably add
|
104 |
+
// style-specific metrics for all of these.
|
105 |
+
delim1: sigma20,
|
106 |
+
getDelim2: function(style) {
|
107 |
+
if (style.size === Style.TEXT.size) {
|
108 |
+
return sigma21;
|
109 |
+
} else if (style.size === Style.SCRIPT.size) {
|
110 |
+
return sigma21Script;
|
111 |
+
} else if (style.size === Style.SCRIPTSCRIPT.size) {
|
112 |
+
return sigma21ScriptScript;
|
113 |
+
}
|
114 |
+
throw new Error("Unexpected style size: " + style.size);
|
115 |
+
},
|
116 |
+
};
|
117 |
+
|
118 |
+
// This map contains a mapping from font name and character code to character
|
119 |
+
// metrics, including height, depth, italic correction, and skew (kern from the
|
120 |
+
// character to the corresponding \skewchar)
|
121 |
+
// This map is generated via `make metrics`. It should not be changed manually.
|
122 |
+
var metricMap = require("./fontMetricsData");
|
123 |
+
|
124 |
+
/**
|
125 |
+
* This function is a convenience function for looking up information in the
|
126 |
+
* metricMap table. It takes a character as a string, and a style.
|
127 |
+
*
|
128 |
+
* Note: the `width` property may be undefined if fontMetricsData.js wasn't
|
129 |
+
* built using `Make extended_metrics`.
|
130 |
+
*/
|
131 |
+
var getCharacterMetrics = function(character, style) {
|
132 |
+
var metrics = metricMap[style][character.charCodeAt(0)];
|
133 |
+
if (metrics) {
|
134 |
+
return {
|
135 |
+
depth: metrics[0],
|
136 |
+
height: metrics[1],
|
137 |
+
italic: metrics[2],
|
138 |
+
skew: metrics[3],
|
139 |
+
width: metrics[4],
|
140 |
+
};
|
141 |
+
}
|
142 |
+
};
|
143 |
+
|
144 |
+
module.exports = {
|
145 |
+
metrics: metrics,
|
146 |
+
getCharacterMetrics: getCharacterMetrics,
|
147 |
+
};
|
modules/tokenize_latex/third_party/katex/src/fontMetricsData.js
ADDED
@@ -0,0 +1,1752 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
"AMS-Regular": {
|
3 |
+
"65": [0, 0.68889, 0, 0],
|
4 |
+
"66": [0, 0.68889, 0, 0],
|
5 |
+
"67": [0, 0.68889, 0, 0],
|
6 |
+
"68": [0, 0.68889, 0, 0],
|
7 |
+
"69": [0, 0.68889, 0, 0],
|
8 |
+
"70": [0, 0.68889, 0, 0],
|
9 |
+
"71": [0, 0.68889, 0, 0],
|
10 |
+
"72": [0, 0.68889, 0, 0],
|
11 |
+
"73": [0, 0.68889, 0, 0],
|
12 |
+
"74": [0.16667, 0.68889, 0, 0],
|
13 |
+
"75": [0, 0.68889, 0, 0],
|
14 |
+
"76": [0, 0.68889, 0, 0],
|
15 |
+
"77": [0, 0.68889, 0, 0],
|
16 |
+
"78": [0, 0.68889, 0, 0],
|
17 |
+
"79": [0.16667, 0.68889, 0, 0],
|
18 |
+
"80": [0, 0.68889, 0, 0],
|
19 |
+
"81": [0.16667, 0.68889, 0, 0],
|
20 |
+
"82": [0, 0.68889, 0, 0],
|
21 |
+
"83": [0, 0.68889, 0, 0],
|
22 |
+
"84": [0, 0.68889, 0, 0],
|
23 |
+
"85": [0, 0.68889, 0, 0],
|
24 |
+
"86": [0, 0.68889, 0, 0],
|
25 |
+
"87": [0, 0.68889, 0, 0],
|
26 |
+
"88": [0, 0.68889, 0, 0],
|
27 |
+
"89": [0, 0.68889, 0, 0],
|
28 |
+
"90": [0, 0.68889, 0, 0],
|
29 |
+
"107": [0, 0.68889, 0, 0],
|
30 |
+
"165": [0, 0.675, 0.025, 0],
|
31 |
+
"174": [0.15559, 0.69224, 0, 0],
|
32 |
+
"240": [0, 0.68889, 0, 0],
|
33 |
+
"295": [0, 0.68889, 0, 0],
|
34 |
+
"710": [0, 0.825, 0, 0],
|
35 |
+
"732": [0, 0.9, 0, 0],
|
36 |
+
"770": [0, 0.825, 0, 0],
|
37 |
+
"771": [0, 0.9, 0, 0],
|
38 |
+
"989": [0.08167, 0.58167, 0, 0],
|
39 |
+
"1008": [0, 0.43056, 0.04028, 0],
|
40 |
+
"8245": [0, 0.54986, 0, 0],
|
41 |
+
"8463": [0, 0.68889, 0, 0],
|
42 |
+
"8487": [0, 0.68889, 0, 0],
|
43 |
+
"8498": [0, 0.68889, 0, 0],
|
44 |
+
"8502": [0, 0.68889, 0, 0],
|
45 |
+
"8503": [0, 0.68889, 0, 0],
|
46 |
+
"8504": [0, 0.68889, 0, 0],
|
47 |
+
"8513": [0, 0.68889, 0, 0],
|
48 |
+
"8592": [-0.03598, 0.46402, 0, 0],
|
49 |
+
"8594": [-0.03598, 0.46402, 0, 0],
|
50 |
+
"8602": [-0.13313, 0.36687, 0, 0],
|
51 |
+
"8603": [-0.13313, 0.36687, 0, 0],
|
52 |
+
"8606": [0.01354, 0.52239, 0, 0],
|
53 |
+
"8608": [0.01354, 0.52239, 0, 0],
|
54 |
+
"8610": [0.01354, 0.52239, 0, 0],
|
55 |
+
"8611": [0.01354, 0.52239, 0, 0],
|
56 |
+
"8619": [0, 0.54986, 0, 0],
|
57 |
+
"8620": [0, 0.54986, 0, 0],
|
58 |
+
"8621": [-0.13313, 0.37788, 0, 0],
|
59 |
+
"8622": [-0.13313, 0.36687, 0, 0],
|
60 |
+
"8624": [0, 0.69224, 0, 0],
|
61 |
+
"8625": [0, 0.69224, 0, 0],
|
62 |
+
"8630": [0, 0.43056, 0, 0],
|
63 |
+
"8631": [0, 0.43056, 0, 0],
|
64 |
+
"8634": [0.08198, 0.58198, 0, 0],
|
65 |
+
"8635": [0.08198, 0.58198, 0, 0],
|
66 |
+
"8638": [0.19444, 0.69224, 0, 0],
|
67 |
+
"8639": [0.19444, 0.69224, 0, 0],
|
68 |
+
"8642": [0.19444, 0.69224, 0, 0],
|
69 |
+
"8643": [0.19444, 0.69224, 0, 0],
|
70 |
+
"8644": [0.1808, 0.675, 0, 0],
|
71 |
+
"8646": [0.1808, 0.675, 0, 0],
|
72 |
+
"8647": [0.1808, 0.675, 0, 0],
|
73 |
+
"8648": [0.19444, 0.69224, 0, 0],
|
74 |
+
"8649": [0.1808, 0.675, 0, 0],
|
75 |
+
"8650": [0.19444, 0.69224, 0, 0],
|
76 |
+
"8651": [0.01354, 0.52239, 0, 0],
|
77 |
+
"8652": [0.01354, 0.52239, 0, 0],
|
78 |
+
"8653": [-0.13313, 0.36687, 0, 0],
|
79 |
+
"8654": [-0.13313, 0.36687, 0, 0],
|
80 |
+
"8655": [-0.13313, 0.36687, 0, 0],
|
81 |
+
"8666": [0.13667, 0.63667, 0, 0],
|
82 |
+
"8667": [0.13667, 0.63667, 0, 0],
|
83 |
+
"8669": [-0.13313, 0.37788, 0, 0],
|
84 |
+
"8672": [-0.064, 0.437, 0, 0],
|
85 |
+
"8674": [-0.064, 0.437, 0, 0],
|
86 |
+
"8705": [0, 0.825, 0, 0],
|
87 |
+
"8708": [0, 0.68889, 0, 0],
|
88 |
+
"8709": [0.08167, 0.58167, 0, 0],
|
89 |
+
"8717": [0, 0.43056, 0, 0],
|
90 |
+
"8722": [-0.03598, 0.46402, 0, 0],
|
91 |
+
"8724": [0.08198, 0.69224, 0, 0],
|
92 |
+
"8726": [0.08167, 0.58167, 0, 0],
|
93 |
+
"8733": [0, 0.69224, 0, 0],
|
94 |
+
"8736": [0, 0.69224, 0, 0],
|
95 |
+
"8737": [0, 0.69224, 0, 0],
|
96 |
+
"8738": [0.03517, 0.52239, 0, 0],
|
97 |
+
"8739": [0.08167, 0.58167, 0, 0],
|
98 |
+
"8740": [0.25142, 0.74111, 0, 0],
|
99 |
+
"8741": [0.08167, 0.58167, 0, 0],
|
100 |
+
"8742": [0.25142, 0.74111, 0, 0],
|
101 |
+
"8756": [0, 0.69224, 0, 0],
|
102 |
+
"8757": [0, 0.69224, 0, 0],
|
103 |
+
"8764": [-0.13313, 0.36687, 0, 0],
|
104 |
+
"8765": [-0.13313, 0.37788, 0, 0],
|
105 |
+
"8769": [-0.13313, 0.36687, 0, 0],
|
106 |
+
"8770": [-0.03625, 0.46375, 0, 0],
|
107 |
+
"8774": [0.30274, 0.79383, 0, 0],
|
108 |
+
"8776": [-0.01688, 0.48312, 0, 0],
|
109 |
+
"8778": [0.08167, 0.58167, 0, 0],
|
110 |
+
"8782": [0.06062, 0.54986, 0, 0],
|
111 |
+
"8783": [0.06062, 0.54986, 0, 0],
|
112 |
+
"8785": [0.08198, 0.58198, 0, 0],
|
113 |
+
"8786": [0.08198, 0.58198, 0, 0],
|
114 |
+
"8787": [0.08198, 0.58198, 0, 0],
|
115 |
+
"8790": [0, 0.69224, 0, 0],
|
116 |
+
"8791": [0.22958, 0.72958, 0, 0],
|
117 |
+
"8796": [0.08198, 0.91667, 0, 0],
|
118 |
+
"8806": [0.25583, 0.75583, 0, 0],
|
119 |
+
"8807": [0.25583, 0.75583, 0, 0],
|
120 |
+
"8808": [0.25142, 0.75726, 0, 0],
|
121 |
+
"8809": [0.25142, 0.75726, 0, 0],
|
122 |
+
"8812": [0.25583, 0.75583, 0, 0],
|
123 |
+
"8814": [0.20576, 0.70576, 0, 0],
|
124 |
+
"8815": [0.20576, 0.70576, 0, 0],
|
125 |
+
"8816": [0.30274, 0.79383, 0, 0],
|
126 |
+
"8817": [0.30274, 0.79383, 0, 0],
|
127 |
+
"8818": [0.22958, 0.72958, 0, 0],
|
128 |
+
"8819": [0.22958, 0.72958, 0, 0],
|
129 |
+
"8822": [0.1808, 0.675, 0, 0],
|
130 |
+
"8823": [0.1808, 0.675, 0, 0],
|
131 |
+
"8828": [0.13667, 0.63667, 0, 0],
|
132 |
+
"8829": [0.13667, 0.63667, 0, 0],
|
133 |
+
"8830": [0.22958, 0.72958, 0, 0],
|
134 |
+
"8831": [0.22958, 0.72958, 0, 0],
|
135 |
+
"8832": [0.20576, 0.70576, 0, 0],
|
136 |
+
"8833": [0.20576, 0.70576, 0, 0],
|
137 |
+
"8840": [0.30274, 0.79383, 0, 0],
|
138 |
+
"8841": [0.30274, 0.79383, 0, 0],
|
139 |
+
"8842": [0.13597, 0.63597, 0, 0],
|
140 |
+
"8843": [0.13597, 0.63597, 0, 0],
|
141 |
+
"8847": [0.03517, 0.54986, 0, 0],
|
142 |
+
"8848": [0.03517, 0.54986, 0, 0],
|
143 |
+
"8858": [0.08198, 0.58198, 0, 0],
|
144 |
+
"8859": [0.08198, 0.58198, 0, 0],
|
145 |
+
"8861": [0.08198, 0.58198, 0, 0],
|
146 |
+
"8862": [0, 0.675, 0, 0],
|
147 |
+
"8863": [0, 0.675, 0, 0],
|
148 |
+
"8864": [0, 0.675, 0, 0],
|
149 |
+
"8865": [0, 0.675, 0, 0],
|
150 |
+
"8872": [0, 0.69224, 0, 0],
|
151 |
+
"8873": [0, 0.69224, 0, 0],
|
152 |
+
"8874": [0, 0.69224, 0, 0],
|
153 |
+
"8876": [0, 0.68889, 0, 0],
|
154 |
+
"8877": [0, 0.68889, 0, 0],
|
155 |
+
"8878": [0, 0.68889, 0, 0],
|
156 |
+
"8879": [0, 0.68889, 0, 0],
|
157 |
+
"8882": [0.03517, 0.54986, 0, 0],
|
158 |
+
"8883": [0.03517, 0.54986, 0, 0],
|
159 |
+
"8884": [0.13667, 0.63667, 0, 0],
|
160 |
+
"8885": [0.13667, 0.63667, 0, 0],
|
161 |
+
"8888": [0, 0.54986, 0, 0],
|
162 |
+
"8890": [0.19444, 0.43056, 0, 0],
|
163 |
+
"8891": [0.19444, 0.69224, 0, 0],
|
164 |
+
"8892": [0.19444, 0.69224, 0, 0],
|
165 |
+
"8901": [0, 0.54986, 0, 0],
|
166 |
+
"8903": [0.08167, 0.58167, 0, 0],
|
167 |
+
"8905": [0.08167, 0.58167, 0, 0],
|
168 |
+
"8906": [0.08167, 0.58167, 0, 0],
|
169 |
+
"8907": [0, 0.69224, 0, 0],
|
170 |
+
"8908": [0, 0.69224, 0, 0],
|
171 |
+
"8909": [-0.03598, 0.46402, 0, 0],
|
172 |
+
"8910": [0, 0.54986, 0, 0],
|
173 |
+
"8911": [0, 0.54986, 0, 0],
|
174 |
+
"8912": [0.03517, 0.54986, 0, 0],
|
175 |
+
"8913": [0.03517, 0.54986, 0, 0],
|
176 |
+
"8914": [0, 0.54986, 0, 0],
|
177 |
+
"8915": [0, 0.54986, 0, 0],
|
178 |
+
"8916": [0, 0.69224, 0, 0],
|
179 |
+
"8918": [0.0391, 0.5391, 0, 0],
|
180 |
+
"8919": [0.0391, 0.5391, 0, 0],
|
181 |
+
"8920": [0.03517, 0.54986, 0, 0],
|
182 |
+
"8921": [0.03517, 0.54986, 0, 0],
|
183 |
+
"8922": [0.38569, 0.88569, 0, 0],
|
184 |
+
"8923": [0.38569, 0.88569, 0, 0],
|
185 |
+
"8926": [0.13667, 0.63667, 0, 0],
|
186 |
+
"8927": [0.13667, 0.63667, 0, 0],
|
187 |
+
"8928": [0.30274, 0.79383, 0, 0],
|
188 |
+
"8929": [0.30274, 0.79383, 0, 0],
|
189 |
+
"8934": [0.23222, 0.74111, 0, 0],
|
190 |
+
"8935": [0.23222, 0.74111, 0, 0],
|
191 |
+
"8936": [0.23222, 0.74111, 0, 0],
|
192 |
+
"8937": [0.23222, 0.74111, 0, 0],
|
193 |
+
"8938": [0.20576, 0.70576, 0, 0],
|
194 |
+
"8939": [0.20576, 0.70576, 0, 0],
|
195 |
+
"8940": [0.30274, 0.79383, 0, 0],
|
196 |
+
"8941": [0.30274, 0.79383, 0, 0],
|
197 |
+
"8994": [0.19444, 0.69224, 0, 0],
|
198 |
+
"8995": [0.19444, 0.69224, 0, 0],
|
199 |
+
"9416": [0.15559, 0.69224, 0, 0],
|
200 |
+
"9484": [0, 0.69224, 0, 0],
|
201 |
+
"9488": [0, 0.69224, 0, 0],
|
202 |
+
"9492": [0, 0.37788, 0, 0],
|
203 |
+
"9496": [0, 0.37788, 0, 0],
|
204 |
+
"9585": [0.19444, 0.68889, 0, 0],
|
205 |
+
"9586": [0.19444, 0.74111, 0, 0],
|
206 |
+
"9632": [0, 0.675, 0, 0],
|
207 |
+
"9633": [0, 0.675, 0, 0],
|
208 |
+
"9650": [0, 0.54986, 0, 0],
|
209 |
+
"9651": [0, 0.54986, 0, 0],
|
210 |
+
"9654": [0.03517, 0.54986, 0, 0],
|
211 |
+
"9660": [0, 0.54986, 0, 0],
|
212 |
+
"9661": [0, 0.54986, 0, 0],
|
213 |
+
"9664": [0.03517, 0.54986, 0, 0],
|
214 |
+
"9674": [0.11111, 0.69224, 0, 0],
|
215 |
+
"9733": [0.19444, 0.69224, 0, 0],
|
216 |
+
"10003": [0, 0.69224, 0, 0],
|
217 |
+
"10016": [0, 0.69224, 0, 0],
|
218 |
+
"10731": [0.11111, 0.69224, 0, 0],
|
219 |
+
"10846": [0.19444, 0.75583, 0, 0],
|
220 |
+
"10877": [0.13667, 0.63667, 0, 0],
|
221 |
+
"10878": [0.13667, 0.63667, 0, 0],
|
222 |
+
"10885": [0.25583, 0.75583, 0, 0],
|
223 |
+
"10886": [0.25583, 0.75583, 0, 0],
|
224 |
+
"10887": [0.13597, 0.63597, 0, 0],
|
225 |
+
"10888": [0.13597, 0.63597, 0, 0],
|
226 |
+
"10889": [0.26167, 0.75726, 0, 0],
|
227 |
+
"10890": [0.26167, 0.75726, 0, 0],
|
228 |
+
"10891": [0.48256, 0.98256, 0, 0],
|
229 |
+
"10892": [0.48256, 0.98256, 0, 0],
|
230 |
+
"10901": [0.13667, 0.63667, 0, 0],
|
231 |
+
"10902": [0.13667, 0.63667, 0, 0],
|
232 |
+
"10933": [0.25142, 0.75726, 0, 0],
|
233 |
+
"10934": [0.25142, 0.75726, 0, 0],
|
234 |
+
"10935": [0.26167, 0.75726, 0, 0],
|
235 |
+
"10936": [0.26167, 0.75726, 0, 0],
|
236 |
+
"10937": [0.26167, 0.75726, 0, 0],
|
237 |
+
"10938": [0.26167, 0.75726, 0, 0],
|
238 |
+
"10949": [0.25583, 0.75583, 0, 0],
|
239 |
+
"10950": [0.25583, 0.75583, 0, 0],
|
240 |
+
"10955": [0.28481, 0.79383, 0, 0],
|
241 |
+
"10956": [0.28481, 0.79383, 0, 0],
|
242 |
+
"57350": [0.08167, 0.58167, 0, 0],
|
243 |
+
"57351": [0.08167, 0.58167, 0, 0],
|
244 |
+
"57352": [0.08167, 0.58167, 0, 0],
|
245 |
+
"57353": [0, 0.43056, 0.04028, 0],
|
246 |
+
"57356": [0.25142, 0.75726, 0, 0],
|
247 |
+
"57357": [0.25142, 0.75726, 0, 0],
|
248 |
+
"57358": [0.41951, 0.91951, 0, 0],
|
249 |
+
"57359": [0.30274, 0.79383, 0, 0],
|
250 |
+
"57360": [0.30274, 0.79383, 0, 0],
|
251 |
+
"57361": [0.41951, 0.91951, 0, 0],
|
252 |
+
"57366": [0.25142, 0.75726, 0, 0],
|
253 |
+
"57367": [0.25142, 0.75726, 0, 0],
|
254 |
+
"57368": [0.25142, 0.75726, 0, 0],
|
255 |
+
"57369": [0.25142, 0.75726, 0, 0],
|
256 |
+
"57370": [0.13597, 0.63597, 0, 0],
|
257 |
+
"57371": [0.13597, 0.63597, 0, 0],
|
258 |
+
},
|
259 |
+
"Caligraphic-Regular": {
|
260 |
+
"48": [0, 0.43056, 0, 0],
|
261 |
+
"49": [0, 0.43056, 0, 0],
|
262 |
+
"50": [0, 0.43056, 0, 0],
|
263 |
+
"51": [0.19444, 0.43056, 0, 0],
|
264 |
+
"52": [0.19444, 0.43056, 0, 0],
|
265 |
+
"53": [0.19444, 0.43056, 0, 0],
|
266 |
+
"54": [0, 0.64444, 0, 0],
|
267 |
+
"55": [0.19444, 0.43056, 0, 0],
|
268 |
+
"56": [0, 0.64444, 0, 0],
|
269 |
+
"57": [0.19444, 0.43056, 0, 0],
|
270 |
+
"65": [0, 0.68333, 0, 0.19445],
|
271 |
+
"66": [0, 0.68333, 0.03041, 0.13889],
|
272 |
+
"67": [0, 0.68333, 0.05834, 0.13889],
|
273 |
+
"68": [0, 0.68333, 0.02778, 0.08334],
|
274 |
+
"69": [0, 0.68333, 0.08944, 0.11111],
|
275 |
+
"70": [0, 0.68333, 0.09931, 0.11111],
|
276 |
+
"71": [0.09722, 0.68333, 0.0593, 0.11111],
|
277 |
+
"72": [0, 0.68333, 0.00965, 0.11111],
|
278 |
+
"73": [0, 0.68333, 0.07382, 0],
|
279 |
+
"74": [0.09722, 0.68333, 0.18472, 0.16667],
|
280 |
+
"75": [0, 0.68333, 0.01445, 0.05556],
|
281 |
+
"76": [0, 0.68333, 0, 0.13889],
|
282 |
+
"77": [0, 0.68333, 0, 0.13889],
|
283 |
+
"78": [0, 0.68333, 0.14736, 0.08334],
|
284 |
+
"79": [0, 0.68333, 0.02778, 0.11111],
|
285 |
+
"80": [0, 0.68333, 0.08222, 0.08334],
|
286 |
+
"81": [0.09722, 0.68333, 0, 0.11111],
|
287 |
+
"82": [0, 0.68333, 0, 0.08334],
|
288 |
+
"83": [0, 0.68333, 0.075, 0.13889],
|
289 |
+
"84": [0, 0.68333, 0.25417, 0],
|
290 |
+
"85": [0, 0.68333, 0.09931, 0.08334],
|
291 |
+
"86": [0, 0.68333, 0.08222, 0],
|
292 |
+
"87": [0, 0.68333, 0.08222, 0.08334],
|
293 |
+
"88": [0, 0.68333, 0.14643, 0.13889],
|
294 |
+
"89": [0.09722, 0.68333, 0.08222, 0.08334],
|
295 |
+
"90": [0, 0.68333, 0.07944, 0.13889],
|
296 |
+
},
|
297 |
+
"Fraktur-Regular": {
|
298 |
+
"33": [0, 0.69141, 0, 0],
|
299 |
+
"34": [0, 0.69141, 0, 0],
|
300 |
+
"38": [0, 0.69141, 0, 0],
|
301 |
+
"39": [0, 0.69141, 0, 0],
|
302 |
+
"40": [0.24982, 0.74947, 0, 0],
|
303 |
+
"41": [0.24982, 0.74947, 0, 0],
|
304 |
+
"42": [0, 0.62119, 0, 0],
|
305 |
+
"43": [0.08319, 0.58283, 0, 0],
|
306 |
+
"44": [0, 0.10803, 0, 0],
|
307 |
+
"45": [0.08319, 0.58283, 0, 0],
|
308 |
+
"46": [0, 0.10803, 0, 0],
|
309 |
+
"47": [0.24982, 0.74947, 0, 0],
|
310 |
+
"48": [0, 0.47534, 0, 0],
|
311 |
+
"49": [0, 0.47534, 0, 0],
|
312 |
+
"50": [0, 0.47534, 0, 0],
|
313 |
+
"51": [0.18906, 0.47534, 0, 0],
|
314 |
+
"52": [0.18906, 0.47534, 0, 0],
|
315 |
+
"53": [0.18906, 0.47534, 0, 0],
|
316 |
+
"54": [0, 0.69141, 0, 0],
|
317 |
+
"55": [0.18906, 0.47534, 0, 0],
|
318 |
+
"56": [0, 0.69141, 0, 0],
|
319 |
+
"57": [0.18906, 0.47534, 0, 0],
|
320 |
+
"58": [0, 0.47534, 0, 0],
|
321 |
+
"59": [0.12604, 0.47534, 0, 0],
|
322 |
+
"61": [-0.13099, 0.36866, 0, 0],
|
323 |
+
"63": [0, 0.69141, 0, 0],
|
324 |
+
"65": [0, 0.69141, 0, 0],
|
325 |
+
"66": [0, 0.69141, 0, 0],
|
326 |
+
"67": [0, 0.69141, 0, 0],
|
327 |
+
"68": [0, 0.69141, 0, 0],
|
328 |
+
"69": [0, 0.69141, 0, 0],
|
329 |
+
"70": [0.12604, 0.69141, 0, 0],
|
330 |
+
"71": [0, 0.69141, 0, 0],
|
331 |
+
"72": [0.06302, 0.69141, 0, 0],
|
332 |
+
"73": [0, 0.69141, 0, 0],
|
333 |
+
"74": [0.12604, 0.69141, 0, 0],
|
334 |
+
"75": [0, 0.69141, 0, 0],
|
335 |
+
"76": [0, 0.69141, 0, 0],
|
336 |
+
"77": [0, 0.69141, 0, 0],
|
337 |
+
"78": [0, 0.69141, 0, 0],
|
338 |
+
"79": [0, 0.69141, 0, 0],
|
339 |
+
"80": [0.18906, 0.69141, 0, 0],
|
340 |
+
"81": [0.03781, 0.69141, 0, 0],
|
341 |
+
"82": [0, 0.69141, 0, 0],
|
342 |
+
"83": [0, 0.69141, 0, 0],
|
343 |
+
"84": [0, 0.69141, 0, 0],
|
344 |
+
"85": [0, 0.69141, 0, 0],
|
345 |
+
"86": [0, 0.69141, 0, 0],
|
346 |
+
"87": [0, 0.69141, 0, 0],
|
347 |
+
"88": [0, 0.69141, 0, 0],
|
348 |
+
"89": [0.18906, 0.69141, 0, 0],
|
349 |
+
"90": [0.12604, 0.69141, 0, 0],
|
350 |
+
"91": [0.24982, 0.74947, 0, 0],
|
351 |
+
"93": [0.24982, 0.74947, 0, 0],
|
352 |
+
"94": [0, 0.69141, 0, 0],
|
353 |
+
"97": [0, 0.47534, 0, 0],
|
354 |
+
"98": [0, 0.69141, 0, 0],
|
355 |
+
"99": [0, 0.47534, 0, 0],
|
356 |
+
"100": [0, 0.62119, 0, 0],
|
357 |
+
"101": [0, 0.47534, 0, 0],
|
358 |
+
"102": [0.18906, 0.69141, 0, 0],
|
359 |
+
"103": [0.18906, 0.47534, 0, 0],
|
360 |
+
"104": [0.18906, 0.69141, 0, 0],
|
361 |
+
"105": [0, 0.69141, 0, 0],
|
362 |
+
"106": [0, 0.69141, 0, 0],
|
363 |
+
"107": [0, 0.69141, 0, 0],
|
364 |
+
"108": [0, 0.69141, 0, 0],
|
365 |
+
"109": [0, 0.47534, 0, 0],
|
366 |
+
"110": [0, 0.47534, 0, 0],
|
367 |
+
"111": [0, 0.47534, 0, 0],
|
368 |
+
"112": [0.18906, 0.52396, 0, 0],
|
369 |
+
"113": [0.18906, 0.47534, 0, 0],
|
370 |
+
"114": [0, 0.47534, 0, 0],
|
371 |
+
"115": [0, 0.47534, 0, 0],
|
372 |
+
"116": [0, 0.62119, 0, 0],
|
373 |
+
"117": [0, 0.47534, 0, 0],
|
374 |
+
"118": [0, 0.52396, 0, 0],
|
375 |
+
"119": [0, 0.52396, 0, 0],
|
376 |
+
"120": [0.18906, 0.47534, 0, 0],
|
377 |
+
"121": [0.18906, 0.47534, 0, 0],
|
378 |
+
"122": [0.18906, 0.47534, 0, 0],
|
379 |
+
"8216": [0, 0.69141, 0, 0],
|
380 |
+
"8217": [0, 0.69141, 0, 0],
|
381 |
+
"58112": [0, 0.62119, 0, 0],
|
382 |
+
"58113": [0, 0.62119, 0, 0],
|
383 |
+
"58114": [0.18906, 0.69141, 0, 0],
|
384 |
+
"58115": [0.18906, 0.69141, 0, 0],
|
385 |
+
"58116": [0.18906, 0.47534, 0, 0],
|
386 |
+
"58117": [0, 0.69141, 0, 0],
|
387 |
+
"58118": [0, 0.62119, 0, 0],
|
388 |
+
"58119": [0, 0.47534, 0, 0],
|
389 |
+
},
|
390 |
+
"Main-Bold": {
|
391 |
+
"33": [0, 0.69444, 0, 0],
|
392 |
+
"34": [0, 0.69444, 0, 0],
|
393 |
+
"35": [0.19444, 0.69444, 0, 0],
|
394 |
+
"36": [0.05556, 0.75, 0, 0],
|
395 |
+
"37": [0.05556, 0.75, 0, 0],
|
396 |
+
"38": [0, 0.69444, 0, 0],
|
397 |
+
"39": [0, 0.69444, 0, 0],
|
398 |
+
"40": [0.25, 0.75, 0, 0],
|
399 |
+
"41": [0.25, 0.75, 0, 0],
|
400 |
+
"42": [0, 0.75, 0, 0],
|
401 |
+
"43": [0.13333, 0.63333, 0, 0],
|
402 |
+
"44": [0.19444, 0.15556, 0, 0],
|
403 |
+
"45": [0, 0.44444, 0, 0],
|
404 |
+
"46": [0, 0.15556, 0, 0],
|
405 |
+
"47": [0.25, 0.75, 0, 0],
|
406 |
+
"48": [0, 0.64444, 0, 0],
|
407 |
+
"49": [0, 0.64444, 0, 0],
|
408 |
+
"50": [0, 0.64444, 0, 0],
|
409 |
+
"51": [0, 0.64444, 0, 0],
|
410 |
+
"52": [0, 0.64444, 0, 0],
|
411 |
+
"53": [0, 0.64444, 0, 0],
|
412 |
+
"54": [0, 0.64444, 0, 0],
|
413 |
+
"55": [0, 0.64444, 0, 0],
|
414 |
+
"56": [0, 0.64444, 0, 0],
|
415 |
+
"57": [0, 0.64444, 0, 0],
|
416 |
+
"58": [0, 0.44444, 0, 0],
|
417 |
+
"59": [0.19444, 0.44444, 0, 0],
|
418 |
+
"60": [0.08556, 0.58556, 0, 0],
|
419 |
+
"61": [-0.10889, 0.39111, 0, 0],
|
420 |
+
"62": [0.08556, 0.58556, 0, 0],
|
421 |
+
"63": [0, 0.69444, 0, 0],
|
422 |
+
"64": [0, 0.69444, 0, 0],
|
423 |
+
"65": [0, 0.68611, 0, 0],
|
424 |
+
"66": [0, 0.68611, 0, 0],
|
425 |
+
"67": [0, 0.68611, 0, 0],
|
426 |
+
"68": [0, 0.68611, 0, 0],
|
427 |
+
"69": [0, 0.68611, 0, 0],
|
428 |
+
"70": [0, 0.68611, 0, 0],
|
429 |
+
"71": [0, 0.68611, 0, 0],
|
430 |
+
"72": [0, 0.68611, 0, 0],
|
431 |
+
"73": [0, 0.68611, 0, 0],
|
432 |
+
"74": [0, 0.68611, 0, 0],
|
433 |
+
"75": [0, 0.68611, 0, 0],
|
434 |
+
"76": [0, 0.68611, 0, 0],
|
435 |
+
"77": [0, 0.68611, 0, 0],
|
436 |
+
"78": [0, 0.68611, 0, 0],
|
437 |
+
"79": [0, 0.68611, 0, 0],
|
438 |
+
"80": [0, 0.68611, 0, 0],
|
439 |
+
"81": [0.19444, 0.68611, 0, 0],
|
440 |
+
"82": [0, 0.68611, 0, 0],
|
441 |
+
"83": [0, 0.68611, 0, 0],
|
442 |
+
"84": [0, 0.68611, 0, 0],
|
443 |
+
"85": [0, 0.68611, 0, 0],
|
444 |
+
"86": [0, 0.68611, 0.01597, 0],
|
445 |
+
"87": [0, 0.68611, 0.01597, 0],
|
446 |
+
"88": [0, 0.68611, 0, 0],
|
447 |
+
"89": [0, 0.68611, 0.02875, 0],
|
448 |
+
"90": [0, 0.68611, 0, 0],
|
449 |
+
"91": [0.25, 0.75, 0, 0],
|
450 |
+
"92": [0.25, 0.75, 0, 0],
|
451 |
+
"93": [0.25, 0.75, 0, 0],
|
452 |
+
"94": [0, 0.69444, 0, 0],
|
453 |
+
"95": [0.31, 0.13444, 0.03194, 0],
|
454 |
+
"96": [0, 0.69444, 0, 0],
|
455 |
+
"97": [0, 0.44444, 0, 0],
|
456 |
+
"98": [0, 0.69444, 0, 0],
|
457 |
+
"99": [0, 0.44444, 0, 0],
|
458 |
+
"100": [0, 0.69444, 0, 0],
|
459 |
+
"101": [0, 0.44444, 0, 0],
|
460 |
+
"102": [0, 0.69444, 0.10903, 0],
|
461 |
+
"103": [0.19444, 0.44444, 0.01597, 0],
|
462 |
+
"104": [0, 0.69444, 0, 0],
|
463 |
+
"105": [0, 0.69444, 0, 0],
|
464 |
+
"106": [0.19444, 0.69444, 0, 0],
|
465 |
+
"107": [0, 0.69444, 0, 0],
|
466 |
+
"108": [0, 0.69444, 0, 0],
|
467 |
+
"109": [0, 0.44444, 0, 0],
|
468 |
+
"110": [0, 0.44444, 0, 0],
|
469 |
+
"111": [0, 0.44444, 0, 0],
|
470 |
+
"112": [0.19444, 0.44444, 0, 0],
|
471 |
+
"113": [0.19444, 0.44444, 0, 0],
|
472 |
+
"114": [0, 0.44444, 0, 0],
|
473 |
+
"115": [0, 0.44444, 0, 0],
|
474 |
+
"116": [0, 0.63492, 0, 0],
|
475 |
+
"117": [0, 0.44444, 0, 0],
|
476 |
+
"118": [0, 0.44444, 0.01597, 0],
|
477 |
+
"119": [0, 0.44444, 0.01597, 0],
|
478 |
+
"120": [0, 0.44444, 0, 0],
|
479 |
+
"121": [0.19444, 0.44444, 0.01597, 0],
|
480 |
+
"122": [0, 0.44444, 0, 0],
|
481 |
+
"123": [0.25, 0.75, 0, 0],
|
482 |
+
"124": [0.25, 0.75, 0, 0],
|
483 |
+
"125": [0.25, 0.75, 0, 0],
|
484 |
+
"126": [0.35, 0.34444, 0, 0],
|
485 |
+
"168": [0, 0.69444, 0, 0],
|
486 |
+
"172": [0, 0.44444, 0, 0],
|
487 |
+
"175": [0, 0.59611, 0, 0],
|
488 |
+
"176": [0, 0.69444, 0, 0],
|
489 |
+
"177": [0.13333, 0.63333, 0, 0],
|
490 |
+
"180": [0, 0.69444, 0, 0],
|
491 |
+
"215": [0.13333, 0.63333, 0, 0],
|
492 |
+
"247": [0.13333, 0.63333, 0, 0],
|
493 |
+
"305": [0, 0.44444, 0, 0],
|
494 |
+
"567": [0.19444, 0.44444, 0, 0],
|
495 |
+
"710": [0, 0.69444, 0, 0],
|
496 |
+
"711": [0, 0.63194, 0, 0],
|
497 |
+
"713": [0, 0.59611, 0, 0],
|
498 |
+
"714": [0, 0.69444, 0, 0],
|
499 |
+
"715": [0, 0.69444, 0, 0],
|
500 |
+
"728": [0, 0.69444, 0, 0],
|
501 |
+
"729": [0, 0.69444, 0, 0],
|
502 |
+
"730": [0, 0.69444, 0, 0],
|
503 |
+
"732": [0, 0.69444, 0, 0],
|
504 |
+
"768": [0, 0.69444, 0, 0],
|
505 |
+
"769": [0, 0.69444, 0, 0],
|
506 |
+
"770": [0, 0.69444, 0, 0],
|
507 |
+
"771": [0, 0.69444, 0, 0],
|
508 |
+
"772": [0, 0.59611, 0, 0],
|
509 |
+
"774": [0, 0.69444, 0, 0],
|
510 |
+
"775": [0, 0.69444, 0, 0],
|
511 |
+
"776": [0, 0.69444, 0, 0],
|
512 |
+
"778": [0, 0.69444, 0, 0],
|
513 |
+
"779": [0, 0.69444, 0, 0],
|
514 |
+
"780": [0, 0.63194, 0, 0],
|
515 |
+
"824": [0.19444, 0.69444, 0, 0],
|
516 |
+
"915": [0, 0.68611, 0, 0],
|
517 |
+
"916": [0, 0.68611, 0, 0],
|
518 |
+
"920": [0, 0.68611, 0, 0],
|
519 |
+
"923": [0, 0.68611, 0, 0],
|
520 |
+
"926": [0, 0.68611, 0, 0],
|
521 |
+
"928": [0, 0.68611, 0, 0],
|
522 |
+
"931": [0, 0.68611, 0, 0],
|
523 |
+
"933": [0, 0.68611, 0, 0],
|
524 |
+
"934": [0, 0.68611, 0, 0],
|
525 |
+
"936": [0, 0.68611, 0, 0],
|
526 |
+
"937": [0, 0.68611, 0, 0],
|
527 |
+
"8211": [0, 0.44444, 0.03194, 0],
|
528 |
+
"8212": [0, 0.44444, 0.03194, 0],
|
529 |
+
"8216": [0, 0.69444, 0, 0],
|
530 |
+
"8217": [0, 0.69444, 0, 0],
|
531 |
+
"8220": [0, 0.69444, 0, 0],
|
532 |
+
"8221": [0, 0.69444, 0, 0],
|
533 |
+
"8224": [0.19444, 0.69444, 0, 0],
|
534 |
+
"8225": [0.19444, 0.69444, 0, 0],
|
535 |
+
"8242": [0, 0.55556, 0, 0],
|
536 |
+
"8407": [0, 0.72444, 0.15486, 0],
|
537 |
+
"8463": [0, 0.69444, 0, 0],
|
538 |
+
"8465": [0, 0.69444, 0, 0],
|
539 |
+
"8467": [0, 0.69444, 0, 0],
|
540 |
+
"8472": [0.19444, 0.44444, 0, 0],
|
541 |
+
"8476": [0, 0.69444, 0, 0],
|
542 |
+
"8501": [0, 0.69444, 0, 0],
|
543 |
+
"8592": [-0.10889, 0.39111, 0, 0],
|
544 |
+
"8593": [0.19444, 0.69444, 0, 0],
|
545 |
+
"8594": [-0.10889, 0.39111, 0, 0],
|
546 |
+
"8595": [0.19444, 0.69444, 0, 0],
|
547 |
+
"8596": [-0.10889, 0.39111, 0, 0],
|
548 |
+
"8597": [0.25, 0.75, 0, 0],
|
549 |
+
"8598": [0.19444, 0.69444, 0, 0],
|
550 |
+
"8599": [0.19444, 0.69444, 0, 0],
|
551 |
+
"8600": [0.19444, 0.69444, 0, 0],
|
552 |
+
"8601": [0.19444, 0.69444, 0, 0],
|
553 |
+
"8636": [-0.10889, 0.39111, 0, 0],
|
554 |
+
"8637": [-0.10889, 0.39111, 0, 0],
|
555 |
+
"8640": [-0.10889, 0.39111, 0, 0],
|
556 |
+
"8641": [-0.10889, 0.39111, 0, 0],
|
557 |
+
"8656": [-0.10889, 0.39111, 0, 0],
|
558 |
+
"8657": [0.19444, 0.69444, 0, 0],
|
559 |
+
"8658": [-0.10889, 0.39111, 0, 0],
|
560 |
+
"8659": [0.19444, 0.69444, 0, 0],
|
561 |
+
"8660": [-0.10889, 0.39111, 0, 0],
|
562 |
+
"8661": [0.25, 0.75, 0, 0],
|
563 |
+
"8704": [0, 0.69444, 0, 0],
|
564 |
+
"8706": [0, 0.69444, 0.06389, 0],
|
565 |
+
"8707": [0, 0.69444, 0, 0],
|
566 |
+
"8709": [0.05556, 0.75, 0, 0],
|
567 |
+
"8711": [0, 0.68611, 0, 0],
|
568 |
+
"8712": [0.08556, 0.58556, 0, 0],
|
569 |
+
"8715": [0.08556, 0.58556, 0, 0],
|
570 |
+
"8722": [0.13333, 0.63333, 0, 0],
|
571 |
+
"8723": [0.13333, 0.63333, 0, 0],
|
572 |
+
"8725": [0.25, 0.75, 0, 0],
|
573 |
+
"8726": [0.25, 0.75, 0, 0],
|
574 |
+
"8727": [-0.02778, 0.47222, 0, 0],
|
575 |
+
"8728": [-0.02639, 0.47361, 0, 0],
|
576 |
+
"8729": [-0.02639, 0.47361, 0, 0],
|
577 |
+
"8730": [0.18, 0.82, 0, 0],
|
578 |
+
"8733": [0, 0.44444, 0, 0],
|
579 |
+
"8734": [0, 0.44444, 0, 0],
|
580 |
+
"8736": [0, 0.69224, 0, 0],
|
581 |
+
"8739": [0.25, 0.75, 0, 0],
|
582 |
+
"8741": [0.25, 0.75, 0, 0],
|
583 |
+
"8743": [0, 0.55556, 0, 0],
|
584 |
+
"8744": [0, 0.55556, 0, 0],
|
585 |
+
"8745": [0, 0.55556, 0, 0],
|
586 |
+
"8746": [0, 0.55556, 0, 0],
|
587 |
+
"8747": [0.19444, 0.69444, 0.12778, 0],
|
588 |
+
"8764": [-0.10889, 0.39111, 0, 0],
|
589 |
+
"8768": [0.19444, 0.69444, 0, 0],
|
590 |
+
"8771": [0.00222, 0.50222, 0, 0],
|
591 |
+
"8776": [0.02444, 0.52444, 0, 0],
|
592 |
+
"8781": [0.00222, 0.50222, 0, 0],
|
593 |
+
"8801": [0.00222, 0.50222, 0, 0],
|
594 |
+
"8804": [0.19667, 0.69667, 0, 0],
|
595 |
+
"8805": [0.19667, 0.69667, 0, 0],
|
596 |
+
"8810": [0.08556, 0.58556, 0, 0],
|
597 |
+
"8811": [0.08556, 0.58556, 0, 0],
|
598 |
+
"8826": [0.08556, 0.58556, 0, 0],
|
599 |
+
"8827": [0.08556, 0.58556, 0, 0],
|
600 |
+
"8834": [0.08556, 0.58556, 0, 0],
|
601 |
+
"8835": [0.08556, 0.58556, 0, 0],
|
602 |
+
"8838": [0.19667, 0.69667, 0, 0],
|
603 |
+
"8839": [0.19667, 0.69667, 0, 0],
|
604 |
+
"8846": [0, 0.55556, 0, 0],
|
605 |
+
"8849": [0.19667, 0.69667, 0, 0],
|
606 |
+
"8850": [0.19667, 0.69667, 0, 0],
|
607 |
+
"8851": [0, 0.55556, 0, 0],
|
608 |
+
"8852": [0, 0.55556, 0, 0],
|
609 |
+
"8853": [0.13333, 0.63333, 0, 0],
|
610 |
+
"8854": [0.13333, 0.63333, 0, 0],
|
611 |
+
"8855": [0.13333, 0.63333, 0, 0],
|
612 |
+
"8856": [0.13333, 0.63333, 0, 0],
|
613 |
+
"8857": [0.13333, 0.63333, 0, 0],
|
614 |
+
"8866": [0, 0.69444, 0, 0],
|
615 |
+
"8867": [0, 0.69444, 0, 0],
|
616 |
+
"8868": [0, 0.69444, 0, 0],
|
617 |
+
"8869": [0, 0.69444, 0, 0],
|
618 |
+
"8900": [-0.02639, 0.47361, 0, 0],
|
619 |
+
"8901": [-0.02639, 0.47361, 0, 0],
|
620 |
+
"8902": [-0.02778, 0.47222, 0, 0],
|
621 |
+
"8968": [0.25, 0.75, 0, 0],
|
622 |
+
"8969": [0.25, 0.75, 0, 0],
|
623 |
+
"8970": [0.25, 0.75, 0, 0],
|
624 |
+
"8971": [0.25, 0.75, 0, 0],
|
625 |
+
"8994": [-0.13889, 0.36111, 0, 0],
|
626 |
+
"8995": [-0.13889, 0.36111, 0, 0],
|
627 |
+
"9651": [0.19444, 0.69444, 0, 0],
|
628 |
+
"9657": [-0.02778, 0.47222, 0, 0],
|
629 |
+
"9661": [0.19444, 0.69444, 0, 0],
|
630 |
+
"9667": [-0.02778, 0.47222, 0, 0],
|
631 |
+
"9711": [0.19444, 0.69444, 0, 0],
|
632 |
+
"9824": [0.12963, 0.69444, 0, 0],
|
633 |
+
"9825": [0.12963, 0.69444, 0, 0],
|
634 |
+
"9826": [0.12963, 0.69444, 0, 0],
|
635 |
+
"9827": [0.12963, 0.69444, 0, 0],
|
636 |
+
"9837": [0, 0.75, 0, 0],
|
637 |
+
"9838": [0.19444, 0.69444, 0, 0],
|
638 |
+
"9839": [0.19444, 0.69444, 0, 0],
|
639 |
+
"10216": [0.25, 0.75, 0, 0],
|
640 |
+
"10217": [0.25, 0.75, 0, 0],
|
641 |
+
"10815": [0, 0.68611, 0, 0],
|
642 |
+
"10927": [0.19667, 0.69667, 0, 0],
|
643 |
+
"10928": [0.19667, 0.69667, 0, 0],
|
644 |
+
},
|
645 |
+
"Main-Italic": {
|
646 |
+
"33": [0, 0.69444, 0.12417, 0],
|
647 |
+
"34": [0, 0.69444, 0.06961, 0],
|
648 |
+
"35": [0.19444, 0.69444, 0.06616, 0],
|
649 |
+
"37": [0.05556, 0.75, 0.13639, 0],
|
650 |
+
"38": [0, 0.69444, 0.09694, 0],
|
651 |
+
"39": [0, 0.69444, 0.12417, 0],
|
652 |
+
"40": [0.25, 0.75, 0.16194, 0],
|
653 |
+
"41": [0.25, 0.75, 0.03694, 0],
|
654 |
+
"42": [0, 0.75, 0.14917, 0],
|
655 |
+
"43": [0.05667, 0.56167, 0.03694, 0],
|
656 |
+
"44": [0.19444, 0.10556, 0, 0],
|
657 |
+
"45": [0, 0.43056, 0.02826, 0],
|
658 |
+
"46": [0, 0.10556, 0, 0],
|
659 |
+
"47": [0.25, 0.75, 0.16194, 0],
|
660 |
+
"48": [0, 0.64444, 0.13556, 0],
|
661 |
+
"49": [0, 0.64444, 0.13556, 0],
|
662 |
+
"50": [0, 0.64444, 0.13556, 0],
|
663 |
+
"51": [0, 0.64444, 0.13556, 0],
|
664 |
+
"52": [0.19444, 0.64444, 0.13556, 0],
|
665 |
+
"53": [0, 0.64444, 0.13556, 0],
|
666 |
+
"54": [0, 0.64444, 0.13556, 0],
|
667 |
+
"55": [0.19444, 0.64444, 0.13556, 0],
|
668 |
+
"56": [0, 0.64444, 0.13556, 0],
|
669 |
+
"57": [0, 0.64444, 0.13556, 0],
|
670 |
+
"58": [0, 0.43056, 0.0582, 0],
|
671 |
+
"59": [0.19444, 0.43056, 0.0582, 0],
|
672 |
+
"61": [-0.13313, 0.36687, 0.06616, 0],
|
673 |
+
"63": [0, 0.69444, 0.1225, 0],
|
674 |
+
"64": [0, 0.69444, 0.09597, 0],
|
675 |
+
"65": [0, 0.68333, 0, 0],
|
676 |
+
"66": [0, 0.68333, 0.10257, 0],
|
677 |
+
"67": [0, 0.68333, 0.14528, 0],
|
678 |
+
"68": [0, 0.68333, 0.09403, 0],
|
679 |
+
"69": [0, 0.68333, 0.12028, 0],
|
680 |
+
"70": [0, 0.68333, 0.13305, 0],
|
681 |
+
"71": [0, 0.68333, 0.08722, 0],
|
682 |
+
"72": [0, 0.68333, 0.16389, 0],
|
683 |
+
"73": [0, 0.68333, 0.15806, 0],
|
684 |
+
"74": [0, 0.68333, 0.14028, 0],
|
685 |
+
"75": [0, 0.68333, 0.14528, 0],
|
686 |
+
"76": [0, 0.68333, 0, 0],
|
687 |
+
"77": [0, 0.68333, 0.16389, 0],
|
688 |
+
"78": [0, 0.68333, 0.16389, 0],
|
689 |
+
"79": [0, 0.68333, 0.09403, 0],
|
690 |
+
"80": [0, 0.68333, 0.10257, 0],
|
691 |
+
"81": [0.19444, 0.68333, 0.09403, 0],
|
692 |
+
"82": [0, 0.68333, 0.03868, 0],
|
693 |
+
"83": [0, 0.68333, 0.11972, 0],
|
694 |
+
"84": [0, 0.68333, 0.13305, 0],
|
695 |
+
"85": [0, 0.68333, 0.16389, 0],
|
696 |
+
"86": [0, 0.68333, 0.18361, 0],
|
697 |
+
"87": [0, 0.68333, 0.18361, 0],
|
698 |
+
"88": [0, 0.68333, 0.15806, 0],
|
699 |
+
"89": [0, 0.68333, 0.19383, 0],
|
700 |
+
"90": [0, 0.68333, 0.14528, 0],
|
701 |
+
"91": [0.25, 0.75, 0.1875, 0],
|
702 |
+
"93": [0.25, 0.75, 0.10528, 0],
|
703 |
+
"94": [0, 0.69444, 0.06646, 0],
|
704 |
+
"95": [0.31, 0.12056, 0.09208, 0],
|
705 |
+
"97": [0, 0.43056, 0.07671, 0],
|
706 |
+
"98": [0, 0.69444, 0.06312, 0],
|
707 |
+
"99": [0, 0.43056, 0.05653, 0],
|
708 |
+
"100": [0, 0.69444, 0.10333, 0],
|
709 |
+
"101": [0, 0.43056, 0.07514, 0],
|
710 |
+
"102": [0.19444, 0.69444, 0.21194, 0],
|
711 |
+
"103": [0.19444, 0.43056, 0.08847, 0],
|
712 |
+
"104": [0, 0.69444, 0.07671, 0],
|
713 |
+
"105": [0, 0.65536, 0.1019, 0],
|
714 |
+
"106": [0.19444, 0.65536, 0.14467, 0],
|
715 |
+
"107": [0, 0.69444, 0.10764, 0],
|
716 |
+
"108": [0, 0.69444, 0.10333, 0],
|
717 |
+
"109": [0, 0.43056, 0.07671, 0],
|
718 |
+
"110": [0, 0.43056, 0.07671, 0],
|
719 |
+
"111": [0, 0.43056, 0.06312, 0],
|
720 |
+
"112": [0.19444, 0.43056, 0.06312, 0],
|
721 |
+
"113": [0.19444, 0.43056, 0.08847, 0],
|
722 |
+
"114": [0, 0.43056, 0.10764, 0],
|
723 |
+
"115": [0, 0.43056, 0.08208, 0],
|
724 |
+
"116": [0, 0.61508, 0.09486, 0],
|
725 |
+
"117": [0, 0.43056, 0.07671, 0],
|
726 |
+
"118": [0, 0.43056, 0.10764, 0],
|
727 |
+
"119": [0, 0.43056, 0.10764, 0],
|
728 |
+
"120": [0, 0.43056, 0.12042, 0],
|
729 |
+
"121": [0.19444, 0.43056, 0.08847, 0],
|
730 |
+
"122": [0, 0.43056, 0.12292, 0],
|
731 |
+
"126": [0.35, 0.31786, 0.11585, 0],
|
732 |
+
"163": [0, 0.69444, 0, 0],
|
733 |
+
"305": [0, 0.43056, 0, 0.02778],
|
734 |
+
"567": [0.19444, 0.43056, 0, 0.08334],
|
735 |
+
"768": [0, 0.69444, 0, 0],
|
736 |
+
"769": [0, 0.69444, 0.09694, 0],
|
737 |
+
"770": [0, 0.69444, 0.06646, 0],
|
738 |
+
"771": [0, 0.66786, 0.11585, 0],
|
739 |
+
"772": [0, 0.56167, 0.10333, 0],
|
740 |
+
"774": [0, 0.69444, 0.10806, 0],
|
741 |
+
"775": [0, 0.66786, 0.11752, 0],
|
742 |
+
"776": [0, 0.66786, 0.10474, 0],
|
743 |
+
"778": [0, 0.69444, 0, 0],
|
744 |
+
"779": [0, 0.69444, 0.1225, 0],
|
745 |
+
"780": [0, 0.62847, 0.08295, 0],
|
746 |
+
"915": [0, 0.68333, 0.13305, 0],
|
747 |
+
"916": [0, 0.68333, 0, 0],
|
748 |
+
"920": [0, 0.68333, 0.09403, 0],
|
749 |
+
"923": [0, 0.68333, 0, 0],
|
750 |
+
"926": [0, 0.68333, 0.15294, 0],
|
751 |
+
"928": [0, 0.68333, 0.16389, 0],
|
752 |
+
"931": [0, 0.68333, 0.12028, 0],
|
753 |
+
"933": [0, 0.68333, 0.11111, 0],
|
754 |
+
"934": [0, 0.68333, 0.05986, 0],
|
755 |
+
"936": [0, 0.68333, 0.11111, 0],
|
756 |
+
"937": [0, 0.68333, 0.10257, 0],
|
757 |
+
"8211": [0, 0.43056, 0.09208, 0],
|
758 |
+
"8212": [0, 0.43056, 0.09208, 0],
|
759 |
+
"8216": [0, 0.69444, 0.12417, 0],
|
760 |
+
"8217": [0, 0.69444, 0.12417, 0],
|
761 |
+
"8220": [0, 0.69444, 0.1685, 0],
|
762 |
+
"8221": [0, 0.69444, 0.06961, 0],
|
763 |
+
"8463": [0, 0.68889, 0, 0],
|
764 |
+
},
|
765 |
+
"Main-Regular": {
|
766 |
+
"32": [0, 0, 0, 0],
|
767 |
+
"33": [0, 0.69444, 0, 0],
|
768 |
+
"34": [0, 0.69444, 0, 0],
|
769 |
+
"35": [0.19444, 0.69444, 0, 0],
|
770 |
+
"36": [0.05556, 0.75, 0, 0],
|
771 |
+
"37": [0.05556, 0.75, 0, 0],
|
772 |
+
"38": [0, 0.69444, 0, 0],
|
773 |
+
"39": [0, 0.69444, 0, 0],
|
774 |
+
"40": [0.25, 0.75, 0, 0],
|
775 |
+
"41": [0.25, 0.75, 0, 0],
|
776 |
+
"42": [0, 0.75, 0, 0],
|
777 |
+
"43": [0.08333, 0.58333, 0, 0],
|
778 |
+
"44": [0.19444, 0.10556, 0, 0],
|
779 |
+
"45": [0, 0.43056, 0, 0],
|
780 |
+
"46": [0, 0.10556, 0, 0],
|
781 |
+
"47": [0.25, 0.75, 0, 0],
|
782 |
+
"48": [0, 0.64444, 0, 0],
|
783 |
+
"49": [0, 0.64444, 0, 0],
|
784 |
+
"50": [0, 0.64444, 0, 0],
|
785 |
+
"51": [0, 0.64444, 0, 0],
|
786 |
+
"52": [0, 0.64444, 0, 0],
|
787 |
+
"53": [0, 0.64444, 0, 0],
|
788 |
+
"54": [0, 0.64444, 0, 0],
|
789 |
+
"55": [0, 0.64444, 0, 0],
|
790 |
+
"56": [0, 0.64444, 0, 0],
|
791 |
+
"57": [0, 0.64444, 0, 0],
|
792 |
+
"58": [0, 0.43056, 0, 0],
|
793 |
+
"59": [0.19444, 0.43056, 0, 0],
|
794 |
+
"60": [0.0391, 0.5391, 0, 0],
|
795 |
+
"61": [-0.13313, 0.36687, 0, 0],
|
796 |
+
"62": [0.0391, 0.5391, 0, 0],
|
797 |
+
"63": [0, 0.69444, 0, 0],
|
798 |
+
"64": [0, 0.69444, 0, 0],
|
799 |
+
"65": [0, 0.68333, 0, 0],
|
800 |
+
"66": [0, 0.68333, 0, 0],
|
801 |
+
"67": [0, 0.68333, 0, 0],
|
802 |
+
"68": [0, 0.68333, 0, 0],
|
803 |
+
"69": [0, 0.68333, 0, 0],
|
804 |
+
"70": [0, 0.68333, 0, 0],
|
805 |
+
"71": [0, 0.68333, 0, 0],
|
806 |
+
"72": [0, 0.68333, 0, 0],
|
807 |
+
"73": [0, 0.68333, 0, 0],
|
808 |
+
"74": [0, 0.68333, 0, 0],
|
809 |
+
"75": [0, 0.68333, 0, 0],
|
810 |
+
"76": [0, 0.68333, 0, 0],
|
811 |
+
"77": [0, 0.68333, 0, 0],
|
812 |
+
"78": [0, 0.68333, 0, 0],
|
813 |
+
"79": [0, 0.68333, 0, 0],
|
814 |
+
"80": [0, 0.68333, 0, 0],
|
815 |
+
"81": [0.19444, 0.68333, 0, 0],
|
816 |
+
"82": [0, 0.68333, 0, 0],
|
817 |
+
"83": [0, 0.68333, 0, 0],
|
818 |
+
"84": [0, 0.68333, 0, 0],
|
819 |
+
"85": [0, 0.68333, 0, 0],
|
820 |
+
"86": [0, 0.68333, 0.01389, 0],
|
821 |
+
"87": [0, 0.68333, 0.01389, 0],
|
822 |
+
"88": [0, 0.68333, 0, 0],
|
823 |
+
"89": [0, 0.68333, 0.025, 0],
|
824 |
+
"90": [0, 0.68333, 0, 0],
|
825 |
+
"91": [0.25, 0.75, 0, 0],
|
826 |
+
"92": [0.25, 0.75, 0, 0],
|
827 |
+
"93": [0.25, 0.75, 0, 0],
|
828 |
+
"94": [0, 0.69444, 0, 0],
|
829 |
+
"95": [0.31, 0.12056, 0.02778, 0],
|
830 |
+
"96": [0, 0.69444, 0, 0],
|
831 |
+
"97": [0, 0.43056, 0, 0],
|
832 |
+
"98": [0, 0.69444, 0, 0],
|
833 |
+
"99": [0, 0.43056, 0, 0],
|
834 |
+
"100": [0, 0.69444, 0, 0],
|
835 |
+
"101": [0, 0.43056, 0, 0],
|
836 |
+
"102": [0, 0.69444, 0.07778, 0],
|
837 |
+
"103": [0.19444, 0.43056, 0.01389, 0],
|
838 |
+
"104": [0, 0.69444, 0, 0],
|
839 |
+
"105": [0, 0.66786, 0, 0],
|
840 |
+
"106": [0.19444, 0.66786, 0, 0],
|
841 |
+
"107": [0, 0.69444, 0, 0],
|
842 |
+
"108": [0, 0.69444, 0, 0],
|
843 |
+
"109": [0, 0.43056, 0, 0],
|
844 |
+
"110": [0, 0.43056, 0, 0],
|
845 |
+
"111": [0, 0.43056, 0, 0],
|
846 |
+
"112": [0.19444, 0.43056, 0, 0],
|
847 |
+
"113": [0.19444, 0.43056, 0, 0],
|
848 |
+
"114": [0, 0.43056, 0, 0],
|
849 |
+
"115": [0, 0.43056, 0, 0],
|
850 |
+
"116": [0, 0.61508, 0, 0],
|
851 |
+
"117": [0, 0.43056, 0, 0],
|
852 |
+
"118": [0, 0.43056, 0.01389, 0],
|
853 |
+
"119": [0, 0.43056, 0.01389, 0],
|
854 |
+
"120": [0, 0.43056, 0, 0],
|
855 |
+
"121": [0.19444, 0.43056, 0.01389, 0],
|
856 |
+
"122": [0, 0.43056, 0, 0],
|
857 |
+
"123": [0.25, 0.75, 0, 0],
|
858 |
+
"124": [0.25, 0.75, 0, 0],
|
859 |
+
"125": [0.25, 0.75, 0, 0],
|
860 |
+
"126": [0.35, 0.31786, 0, 0],
|
861 |
+
"160": [0, 0, 0, 0],
|
862 |
+
"168": [0, 0.66786, 0, 0],
|
863 |
+
"172": [0, 0.43056, 0, 0],
|
864 |
+
"175": [0, 0.56778, 0, 0],
|
865 |
+
"176": [0, 0.69444, 0, 0],
|
866 |
+
"177": [0.08333, 0.58333, 0, 0],
|
867 |
+
"180": [0, 0.69444, 0, 0],
|
868 |
+
"215": [0.08333, 0.58333, 0, 0],
|
869 |
+
"247": [0.08333, 0.58333, 0, 0],
|
870 |
+
"305": [0, 0.43056, 0, 0],
|
871 |
+
"567": [0.19444, 0.43056, 0, 0],
|
872 |
+
"710": [0, 0.69444, 0, 0],
|
873 |
+
"711": [0, 0.62847, 0, 0],
|
874 |
+
"713": [0, 0.56778, 0, 0],
|
875 |
+
"714": [0, 0.69444, 0, 0],
|
876 |
+
"715": [0, 0.69444, 0, 0],
|
877 |
+
"728": [0, 0.69444, 0, 0],
|
878 |
+
"729": [0, 0.66786, 0, 0],
|
879 |
+
"730": [0, 0.69444, 0, 0],
|
880 |
+
"732": [0, 0.66786, 0, 0],
|
881 |
+
"768": [0, 0.69444, 0, 0],
|
882 |
+
"769": [0, 0.69444, 0, 0],
|
883 |
+
"770": [0, 0.69444, 0, 0],
|
884 |
+
"771": [0, 0.66786, 0, 0],
|
885 |
+
"772": [0, 0.56778, 0, 0],
|
886 |
+
"774": [0, 0.69444, 0, 0],
|
887 |
+
"775": [0, 0.66786, 0, 0],
|
888 |
+
"776": [0, 0.66786, 0, 0],
|
889 |
+
"778": [0, 0.69444, 0, 0],
|
890 |
+
"779": [0, 0.69444, 0, 0],
|
891 |
+
"780": [0, 0.62847, 0, 0],
|
892 |
+
"824": [0.19444, 0.69444, 0, 0],
|
893 |
+
"915": [0, 0.68333, 0, 0],
|
894 |
+
"916": [0, 0.68333, 0, 0],
|
895 |
+
"920": [0, 0.68333, 0, 0],
|
896 |
+
"923": [0, 0.68333, 0, 0],
|
897 |
+
"926": [0, 0.68333, 0, 0],
|
898 |
+
"928": [0, 0.68333, 0, 0],
|
899 |
+
"931": [0, 0.68333, 0, 0],
|
900 |
+
"933": [0, 0.68333, 0, 0],
|
901 |
+
"934": [0, 0.68333, 0, 0],
|
902 |
+
"936": [0, 0.68333, 0, 0],
|
903 |
+
"937": [0, 0.68333, 0, 0],
|
904 |
+
"8211": [0, 0.43056, 0.02778, 0],
|
905 |
+
"8212": [0, 0.43056, 0.02778, 0],
|
906 |
+
"8216": [0, 0.69444, 0, 0],
|
907 |
+
"8217": [0, 0.69444, 0, 0],
|
908 |
+
"8220": [0, 0.69444, 0, 0],
|
909 |
+
"8221": [0, 0.69444, 0, 0],
|
910 |
+
"8224": [0.19444, 0.69444, 0, 0],
|
911 |
+
"8225": [0.19444, 0.69444, 0, 0],
|
912 |
+
"8230": [0, 0.12, 0, 0],
|
913 |
+
"8242": [0, 0.55556, 0, 0],
|
914 |
+
"8407": [0, 0.71444, 0.15382, 0],
|
915 |
+
"8463": [0, 0.68889, 0, 0],
|
916 |
+
"8465": [0, 0.69444, 0, 0],
|
917 |
+
"8467": [0, 0.69444, 0, 0.11111],
|
918 |
+
"8472": [0.19444, 0.43056, 0, 0.11111],
|
919 |
+
"8476": [0, 0.69444, 0, 0],
|
920 |
+
"8501": [0, 0.69444, 0, 0],
|
921 |
+
"8592": [-0.13313, 0.36687, 0, 0],
|
922 |
+
"8593": [0.19444, 0.69444, 0, 0],
|
923 |
+
"8594": [-0.13313, 0.36687, 0, 0],
|
924 |
+
"8595": [0.19444, 0.69444, 0, 0],
|
925 |
+
"8596": [-0.13313, 0.36687, 0, 0],
|
926 |
+
"8597": [0.25, 0.75, 0, 0],
|
927 |
+
"8598": [0.19444, 0.69444, 0, 0],
|
928 |
+
"8599": [0.19444, 0.69444, 0, 0],
|
929 |
+
"8600": [0.19444, 0.69444, 0, 0],
|
930 |
+
"8601": [0.19444, 0.69444, 0, 0],
|
931 |
+
"8614": [0.011, 0.511, 0, 0],
|
932 |
+
"8617": [0.011, 0.511, 0, 0],
|
933 |
+
"8618": [0.011, 0.511, 0, 0],
|
934 |
+
"8636": [-0.13313, 0.36687, 0, 0],
|
935 |
+
"8637": [-0.13313, 0.36687, 0, 0],
|
936 |
+
"8640": [-0.13313, 0.36687, 0, 0],
|
937 |
+
"8641": [-0.13313, 0.36687, 0, 0],
|
938 |
+
"8652": [0.011, 0.671, 0, 0],
|
939 |
+
"8656": [-0.13313, 0.36687, 0, 0],
|
940 |
+
"8657": [0.19444, 0.69444, 0, 0],
|
941 |
+
"8658": [-0.13313, 0.36687, 0, 0],
|
942 |
+
"8659": [0.19444, 0.69444, 0, 0],
|
943 |
+
"8660": [-0.13313, 0.36687, 0, 0],
|
944 |
+
"8661": [0.25, 0.75, 0, 0],
|
945 |
+
"8704": [0, 0.69444, 0, 0],
|
946 |
+
"8706": [0, 0.69444, 0.05556, 0.08334],
|
947 |
+
"8707": [0, 0.69444, 0, 0],
|
948 |
+
"8709": [0.05556, 0.75, 0, 0],
|
949 |
+
"8711": [0, 0.68333, 0, 0],
|
950 |
+
"8712": [0.0391, 0.5391, 0, 0],
|
951 |
+
"8715": [0.0391, 0.5391, 0, 0],
|
952 |
+
"8722": [0.08333, 0.58333, 0, 0],
|
953 |
+
"8723": [0.08333, 0.58333, 0, 0],
|
954 |
+
"8725": [0.25, 0.75, 0, 0],
|
955 |
+
"8726": [0.25, 0.75, 0, 0],
|
956 |
+
"8727": [-0.03472, 0.46528, 0, 0],
|
957 |
+
"8728": [-0.05555, 0.44445, 0, 0],
|
958 |
+
"8729": [-0.05555, 0.44445, 0, 0],
|
959 |
+
"8730": [0.2, 0.8, 0, 0],
|
960 |
+
"8733": [0, 0.43056, 0, 0],
|
961 |
+
"8734": [0, 0.43056, 0, 0],
|
962 |
+
"8736": [0, 0.69224, 0, 0],
|
963 |
+
"8739": [0.25, 0.75, 0, 0],
|
964 |
+
"8741": [0.25, 0.75, 0, 0],
|
965 |
+
"8743": [0, 0.55556, 0, 0],
|
966 |
+
"8744": [0, 0.55556, 0, 0],
|
967 |
+
"8745": [0, 0.55556, 0, 0],
|
968 |
+
"8746": [0, 0.55556, 0, 0],
|
969 |
+
"8747": [0.19444, 0.69444, 0.11111, 0],
|
970 |
+
"8764": [-0.13313, 0.36687, 0, 0],
|
971 |
+
"8768": [0.19444, 0.69444, 0, 0],
|
972 |
+
"8771": [-0.03625, 0.46375, 0, 0],
|
973 |
+
"8773": [-0.022, 0.589, 0, 0],
|
974 |
+
"8776": [-0.01688, 0.48312, 0, 0],
|
975 |
+
"8781": [-0.03625, 0.46375, 0, 0],
|
976 |
+
"8784": [-0.133, 0.67, 0, 0],
|
977 |
+
"8800": [0.215, 0.716, 0, 0],
|
978 |
+
"8801": [-0.03625, 0.46375, 0, 0],
|
979 |
+
"8804": [0.13597, 0.63597, 0, 0],
|
980 |
+
"8805": [0.13597, 0.63597, 0, 0],
|
981 |
+
"8810": [0.0391, 0.5391, 0, 0],
|
982 |
+
"8811": [0.0391, 0.5391, 0, 0],
|
983 |
+
"8826": [0.0391, 0.5391, 0, 0],
|
984 |
+
"8827": [0.0391, 0.5391, 0, 0],
|
985 |
+
"8834": [0.0391, 0.5391, 0, 0],
|
986 |
+
"8835": [0.0391, 0.5391, 0, 0],
|
987 |
+
"8838": [0.13597, 0.63597, 0, 0],
|
988 |
+
"8839": [0.13597, 0.63597, 0, 0],
|
989 |
+
"8846": [0, 0.55556, 0, 0],
|
990 |
+
"8849": [0.13597, 0.63597, 0, 0],
|
991 |
+
"8850": [0.13597, 0.63597, 0, 0],
|
992 |
+
"8851": [0, 0.55556, 0, 0],
|
993 |
+
"8852": [0, 0.55556, 0, 0],
|
994 |
+
"8853": [0.08333, 0.58333, 0, 0],
|
995 |
+
"8854": [0.08333, 0.58333, 0, 0],
|
996 |
+
"8855": [0.08333, 0.58333, 0, 0],
|
997 |
+
"8856": [0.08333, 0.58333, 0, 0],
|
998 |
+
"8857": [0.08333, 0.58333, 0, 0],
|
999 |
+
"8866": [0, 0.69444, 0, 0],
|
1000 |
+
"8867": [0, 0.69444, 0, 0],
|
1001 |
+
"8868": [0, 0.69444, 0, 0],
|
1002 |
+
"8869": [0, 0.69444, 0, 0],
|
1003 |
+
"8872": [0.249, 0.75, 0, 0],
|
1004 |
+
"8900": [-0.05555, 0.44445, 0, 0],
|
1005 |
+
"8901": [-0.05555, 0.44445, 0, 0],
|
1006 |
+
"8902": [-0.03472, 0.46528, 0, 0],
|
1007 |
+
"8904": [0.005, 0.505, 0, 0],
|
1008 |
+
"8942": [0.03, 0.9, 0, 0],
|
1009 |
+
"8943": [-0.19, 0.31, 0, 0],
|
1010 |
+
"8945": [-0.1, 0.82, 0, 0],
|
1011 |
+
"8968": [0.25, 0.75, 0, 0],
|
1012 |
+
"8969": [0.25, 0.75, 0, 0],
|
1013 |
+
"8970": [0.25, 0.75, 0, 0],
|
1014 |
+
"8971": [0.25, 0.75, 0, 0],
|
1015 |
+
"8994": [-0.14236, 0.35764, 0, 0],
|
1016 |
+
"8995": [-0.14236, 0.35764, 0, 0],
|
1017 |
+
"9136": [0.244, 0.744, 0, 0],
|
1018 |
+
"9137": [0.244, 0.744, 0, 0],
|
1019 |
+
"9651": [0.19444, 0.69444, 0, 0],
|
1020 |
+
"9657": [-0.03472, 0.46528, 0, 0],
|
1021 |
+
"9661": [0.19444, 0.69444, 0, 0],
|
1022 |
+
"9667": [-0.03472, 0.46528, 0, 0],
|
1023 |
+
"9711": [0.19444, 0.69444, 0, 0],
|
1024 |
+
"9824": [0.12963, 0.69444, 0, 0],
|
1025 |
+
"9825": [0.12963, 0.69444, 0, 0],
|
1026 |
+
"9826": [0.12963, 0.69444, 0, 0],
|
1027 |
+
"9827": [0.12963, 0.69444, 0, 0],
|
1028 |
+
"9837": [0, 0.75, 0, 0],
|
1029 |
+
"9838": [0.19444, 0.69444, 0, 0],
|
1030 |
+
"9839": [0.19444, 0.69444, 0, 0],
|
1031 |
+
"10216": [0.25, 0.75, 0, 0],
|
1032 |
+
"10217": [0.25, 0.75, 0, 0],
|
1033 |
+
"10222": [0.244, 0.744, 0, 0],
|
1034 |
+
"10223": [0.244, 0.744, 0, 0],
|
1035 |
+
"10229": [0.011, 0.511, 0, 0],
|
1036 |
+
"10230": [0.011, 0.511, 0, 0],
|
1037 |
+
"10231": [0.011, 0.511, 0, 0],
|
1038 |
+
"10232": [0.024, 0.525, 0, 0],
|
1039 |
+
"10233": [0.024, 0.525, 0, 0],
|
1040 |
+
"10234": [0.024, 0.525, 0, 0],
|
1041 |
+
"10236": [0.011, 0.511, 0, 0],
|
1042 |
+
"10815": [0, 0.68333, 0, 0],
|
1043 |
+
"10927": [0.13597, 0.63597, 0, 0],
|
1044 |
+
"10928": [0.13597, 0.63597, 0, 0],
|
1045 |
+
},
|
1046 |
+
"Math-BoldItalic": {
|
1047 |
+
"47": [0.19444, 0.69444, 0, 0],
|
1048 |
+
"65": [0, 0.68611, 0, 0],
|
1049 |
+
"66": [0, 0.68611, 0.04835, 0],
|
1050 |
+
"67": [0, 0.68611, 0.06979, 0],
|
1051 |
+
"68": [0, 0.68611, 0.03194, 0],
|
1052 |
+
"69": [0, 0.68611, 0.05451, 0],
|
1053 |
+
"70": [0, 0.68611, 0.15972, 0],
|
1054 |
+
"71": [0, 0.68611, 0, 0],
|
1055 |
+
"72": [0, 0.68611, 0.08229, 0],
|
1056 |
+
"73": [0, 0.68611, 0.07778, 0],
|
1057 |
+
"74": [0, 0.68611, 0.10069, 0],
|
1058 |
+
"75": [0, 0.68611, 0.06979, 0],
|
1059 |
+
"76": [0, 0.68611, 0, 0],
|
1060 |
+
"77": [0, 0.68611, 0.11424, 0],
|
1061 |
+
"78": [0, 0.68611, 0.11424, 0],
|
1062 |
+
"79": [0, 0.68611, 0.03194, 0],
|
1063 |
+
"80": [0, 0.68611, 0.15972, 0],
|
1064 |
+
"81": [0.19444, 0.68611, 0, 0],
|
1065 |
+
"82": [0, 0.68611, 0.00421, 0],
|
1066 |
+
"83": [0, 0.68611, 0.05382, 0],
|
1067 |
+
"84": [0, 0.68611, 0.15972, 0],
|
1068 |
+
"85": [0, 0.68611, 0.11424, 0],
|
1069 |
+
"86": [0, 0.68611, 0.25555, 0],
|
1070 |
+
"87": [0, 0.68611, 0.15972, 0],
|
1071 |
+
"88": [0, 0.68611, 0.07778, 0],
|
1072 |
+
"89": [0, 0.68611, 0.25555, 0],
|
1073 |
+
"90": [0, 0.68611, 0.06979, 0],
|
1074 |
+
"97": [0, 0.44444, 0, 0],
|
1075 |
+
"98": [0, 0.69444, 0, 0],
|
1076 |
+
"99": [0, 0.44444, 0, 0],
|
1077 |
+
"100": [0, 0.69444, 0, 0],
|
1078 |
+
"101": [0, 0.44444, 0, 0],
|
1079 |
+
"102": [0.19444, 0.69444, 0.11042, 0],
|
1080 |
+
"103": [0.19444, 0.44444, 0.03704, 0],
|
1081 |
+
"104": [0, 0.69444, 0, 0],
|
1082 |
+
"105": [0, 0.69326, 0, 0],
|
1083 |
+
"106": [0.19444, 0.69326, 0.0622, 0],
|
1084 |
+
"107": [0, 0.69444, 0.01852, 0],
|
1085 |
+
"108": [0, 0.69444, 0.0088, 0],
|
1086 |
+
"109": [0, 0.44444, 0, 0],
|
1087 |
+
"110": [0, 0.44444, 0, 0],
|
1088 |
+
"111": [0, 0.44444, 0, 0],
|
1089 |
+
"112": [0.19444, 0.44444, 0, 0],
|
1090 |
+
"113": [0.19444, 0.44444, 0.03704, 0],
|
1091 |
+
"114": [0, 0.44444, 0.03194, 0],
|
1092 |
+
"115": [0, 0.44444, 0, 0],
|
1093 |
+
"116": [0, 0.63492, 0, 0],
|
1094 |
+
"117": [0, 0.44444, 0, 0],
|
1095 |
+
"118": [0, 0.44444, 0.03704, 0],
|
1096 |
+
"119": [0, 0.44444, 0.02778, 0],
|
1097 |
+
"120": [0, 0.44444, 0, 0],
|
1098 |
+
"121": [0.19444, 0.44444, 0.03704, 0],
|
1099 |
+
"122": [0, 0.44444, 0.04213, 0],
|
1100 |
+
"915": [0, 0.68611, 0.15972, 0],
|
1101 |
+
"916": [0, 0.68611, 0, 0],
|
1102 |
+
"920": [0, 0.68611, 0.03194, 0],
|
1103 |
+
"923": [0, 0.68611, 0, 0],
|
1104 |
+
"926": [0, 0.68611, 0.07458, 0],
|
1105 |
+
"928": [0, 0.68611, 0.08229, 0],
|
1106 |
+
"931": [0, 0.68611, 0.05451, 0],
|
1107 |
+
"933": [0, 0.68611, 0.15972, 0],
|
1108 |
+
"934": [0, 0.68611, 0, 0],
|
1109 |
+
"936": [0, 0.68611, 0.11653, 0],
|
1110 |
+
"937": [0, 0.68611, 0.04835, 0],
|
1111 |
+
"945": [0, 0.44444, 0, 0],
|
1112 |
+
"946": [0.19444, 0.69444, 0.03403, 0],
|
1113 |
+
"947": [0.19444, 0.44444, 0.06389, 0],
|
1114 |
+
"948": [0, 0.69444, 0.03819, 0],
|
1115 |
+
"949": [0, 0.44444, 0, 0],
|
1116 |
+
"950": [0.19444, 0.69444, 0.06215, 0],
|
1117 |
+
"951": [0.19444, 0.44444, 0.03704, 0],
|
1118 |
+
"952": [0, 0.69444, 0.03194, 0],
|
1119 |
+
"953": [0, 0.44444, 0, 0],
|
1120 |
+
"954": [0, 0.44444, 0, 0],
|
1121 |
+
"955": [0, 0.69444, 0, 0],
|
1122 |
+
"956": [0.19444, 0.44444, 0, 0],
|
1123 |
+
"957": [0, 0.44444, 0.06898, 0],
|
1124 |
+
"958": [0.19444, 0.69444, 0.03021, 0],
|
1125 |
+
"959": [0, 0.44444, 0, 0],
|
1126 |
+
"960": [0, 0.44444, 0.03704, 0],
|
1127 |
+
"961": [0.19444, 0.44444, 0, 0],
|
1128 |
+
"962": [0.09722, 0.44444, 0.07917, 0],
|
1129 |
+
"963": [0, 0.44444, 0.03704, 0],
|
1130 |
+
"964": [0, 0.44444, 0.13472, 0],
|
1131 |
+
"965": [0, 0.44444, 0.03704, 0],
|
1132 |
+
"966": [0.19444, 0.44444, 0, 0],
|
1133 |
+
"967": [0.19444, 0.44444, 0, 0],
|
1134 |
+
"968": [0.19444, 0.69444, 0.03704, 0],
|
1135 |
+
"969": [0, 0.44444, 0.03704, 0],
|
1136 |
+
"977": [0, 0.69444, 0, 0],
|
1137 |
+
"981": [0.19444, 0.69444, 0, 0],
|
1138 |
+
"982": [0, 0.44444, 0.03194, 0],
|
1139 |
+
"1009": [0.19444, 0.44444, 0, 0],
|
1140 |
+
"1013": [0, 0.44444, 0, 0],
|
1141 |
+
},
|
1142 |
+
"Math-Italic": {
|
1143 |
+
"47": [0.19444, 0.69444, 0, 0],
|
1144 |
+
"65": [0, 0.68333, 0, 0.13889],
|
1145 |
+
"66": [0, 0.68333, 0.05017, 0.08334],
|
1146 |
+
"67": [0, 0.68333, 0.07153, 0.08334],
|
1147 |
+
"68": [0, 0.68333, 0.02778, 0.05556],
|
1148 |
+
"69": [0, 0.68333, 0.05764, 0.08334],
|
1149 |
+
"70": [0, 0.68333, 0.13889, 0.08334],
|
1150 |
+
"71": [0, 0.68333, 0, 0.08334],
|
1151 |
+
"72": [0, 0.68333, 0.08125, 0.05556],
|
1152 |
+
"73": [0, 0.68333, 0.07847, 0.11111],
|
1153 |
+
"74": [0, 0.68333, 0.09618, 0.16667],
|
1154 |
+
"75": [0, 0.68333, 0.07153, 0.05556],
|
1155 |
+
"76": [0, 0.68333, 0, 0.02778],
|
1156 |
+
"77": [0, 0.68333, 0.10903, 0.08334],
|
1157 |
+
"78": [0, 0.68333, 0.10903, 0.08334],
|
1158 |
+
"79": [0, 0.68333, 0.02778, 0.08334],
|
1159 |
+
"80": [0, 0.68333, 0.13889, 0.08334],
|
1160 |
+
"81": [0.19444, 0.68333, 0, 0.08334],
|
1161 |
+
"82": [0, 0.68333, 0.00773, 0.08334],
|
1162 |
+
"83": [0, 0.68333, 0.05764, 0.08334],
|
1163 |
+
"84": [0, 0.68333, 0.13889, 0.08334],
|
1164 |
+
"85": [0, 0.68333, 0.10903, 0.02778],
|
1165 |
+
"86": [0, 0.68333, 0.22222, 0],
|
1166 |
+
"87": [0, 0.68333, 0.13889, 0],
|
1167 |
+
"88": [0, 0.68333, 0.07847, 0.08334],
|
1168 |
+
"89": [0, 0.68333, 0.22222, 0],
|
1169 |
+
"90": [0, 0.68333, 0.07153, 0.08334],
|
1170 |
+
"97": [0, 0.43056, 0, 0],
|
1171 |
+
"98": [0, 0.69444, 0, 0],
|
1172 |
+
"99": [0, 0.43056, 0, 0.05556],
|
1173 |
+
"100": [0, 0.69444, 0, 0.16667],
|
1174 |
+
"101": [0, 0.43056, 0, 0.05556],
|
1175 |
+
"102": [0.19444, 0.69444, 0.10764, 0.16667],
|
1176 |
+
"103": [0.19444, 0.43056, 0.03588, 0.02778],
|
1177 |
+
"104": [0, 0.69444, 0, 0],
|
1178 |
+
"105": [0, 0.65952, 0, 0],
|
1179 |
+
"106": [0.19444, 0.65952, 0.05724, 0],
|
1180 |
+
"107": [0, 0.69444, 0.03148, 0],
|
1181 |
+
"108": [0, 0.69444, 0.01968, 0.08334],
|
1182 |
+
"109": [0, 0.43056, 0, 0],
|
1183 |
+
"110": [0, 0.43056, 0, 0],
|
1184 |
+
"111": [0, 0.43056, 0, 0.05556],
|
1185 |
+
"112": [0.19444, 0.43056, 0, 0.08334],
|
1186 |
+
"113": [0.19444, 0.43056, 0.03588, 0.08334],
|
1187 |
+
"114": [0, 0.43056, 0.02778, 0.05556],
|
1188 |
+
"115": [0, 0.43056, 0, 0.05556],
|
1189 |
+
"116": [0, 0.61508, 0, 0.08334],
|
1190 |
+
"117": [0, 0.43056, 0, 0.02778],
|
1191 |
+
"118": [0, 0.43056, 0.03588, 0.02778],
|
1192 |
+
"119": [0, 0.43056, 0.02691, 0.08334],
|
1193 |
+
"120": [0, 0.43056, 0, 0.02778],
|
1194 |
+
"121": [0.19444, 0.43056, 0.03588, 0.05556],
|
1195 |
+
"122": [0, 0.43056, 0.04398, 0.05556],
|
1196 |
+
"915": [0, 0.68333, 0.13889, 0.08334],
|
1197 |
+
"916": [0, 0.68333, 0, 0.16667],
|
1198 |
+
"920": [0, 0.68333, 0.02778, 0.08334],
|
1199 |
+
"923": [0, 0.68333, 0, 0.16667],
|
1200 |
+
"926": [0, 0.68333, 0.07569, 0.08334],
|
1201 |
+
"928": [0, 0.68333, 0.08125, 0.05556],
|
1202 |
+
"931": [0, 0.68333, 0.05764, 0.08334],
|
1203 |
+
"933": [0, 0.68333, 0.13889, 0.05556],
|
1204 |
+
"934": [0, 0.68333, 0, 0.08334],
|
1205 |
+
"936": [0, 0.68333, 0.11, 0.05556],
|
1206 |
+
"937": [0, 0.68333, 0.05017, 0.08334],
|
1207 |
+
"945": [0, 0.43056, 0.0037, 0.02778],
|
1208 |
+
"946": [0.19444, 0.69444, 0.05278, 0.08334],
|
1209 |
+
"947": [0.19444, 0.43056, 0.05556, 0],
|
1210 |
+
"948": [0, 0.69444, 0.03785, 0.05556],
|
1211 |
+
"949": [0, 0.43056, 0, 0.08334],
|
1212 |
+
"950": [0.19444, 0.69444, 0.07378, 0.08334],
|
1213 |
+
"951": [0.19444, 0.43056, 0.03588, 0.05556],
|
1214 |
+
"952": [0, 0.69444, 0.02778, 0.08334],
|
1215 |
+
"953": [0, 0.43056, 0, 0.05556],
|
1216 |
+
"954": [0, 0.43056, 0, 0],
|
1217 |
+
"955": [0, 0.69444, 0, 0],
|
1218 |
+
"956": [0.19444, 0.43056, 0, 0.02778],
|
1219 |
+
"957": [0, 0.43056, 0.06366, 0.02778],
|
1220 |
+
"958": [0.19444, 0.69444, 0.04601, 0.11111],
|
1221 |
+
"959": [0, 0.43056, 0, 0.05556],
|
1222 |
+
"960": [0, 0.43056, 0.03588, 0],
|
1223 |
+
"961": [0.19444, 0.43056, 0, 0.08334],
|
1224 |
+
"962": [0.09722, 0.43056, 0.07986, 0.08334],
|
1225 |
+
"963": [0, 0.43056, 0.03588, 0],
|
1226 |
+
"964": [0, 0.43056, 0.1132, 0.02778],
|
1227 |
+
"965": [0, 0.43056, 0.03588, 0.02778],
|
1228 |
+
"966": [0.19444, 0.43056, 0, 0.08334],
|
1229 |
+
"967": [0.19444, 0.43056, 0, 0.05556],
|
1230 |
+
"968": [0.19444, 0.69444, 0.03588, 0.11111],
|
1231 |
+
"969": [0, 0.43056, 0.03588, 0],
|
1232 |
+
"977": [0, 0.69444, 0, 0.08334],
|
1233 |
+
"981": [0.19444, 0.69444, 0, 0.08334],
|
1234 |
+
"982": [0, 0.43056, 0.02778, 0],
|
1235 |
+
"1009": [0.19444, 0.43056, 0, 0.08334],
|
1236 |
+
"1013": [0, 0.43056, 0, 0.05556],
|
1237 |
+
},
|
1238 |
+
"Math-Regular": {
|
1239 |
+
"65": [0, 0.68333, 0, 0.13889],
|
1240 |
+
"66": [0, 0.68333, 0.05017, 0.08334],
|
1241 |
+
"67": [0, 0.68333, 0.07153, 0.08334],
|
1242 |
+
"68": [0, 0.68333, 0.02778, 0.05556],
|
1243 |
+
"69": [0, 0.68333, 0.05764, 0.08334],
|
1244 |
+
"70": [0, 0.68333, 0.13889, 0.08334],
|
1245 |
+
"71": [0, 0.68333, 0, 0.08334],
|
1246 |
+
"72": [0, 0.68333, 0.08125, 0.05556],
|
1247 |
+
"73": [0, 0.68333, 0.07847, 0.11111],
|
1248 |
+
"74": [0, 0.68333, 0.09618, 0.16667],
|
1249 |
+
"75": [0, 0.68333, 0.07153, 0.05556],
|
1250 |
+
"76": [0, 0.68333, 0, 0.02778],
|
1251 |
+
"77": [0, 0.68333, 0.10903, 0.08334],
|
1252 |
+
"78": [0, 0.68333, 0.10903, 0.08334],
|
1253 |
+
"79": [0, 0.68333, 0.02778, 0.08334],
|
1254 |
+
"80": [0, 0.68333, 0.13889, 0.08334],
|
1255 |
+
"81": [0.19444, 0.68333, 0, 0.08334],
|
1256 |
+
"82": [0, 0.68333, 0.00773, 0.08334],
|
1257 |
+
"83": [0, 0.68333, 0.05764, 0.08334],
|
1258 |
+
"84": [0, 0.68333, 0.13889, 0.08334],
|
1259 |
+
"85": [0, 0.68333, 0.10903, 0.02778],
|
1260 |
+
"86": [0, 0.68333, 0.22222, 0],
|
1261 |
+
"87": [0, 0.68333, 0.13889, 0],
|
1262 |
+
"88": [0, 0.68333, 0.07847, 0.08334],
|
1263 |
+
"89": [0, 0.68333, 0.22222, 0],
|
1264 |
+
"90": [0, 0.68333, 0.07153, 0.08334],
|
1265 |
+
"97": [0, 0.43056, 0, 0],
|
1266 |
+
"98": [0, 0.69444, 0, 0],
|
1267 |
+
"99": [0, 0.43056, 0, 0.05556],
|
1268 |
+
"100": [0, 0.69444, 0, 0.16667],
|
1269 |
+
"101": [0, 0.43056, 0, 0.05556],
|
1270 |
+
"102": [0.19444, 0.69444, 0.10764, 0.16667],
|
1271 |
+
"103": [0.19444, 0.43056, 0.03588, 0.02778],
|
1272 |
+
"104": [0, 0.69444, 0, 0],
|
1273 |
+
"105": [0, 0.65952, 0, 0],
|
1274 |
+
"106": [0.19444, 0.65952, 0.05724, 0],
|
1275 |
+
"107": [0, 0.69444, 0.03148, 0],
|
1276 |
+
"108": [0, 0.69444, 0.01968, 0.08334],
|
1277 |
+
"109": [0, 0.43056, 0, 0],
|
1278 |
+
"110": [0, 0.43056, 0, 0],
|
1279 |
+
"111": [0, 0.43056, 0, 0.05556],
|
1280 |
+
"112": [0.19444, 0.43056, 0, 0.08334],
|
1281 |
+
"113": [0.19444, 0.43056, 0.03588, 0.08334],
|
1282 |
+
"114": [0, 0.43056, 0.02778, 0.05556],
|
1283 |
+
"115": [0, 0.43056, 0, 0.05556],
|
1284 |
+
"116": [0, 0.61508, 0, 0.08334],
|
1285 |
+
"117": [0, 0.43056, 0, 0.02778],
|
1286 |
+
"118": [0, 0.43056, 0.03588, 0.02778],
|
1287 |
+
"119": [0, 0.43056, 0.02691, 0.08334],
|
1288 |
+
"120": [0, 0.43056, 0, 0.02778],
|
1289 |
+
"121": [0.19444, 0.43056, 0.03588, 0.05556],
|
1290 |
+
"122": [0, 0.43056, 0.04398, 0.05556],
|
1291 |
+
"915": [0, 0.68333, 0.13889, 0.08334],
|
1292 |
+
"916": [0, 0.68333, 0, 0.16667],
|
1293 |
+
"920": [0, 0.68333, 0.02778, 0.08334],
|
1294 |
+
"923": [0, 0.68333, 0, 0.16667],
|
1295 |
+
"926": [0, 0.68333, 0.07569, 0.08334],
|
1296 |
+
"928": [0, 0.68333, 0.08125, 0.05556],
|
1297 |
+
"931": [0, 0.68333, 0.05764, 0.08334],
|
1298 |
+
"933": [0, 0.68333, 0.13889, 0.05556],
|
1299 |
+
"934": [0, 0.68333, 0, 0.08334],
|
1300 |
+
"936": [0, 0.68333, 0.11, 0.05556],
|
1301 |
+
"937": [0, 0.68333, 0.05017, 0.08334],
|
1302 |
+
"945": [0, 0.43056, 0.0037, 0.02778],
|
1303 |
+
"946": [0.19444, 0.69444, 0.05278, 0.08334],
|
1304 |
+
"947": [0.19444, 0.43056, 0.05556, 0],
|
1305 |
+
"948": [0, 0.69444, 0.03785, 0.05556],
|
1306 |
+
"949": [0, 0.43056, 0, 0.08334],
|
1307 |
+
"950": [0.19444, 0.69444, 0.07378, 0.08334],
|
1308 |
+
"951": [0.19444, 0.43056, 0.03588, 0.05556],
|
1309 |
+
"952": [0, 0.69444, 0.02778, 0.08334],
|
1310 |
+
"953": [0, 0.43056, 0, 0.05556],
|
1311 |
+
"954": [0, 0.43056, 0, 0],
|
1312 |
+
"955": [0, 0.69444, 0, 0],
|
1313 |
+
"956": [0.19444, 0.43056, 0, 0.02778],
|
1314 |
+
"957": [0, 0.43056, 0.06366, 0.02778],
|
1315 |
+
"958": [0.19444, 0.69444, 0.04601, 0.11111],
|
1316 |
+
"959": [0, 0.43056, 0, 0.05556],
|
1317 |
+
"960": [0, 0.43056, 0.03588, 0],
|
1318 |
+
"961": [0.19444, 0.43056, 0, 0.08334],
|
1319 |
+
"962": [0.09722, 0.43056, 0.07986, 0.08334],
|
1320 |
+
"963": [0, 0.43056, 0.03588, 0],
|
1321 |
+
"964": [0, 0.43056, 0.1132, 0.02778],
|
1322 |
+
"965": [0, 0.43056, 0.03588, 0.02778],
|
1323 |
+
"966": [0.19444, 0.43056, 0, 0.08334],
|
1324 |
+
"967": [0.19444, 0.43056, 0, 0.05556],
|
1325 |
+
"968": [0.19444, 0.69444, 0.03588, 0.11111],
|
1326 |
+
"969": [0, 0.43056, 0.03588, 0],
|
1327 |
+
"977": [0, 0.69444, 0, 0.08334],
|
1328 |
+
"981": [0.19444, 0.69444, 0, 0.08334],
|
1329 |
+
"982": [0, 0.43056, 0.02778, 0],
|
1330 |
+
"1009": [0.19444, 0.43056, 0, 0.08334],
|
1331 |
+
"1013": [0, 0.43056, 0, 0.05556],
|
1332 |
+
},
|
1333 |
+
"SansSerif-Regular": {
|
1334 |
+
"33": [0, 0.69444, 0, 0],
|
1335 |
+
"34": [0, 0.69444, 0, 0],
|
1336 |
+
"35": [0.19444, 0.69444, 0, 0],
|
1337 |
+
"36": [0.05556, 0.75, 0, 0],
|
1338 |
+
"37": [0.05556, 0.75, 0, 0],
|
1339 |
+
"38": [0, 0.69444, 0, 0],
|
1340 |
+
"39": [0, 0.69444, 0, 0],
|
1341 |
+
"40": [0.25, 0.75, 0, 0],
|
1342 |
+
"41": [0.25, 0.75, 0, 0],
|
1343 |
+
"42": [0, 0.75, 0, 0],
|
1344 |
+
"43": [0.08333, 0.58333, 0, 0],
|
1345 |
+
"44": [0.125, 0.08333, 0, 0],
|
1346 |
+
"45": [0, 0.44444, 0, 0],
|
1347 |
+
"46": [0, 0.08333, 0, 0],
|
1348 |
+
"47": [0.25, 0.75, 0, 0],
|
1349 |
+
"48": [0, 0.65556, 0, 0],
|
1350 |
+
"49": [0, 0.65556, 0, 0],
|
1351 |
+
"50": [0, 0.65556, 0, 0],
|
1352 |
+
"51": [0, 0.65556, 0, 0],
|
1353 |
+
"52": [0, 0.65556, 0, 0],
|
1354 |
+
"53": [0, 0.65556, 0, 0],
|
1355 |
+
"54": [0, 0.65556, 0, 0],
|
1356 |
+
"55": [0, 0.65556, 0, 0],
|
1357 |
+
"56": [0, 0.65556, 0, 0],
|
1358 |
+
"57": [0, 0.65556, 0, 0],
|
1359 |
+
"58": [0, 0.44444, 0, 0],
|
1360 |
+
"59": [0.125, 0.44444, 0, 0],
|
1361 |
+
"61": [-0.13, 0.37, 0, 0],
|
1362 |
+
"63": [0, 0.69444, 0, 0],
|
1363 |
+
"64": [0, 0.69444, 0, 0],
|
1364 |
+
"65": [0, 0.69444, 0, 0],
|
1365 |
+
"66": [0, 0.69444, 0, 0],
|
1366 |
+
"67": [0, 0.69444, 0, 0],
|
1367 |
+
"68": [0, 0.69444, 0, 0],
|
1368 |
+
"69": [0, 0.69444, 0, 0],
|
1369 |
+
"70": [0, 0.69444, 0, 0],
|
1370 |
+
"71": [0, 0.69444, 0, 0],
|
1371 |
+
"72": [0, 0.69444, 0, 0],
|
1372 |
+
"73": [0, 0.69444, 0, 0],
|
1373 |
+
"74": [0, 0.69444, 0, 0],
|
1374 |
+
"75": [0, 0.69444, 0, 0],
|
1375 |
+
"76": [0, 0.69444, 0, 0],
|
1376 |
+
"77": [0, 0.69444, 0, 0],
|
1377 |
+
"78": [0, 0.69444, 0, 0],
|
1378 |
+
"79": [0, 0.69444, 0, 0],
|
1379 |
+
"80": [0, 0.69444, 0, 0],
|
1380 |
+
"81": [0.125, 0.69444, 0, 0],
|
1381 |
+
"82": [0, 0.69444, 0, 0],
|
1382 |
+
"83": [0, 0.69444, 0, 0],
|
1383 |
+
"84": [0, 0.69444, 0, 0],
|
1384 |
+
"85": [0, 0.69444, 0, 0],
|
1385 |
+
"86": [0, 0.69444, 0.01389, 0],
|
1386 |
+
"87": [0, 0.69444, 0.01389, 0],
|
1387 |
+
"88": [0, 0.69444, 0, 0],
|
1388 |
+
"89": [0, 0.69444, 0.025, 0],
|
1389 |
+
"90": [0, 0.69444, 0, 0],
|
1390 |
+
"91": [0.25, 0.75, 0, 0],
|
1391 |
+
"93": [0.25, 0.75, 0, 0],
|
1392 |
+
"94": [0, 0.69444, 0, 0],
|
1393 |
+
"95": [0.35, 0.09444, 0.02778, 0],
|
1394 |
+
"97": [0, 0.44444, 0, 0],
|
1395 |
+
"98": [0, 0.69444, 0, 0],
|
1396 |
+
"99": [0, 0.44444, 0, 0],
|
1397 |
+
"100": [0, 0.69444, 0, 0],
|
1398 |
+
"101": [0, 0.44444, 0, 0],
|
1399 |
+
"102": [0, 0.69444, 0.06944, 0],
|
1400 |
+
"103": [0.19444, 0.44444, 0.01389, 0],
|
1401 |
+
"104": [0, 0.69444, 0, 0],
|
1402 |
+
"105": [0, 0.67937, 0, 0],
|
1403 |
+
"106": [0.19444, 0.67937, 0, 0],
|
1404 |
+
"107": [0, 0.69444, 0, 0],
|
1405 |
+
"108": [0, 0.69444, 0, 0],
|
1406 |
+
"109": [0, 0.44444, 0, 0],
|
1407 |
+
"110": [0, 0.44444, 0, 0],
|
1408 |
+
"111": [0, 0.44444, 0, 0],
|
1409 |
+
"112": [0.19444, 0.44444, 0, 0],
|
1410 |
+
"113": [0.19444, 0.44444, 0, 0],
|
1411 |
+
"114": [0, 0.44444, 0.01389, 0],
|
1412 |
+
"115": [0, 0.44444, 0, 0],
|
1413 |
+
"116": [0, 0.57143, 0, 0],
|
1414 |
+
"117": [0, 0.44444, 0, 0],
|
1415 |
+
"118": [0, 0.44444, 0.01389, 0],
|
1416 |
+
"119": [0, 0.44444, 0.01389, 0],
|
1417 |
+
"120": [0, 0.44444, 0, 0],
|
1418 |
+
"121": [0.19444, 0.44444, 0.01389, 0],
|
1419 |
+
"122": [0, 0.44444, 0, 0],
|
1420 |
+
"126": [0.35, 0.32659, 0, 0],
|
1421 |
+
"305": [0, 0.44444, 0, 0],
|
1422 |
+
"567": [0.19444, 0.44444, 0, 0],
|
1423 |
+
"768": [0, 0.69444, 0, 0],
|
1424 |
+
"769": [0, 0.69444, 0, 0],
|
1425 |
+
"770": [0, 0.69444, 0, 0],
|
1426 |
+
"771": [0, 0.67659, 0, 0],
|
1427 |
+
"772": [0, 0.60889, 0, 0],
|
1428 |
+
"774": [0, 0.69444, 0, 0],
|
1429 |
+
"775": [0, 0.67937, 0, 0],
|
1430 |
+
"776": [0, 0.67937, 0, 0],
|
1431 |
+
"778": [0, 0.69444, 0, 0],
|
1432 |
+
"779": [0, 0.69444, 0, 0],
|
1433 |
+
"780": [0, 0.63194, 0, 0],
|
1434 |
+
"915": [0, 0.69444, 0, 0],
|
1435 |
+
"916": [0, 0.69444, 0, 0],
|
1436 |
+
"920": [0, 0.69444, 0, 0],
|
1437 |
+
"923": [0, 0.69444, 0, 0],
|
1438 |
+
"926": [0, 0.69444, 0, 0],
|
1439 |
+
"928": [0, 0.69444, 0, 0],
|
1440 |
+
"931": [0, 0.69444, 0, 0],
|
1441 |
+
"933": [0, 0.69444, 0, 0],
|
1442 |
+
"934": [0, 0.69444, 0, 0],
|
1443 |
+
"936": [0, 0.69444, 0, 0],
|
1444 |
+
"937": [0, 0.69444, 0, 0],
|
1445 |
+
"8211": [0, 0.44444, 0.02778, 0],
|
1446 |
+
"8212": [0, 0.44444, 0.02778, 0],
|
1447 |
+
"8216": [0, 0.69444, 0, 0],
|
1448 |
+
"8217": [0, 0.69444, 0, 0],
|
1449 |
+
"8220": [0, 0.69444, 0, 0],
|
1450 |
+
"8221": [0, 0.69444, 0, 0],
|
1451 |
+
},
|
1452 |
+
"Script-Regular": {
|
1453 |
+
"65": [0, 0.7, 0.22925, 0],
|
1454 |
+
"66": [0, 0.7, 0.04087, 0],
|
1455 |
+
"67": [0, 0.7, 0.1689, 0],
|
1456 |
+
"68": [0, 0.7, 0.09371, 0],
|
1457 |
+
"69": [0, 0.7, 0.18583, 0],
|
1458 |
+
"70": [0, 0.7, 0.13634, 0],
|
1459 |
+
"71": [0, 0.7, 0.17322, 0],
|
1460 |
+
"72": [0, 0.7, 0.29694, 0],
|
1461 |
+
"73": [0, 0.7, 0.19189, 0],
|
1462 |
+
"74": [0.27778, 0.7, 0.19189, 0],
|
1463 |
+
"75": [0, 0.7, 0.31259, 0],
|
1464 |
+
"76": [0, 0.7, 0.19189, 0],
|
1465 |
+
"77": [0, 0.7, 0.15981, 0],
|
1466 |
+
"78": [0, 0.7, 0.3525, 0],
|
1467 |
+
"79": [0, 0.7, 0.08078, 0],
|
1468 |
+
"80": [0, 0.7, 0.08078, 0],
|
1469 |
+
"81": [0, 0.7, 0.03305, 0],
|
1470 |
+
"82": [0, 0.7, 0.06259, 0],
|
1471 |
+
"83": [0, 0.7, 0.19189, 0],
|
1472 |
+
"84": [0, 0.7, 0.29087, 0],
|
1473 |
+
"85": [0, 0.7, 0.25815, 0],
|
1474 |
+
"86": [0, 0.7, 0.27523, 0],
|
1475 |
+
"87": [0, 0.7, 0.27523, 0],
|
1476 |
+
"88": [0, 0.7, 0.26006, 0],
|
1477 |
+
"89": [0, 0.7, 0.2939, 0],
|
1478 |
+
"90": [0, 0.7, 0.24037, 0],
|
1479 |
+
},
|
1480 |
+
"Size1-Regular": {
|
1481 |
+
"40": [0.35001, 0.85, 0, 0],
|
1482 |
+
"41": [0.35001, 0.85, 0, 0],
|
1483 |
+
"47": [0.35001, 0.85, 0, 0],
|
1484 |
+
"91": [0.35001, 0.85, 0, 0],
|
1485 |
+
"92": [0.35001, 0.85, 0, 0],
|
1486 |
+
"93": [0.35001, 0.85, 0, 0],
|
1487 |
+
"123": [0.35001, 0.85, 0, 0],
|
1488 |
+
"125": [0.35001, 0.85, 0, 0],
|
1489 |
+
"710": [0, 0.72222, 0, 0],
|
1490 |
+
"732": [0, 0.72222, 0, 0],
|
1491 |
+
"770": [0, 0.72222, 0, 0],
|
1492 |
+
"771": [0, 0.72222, 0, 0],
|
1493 |
+
"8214": [-0.00099, 0.601, 0, 0],
|
1494 |
+
"8593": [1e-05, 0.6, 0, 0],
|
1495 |
+
"8595": [1e-05, 0.6, 0, 0],
|
1496 |
+
"8657": [1e-05, 0.6, 0, 0],
|
1497 |
+
"8659": [1e-05, 0.6, 0, 0],
|
1498 |
+
"8719": [0.25001, 0.75, 0, 0],
|
1499 |
+
"8720": [0.25001, 0.75, 0, 0],
|
1500 |
+
"8721": [0.25001, 0.75, 0, 0],
|
1501 |
+
"8730": [0.35001, 0.85, 0, 0],
|
1502 |
+
"8739": [-0.00599, 0.606, 0, 0],
|
1503 |
+
"8741": [-0.00599, 0.606, 0, 0],
|
1504 |
+
"8747": [0.30612, 0.805, 0.19445, 0],
|
1505 |
+
"8748": [0.306, 0.805, 0.19445, 0],
|
1506 |
+
"8749": [0.306, 0.805, 0.19445, 0],
|
1507 |
+
"8750": [0.30612, 0.805, 0.19445, 0],
|
1508 |
+
"8896": [0.25001, 0.75, 0, 0],
|
1509 |
+
"8897": [0.25001, 0.75, 0, 0],
|
1510 |
+
"8898": [0.25001, 0.75, 0, 0],
|
1511 |
+
"8899": [0.25001, 0.75, 0, 0],
|
1512 |
+
"8968": [0.35001, 0.85, 0, 0],
|
1513 |
+
"8969": [0.35001, 0.85, 0, 0],
|
1514 |
+
"8970": [0.35001, 0.85, 0, 0],
|
1515 |
+
"8971": [0.35001, 0.85, 0, 0],
|
1516 |
+
"9168": [-0.00099, 0.601, 0, 0],
|
1517 |
+
"10216": [0.35001, 0.85, 0, 0],
|
1518 |
+
"10217": [0.35001, 0.85, 0, 0],
|
1519 |
+
"10752": [0.25001, 0.75, 0, 0],
|
1520 |
+
"10753": [0.25001, 0.75, 0, 0],
|
1521 |
+
"10754": [0.25001, 0.75, 0, 0],
|
1522 |
+
"10756": [0.25001, 0.75, 0, 0],
|
1523 |
+
"10758": [0.25001, 0.75, 0, 0],
|
1524 |
+
},
|
1525 |
+
"Size2-Regular": {
|
1526 |
+
"40": [0.65002, 1.15, 0, 0],
|
1527 |
+
"41": [0.65002, 1.15, 0, 0],
|
1528 |
+
"47": [0.65002, 1.15, 0, 0],
|
1529 |
+
"91": [0.65002, 1.15, 0, 0],
|
1530 |
+
"92": [0.65002, 1.15, 0, 0],
|
1531 |
+
"93": [0.65002, 1.15, 0, 0],
|
1532 |
+
"123": [0.65002, 1.15, 0, 0],
|
1533 |
+
"125": [0.65002, 1.15, 0, 0],
|
1534 |
+
"710": [0, 0.75, 0, 0],
|
1535 |
+
"732": [0, 0.75, 0, 0],
|
1536 |
+
"770": [0, 0.75, 0, 0],
|
1537 |
+
"771": [0, 0.75, 0, 0],
|
1538 |
+
"8719": [0.55001, 1.05, 0, 0],
|
1539 |
+
"8720": [0.55001, 1.05, 0, 0],
|
1540 |
+
"8721": [0.55001, 1.05, 0, 0],
|
1541 |
+
"8730": [0.65002, 1.15, 0, 0],
|
1542 |
+
"8747": [0.86225, 1.36, 0.44445, 0],
|
1543 |
+
"8748": [0.862, 1.36, 0.44445, 0],
|
1544 |
+
"8749": [0.862, 1.36, 0.44445, 0],
|
1545 |
+
"8750": [0.86225, 1.36, 0.44445, 0],
|
1546 |
+
"8896": [0.55001, 1.05, 0, 0],
|
1547 |
+
"8897": [0.55001, 1.05, 0, 0],
|
1548 |
+
"8898": [0.55001, 1.05, 0, 0],
|
1549 |
+
"8899": [0.55001, 1.05, 0, 0],
|
1550 |
+
"8968": [0.65002, 1.15, 0, 0],
|
1551 |
+
"8969": [0.65002, 1.15, 0, 0],
|
1552 |
+
"8970": [0.65002, 1.15, 0, 0],
|
1553 |
+
"8971": [0.65002, 1.15, 0, 0],
|
1554 |
+
"10216": [0.65002, 1.15, 0, 0],
|
1555 |
+
"10217": [0.65002, 1.15, 0, 0],
|
1556 |
+
"10752": [0.55001, 1.05, 0, 0],
|
1557 |
+
"10753": [0.55001, 1.05, 0, 0],
|
1558 |
+
"10754": [0.55001, 1.05, 0, 0],
|
1559 |
+
"10756": [0.55001, 1.05, 0, 0],
|
1560 |
+
"10758": [0.55001, 1.05, 0, 0],
|
1561 |
+
},
|
1562 |
+
"Size3-Regular": {
|
1563 |
+
"40": [0.95003, 1.45, 0, 0],
|
1564 |
+
"41": [0.95003, 1.45, 0, 0],
|
1565 |
+
"47": [0.95003, 1.45, 0, 0],
|
1566 |
+
"91": [0.95003, 1.45, 0, 0],
|
1567 |
+
"92": [0.95003, 1.45, 0, 0],
|
1568 |
+
"93": [0.95003, 1.45, 0, 0],
|
1569 |
+
"123": [0.95003, 1.45, 0, 0],
|
1570 |
+
"125": [0.95003, 1.45, 0, 0],
|
1571 |
+
"710": [0, 0.75, 0, 0],
|
1572 |
+
"732": [0, 0.75, 0, 0],
|
1573 |
+
"770": [0, 0.75, 0, 0],
|
1574 |
+
"771": [0, 0.75, 0, 0],
|
1575 |
+
"8730": [0.95003, 1.45, 0, 0],
|
1576 |
+
"8968": [0.95003, 1.45, 0, 0],
|
1577 |
+
"8969": [0.95003, 1.45, 0, 0],
|
1578 |
+
"8970": [0.95003, 1.45, 0, 0],
|
1579 |
+
"8971": [0.95003, 1.45, 0, 0],
|
1580 |
+
"10216": [0.95003, 1.45, 0, 0],
|
1581 |
+
"10217": [0.95003, 1.45, 0, 0],
|
1582 |
+
},
|
1583 |
+
"Size4-Regular": {
|
1584 |
+
"40": [1.25003, 1.75, 0, 0],
|
1585 |
+
"41": [1.25003, 1.75, 0, 0],
|
1586 |
+
"47": [1.25003, 1.75, 0, 0],
|
1587 |
+
"91": [1.25003, 1.75, 0, 0],
|
1588 |
+
"92": [1.25003, 1.75, 0, 0],
|
1589 |
+
"93": [1.25003, 1.75, 0, 0],
|
1590 |
+
"123": [1.25003, 1.75, 0, 0],
|
1591 |
+
"125": [1.25003, 1.75, 0, 0],
|
1592 |
+
"710": [0, 0.825, 0, 0],
|
1593 |
+
"732": [0, 0.825, 0, 0],
|
1594 |
+
"770": [0, 0.825, 0, 0],
|
1595 |
+
"771": [0, 0.825, 0, 0],
|
1596 |
+
"8730": [1.25003, 1.75, 0, 0],
|
1597 |
+
"8968": [1.25003, 1.75, 0, 0],
|
1598 |
+
"8969": [1.25003, 1.75, 0, 0],
|
1599 |
+
"8970": [1.25003, 1.75, 0, 0],
|
1600 |
+
"8971": [1.25003, 1.75, 0, 0],
|
1601 |
+
"9115": [0.64502, 1.155, 0, 0],
|
1602 |
+
"9116": [1e-05, 0.6, 0, 0],
|
1603 |
+
"9117": [0.64502, 1.155, 0, 0],
|
1604 |
+
"9118": [0.64502, 1.155, 0, 0],
|
1605 |
+
"9119": [1e-05, 0.6, 0, 0],
|
1606 |
+
"9120": [0.64502, 1.155, 0, 0],
|
1607 |
+
"9121": [0.64502, 1.155, 0, 0],
|
1608 |
+
"9122": [-0.00099, 0.601, 0, 0],
|
1609 |
+
"9123": [0.64502, 1.155, 0, 0],
|
1610 |
+
"9124": [0.64502, 1.155, 0, 0],
|
1611 |
+
"9125": [-0.00099, 0.601, 0, 0],
|
1612 |
+
"9126": [0.64502, 1.155, 0, 0],
|
1613 |
+
"9127": [1e-05, 0.9, 0, 0],
|
1614 |
+
"9128": [0.65002, 1.15, 0, 0],
|
1615 |
+
"9129": [0.90001, 0, 0, 0],
|
1616 |
+
"9130": [0, 0.3, 0, 0],
|
1617 |
+
"9131": [1e-05, 0.9, 0, 0],
|
1618 |
+
"9132": [0.65002, 1.15, 0, 0],
|
1619 |
+
"9133": [0.90001, 0, 0, 0],
|
1620 |
+
"9143": [0.88502, 0.915, 0, 0],
|
1621 |
+
"10216": [1.25003, 1.75, 0, 0],
|
1622 |
+
"10217": [1.25003, 1.75, 0, 0],
|
1623 |
+
"57344": [-0.00499, 0.605, 0, 0],
|
1624 |
+
"57345": [-0.00499, 0.605, 0, 0],
|
1625 |
+
"57680": [0, 0.12, 0, 0],
|
1626 |
+
"57681": [0, 0.12, 0, 0],
|
1627 |
+
"57682": [0, 0.12, 0, 0],
|
1628 |
+
"57683": [0, 0.12, 0, 0],
|
1629 |
+
},
|
1630 |
+
"Typewriter-Regular": {
|
1631 |
+
"33": [0, 0.61111, 0, 0],
|
1632 |
+
"34": [0, 0.61111, 0, 0],
|
1633 |
+
"35": [0, 0.61111, 0, 0],
|
1634 |
+
"36": [0.08333, 0.69444, 0, 0],
|
1635 |
+
"37": [0.08333, 0.69444, 0, 0],
|
1636 |
+
"38": [0, 0.61111, 0, 0],
|
1637 |
+
"39": [0, 0.61111, 0, 0],
|
1638 |
+
"40": [0.08333, 0.69444, 0, 0],
|
1639 |
+
"41": [0.08333, 0.69444, 0, 0],
|
1640 |
+
"42": [0, 0.52083, 0, 0],
|
1641 |
+
"43": [-0.08056, 0.53055, 0, 0],
|
1642 |
+
"44": [0.13889, 0.125, 0, 0],
|
1643 |
+
"45": [-0.08056, 0.53055, 0, 0],
|
1644 |
+
"46": [0, 0.125, 0, 0],
|
1645 |
+
"47": [0.08333, 0.69444, 0, 0],
|
1646 |
+
"48": [0, 0.61111, 0, 0],
|
1647 |
+
"49": [0, 0.61111, 0, 0],
|
1648 |
+
"50": [0, 0.61111, 0, 0],
|
1649 |
+
"51": [0, 0.61111, 0, 0],
|
1650 |
+
"52": [0, 0.61111, 0, 0],
|
1651 |
+
"53": [0, 0.61111, 0, 0],
|
1652 |
+
"54": [0, 0.61111, 0, 0],
|
1653 |
+
"55": [0, 0.61111, 0, 0],
|
1654 |
+
"56": [0, 0.61111, 0, 0],
|
1655 |
+
"57": [0, 0.61111, 0, 0],
|
1656 |
+
"58": [0, 0.43056, 0, 0],
|
1657 |
+
"59": [0.13889, 0.43056, 0, 0],
|
1658 |
+
"60": [-0.05556, 0.55556, 0, 0],
|
1659 |
+
"61": [-0.19549, 0.41562, 0, 0],
|
1660 |
+
"62": [-0.05556, 0.55556, 0, 0],
|
1661 |
+
"63": [0, 0.61111, 0, 0],
|
1662 |
+
"64": [0, 0.61111, 0, 0],
|
1663 |
+
"65": [0, 0.61111, 0, 0],
|
1664 |
+
"66": [0, 0.61111, 0, 0],
|
1665 |
+
"67": [0, 0.61111, 0, 0],
|
1666 |
+
"68": [0, 0.61111, 0, 0],
|
1667 |
+
"69": [0, 0.61111, 0, 0],
|
1668 |
+
"70": [0, 0.61111, 0, 0],
|
1669 |
+
"71": [0, 0.61111, 0, 0],
|
1670 |
+
"72": [0, 0.61111, 0, 0],
|
1671 |
+
"73": [0, 0.61111, 0, 0],
|
1672 |
+
"74": [0, 0.61111, 0, 0],
|
1673 |
+
"75": [0, 0.61111, 0, 0],
|
1674 |
+
"76": [0, 0.61111, 0, 0],
|
1675 |
+
"77": [0, 0.61111, 0, 0],
|
1676 |
+
"78": [0, 0.61111, 0, 0],
|
1677 |
+
"79": [0, 0.61111, 0, 0],
|
1678 |
+
"80": [0, 0.61111, 0, 0],
|
1679 |
+
"81": [0.13889, 0.61111, 0, 0],
|
1680 |
+
"82": [0, 0.61111, 0, 0],
|
1681 |
+
"83": [0, 0.61111, 0, 0],
|
1682 |
+
"84": [0, 0.61111, 0, 0],
|
1683 |
+
"85": [0, 0.61111, 0, 0],
|
1684 |
+
"86": [0, 0.61111, 0, 0],
|
1685 |
+
"87": [0, 0.61111, 0, 0],
|
1686 |
+
"88": [0, 0.61111, 0, 0],
|
1687 |
+
"89": [0, 0.61111, 0, 0],
|
1688 |
+
"90": [0, 0.61111, 0, 0],
|
1689 |
+
"91": [0.08333, 0.69444, 0, 0],
|
1690 |
+
"92": [0.08333, 0.69444, 0, 0],
|
1691 |
+
"93": [0.08333, 0.69444, 0, 0],
|
1692 |
+
"94": [0, 0.61111, 0, 0],
|
1693 |
+
"95": [0.09514, 0, 0, 0],
|
1694 |
+
"96": [0, 0.61111, 0, 0],
|
1695 |
+
"97": [0, 0.43056, 0, 0],
|
1696 |
+
"98": [0, 0.61111, 0, 0],
|
1697 |
+
"99": [0, 0.43056, 0, 0],
|
1698 |
+
"100": [0, 0.61111, 0, 0],
|
1699 |
+
"101": [0, 0.43056, 0, 0],
|
1700 |
+
"102": [0, 0.61111, 0, 0],
|
1701 |
+
"103": [0.22222, 0.43056, 0, 0],
|
1702 |
+
"104": [0, 0.61111, 0, 0],
|
1703 |
+
"105": [0, 0.61111, 0, 0],
|
1704 |
+
"106": [0.22222, 0.61111, 0, 0],
|
1705 |
+
"107": [0, 0.61111, 0, 0],
|
1706 |
+
"108": [0, 0.61111, 0, 0],
|
1707 |
+
"109": [0, 0.43056, 0, 0],
|
1708 |
+
"110": [0, 0.43056, 0, 0],
|
1709 |
+
"111": [0, 0.43056, 0, 0],
|
1710 |
+
"112": [0.22222, 0.43056, 0, 0],
|
1711 |
+
"113": [0.22222, 0.43056, 0, 0],
|
1712 |
+
"114": [0, 0.43056, 0, 0],
|
1713 |
+
"115": [0, 0.43056, 0, 0],
|
1714 |
+
"116": [0, 0.55358, 0, 0],
|
1715 |
+
"117": [0, 0.43056, 0, 0],
|
1716 |
+
"118": [0, 0.43056, 0, 0],
|
1717 |
+
"119": [0, 0.43056, 0, 0],
|
1718 |
+
"120": [0, 0.43056, 0, 0],
|
1719 |
+
"121": [0.22222, 0.43056, 0, 0],
|
1720 |
+
"122": [0, 0.43056, 0, 0],
|
1721 |
+
"123": [0.08333, 0.69444, 0, 0],
|
1722 |
+
"124": [0.08333, 0.69444, 0, 0],
|
1723 |
+
"125": [0.08333, 0.69444, 0, 0],
|
1724 |
+
"126": [0, 0.61111, 0, 0],
|
1725 |
+
"127": [0, 0.61111, 0, 0],
|
1726 |
+
"305": [0, 0.43056, 0, 0],
|
1727 |
+
"567": [0.22222, 0.43056, 0, 0],
|
1728 |
+
"768": [0, 0.61111, 0, 0],
|
1729 |
+
"769": [0, 0.61111, 0, 0],
|
1730 |
+
"770": [0, 0.61111, 0, 0],
|
1731 |
+
"771": [0, 0.61111, 0, 0],
|
1732 |
+
"772": [0, 0.56555, 0, 0],
|
1733 |
+
"774": [0, 0.61111, 0, 0],
|
1734 |
+
"776": [0, 0.61111, 0, 0],
|
1735 |
+
"778": [0, 0.61111, 0, 0],
|
1736 |
+
"780": [0, 0.56597, 0, 0],
|
1737 |
+
"915": [0, 0.61111, 0, 0],
|
1738 |
+
"916": [0, 0.61111, 0, 0],
|
1739 |
+
"920": [0, 0.61111, 0, 0],
|
1740 |
+
"923": [0, 0.61111, 0, 0],
|
1741 |
+
"926": [0, 0.61111, 0, 0],
|
1742 |
+
"928": [0, 0.61111, 0, 0],
|
1743 |
+
"931": [0, 0.61111, 0, 0],
|
1744 |
+
"933": [0, 0.61111, 0, 0],
|
1745 |
+
"934": [0, 0.61111, 0, 0],
|
1746 |
+
"936": [0, 0.61111, 0, 0],
|
1747 |
+
"937": [0, 0.61111, 0, 0],
|
1748 |
+
"2018": [0, 0.61111, 0, 0],
|
1749 |
+
"2019": [0, 0.61111, 0, 0],
|
1750 |
+
"8242": [0, 0.61111, 0, 0],
|
1751 |
+
},
|
1752 |
+
};
|
modules/tokenize_latex/third_party/katex/src/functions.js
ADDED
@@ -0,0 +1,585 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var utils = require("./utils");
|
2 |
+
var ParseError = require("./ParseError");
|
3 |
+
|
4 |
+
/* This file contains a list of functions that we parse, identified by
|
5 |
+
* the calls to defineFunction.
|
6 |
+
*
|
7 |
+
* The first argument to defineFunction is a single name or a list of names.
|
8 |
+
* All functions named in such a list will share a single implementation.
|
9 |
+
*
|
10 |
+
* Each declared function can have associated properties, which
|
11 |
+
* include the following:
|
12 |
+
*
|
13 |
+
* - numArgs: The number of arguments the function takes.
|
14 |
+
* If this is the only property, it can be passed as a number
|
15 |
+
* instead of an element of a properties object.
|
16 |
+
* - argTypes: (optional) An array corresponding to each argument of the
|
17 |
+
* function, giving the type of argument that should be parsed. Its
|
18 |
+
* length should be equal to `numArgs + numOptionalArgs`. Valid
|
19 |
+
* types:
|
20 |
+
* - "size": A size-like thing, such as "1em" or "5ex"
|
21 |
+
* - "color": An html color, like "#abc" or "blue"
|
22 |
+
* - "original": The same type as the environment that the
|
23 |
+
* function being parsed is in (e.g. used for the
|
24 |
+
* bodies of functions like \color where the first
|
25 |
+
* argument is special and the second argument is
|
26 |
+
* parsed normally)
|
27 |
+
* Other possible types (probably shouldn't be used)
|
28 |
+
* - "text": Text-like (e.g. \text)
|
29 |
+
* - "math": Normal math
|
30 |
+
* If undefined, this will be treated as an appropriate length
|
31 |
+
* array of "original" strings
|
32 |
+
* - greediness: (optional) The greediness of the function to use ungrouped
|
33 |
+
* arguments.
|
34 |
+
*
|
35 |
+
* E.g. if you have an expression
|
36 |
+
* \sqrt \frac 1 2
|
37 |
+
* since \frac has greediness=2 vs \sqrt's greediness=1, \frac
|
38 |
+
* will use the two arguments '1' and '2' as its two arguments,
|
39 |
+
* then that whole function will be used as the argument to
|
40 |
+
* \sqrt. On the other hand, the expressions
|
41 |
+
* \frac \frac 1 2 3
|
42 |
+
* and
|
43 |
+
* \frac \sqrt 1 2
|
44 |
+
* will fail because \frac and \frac have equal greediness
|
45 |
+
* and \sqrt has a lower greediness than \frac respectively. To
|
46 |
+
* make these parse, we would have to change them to:
|
47 |
+
* \frac {\frac 1 2} 3
|
48 |
+
* and
|
49 |
+
* \frac {\sqrt 1} 2
|
50 |
+
*
|
51 |
+
* The default value is `1`
|
52 |
+
* - allowedInText: (optional) Whether or not the function is allowed inside
|
53 |
+
* text mode (default false)
|
54 |
+
* - numOptionalArgs: (optional) The number of optional arguments the function
|
55 |
+
* should parse. If the optional arguments aren't found,
|
56 |
+
* `null` will be passed to the handler in their place.
|
57 |
+
* (default 0)
|
58 |
+
*
|
59 |
+
* The last argument is that implementation, the handler for the function(s).
|
60 |
+
* It is called to handle these functions and their arguments.
|
61 |
+
* It receives two arguments:
|
62 |
+
* - context contains information and references provided by the parser
|
63 |
+
* - args is an array of arguments obtained from TeX input
|
64 |
+
* The context contains the following properties:
|
65 |
+
* - funcName: the text (i.e. name) of the function, including \
|
66 |
+
* - parser: the parser object
|
67 |
+
* - lexer: the lexer object
|
68 |
+
* - positions: the positions in the overall string of the function
|
69 |
+
* and the arguments.
|
70 |
+
* The latter three should only be used to produce error messages.
|
71 |
+
*
|
72 |
+
* The function should return an object with the following keys:
|
73 |
+
* - type: The type of element that this is. This is then used in
|
74 |
+
* buildHTML/buildMathML to determine which function
|
75 |
+
* should be called to build this node into a DOM node
|
76 |
+
* Any other data can be added to the object, which will be passed
|
77 |
+
* in to the function in buildHTML/buildMathML as `group.value`.
|
78 |
+
*/
|
79 |
+
|
80 |
+
function defineFunction(names, props, handler) {
|
81 |
+
if (typeof names === "string") {
|
82 |
+
names = [names];
|
83 |
+
}
|
84 |
+
if (typeof props === "number") {
|
85 |
+
props = { numArgs: props };
|
86 |
+
}
|
87 |
+
// Set default values of functions
|
88 |
+
var data = {
|
89 |
+
numArgs: props.numArgs,
|
90 |
+
argTypes: props.argTypes,
|
91 |
+
greediness: (props.greediness === undefined) ? 1 : props.greediness,
|
92 |
+
allowedInText: !!props.allowedInText,
|
93 |
+
numOptionalArgs: props.numOptionalArgs || 0,
|
94 |
+
handler: handler,
|
95 |
+
};
|
96 |
+
for (var i = 0; i < names.length; ++i) {
|
97 |
+
module.exports[names[i]] = data;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
// A normal square root
|
102 |
+
defineFunction("\\sqrt", {
|
103 |
+
numArgs: 1,
|
104 |
+
numOptionalArgs: 1,
|
105 |
+
}, function(context, args) {
|
106 |
+
var index = args[0];
|
107 |
+
var body = args[1];
|
108 |
+
return {
|
109 |
+
type: "sqrt",
|
110 |
+
body: body,
|
111 |
+
index: index,
|
112 |
+
};
|
113 |
+
});
|
114 |
+
|
115 |
+
// Some non-mathy text
|
116 |
+
defineFunction(["\\text", "\\mbox", "\\hbox", "\\vbox"], {
|
117 |
+
numArgs: 1,
|
118 |
+
argTypes: ["text"],
|
119 |
+
greediness: 2,
|
120 |
+
}, function(context, args) {
|
121 |
+
var body = args[0];
|
122 |
+
// Since the corresponding buildHTML/buildMathML function expects a
|
123 |
+
// list of elements, we normalize for different kinds of arguments
|
124 |
+
// TODO(emily): maybe this should be done somewhere else
|
125 |
+
var inner;
|
126 |
+
if (body.type === "ordgroup") {
|
127 |
+
inner = body.value;
|
128 |
+
} else {
|
129 |
+
inner = [body];
|
130 |
+
}
|
131 |
+
|
132 |
+
return {
|
133 |
+
type: "text",
|
134 |
+
body: inner,
|
135 |
+
};
|
136 |
+
});
|
137 |
+
|
138 |
+
// A two-argument custom color
|
139 |
+
defineFunction("\\color", {
|
140 |
+
numArgs: 2,
|
141 |
+
allowedInText: true,
|
142 |
+
greediness: 3,
|
143 |
+
argTypes: ["color", "original"],
|
144 |
+
}, function(context, args) {
|
145 |
+
var color = args[0];
|
146 |
+
var body = args[1];
|
147 |
+
// Normalize the different kinds of bodies (see \text above)
|
148 |
+
var inner;
|
149 |
+
if (body.type === "ordgroup") {
|
150 |
+
inner = body.value;
|
151 |
+
} else {
|
152 |
+
inner = [body];
|
153 |
+
}
|
154 |
+
|
155 |
+
return {
|
156 |
+
type: "color",
|
157 |
+
color: color.value,
|
158 |
+
value: inner,
|
159 |
+
};
|
160 |
+
});
|
161 |
+
|
162 |
+
// An overline
|
163 |
+
defineFunction("\\overline", {
|
164 |
+
numArgs: 1,
|
165 |
+
}, function(context, args) {
|
166 |
+
var body = args[0];
|
167 |
+
return {
|
168 |
+
type: "overline",
|
169 |
+
body: body,
|
170 |
+
};
|
171 |
+
});
|
172 |
+
|
173 |
+
// An underline
|
174 |
+
defineFunction("\\underline", {
|
175 |
+
numArgs: 1,
|
176 |
+
}, function(context, args) {
|
177 |
+
var body = args[0];
|
178 |
+
return {
|
179 |
+
type: "underline",
|
180 |
+
body: body,
|
181 |
+
};
|
182 |
+
});
|
183 |
+
|
184 |
+
// A box of the width and height
|
185 |
+
defineFunction("\\rule", {
|
186 |
+
numArgs: 2,
|
187 |
+
numOptionalArgs: 1,
|
188 |
+
argTypes: ["size", "size", "size"],
|
189 |
+
}, function(context, args) {
|
190 |
+
var shift = args[0];
|
191 |
+
var width = args[1];
|
192 |
+
var height = args[2];
|
193 |
+
return {
|
194 |
+
type: "rule",
|
195 |
+
shift: shift && shift.value,
|
196 |
+
width: width.value,
|
197 |
+
height: height.value,
|
198 |
+
};
|
199 |
+
});
|
200 |
+
|
201 |
+
// A KaTeX logo
|
202 |
+
defineFunction("\\KaTeX", {
|
203 |
+
numArgs: 0,
|
204 |
+
}, function(context) {
|
205 |
+
return {
|
206 |
+
type: "katex",
|
207 |
+
};
|
208 |
+
});
|
209 |
+
|
210 |
+
defineFunction("\\phantom", {
|
211 |
+
numArgs: 1,
|
212 |
+
}, function(context, args) {
|
213 |
+
var body = args[0];
|
214 |
+
var inner;
|
215 |
+
if (body.type === "ordgroup") {
|
216 |
+
inner = body.value;
|
217 |
+
} else {
|
218 |
+
inner = [body];
|
219 |
+
}
|
220 |
+
|
221 |
+
return {
|
222 |
+
type: "phantom",
|
223 |
+
value: inner,
|
224 |
+
};
|
225 |
+
});
|
226 |
+
|
227 |
+
// Extra data needed for the delimiter handler down below
|
228 |
+
var delimiterSizes = {
|
229 |
+
"\\bigl" : {type: "open", size: 1},
|
230 |
+
"\\Bigl" : {type: "open", size: 2},
|
231 |
+
"\\biggl": {type: "open", size: 3},
|
232 |
+
"\\Biggl": {type: "open", size: 4},
|
233 |
+
"\\bigr" : {type: "close", size: 1},
|
234 |
+
"\\Bigr" : {type: "close", size: 2},
|
235 |
+
"\\biggr": {type: "close", size: 3},
|
236 |
+
"\\Biggr": {type: "close", size: 4},
|
237 |
+
"\\bigm" : {type: "rel", size: 1},
|
238 |
+
"\\Bigm" : {type: "rel", size: 2},
|
239 |
+
"\\biggm": {type: "rel", size: 3},
|
240 |
+
"\\Biggm": {type: "rel", size: 4},
|
241 |
+
"\\big" : {type: "textord", size: 1},
|
242 |
+
"\\Big" : {type: "textord", size: 2},
|
243 |
+
"\\bigg" : {type: "textord", size: 3},
|
244 |
+
"\\Bigg" : {type: "textord", size: 4},
|
245 |
+
};
|
246 |
+
|
247 |
+
var delimiters = [
|
248 |
+
"(", ")", "[", "\\lbrack", "]", "\\rbrack",
|
249 |
+
"\\{", "\\lbrace", "\\}", "\\rbrace",
|
250 |
+
"\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
|
251 |
+
"<", ">", "\\langle", "\\rangle", "\\lt", "\\gt",
|
252 |
+
"\\lvert", "\\rvert", "\\lVert", "\\rVert",
|
253 |
+
"\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
|
254 |
+
"/", "\\backslash",
|
255 |
+
"|", "\\vert", "\\|", "\\Vert",
|
256 |
+
"\\uparrow", "\\Uparrow",
|
257 |
+
"\\downarrow", "\\Downarrow",
|
258 |
+
"\\updownarrow", "\\Updownarrow",
|
259 |
+
".",
|
260 |
+
];
|
261 |
+
|
262 |
+
var fontAliases = {
|
263 |
+
"\\Bbb": "\\mathbb",
|
264 |
+
"\\bold": "\\mathbf",
|
265 |
+
"\\frak": "\\mathfrak",
|
266 |
+
};
|
267 |
+
|
268 |
+
// Single-argument color functions
|
269 |
+
defineFunction([
|
270 |
+
"\\blue", "\\orange", "\\pink", "\\red",
|
271 |
+
"\\green", "\\gray", "\\purple",
|
272 |
+
"\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
|
273 |
+
"\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
|
274 |
+
"\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
|
275 |
+
"\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
|
276 |
+
"\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
|
277 |
+
"\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
|
278 |
+
"\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
|
279 |
+
"\\mintA", "\\mintB", "\\mintC",
|
280 |
+
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
|
281 |
+
"\\grayF", "\\grayG", "\\grayH", "\\grayI",
|
282 |
+
"\\kaBlue", "\\kaGreen",
|
283 |
+
], {
|
284 |
+
numArgs: 1,
|
285 |
+
allowedInText: true,
|
286 |
+
greediness: 3,
|
287 |
+
}, function(context, args) {
|
288 |
+
var body = args[0];
|
289 |
+
var atoms;
|
290 |
+
if (body.type === "ordgroup") {
|
291 |
+
atoms = body.value;
|
292 |
+
} else {
|
293 |
+
atoms = [body];
|
294 |
+
}
|
295 |
+
|
296 |
+
return {
|
297 |
+
type: "color",
|
298 |
+
color: "katex-" + context.funcName.slice(1),
|
299 |
+
value: atoms,
|
300 |
+
};
|
301 |
+
});
|
302 |
+
|
303 |
+
// There are 2 flags for operators; whether they produce limits in
|
304 |
+
// displaystyle, and whether they are symbols and should grow in
|
305 |
+
// displaystyle. These four groups cover the four possible choices.
|
306 |
+
|
307 |
+
// No limits, not symbols
|
308 |
+
defineFunction([
|
309 |
+
"\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh",
|
310 |
+
"\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom",
|
311 |
+
"\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh",
|
312 |
+
"\\tan", "\\tanh",
|
313 |
+
], {
|
314 |
+
numArgs: 0,
|
315 |
+
}, function(context) {
|
316 |
+
return {
|
317 |
+
type: "op",
|
318 |
+
limits: false,
|
319 |
+
symbol: false,
|
320 |
+
body: context.funcName,
|
321 |
+
};
|
322 |
+
});
|
323 |
+
|
324 |
+
// Limits, not symbols
|
325 |
+
defineFunction([
|
326 |
+
"\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
|
327 |
+
"\\min", "\\Pr", "\\sup",
|
328 |
+
], {
|
329 |
+
numArgs: 0,
|
330 |
+
}, function(context) {
|
331 |
+
return {
|
332 |
+
type: "op",
|
333 |
+
limits: true,
|
334 |
+
symbol: false,
|
335 |
+
body: context.funcName,
|
336 |
+
};
|
337 |
+
});
|
338 |
+
|
339 |
+
// No limits, symbols
|
340 |
+
defineFunction([
|
341 |
+
"\\int", "\\iint", "\\iiint", "\\oint",
|
342 |
+
], {
|
343 |
+
numArgs: 0,
|
344 |
+
}, function(context) {
|
345 |
+
return {
|
346 |
+
type: "op",
|
347 |
+
limits: false,
|
348 |
+
symbol: true,
|
349 |
+
body: context.funcName,
|
350 |
+
};
|
351 |
+
});
|
352 |
+
|
353 |
+
// Limits, symbols
|
354 |
+
defineFunction([
|
355 |
+
"\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
|
356 |
+
"\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
|
357 |
+
"\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint",
|
358 |
+
], {
|
359 |
+
numArgs: 0,
|
360 |
+
}, function(context) {
|
361 |
+
return {
|
362 |
+
type: "op",
|
363 |
+
limits: true,
|
364 |
+
symbol: true,
|
365 |
+
body: context.funcName,
|
366 |
+
};
|
367 |
+
});
|
368 |
+
|
369 |
+
// Fractions
|
370 |
+
defineFunction([
|
371 |
+
"\\dfrac", "\\frac", "\\tfrac",
|
372 |
+
"\\dbinom", "\\binom", "\\tbinom",
|
373 |
+
], {
|
374 |
+
numArgs: 2,
|
375 |
+
greediness: 2,
|
376 |
+
}, function(context, args) {
|
377 |
+
var numer = args[0];
|
378 |
+
var denom = args[1];
|
379 |
+
var hasBarLine;
|
380 |
+
var leftDelim = null;
|
381 |
+
var rightDelim = null;
|
382 |
+
var size = "auto";
|
383 |
+
|
384 |
+
switch (context.funcName) {
|
385 |
+
case "\\dfrac":
|
386 |
+
case "\\frac":
|
387 |
+
case "\\tfrac":
|
388 |
+
hasBarLine = true;
|
389 |
+
break;
|
390 |
+
case "\\dbinom":
|
391 |
+
case "\\binom":
|
392 |
+
case "\\tbinom":
|
393 |
+
hasBarLine = false;
|
394 |
+
leftDelim = "(";
|
395 |
+
rightDelim = ")";
|
396 |
+
break;
|
397 |
+
default:
|
398 |
+
throw new Error("Unrecognized genfrac command");
|
399 |
+
}
|
400 |
+
|
401 |
+
switch (context.funcName) {
|
402 |
+
case "\\dfrac":
|
403 |
+
case "\\dbinom":
|
404 |
+
size = "display";
|
405 |
+
break;
|
406 |
+
case "\\tfrac":
|
407 |
+
case "\\tbinom":
|
408 |
+
size = "text";
|
409 |
+
break;
|
410 |
+
}
|
411 |
+
|
412 |
+
return {
|
413 |
+
type: "genfrac",
|
414 |
+
numer: numer,
|
415 |
+
denom: denom,
|
416 |
+
hasBarLine: hasBarLine,
|
417 |
+
leftDelim: leftDelim,
|
418 |
+
rightDelim: rightDelim,
|
419 |
+
size: size,
|
420 |
+
};
|
421 |
+
});
|
422 |
+
|
423 |
+
// Left and right overlap functions
|
424 |
+
defineFunction(["\\llap", "\\rlap"], {
|
425 |
+
numArgs: 1,
|
426 |
+
allowedInText: true,
|
427 |
+
}, function(context, args) {
|
428 |
+
var body = args[0];
|
429 |
+
return {
|
430 |
+
type: context.funcName.slice(1),
|
431 |
+
body: body,
|
432 |
+
};
|
433 |
+
});
|
434 |
+
|
435 |
+
// Delimiter functions
|
436 |
+
defineFunction([
|
437 |
+
"\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
|
438 |
+
"\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
|
439 |
+
"\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
|
440 |
+
"\\big", "\\Big", "\\bigg", "\\Bigg",
|
441 |
+
"\\left", "\\right"
|
442 |
+
], {
|
443 |
+
numArgs: 1,
|
444 |
+
}, function(context, args) {
|
445 |
+
var delim = args[0];
|
446 |
+
if (!utils.contains(delimiters, delim.value)) {
|
447 |
+
throw new ParseError(
|
448 |
+
"Invalid delimiter: '" + delim.value + "' after '" +
|
449 |
+
context.funcName + "'",
|
450 |
+
context.lexer, context.positions[1]);
|
451 |
+
}
|
452 |
+
|
453 |
+
// \left and \right are caught somewhere in Parser.js, which is
|
454 |
+
// why this data doesn't match what is in buildHTML.
|
455 |
+
if (context.funcName === "\\left" || context.funcName === "\\right") {
|
456 |
+
return {
|
457 |
+
type: "leftright",
|
458 |
+
value: delim.value,
|
459 |
+
funcName: context.funcName
|
460 |
+
};
|
461 |
+
} else {
|
462 |
+
return {
|
463 |
+
type: "delimsizing",
|
464 |
+
size: delimiterSizes[context.funcName].size,
|
465 |
+
delimType: delimiterSizes[context.funcName].type,
|
466 |
+
value: delim.value,
|
467 |
+
funcName: context.funcName
|
468 |
+
};
|
469 |
+
}
|
470 |
+
});
|
471 |
+
|
472 |
+
// Sizing functions (handled in Parser.js explicitly, hence no handler)
|
473 |
+
defineFunction([
|
474 |
+
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
|
475 |
+
"\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", "\\textrm", "\\rm", "\\cal", "\\bf", "\\siptstyle", "\\boldmath", "\\it"
|
476 |
+
], 0, null);
|
477 |
+
|
478 |
+
// Style changing functions (handled in Parser.js explicitly, hence no
|
479 |
+
// handler)
|
480 |
+
defineFunction([
|
481 |
+
"\\displaystyle", "\\textstyle", "\\scriptstyle",
|
482 |
+
"\\scriptscriptstyle",
|
483 |
+
], 0, null);
|
484 |
+
|
485 |
+
defineFunction([
|
486 |
+
// styles
|
487 |
+
"\\mathrm", "\\mathit", "\\mathbf","\\mathop","\\stackrel",
|
488 |
+
|
489 |
+
// families
|
490 |
+
"\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
|
491 |
+
"\\mathtt",
|
492 |
+
|
493 |
+
"\\label", "\\comment", "\\hspace", "\\vspace", "\\atop", "\\fbox", "\\tag", "\\makebox",
|
494 |
+
"\\raisebox", "\\framebox", "\\circle", "\\line", "\\put", "\\vphantom", "\\textup", "\\noalign",
|
495 |
+
|
496 |
+
// aliases
|
497 |
+
"\\Bbb", "\\bold", "\\frak",
|
498 |
+
], {
|
499 |
+
numArgs: 1,
|
500 |
+
greediness: 2,
|
501 |
+
}, function(context, args) {
|
502 |
+
var body = args[0];
|
503 |
+
var func = context.funcName;
|
504 |
+
if (func in fontAliases) {
|
505 |
+
func = fontAliases[func];
|
506 |
+
}
|
507 |
+
return {
|
508 |
+
type: "font",
|
509 |
+
font: func.slice(1),
|
510 |
+
body: body,
|
511 |
+
};
|
512 |
+
});
|
513 |
+
|
514 |
+
// Accents
|
515 |
+
defineFunction([
|
516 |
+
"\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
|
517 |
+
"\\check", "\\hat", "\\vec", "\\dot",
|
518 |
+
// We don't support expanding accents yet
|
519 |
+
// "\\widetilde", "\\widehat"
|
520 |
+
], {
|
521 |
+
numArgs: 1,
|
522 |
+
}, function(context, args) {
|
523 |
+
var base = args[0];
|
524 |
+
return {
|
525 |
+
type: "accent",
|
526 |
+
accent: context.funcName,
|
527 |
+
base: base,
|
528 |
+
};
|
529 |
+
});
|
530 |
+
|
531 |
+
// Infix generalized fractions
|
532 |
+
defineFunction(["\\over", "\\choose"], {
|
533 |
+
numArgs: 0,
|
534 |
+
}, function(context) {
|
535 |
+
var replaceWith;
|
536 |
+
switch (context.funcName) {
|
537 |
+
case "\\over":
|
538 |
+
replaceWith = "\\frac";
|
539 |
+
break;
|
540 |
+
case "\\choose":
|
541 |
+
replaceWith = "\\binom";
|
542 |
+
break;
|
543 |
+
default:
|
544 |
+
throw new Error("Unrecognized infix genfrac command");
|
545 |
+
}
|
546 |
+
return {
|
547 |
+
type: "infix",
|
548 |
+
replaceWith: replaceWith,
|
549 |
+
};
|
550 |
+
});
|
551 |
+
|
552 |
+
// Row breaks for aligned data
|
553 |
+
defineFunction(["\\\\", "\\cr"], {
|
554 |
+
numArgs: 0,
|
555 |
+
numOptionalArgs: 1,
|
556 |
+
argTypes: ["size"],
|
557 |
+
}, function(context, args) {
|
558 |
+
var size = args[0];
|
559 |
+
return {
|
560 |
+
type: "cr",
|
561 |
+
size: size,
|
562 |
+
};
|
563 |
+
});
|
564 |
+
|
565 |
+
// Environment delimiters
|
566 |
+
defineFunction(["\\begin", "\\end"], {
|
567 |
+
numArgs: 1,
|
568 |
+
argTypes: ["text"],
|
569 |
+
}, function(context, args) {
|
570 |
+
var nameGroup = args[0];
|
571 |
+
if (nameGroup.type !== "ordgroup") {
|
572 |
+
throw new ParseError(
|
573 |
+
"Invalid environment name",
|
574 |
+
context.lexer, context.positions[1]);
|
575 |
+
}
|
576 |
+
var name = "";
|
577 |
+
for (var i = 0; i < nameGroup.value.length; ++i) {
|
578 |
+
name += nameGroup.value[i].value;
|
579 |
+
}
|
580 |
+
return {
|
581 |
+
type: "environment",
|
582 |
+
name: name,
|
583 |
+
namepos: context.positions[1],
|
584 |
+
};
|
585 |
+
});
|
modules/tokenize_latex/third_party/katex/src/mathMLTree.js
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* These objects store data about MathML nodes. This is the MathML equivalent
|
3 |
+
* of the types in domTree.js. Since MathML handles its own rendering, and
|
4 |
+
* since we're mainly using MathML to improve accessibility, we don't manage
|
5 |
+
* any of the styling state that the plain DOM nodes do.
|
6 |
+
*
|
7 |
+
* The `toNode` and `toMarkup` functions work simlarly to how they do in
|
8 |
+
* domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
|
9 |
+
*/
|
10 |
+
|
11 |
+
var utils = require("./utils");
|
12 |
+
|
13 |
+
/**
|
14 |
+
* This node represents a general purpose MathML node of any type. The
|
15 |
+
* constructor requires the type of node to create (for example, `"mo"` or
|
16 |
+
* `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
|
17 |
+
*/
|
18 |
+
function MathNode(type, children) {
|
19 |
+
this.type = type;
|
20 |
+
this.attributes = {};
|
21 |
+
this.children = children || [];
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Sets an attribute on a MathML node. MathML depends on attributes to convey a
|
26 |
+
* semantic content, so this is used heavily.
|
27 |
+
*/
|
28 |
+
MathNode.prototype.setAttribute = function(name, value) {
|
29 |
+
this.attributes[name] = value;
|
30 |
+
};
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Converts the math node into a MathML-namespaced DOM element.
|
34 |
+
*/
|
35 |
+
MathNode.prototype.toNode = function() {
|
36 |
+
var node = document.createElementNS(
|
37 |
+
"http://www.w3.org/1998/Math/MathML", this.type);
|
38 |
+
|
39 |
+
for (var attr in this.attributes) {
|
40 |
+
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
41 |
+
node.setAttribute(attr, this.attributes[attr]);
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
for (var i = 0; i < this.children.length; i++) {
|
46 |
+
node.appendChild(this.children[i].toNode());
|
47 |
+
}
|
48 |
+
|
49 |
+
return node;
|
50 |
+
};
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Converts the math node into an HTML markup string.
|
54 |
+
*/
|
55 |
+
MathNode.prototype.toMarkup = function() {
|
56 |
+
var markup = "<" + this.type;
|
57 |
+
|
58 |
+
// Add the attributes
|
59 |
+
for (var attr in this.attributes) {
|
60 |
+
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
61 |
+
markup += " " + attr + "=\"";
|
62 |
+
markup += utils.escape(this.attributes[attr]);
|
63 |
+
markup += "\"";
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
markup += ">";
|
68 |
+
|
69 |
+
for (var i = 0; i < this.children.length; i++) {
|
70 |
+
markup += this.children[i].toMarkup();
|
71 |
+
}
|
72 |
+
|
73 |
+
markup += "</" + this.type + ">";
|
74 |
+
|
75 |
+
return markup;
|
76 |
+
};
|
77 |
+
|
78 |
+
/**
|
79 |
+
* This node represents a piece of text.
|
80 |
+
*/
|
81 |
+
function TextNode(text) {
|
82 |
+
this.text = text;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Converts the text node into a DOM text node.
|
87 |
+
*/
|
88 |
+
TextNode.prototype.toNode = function() {
|
89 |
+
return document.createTextNode(this.text);
|
90 |
+
};
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Converts the text node into HTML markup (which is just the text itself).
|
94 |
+
*/
|
95 |
+
TextNode.prototype.toMarkup = function() {
|
96 |
+
return utils.escape(this.text);
|
97 |
+
};
|
98 |
+
|
99 |
+
module.exports = {
|
100 |
+
MathNode: MathNode,
|
101 |
+
TextNode: TextNode,
|
102 |
+
};
|
modules/tokenize_latex/third_party/katex/src/parseData.js
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* The resulting parse tree nodes of the parse tree.
|
3 |
+
*/
|
4 |
+
function ParseNode(type, value, mode) {
|
5 |
+
this.type = type;
|
6 |
+
this.value = value;
|
7 |
+
this.mode = mode;
|
8 |
+
}
|
9 |
+
|
10 |
+
module.exports = {
|
11 |
+
ParseNode: ParseNode,
|
12 |
+
};
|
13 |
+
|
modules/tokenize_latex/third_party/katex/src/parseTree.js
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Provides a single function for parsing an expression using a Parser
|
3 |
+
* TODO(emily): Remove this
|
4 |
+
*/
|
5 |
+
|
6 |
+
var Parser = require("./Parser");
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Parses an expression using a Parser, then returns the parsed result.
|
10 |
+
*/
|
11 |
+
var parseTree = function(toParse, settings) {
|
12 |
+
var parser = new Parser(toParse, settings);
|
13 |
+
|
14 |
+
return parser.parse();
|
15 |
+
};
|
16 |
+
|
17 |
+
module.exports = parseTree;
|
modules/tokenize_latex/third_party/katex/src/symbols.js
ADDED
@@ -0,0 +1,687 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file holds a list of all no-argument functions and single-character
|
3 |
+
* symbols (like 'a' or ';').
|
4 |
+
*
|
5 |
+
* For each of the symbols, there are three properties they can have:
|
6 |
+
* - font (required): the font to be used for this symbol. Either "main" (the
|
7 |
+
normal font), or "ams" (the ams fonts).
|
8 |
+
* - group (required): the ParseNode group type the symbol should have (i.e.
|
9 |
+
"textord", "mathord", etc).
|
10 |
+
See https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
|
11 |
+
* - replace: the character that this symbol or function should be
|
12 |
+
* replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi
|
13 |
+
* character in the main font).
|
14 |
+
*
|
15 |
+
* The outermost map in the table indicates what mode the symbols should be
|
16 |
+
* accepted in (e.g. "math" or "text").
|
17 |
+
*/
|
18 |
+
|
19 |
+
module.exports = {
|
20 |
+
math: {},
|
21 |
+
text: {},
|
22 |
+
};
|
23 |
+
|
24 |
+
function defineSymbol(mode, font, group, replace, name) {
|
25 |
+
module.exports[mode][name] = {
|
26 |
+
font: font,
|
27 |
+
group: group,
|
28 |
+
replace: replace,
|
29 |
+
};
|
30 |
+
}
|
31 |
+
|
32 |
+
// Some abbreviations for commonly used strings.
|
33 |
+
// This helps minify the code, and also spotting typos using jshint.
|
34 |
+
|
35 |
+
// modes:
|
36 |
+
var math = "math";
|
37 |
+
var text = "text";
|
38 |
+
|
39 |
+
// fonts:
|
40 |
+
var main = "main";
|
41 |
+
var ams = "ams";
|
42 |
+
|
43 |
+
// groups:
|
44 |
+
var accent = "accent";
|
45 |
+
var bin = "bin";
|
46 |
+
var close = "close";
|
47 |
+
var inner = "inner";
|
48 |
+
var mathord = "mathord";
|
49 |
+
var op = "op";
|
50 |
+
var open = "open";
|
51 |
+
var punct = "punct";
|
52 |
+
var rel = "rel";
|
53 |
+
var spacing = "spacing";
|
54 |
+
var textord = "textord";
|
55 |
+
|
56 |
+
// Now comes the symbol table
|
57 |
+
|
58 |
+
// Relation Symbols
|
59 |
+
defineSymbol(math, main, rel, "\u2261", "\\equiv");
|
60 |
+
defineSymbol(math, main, rel, "\u227a", "\\prec");
|
61 |
+
defineSymbol(math, main, rel, "\u227b", "\\succ");
|
62 |
+
defineSymbol(math, main, rel, "\u223c", "\\sim");
|
63 |
+
defineSymbol(math, main, rel, "\u22a5", "\\perp");
|
64 |
+
defineSymbol(math, main, rel, "\u2aaf", "\\preceq");
|
65 |
+
defineSymbol(math, main, rel, "\u2ab0", "\\succeq");
|
66 |
+
defineSymbol(math, main, rel, "\u2243", "\\simeq");
|
67 |
+
defineSymbol(math, main, rel, "\u2223", "\\mid");
|
68 |
+
defineSymbol(math, main, rel, "\u226a", "\\ll");
|
69 |
+
defineSymbol(math, main, rel, "\u226b", "\\gg");
|
70 |
+
defineSymbol(math, main, rel, "\u224d", "\\asymp");
|
71 |
+
defineSymbol(math, main, rel, "\u2225", "\\parallel");
|
72 |
+
defineSymbol(math, main, rel, "\u22c8", "\\bowtie");
|
73 |
+
defineSymbol(math, main, rel, "\u2323", "\\smile");
|
74 |
+
defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq");
|
75 |
+
defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq");
|
76 |
+
defineSymbol(math, main, rel, "\u2250", "\\doteq");
|
77 |
+
defineSymbol(math, main, rel, "\u2322", "\\frown");
|
78 |
+
defineSymbol(math, main, rel, "\u220b", "\\ni");
|
79 |
+
defineSymbol(math, main, rel, "\u221d", "\\propto");
|
80 |
+
defineSymbol(math, main, rel, "\u22a2", "\\vdash");
|
81 |
+
defineSymbol(math, main, rel, "\u22a3", "\\dashv");
|
82 |
+
defineSymbol(math, main, rel, "\u220b", "\\owns");
|
83 |
+
|
84 |
+
defineSymbol(math, main, rel, "\u220b", "\\widehat");
|
85 |
+
defineSymbol(math, main, rel, "\u220b", "\\widetilde");
|
86 |
+
defineSymbol(math, main, rel, "\u220b", "\\sp");
|
87 |
+
defineSymbol(math, main, rel, "\u220b", "\\quad");
|
88 |
+
// defineSymbol(math, main, rel, "\u220b", "\\cr");
|
89 |
+
defineSymbol(math, main, rel, "\u220b", "\\\\sim");
|
90 |
+
defineSymbol(math, main, rel, "\u220b", "\\nonumber");
|
91 |
+
defineSymbol(math, main, rel, "\u220b", "\\dots");
|
92 |
+
defineSymbol(math, main, rel, "\u220b", "\\cases");
|
93 |
+
defineSymbol(math, main, rel, "\u220b", "\\mit");
|
94 |
+
defineSymbol(math, main, rel, "\u220b", "\\smallskip");
|
95 |
+
defineSymbol(math, main, rel, "\u220b", "\\slash");
|
96 |
+
defineSymbol(math, main, rel, "\u220b", "\\d");
|
97 |
+
defineSymbol(math, main, rel, "\u220b", "\\c");
|
98 |
+
defineSymbol(math, main, rel, "\u220b", "\\b");
|
99 |
+
defineSymbol(math, main, rel, "\u220b", "\\M");
|
100 |
+
defineSymbol(math, main, rel, "\u220b", "\\S");
|
101 |
+
defineSymbol(math, main, rel, "\u220b", "\\(");
|
102 |
+
defineSymbol(math, main, rel, "\u220b", "\\)");
|
103 |
+
// defineSymbol(math, main, rel, "\u220b", "\\Comp");
|
104 |
+
defineSymbol(math, main, rel, "\u220b", "\\thinspace");
|
105 |
+
defineSymbol(math, main, rel, "\u220b", "\\hskip");
|
106 |
+
defineSymbol(math, main, rel, "\u220b", "\\tt");
|
107 |
+
defineSymbol(math, main, rel, "\u220b", "\\not");
|
108 |
+
defineSymbol(math, main, rel, "\u220b", "\\boldmathr");
|
109 |
+
defineSymbol(math, main, rel, "\u220b", "\\overleftarrow");
|
110 |
+
defineSymbol(math, main, rel, "\u220b", "\\overrightarrow");
|
111 |
+
defineSymbol(math, main, rel, "\u220b", "\\intf");
|
112 |
+
defineSymbol(math, main, rel, "\u220b", "\\sf");
|
113 |
+
defineSymbol(math, main, rel, "\u220b", "\\textbf");
|
114 |
+
defineSymbol(math, main, rel, "\u220b", "\\L");
|
115 |
+
defineSymbol(math, main, rel, "\u220b", "\\pii");
|
116 |
+
defineSymbol(math, main, rel, "\u220b", "\\unitlength");
|
117 |
+
defineSymbol(math, main, rel, "\u220b", "\\arowtor5linv");
|
118 |
+
defineSymbol(math, main, rel, "\u220b", "\\hline");
|
119 |
+
defineSymbol(math, main, rel, "\u220b", "\\mathbin");
|
120 |
+
defineSymbol(math, main, rel, "\u220b", "\\nc");
|
121 |
+
defineSymbol(math, main, rel, "\u220b", "\\underbrace");
|
122 |
+
defineSymbol(math, main, rel, "\u220b", "\\o");
|
123 |
+
defineSymbol(math, main, rel, "\u220b", "\\a");
|
124 |
+
defineSymbol(math, main, rel, "\u220b", "\\b");
|
125 |
+
defineSymbol(math, main, rel, "\u220b", "\\c");
|
126 |
+
defineSymbol(math, main, rel, "\u220b", "\\d");
|
127 |
+
defineSymbol(math, main, rel, "\u220b", "\\e");
|
128 |
+
defineSymbol(math, main, rel, "\u220b", "\\f");
|
129 |
+
defineSymbol(math, main, rel, "\u220b", "\\g");
|
130 |
+
defineSymbol(math, main, rel, "\u220b", "\\h");
|
131 |
+
defineSymbol(math, main, rel, "\u220b", "\\i");
|
132 |
+
defineSymbol(math, main, rel, "\u220b", "\\j");
|
133 |
+
defineSymbol(math, main, rel, "\u220b", "\\k");
|
134 |
+
defineSymbol(math, main, rel, "\u220b", "\\l");
|
135 |
+
defineSymbol(math, main, rel, "\u220b", "\\m");
|
136 |
+
defineSymbol(math, main, rel, "\u220b", "\\n");
|
137 |
+
defineSymbol(math, main, rel, "\u220b", "\\o");
|
138 |
+
// defineSymbol(math, main, rel, "\u220b", "\\wedgee");
|
139 |
+
defineSymbol(math, main, rel, "\u220b", "\\sb");
|
140 |
+
defineSymbol(math, main, rel, "\u220b", "\\do");
|
141 |
+
defineSymbol(math, main, rel, "\u220b", "\\em");
|
142 |
+
// defineSymbol(math, main, rel, "\u220b", "\\diamonda");
|
143 |
+
|
144 |
+
|
145 |
+
defineSymbol(math, main, rel, "\u220b", "\\dint");
|
146 |
+
defineSymbol(math, main, rel, "\u220b", "\\intd");
|
147 |
+
|
148 |
+
|
149 |
+
// Punctuation
|
150 |
+
defineSymbol(math, main, punct, "\u002e", "\\ldotp");
|
151 |
+
defineSymbol(math, main, punct, "\u22c5", "\\cdotp");
|
152 |
+
|
153 |
+
// Misc Symbols
|
154 |
+
defineSymbol(math, main, textord, "\u0023", "\\#");
|
155 |
+
defineSymbol(math, main, textord, "\u0026", "\\&");
|
156 |
+
defineSymbol(math, main, textord, "\u2135", "\\aleph");
|
157 |
+
defineSymbol(math, main, textord, "\u2200", "\\forall");
|
158 |
+
defineSymbol(math, main, textord, "\u210f", "\\hbar");
|
159 |
+
defineSymbol(math, main, textord, "\u2203", "\\eixsts");
|
160 |
+
defineSymbol(math, main, textord, "\u2207", "\\nabla");
|
161 |
+
defineSymbol(math, main, textord, "\u266d", "\\flat");
|
162 |
+
defineSymbol(math, main, textord, "\u2113", "\\ell");
|
163 |
+
defineSymbol(math, main, textord, "\u266e", "\\natural");
|
164 |
+
defineSymbol(math, main, textord, "\u2663", "\\clubsuit");
|
165 |
+
defineSymbol(math, main, textord, "\u2118", "\\wp");
|
166 |
+
defineSymbol(math, main, textord, "\u266f", "\\sharp");
|
167 |
+
defineSymbol(math, main, textord, "\u2662", "\\diamondsuit");
|
168 |
+
defineSymbol(math, main, textord, "\u211c", "\\Re");
|
169 |
+
defineSymbol(math, main, textord, "\u2661", "\\heartsuit");
|
170 |
+
defineSymbol(math, main, textord, "\u2111", "\\Im");
|
171 |
+
defineSymbol(math, main, textord, "\u2660", "\\spadesuit");
|
172 |
+
|
173 |
+
// Math and Text
|
174 |
+
defineSymbol(math, main, textord, "\u2020", "\\dag");
|
175 |
+
defineSymbol(math, main, textord, "\u2021", "\\ddag");
|
176 |
+
|
177 |
+
// Large Delimiters
|
178 |
+
defineSymbol(math, main, close, "\u23b1", "\\rmoustache");
|
179 |
+
defineSymbol(math, main, open, "\u23b0", "\\lmoustache");
|
180 |
+
defineSymbol(math, main, close, "\u27ef", "\\rgroup");
|
181 |
+
defineSymbol(math, main, open, "\u27ee", "\\lgroup");
|
182 |
+
|
183 |
+
// Binary Operators
|
184 |
+
defineSymbol(math, main, bin, "\u2213", "\\mp");
|
185 |
+
defineSymbol(math, main, bin, "\u2296", "\\ominus");
|
186 |
+
defineSymbol(math, main, bin, "\u228e", "\\uplus");
|
187 |
+
defineSymbol(math, main, bin, "\u2293", "\\sqcap");
|
188 |
+
defineSymbol(math, main, bin, "\u2217", "\\ast");
|
189 |
+
defineSymbol(math, main, bin, "\u2294", "\\sqcup");
|
190 |
+
defineSymbol(math, main, bin, "\u25ef", "\\bigcirc");
|
191 |
+
defineSymbol(math, main, bin, "\u2219", "\\bullet");
|
192 |
+
defineSymbol(math, main, bin, "\u2021", "\\ddagger");
|
193 |
+
defineSymbol(math, main, bin, "\u2240", "\\wr");
|
194 |
+
defineSymbol(math, main, bin, "\u2a3f", "\\amalg");
|
195 |
+
|
196 |
+
// Arrow Symbols
|
197 |
+
defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow");
|
198 |
+
defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow");
|
199 |
+
defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow");
|
200 |
+
defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow");
|
201 |
+
defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow");
|
202 |
+
defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow");
|
203 |
+
defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow");
|
204 |
+
defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow");
|
205 |
+
defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow");
|
206 |
+
defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow");
|
207 |
+
defineSymbol(math, main, rel, "\u21a6", "\\mapsto");
|
208 |
+
defineSymbol(math, main, rel, "\u27fc", "\\longmapsto");
|
209 |
+
defineSymbol(math, main, rel, "\u2197", "\\nearrow");
|
210 |
+
defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow");
|
211 |
+
defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow");
|
212 |
+
defineSymbol(math, main, rel, "\u2198", "\\searrow");
|
213 |
+
defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup");
|
214 |
+
defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup");
|
215 |
+
defineSymbol(math, main, rel, "\u2199", "\\swarrow");
|
216 |
+
defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown");
|
217 |
+
defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown");
|
218 |
+
defineSymbol(math, main, rel, "\u2196", "\\nwarrow");
|
219 |
+
defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons");
|
220 |
+
|
221 |
+
// AMS Negated Binary Relations
|
222 |
+
defineSymbol(math, ams, rel, "\u226e", "\\nless");
|
223 |
+
defineSymbol(math, ams, rel, "\ue010", "\\nleqslant");
|
224 |
+
defineSymbol(math, ams, rel, "\ue011", "\\nleqq");
|
225 |
+
defineSymbol(math, ams, rel, "\u2a87", "\\lneq");
|
226 |
+
defineSymbol(math, ams, rel, "\u2268", "\\lneqq");
|
227 |
+
defineSymbol(math, ams, rel, "\ue00c", "\\lvertneqq");
|
228 |
+
defineSymbol(math, ams, rel, "\u22e6", "\\lnsim");
|
229 |
+
defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox");
|
230 |
+
defineSymbol(math, ams, rel, "\u2280", "\\nprec");
|
231 |
+
defineSymbol(math, ams, rel, "\u22e0", "\\npreceq");
|
232 |
+
defineSymbol(math, ams, rel, "\u22e8", "\\precnsim");
|
233 |
+
defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox");
|
234 |
+
defineSymbol(math, ams, rel, "\u2241", "\\nsim");
|
235 |
+
defineSymbol(math, ams, rel, "\ue006", "\\nshortmid");
|
236 |
+
defineSymbol(math, ams, rel, "\u2224", "\\nmid");
|
237 |
+
defineSymbol(math, ams, rel, "\u22ac", "\\nvdash");
|
238 |
+
defineSymbol(math, ams, rel, "\u22ad", "\\nvDash");
|
239 |
+
defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft");
|
240 |
+
defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq");
|
241 |
+
defineSymbol(math, ams, rel, "\u228a", "\\subsetneq");
|
242 |
+
defineSymbol(math, ams, rel, "\ue01a", "\\varsubsetneq");
|
243 |
+
defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq");
|
244 |
+
defineSymbol(math, ams, rel, "\ue017", "\\varsubsetneqq");
|
245 |
+
defineSymbol(math, ams, rel, "\u226f", "\\ngtr");
|
246 |
+
defineSymbol(math, ams, rel, "\ue00f", "\\ngeqslant");
|
247 |
+
defineSymbol(math, ams, rel, "\ue00e", "\\ngeqq");
|
248 |
+
defineSymbol(math, ams, rel, "\u2a88", "\\gneq");
|
249 |
+
defineSymbol(math, ams, rel, "\u2269", "\\gneqq");
|
250 |
+
defineSymbol(math, ams, rel, "\ue00d", "\\gvertneqq");
|
251 |
+
defineSymbol(math, ams, rel, "\u22e7", "\\gnsim");
|
252 |
+
defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox");
|
253 |
+
defineSymbol(math, ams, rel, "\u2281", "\\nsucc");
|
254 |
+
defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq");
|
255 |
+
defineSymbol(math, ams, rel, "\u22e9", "\\succnsim");
|
256 |
+
defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox");
|
257 |
+
defineSymbol(math, ams, rel, "\u2246", "\\ncong");
|
258 |
+
defineSymbol(math, ams, rel, "\ue007", "\\nshortparallel");
|
259 |
+
defineSymbol(math, ams, rel, "\u2226", "\\nparallel");
|
260 |
+
defineSymbol(math, ams, rel, "\u22af", "\\nVDash");
|
261 |
+
defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright");
|
262 |
+
defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq");
|
263 |
+
defineSymbol(math, ams, rel, "\ue018", "\\nsupseteqq");
|
264 |
+
defineSymbol(math, ams, rel, "\u228b", "\\supsetneq");
|
265 |
+
defineSymbol(math, ams, rel, "\ue01b", "\\varsupsetneq");
|
266 |
+
defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq");
|
267 |
+
defineSymbol(math, ams, rel, "\ue019", "\\varsupsetneqq");
|
268 |
+
defineSymbol(math, ams, rel, "\u22ae", "\\nVdash");
|
269 |
+
defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq");
|
270 |
+
defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq");
|
271 |
+
defineSymbol(math, ams, rel, "\ue016", "\\nsubseteqq");
|
272 |
+
defineSymbol(math, ams, bin, "\u22b4", "\\unlhd");
|
273 |
+
defineSymbol(math, ams, bin, "\u22b5", "\\unrhd");
|
274 |
+
|
275 |
+
// AMS Negated Arrows
|
276 |
+
defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow");
|
277 |
+
defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow");
|
278 |
+
defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow");
|
279 |
+
defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow");
|
280 |
+
defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow");
|
281 |
+
defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow");
|
282 |
+
|
283 |
+
// AMS Misc
|
284 |
+
defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle");
|
285 |
+
defineSymbol(math, ams, textord, "\u210f", "\\hslash");
|
286 |
+
defineSymbol(math, ams, textord, "\u25bd", "\\triangledown");
|
287 |
+
defineSymbol(math, ams, textord, "\u25ca", "\\lozenge");
|
288 |
+
defineSymbol(math, ams, textord, "\u24c8", "\\circledS");
|
289 |
+
defineSymbol(math, ams, textord, "\u00ae", "\\circledR");
|
290 |
+
defineSymbol(math, ams, textord, "\u2221", "\\measuredangle");
|
291 |
+
defineSymbol(math, ams, textord, "\u2204", "\\nexists");
|
292 |
+
defineSymbol(math, ams, textord, "\u2127", "\\mho");
|
293 |
+
defineSymbol(math, ams, textord, "\u2132", "\\Finv");
|
294 |
+
defineSymbol(math, ams, textord, "\u2141", "\\Game");
|
295 |
+
defineSymbol(math, ams, textord, "\u006b", "\\Bbbk");
|
296 |
+
defineSymbol(math, ams, textord, "\u2035", "\\backprime");
|
297 |
+
defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle");
|
298 |
+
defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown");
|
299 |
+
defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare");
|
300 |
+
defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge");
|
301 |
+
defineSymbol(math, ams, textord, "\u2605", "\\bigstar");
|
302 |
+
defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle");
|
303 |
+
defineSymbol(math, ams, textord, "\u2201", "\\complement");
|
304 |
+
defineSymbol(math, ams, textord, "\u00f0", "\\eth");
|
305 |
+
defineSymbol(math, ams, textord, "\u2571", "\\diagup");
|
306 |
+
defineSymbol(math, ams, textord, "\u2572", "\\diagdown");
|
307 |
+
defineSymbol(math, ams, textord, "\u25a1", "\\square");
|
308 |
+
defineSymbol(math, ams, textord, "\u25a1", "\\Box");
|
309 |
+
defineSymbol(math, ams, textord, "\u25ca", "\\Diamond");
|
310 |
+
defineSymbol(math, ams, textord, "\u00a5", "\\yen");
|
311 |
+
defineSymbol(math, ams, textord, "\u2713", "\\checkmark");
|
312 |
+
|
313 |
+
// AMS Hebrew
|
314 |
+
defineSymbol(math, ams, textord, "\u2136", "\\beth");
|
315 |
+
defineSymbol(math, ams, textord, "\u2138", "\\daleth");
|
316 |
+
defineSymbol(math, ams, textord, "\u2137", "\\gimel");
|
317 |
+
|
318 |
+
// AMS Greek
|
319 |
+
defineSymbol(math, ams, textord, "\u03dd", "\\digamma");
|
320 |
+
defineSymbol(math, ams, textord, "\u03f0", "\\varkappa");
|
321 |
+
|
322 |
+
// AMS Delimiters
|
323 |
+
defineSymbol(math, ams, open, "\u250c", "\\ulcorner");
|
324 |
+
defineSymbol(math, ams, close, "\u2510", "\\urcorner");
|
325 |
+
defineSymbol(math, ams, open, "\u2514", "\\llcorner");
|
326 |
+
defineSymbol(math, ams, close, "\u2518", "\\lrcorner");
|
327 |
+
|
328 |
+
// AMS Binary Relations
|
329 |
+
defineSymbol(math, ams, rel, "\u2266", "\\leqq");
|
330 |
+
defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant");
|
331 |
+
defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless");
|
332 |
+
defineSymbol(math, ams, rel, "\u2272", "\\lesssim");
|
333 |
+
defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox");
|
334 |
+
defineSymbol(math, ams, rel, "\u224a", "\\approxeq");
|
335 |
+
defineSymbol(math, ams, bin, "\u22d6", "\\lessdot");
|
336 |
+
defineSymbol(math, ams, rel, "\u22d8", "\\lll");
|
337 |
+
defineSymbol(math, ams, rel, "\u2276", "\\lessgtr");
|
338 |
+
defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr");
|
339 |
+
defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr");
|
340 |
+
defineSymbol(math, ams, rel, "\u2251", "\\doteqdot");
|
341 |
+
defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq");
|
342 |
+
defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq");
|
343 |
+
defineSymbol(math, ams, rel, "\u223d", "\\backsim");
|
344 |
+
defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq");
|
345 |
+
defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq");
|
346 |
+
defineSymbol(math, ams, rel, "\u22d0", "\\Subset");
|
347 |
+
defineSymbol(math, ams, rel, "\u228f", "\\sqsubset");
|
348 |
+
defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq");
|
349 |
+
defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec");
|
350 |
+
defineSymbol(math, ams, rel, "\u227e", "\\precsim");
|
351 |
+
defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox");
|
352 |
+
defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft");
|
353 |
+
defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq");
|
354 |
+
defineSymbol(math, ams, rel, "\u22a8", "\\vDash");
|
355 |
+
defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash");
|
356 |
+
defineSymbol(math, ams, rel, "\u2323", "\\smallsmile");
|
357 |
+
defineSymbol(math, ams, rel, "\u2322", "\\smallfrown");
|
358 |
+
defineSymbol(math, ams, rel, "\u224f", "\\bumpeq");
|
359 |
+
defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq");
|
360 |
+
defineSymbol(math, ams, rel, "\u2267", "\\geqq");
|
361 |
+
defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant");
|
362 |
+
defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr");
|
363 |
+
defineSymbol(math, ams, rel, "\u2273", "\\gtrsim");
|
364 |
+
defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox");
|
365 |
+
defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot");
|
366 |
+
defineSymbol(math, ams, rel, "\u22d9", "\\ggg");
|
367 |
+
defineSymbol(math, ams, rel, "\u2277", "\\gtrless");
|
368 |
+
defineSymbol(math, ams, rel, "\u22db", "\\gtreqless");
|
369 |
+
defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless");
|
370 |
+
defineSymbol(math, ams, rel, "\u2256", "\\eqcirc");
|
371 |
+
defineSymbol(math, ams, rel, "\u2257", "\\circeq");
|
372 |
+
defineSymbol(math, ams, rel, "\u225c", "\\triangleq");
|
373 |
+
defineSymbol(math, ams, rel, "\u223c", "\\thicksim");
|
374 |
+
defineSymbol(math, ams, rel, "\u2248", "\\thickapprox");
|
375 |
+
defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq");
|
376 |
+
defineSymbol(math, ams, rel, "\u22d1", "\\Supset");
|
377 |
+
defineSymbol(math, ams, rel, "\u2290", "\\sqsupset");
|
378 |
+
defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq");
|
379 |
+
defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc");
|
380 |
+
defineSymbol(math, ams, rel, "\u227f", "\\succsim");
|
381 |
+
defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox");
|
382 |
+
defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright");
|
383 |
+
defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq");
|
384 |
+
defineSymbol(math, ams, rel, "\u22a9", "\\Vdash");
|
385 |
+
defineSymbol(math, ams, rel, "\u2223", "\\shortmid");
|
386 |
+
defineSymbol(math, ams, rel, "\u2225", "\\shortparallel");
|
387 |
+
defineSymbol(math, ams, rel, "\u226c", "\\between");
|
388 |
+
defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork");
|
389 |
+
defineSymbol(math, ams, rel, "\u221d", "\\varpropto");
|
390 |
+
defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft");
|
391 |
+
defineSymbol(math, ams, rel, "\u2234", "\\therefore");
|
392 |
+
defineSymbol(math, ams, rel, "\u220d", "\\backepsilon");
|
393 |
+
defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright");
|
394 |
+
defineSymbol(math, ams, rel, "\u2235", "\\because");
|
395 |
+
defineSymbol(math, ams, rel, "\u22d8", "\\llless");
|
396 |
+
defineSymbol(math, ams, rel, "\u22d9", "\\gggtr");
|
397 |
+
defineSymbol(math, ams, bin, "\u22b2", "\\lhd");
|
398 |
+
defineSymbol(math, ams, bin, "\u22b3", "\\rhd");
|
399 |
+
defineSymbol(math, ams, rel, "\u2242", "\\eqsim");
|
400 |
+
defineSymbol(math, main, rel, "\u22c8", "\\Join");
|
401 |
+
defineSymbol(math, ams, rel, "\u2251", "\\Doteq");
|
402 |
+
|
403 |
+
// AMS Binary Operators
|
404 |
+
defineSymbol(math, ams, bin, "\u2214", "\\dotplus");
|
405 |
+
defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus");
|
406 |
+
defineSymbol(math, ams, bin, "\u22d2", "\\Cap");
|
407 |
+
defineSymbol(math, ams, bin, "\u22d3", "\\Cup");
|
408 |
+
defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge");
|
409 |
+
defineSymbol(math, ams, bin, "\u229f", "\\boxminus");
|
410 |
+
defineSymbol(math, ams, bin, "\u229e", "\\boxplus");
|
411 |
+
defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes");
|
412 |
+
defineSymbol(math, ams, bin, "\u22c9", "\\ltimes");
|
413 |
+
defineSymbol(math, ams, bin, "\u22ca", "\\rtimes");
|
414 |
+
defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes");
|
415 |
+
defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes");
|
416 |
+
defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge");
|
417 |
+
defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee");
|
418 |
+
defineSymbol(math, ams, bin, "\u229d", "\\circleddash");
|
419 |
+
defineSymbol(math, ams, bin, "\u229b", "\\circledast");
|
420 |
+
defineSymbol(math, ams, bin, "\u22c5", "\\centerdot");
|
421 |
+
defineSymbol(math, ams, bin, "\u22ba", "\\intercal");
|
422 |
+
defineSymbol(math, ams, bin, "\u22d2", "\\doublecap");
|
423 |
+
defineSymbol(math, ams, bin, "\u22d3", "\\doublecup");
|
424 |
+
defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes");
|
425 |
+
|
426 |
+
// AMS Arrows
|
427 |
+
defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow");
|
428 |
+
defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow");
|
429 |
+
defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows");
|
430 |
+
defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows");
|
431 |
+
defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow");
|
432 |
+
defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow");
|
433 |
+
defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail");
|
434 |
+
defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft");
|
435 |
+
defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons");
|
436 |
+
defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft");
|
437 |
+
defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft");
|
438 |
+
defineSymbol(math, ams, rel, "\u21b0", "\\Lsh");
|
439 |
+
defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows");
|
440 |
+
defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft");
|
441 |
+
defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft");
|
442 |
+
defineSymbol(math, ams, rel, "\u22b8", "\\multimap");
|
443 |
+
defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow");
|
444 |
+
defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows");
|
445 |
+
defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows");
|
446 |
+
defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow");
|
447 |
+
defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail");
|
448 |
+
defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright");
|
449 |
+
defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright");
|
450 |
+
defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright");
|
451 |
+
defineSymbol(math, ams, rel, "\u21b1", "\\Rsh");
|
452 |
+
defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows");
|
453 |
+
defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright");
|
454 |
+
defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright");
|
455 |
+
defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow");
|
456 |
+
defineSymbol(math, ams, rel, "\u21dd", "\\leadsto");
|
457 |
+
defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow");
|
458 |
+
defineSymbol(math, ams, rel, "\u21be", "\\restriction");
|
459 |
+
|
460 |
+
defineSymbol(math, main, textord, "\u2018", "`");
|
461 |
+
defineSymbol(math, main, textord, "$", "\\$");
|
462 |
+
defineSymbol(math, main, textord, "%", "\\%");
|
463 |
+
defineSymbol(math, main, textord, "_", "\\_");
|
464 |
+
defineSymbol(math, main, textord, "\u2220", "\\angle");
|
465 |
+
defineSymbol(math, main, textord, "\u221e", "\\infty");
|
466 |
+
defineSymbol(math, main, textord, "\u2032", "\\prime");
|
467 |
+
defineSymbol(math, main, textord, "\u25b3", "\\triangle");
|
468 |
+
defineSymbol(math, main, textord, "\u0393", "\\Gamma");
|
469 |
+
defineSymbol(math, main, textord, "\u0394", "\\Delta");
|
470 |
+
defineSymbol(math, main, textord, "\u0398", "\\Theta");
|
471 |
+
defineSymbol(math, main, textord, "\u039b", "\\Lambda");
|
472 |
+
defineSymbol(math, main, textord, "\u039e", "\\Xi");
|
473 |
+
defineSymbol(math, main, textord, "\u03a0", "\\Pi");
|
474 |
+
defineSymbol(math, main, textord, "\u03a3", "\\Sigma");
|
475 |
+
defineSymbol(math, main, textord, "\u03a5", "\\Upsilon");
|
476 |
+
defineSymbol(math, main, textord, "\u03a6", "\\Phi");
|
477 |
+
defineSymbol(math, main, textord, "\u03a8", "\\Psi");
|
478 |
+
defineSymbol(math, main, textord, "\u03a9", "\\Omega");
|
479 |
+
defineSymbol(math, main, textord, "\u00ac", "\\neg");
|
480 |
+
defineSymbol(math, main, textord, "\u00ac", "\\lnot");
|
481 |
+
defineSymbol(math, main, textord, "\u22a4", "\\top");
|
482 |
+
defineSymbol(math, main, textord, "\u22a5", "\\bot");
|
483 |
+
defineSymbol(math, main, textord, "\u2205", "\\emptyset");
|
484 |
+
defineSymbol(math, ams, textord, "\u2205", "\\varnothing");
|
485 |
+
defineSymbol(math, main, mathord, "\u03b1", "\\alpha");
|
486 |
+
defineSymbol(math, main, mathord, "\u03b2", "\\beta");
|
487 |
+
defineSymbol(math, main, mathord, "\u03b3", "\\gamma");
|
488 |
+
defineSymbol(math, main, mathord, "\u03b4", "\\delta");
|
489 |
+
defineSymbol(math, main, mathord, "\u03f5", "\\epsilon");
|
490 |
+
defineSymbol(math, main, mathord, "\u03b6", "\\zeta");
|
491 |
+
defineSymbol(math, main, mathord, "\u03b7", "\\eta");
|
492 |
+
defineSymbol(math, main, mathord, "\u03b8", "\\theta");
|
493 |
+
defineSymbol(math, main, mathord, "\u03b9", "\\iota");
|
494 |
+
defineSymbol(math, main, mathord, "\u03ba", "\\kappa");
|
495 |
+
defineSymbol(math, main, mathord, "\u03bb", "\\lambda");
|
496 |
+
defineSymbol(math, main, mathord, "\u03bc", "\\mu");
|
497 |
+
defineSymbol(math, main, mathord, "\u03bd", "\\nu");
|
498 |
+
defineSymbol(math, main, mathord, "\u03be", "\\xi");
|
499 |
+
defineSymbol(math, main, mathord, "o", "\\omicron");
|
500 |
+
defineSymbol(math, main, mathord, "\u03c0", "\\pi");
|
501 |
+
defineSymbol(math, main, mathord, "\u03c1", "\\rho");
|
502 |
+
defineSymbol(math, main, mathord, "\u03c3", "\\sigma");
|
503 |
+
defineSymbol(math, main, mathord, "\u03c4", "\\tau");
|
504 |
+
defineSymbol(math, main, mathord, "\u03c5", "\\upsilon");
|
505 |
+
defineSymbol(math, main, mathord, "\u03d5", "\\phi");
|
506 |
+
defineSymbol(math, main, mathord, "\u03c7", "\\chi");
|
507 |
+
defineSymbol(math, main, mathord, "\u03c8", "\\psi");
|
508 |
+
defineSymbol(math, main, mathord, "\u03c9", "\\omega");
|
509 |
+
defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon");
|
510 |
+
defineSymbol(math, main, mathord, "\u03d1", "\\vartheta");
|
511 |
+
defineSymbol(math, main, mathord, "\u03d6", "\\varpi");
|
512 |
+
defineSymbol(math, main, mathord, "\u03f1", "\\varrho");
|
513 |
+
defineSymbol(math, main, mathord, "\u03c2", "\\varsigma");
|
514 |
+
defineSymbol(math, main, mathord, "\u03c6", "\\varphi");
|
515 |
+
defineSymbol(math, main, bin, "\u2217", "*");
|
516 |
+
defineSymbol(math, main, bin, "+", "+");
|
517 |
+
defineSymbol(math, main, bin, "\u2212", "-");
|
518 |
+
defineSymbol(math, main, bin, "\u22c5", "\\cdot");
|
519 |
+
defineSymbol(math, main, bin, "\u2218", "\\circ");
|
520 |
+
defineSymbol(math, main, bin, "\u00f7", "\\div");
|
521 |
+
defineSymbol(math, main, bin, "\u00b1", "\\pm");
|
522 |
+
defineSymbol(math, main, bin, "\u00d7", "\\times");
|
523 |
+
defineSymbol(math, main, bin, "\u2229", "\\cap");
|
524 |
+
defineSymbol(math, main, bin, "\u222a", "\\cup");
|
525 |
+
defineSymbol(math, main, bin, "\u2216", "\\setminus");
|
526 |
+
defineSymbol(math, main, bin, "\u2227", "\\land");
|
527 |
+
defineSymbol(math, main, bin, "\u2228", "\\lor");
|
528 |
+
defineSymbol(math, main, bin, "\u2227", "\\wedge");
|
529 |
+
defineSymbol(math, main, bin, "\u2228", "\\vee");
|
530 |
+
defineSymbol(math, main, textord, "\u221a", "\\surd");
|
531 |
+
defineSymbol(math, main, open, "(", "(");
|
532 |
+
defineSymbol(math, main, open, "[", "[");
|
533 |
+
defineSymbol(math, main, open, "\u27e8", "\\langle");
|
534 |
+
defineSymbol(math, main, open, "\u2223", "\\lvert");
|
535 |
+
defineSymbol(math, main, open, "\u2225", "\\lVert");
|
536 |
+
defineSymbol(math, main, close, ")", ")");
|
537 |
+
defineSymbol(math, main, close, "]", "]");
|
538 |
+
defineSymbol(math, main, close, "?", "?");
|
539 |
+
defineSymbol(math, main, close, "!", "!");
|
540 |
+
defineSymbol(math, main, close, "\u27e9", "\\rangle");
|
541 |
+
defineSymbol(math, main, close, "\u2223", "\\rvert");
|
542 |
+
defineSymbol(math, main, close, "\u2225", "\\rVert");
|
543 |
+
defineSymbol(math, main, rel, "=", "=");
|
544 |
+
defineSymbol(math, main, rel, "<", "<");
|
545 |
+
defineSymbol(math, main, rel, ">", ">");
|
546 |
+
defineSymbol(math, main, rel, ":", ":");
|
547 |
+
defineSymbol(math, main, rel, "\u2248", "\\approx");
|
548 |
+
defineSymbol(math, main, rel, "\u2245", "\\cong");
|
549 |
+
defineSymbol(math, main, rel, "\u2265", "\\ge");
|
550 |
+
defineSymbol(math, main, rel, "\u2265", "\\geq");
|
551 |
+
defineSymbol(math, main, rel, "\u2190", "\\gets");
|
552 |
+
defineSymbol(math, main, rel, ">", "\\gt");
|
553 |
+
defineSymbol(math, main, rel, "\u2208", "\\in");
|
554 |
+
defineSymbol(math, main, rel, "\u2209", "\\notin");
|
555 |
+
defineSymbol(math, main, rel, "\u2282", "\\subset");
|
556 |
+
defineSymbol(math, main, rel, "\u2283", "\\supset");
|
557 |
+
defineSymbol(math, main, rel, "\u2286", "\\subseteq");
|
558 |
+
defineSymbol(math, main, rel, "\u2287", "\\supseteq");
|
559 |
+
defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq");
|
560 |
+
defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq");
|
561 |
+
defineSymbol(math, main, rel, "\u22a8", "\\models");
|
562 |
+
defineSymbol(math, main, rel, "\u2190", "\\leftarrow");
|
563 |
+
defineSymbol(math, main, rel, "\u2264", "\\le");
|
564 |
+
defineSymbol(math, main, rel, "\u2264", "\\leq");
|
565 |
+
defineSymbol(math, main, rel, "<", "\\lt");
|
566 |
+
defineSymbol(math, main, rel, "\u2260", "\\ne");
|
567 |
+
defineSymbol(math, main, rel, "\u2260", "\\neq");
|
568 |
+
defineSymbol(math, main, rel, "\u2192", "\\rightarrow");
|
569 |
+
defineSymbol(math, main, rel, "\u2192", "\\to");
|
570 |
+
defineSymbol(math, ams, rel, "\u2271", "\\ngeq");
|
571 |
+
defineSymbol(math, ams, rel, "\u2270", "\\nleq");
|
572 |
+
defineSymbol(math, main, spacing, null, "\\!");
|
573 |
+
defineSymbol(math, main, spacing, "\u00a0", "\\ ");
|
574 |
+
defineSymbol(math, main, spacing, "\u00a0", "~");
|
575 |
+
defineSymbol(math, main, spacing, null, "\\,");
|
576 |
+
defineSymbol(math, main, spacing, null, "\\:");
|
577 |
+
defineSymbol(math, main, spacing, null, "\\;");
|
578 |
+
defineSymbol(math, main, spacing, null, "\\enspace");
|
579 |
+
defineSymbol(math, main, spacing, null, "\\qquad");
|
580 |
+
defineSymbol(math, main, spacing, null, "\\quad");
|
581 |
+
defineSymbol(math, main, spacing, "\u00a0", "\\space");
|
582 |
+
defineSymbol(math, main, punct, ",", ",");
|
583 |
+
defineSymbol(math, main, punct, ";", ";");
|
584 |
+
defineSymbol(math, main, punct, ":", "\\colon");
|
585 |
+
defineSymbol(math, ams, bin, "\u22bc", "\\barwedge");
|
586 |
+
defineSymbol(math, ams, bin, "\u22bb", "\\veebar");
|
587 |
+
defineSymbol(math, main, bin, "\u2299", "\\odot");
|
588 |
+
defineSymbol(math, main, bin, "\u2295", "\\oplus");
|
589 |
+
defineSymbol(math, main, bin, "\u2297", "\\otimes");
|
590 |
+
defineSymbol(math, main, textord, "\u2202", "\\partial");
|
591 |
+
defineSymbol(math, main, bin, "\u2298", "\\oslash");
|
592 |
+
defineSymbol(math, ams, bin, "\u229a", "\\circledcirc");
|
593 |
+
defineSymbol(math, ams, bin, "\u22a1", "\\boxdot");
|
594 |
+
defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup");
|
595 |
+
defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown");
|
596 |
+
defineSymbol(math, main, bin, "\u2020", "\\dagger");
|
597 |
+
defineSymbol(math, main, bin, "\u22c4", "\\diamond");
|
598 |
+
defineSymbol(math, main, bin, "\u22c6", "\\star");
|
599 |
+
defineSymbol(math, main, bin, "\u25c3", "\\triangleleft");
|
600 |
+
defineSymbol(math, main, bin, "\u25b9", "\\triangleright");
|
601 |
+
defineSymbol(math, main, open, "{", "\\{");
|
602 |
+
defineSymbol(math, main, close, "}", "\\}");
|
603 |
+
defineSymbol(math, main, open, "{", "\\lbrace");
|
604 |
+
defineSymbol(math, main, close, "}", "\\rbrace");
|
605 |
+
defineSymbol(math, main, open, "[", "\\lbrack");
|
606 |
+
defineSymbol(math, main, close, "]", "\\rbrack");
|
607 |
+
defineSymbol(math, main, open, "\u230a", "\\lfloor");
|
608 |
+
defineSymbol(math, main, close, "\u230b", "\\rfloor");
|
609 |
+
defineSymbol(math, main, open, "\u2308", "\\lceil");
|
610 |
+
defineSymbol(math, main, close, "\u2309", "\\rceil");
|
611 |
+
defineSymbol(math, main, textord, "\\", "\\backslash");
|
612 |
+
defineSymbol(math, main, textord, "\u2223", "|");
|
613 |
+
defineSymbol(math, main, textord, "\u2223", "\\vert");
|
614 |
+
defineSymbol(math, main, textord, "\u2225", "\\|");
|
615 |
+
defineSymbol(math, main, textord, "\u2225", "\\Vert");
|
616 |
+
defineSymbol(math, main, rel, "\u2191", "\\uparrow");
|
617 |
+
defineSymbol(math, main, rel, "\u21d1", "\\Uparrow");
|
618 |
+
defineSymbol(math, main, rel, "\u2193", "\\downarrow");
|
619 |
+
defineSymbol(math, main, rel, "\u21d3", "\\Downarrow");
|
620 |
+
defineSymbol(math, main, rel, "\u2195", "\\updownarrow");
|
621 |
+
defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow");
|
622 |
+
defineSymbol(math, math, op, "\u2210", "\\coprod");
|
623 |
+
defineSymbol(math, math, op, "\u22c1", "\\bigvee");
|
624 |
+
defineSymbol(math, math, op, "\u22c0", "\\bigwedge");
|
625 |
+
defineSymbol(math, math, op, "\u2a04", "\\biguplus");
|
626 |
+
defineSymbol(math, math, op, "\u22c2", "\\bigcap");
|
627 |
+
defineSymbol(math, math, op, "\u22c3", "\\bigcup");
|
628 |
+
defineSymbol(math, math, op, "\u222b", "\\int");
|
629 |
+
defineSymbol(math, math, op, "\u222b", "\\intop");
|
630 |
+
defineSymbol(math, math, op, "\u222c", "\\iint");
|
631 |
+
defineSymbol(math, math, op, "\u222d", "\\iiint");
|
632 |
+
defineSymbol(math, math, op, "\u220f", "\\prod");
|
633 |
+
defineSymbol(math, math, op, "\u2211", "\\sum");
|
634 |
+
|
635 |
+
defineSymbol(math, math, op, "\u2a02", "\\bigotimes");
|
636 |
+
defineSymbol(math, math, op, "\u2a01", "\\bigoplus");
|
637 |
+
defineSymbol(math, math, op, "\u2a00", "\\bigodot");
|
638 |
+
defineSymbol(math, math, op, "\u222e", "\\oint");
|
639 |
+
defineSymbol(math, math, op, "\u2a06", "\\bigsqcup");
|
640 |
+
defineSymbol(math, math, op, "\u222b", "\\smallint");
|
641 |
+
defineSymbol(math, main, inner, "\u2026", "\\ldots");
|
642 |
+
defineSymbol(math, main, inner, "\u22ef", "\\cdots");
|
643 |
+
defineSymbol(math, main, inner, "\u22f1", "\\ddots");
|
644 |
+
defineSymbol(math, main, textord, "\u22ee", "\\vdots");
|
645 |
+
defineSymbol(math, main, accent, "\u00b4", "\\acute");
|
646 |
+
defineSymbol(math, main, accent, "\u0060", "\\grave");
|
647 |
+
defineSymbol(math, main, accent, "\u00a8", "\\ddot");
|
648 |
+
defineSymbol(math, main, accent, "\u007e", "\\tilde");
|
649 |
+
defineSymbol(math, main, accent, "\u00af", "\\bar");
|
650 |
+
defineSymbol(math, main, accent, "\u02d8", "\\breve");
|
651 |
+
defineSymbol(math, main, accent, "\u02c7", "\\check");
|
652 |
+
defineSymbol(math, main, accent, "\u005e", "\\hat");
|
653 |
+
defineSymbol(math, main, accent, "\u20d7", "\\vec");
|
654 |
+
defineSymbol(math, main, accent, "\u02d9", "\\dot");
|
655 |
+
defineSymbol(math, main, mathord, "\u0131", "\\imath");
|
656 |
+
defineSymbol(math, main, mathord, "\u0237", "\\jmath");
|
657 |
+
|
658 |
+
|
659 |
+
defineSymbol(text, main, spacing, "\u00a0", "\\ ");
|
660 |
+
defineSymbol(text, main, spacing, "\u00a0", " ");
|
661 |
+
defineSymbol(text, main, spacing, "\u00a0", "~");
|
662 |
+
|
663 |
+
// There are lots of symbols which are the same, so we add them in afterwards.
|
664 |
+
var i;
|
665 |
+
var ch;
|
666 |
+
|
667 |
+
// All of these are textords in math mode
|
668 |
+
var mathTextSymbols = "0123456789/@.\"";
|
669 |
+
for (i = 0; i < mathTextSymbols.length; i++) {
|
670 |
+
ch = mathTextSymbols.charAt(i);
|
671 |
+
defineSymbol(math, main, textord, ch, ch);
|
672 |
+
}
|
673 |
+
|
674 |
+
// All of these are textords in text mode
|
675 |
+
var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,";
|
676 |
+
for (i = 0; i < textSymbols.length; i++) {
|
677 |
+
ch = textSymbols.charAt(i);
|
678 |
+
defineSymbol(text, main, textord, ch, ch);
|
679 |
+
}
|
680 |
+
|
681 |
+
// All of these are textords in text mode, and mathords in math mode
|
682 |
+
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
683 |
+
for (i = 0; i < letters.length; i++) {
|
684 |
+
ch = letters.charAt(i);
|
685 |
+
defineSymbol(math, main, mathord, ch, ch);
|
686 |
+
defineSymbol(text, main, textord, ch, ch);
|
687 |
+
}
|
modules/tokenize_latex/third_party/katex/src/utils.js
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file contains a list of utility functions which are useful in other
|
3 |
+
* files.
|
4 |
+
*/
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Provide an `indexOf` function which works in IE8, but defers to native if
|
8 |
+
* possible.
|
9 |
+
*/
|
10 |
+
var nativeIndexOf = Array.prototype.indexOf;
|
11 |
+
var indexOf = function(list, elem) {
|
12 |
+
if (list == null) {
|
13 |
+
return -1;
|
14 |
+
}
|
15 |
+
if (nativeIndexOf && list.indexOf === nativeIndexOf) {
|
16 |
+
return list.indexOf(elem);
|
17 |
+
}
|
18 |
+
var i = 0;
|
19 |
+
var l = list.length;
|
20 |
+
for (; i < l; i++) {
|
21 |
+
if (list[i] === elem) {
|
22 |
+
return i;
|
23 |
+
}
|
24 |
+
}
|
25 |
+
return -1;
|
26 |
+
};
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Return whether an element is contained in a list
|
30 |
+
*/
|
31 |
+
var contains = function(list, elem) {
|
32 |
+
return indexOf(list, elem) !== -1;
|
33 |
+
};
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Provide a default value if a setting is undefined
|
37 |
+
*/
|
38 |
+
var deflt = function(setting, defaultIfUndefined) {
|
39 |
+
return setting === undefined ? defaultIfUndefined : setting;
|
40 |
+
};
|
41 |
+
|
42 |
+
// hyphenate and escape adapted from Facebook's React under Apache 2 license
|
43 |
+
|
44 |
+
var uppercase = /([A-Z])/g;
|
45 |
+
var hyphenate = function(str) {
|
46 |
+
return str.replace(uppercase, "-$1").toLowerCase();
|
47 |
+
};
|
48 |
+
|
49 |
+
var ESCAPE_LOOKUP = {
|
50 |
+
"&": "&",
|
51 |
+
">": ">",
|
52 |
+
"<": "<",
|
53 |
+
"\"": """,
|
54 |
+
"'": "'",
|
55 |
+
};
|
56 |
+
|
57 |
+
var ESCAPE_REGEX = /[&><"']/g;
|
58 |
+
|
59 |
+
function escaper(match) {
|
60 |
+
return ESCAPE_LOOKUP[match];
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Escapes text to prevent scripting attacks.
|
65 |
+
*
|
66 |
+
* @param {*} text Text value to escape.
|
67 |
+
* @return {string} An escaped string.
|
68 |
+
*/
|
69 |
+
function escape(text) {
|
70 |
+
return ("" + text).replace(ESCAPE_REGEX, escaper);
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* A function to set the text content of a DOM element in all supported
|
75 |
+
* browsers. Note that we don't define this if there is no document.
|
76 |
+
*/
|
77 |
+
var setTextContent;
|
78 |
+
if (typeof document !== "undefined") {
|
79 |
+
var testNode = document.createElement("span");
|
80 |
+
if ("textContent" in testNode) {
|
81 |
+
setTextContent = function(node, text) {
|
82 |
+
node.textContent = text;
|
83 |
+
};
|
84 |
+
} else {
|
85 |
+
setTextContent = function(node, text) {
|
86 |
+
node.innerText = text;
|
87 |
+
};
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* A function to clear a node.
|
93 |
+
*/
|
94 |
+
function clearNode(node) {
|
95 |
+
setTextContent(node, "");
|
96 |
+
}
|
97 |
+
|
98 |
+
module.exports = {
|
99 |
+
contains: contains,
|
100 |
+
deflt: deflt,
|
101 |
+
escape: escape,
|
102 |
+
hyphenate: hyphenate,
|
103 |
+
indexOf: indexOf,
|
104 |
+
setTextContent: setTextContent,
|
105 |
+
clearNode: clearNode,
|
106 |
+
};
|
modules/tokenize_latex/third_party/match-at/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# match-at [![Build Status](https://travis-ci.org/spicyj/match-at.svg?branch=master)](https://travis-ci.org/spicyj/match-at)
|
modules/tokenize_latex/third_party/match-at/lib/matchAt.js
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @flow */
|
2 |
+
|
3 |
+
"use strict";
|
4 |
+
|
5 |
+
function getRelocatable(re) {
|
6 |
+
// In the future, this could use a WeakMap instead of an expando.
|
7 |
+
if (!re.__matchAtRelocatable) {
|
8 |
+
// Disjunctions are the lowest-precedence operator, so we can make any
|
9 |
+
// pattern match the empty string by appending `|()` to it:
|
10 |
+
// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-patterns
|
11 |
+
var source = re.source + "|()";
|
12 |
+
|
13 |
+
// We always make the new regex global.
|
14 |
+
var flags = "g" + (re.ignoreCase ? "i" : "") + (re.multiline ? "m" : "") + (re.unicode ? "u" : "")
|
15 |
+
// sticky (/.../y) doesn't make sense in conjunction with our relocation
|
16 |
+
// logic, so we ignore it here.
|
17 |
+
;
|
18 |
+
|
19 |
+
re.__matchAtRelocatable = new RegExp(source, flags);
|
20 |
+
}
|
21 |
+
return re.__matchAtRelocatable;
|
22 |
+
}
|
23 |
+
|
24 |
+
function matchAt(re, str, pos) {
|
25 |
+
if (re.global || re.sticky) {
|
26 |
+
throw new Error("matchAt(...): Only non-global regexes are supported");
|
27 |
+
}
|
28 |
+
var reloc = getRelocatable(re);
|
29 |
+
reloc.lastIndex = pos;
|
30 |
+
var match = reloc.exec(str);
|
31 |
+
// Last capturing group is our sentinel that indicates whether the regex
|
32 |
+
// matched at the given location.
|
33 |
+
if (match[match.length - 1] == null) {
|
34 |
+
// Original regex matched.
|
35 |
+
match.length = match.length - 1;
|
36 |
+
return match;
|
37 |
+
} else {
|
38 |
+
return null;
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
module.exports = matchAt;
|
modules/tokenize_latex/third_party/match-at/package.json
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "match-at",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"description": "Relocatable regular expressions.",
|
5 |
+
"repository": {
|
6 |
+
"type": "git",
|
7 |
+
"url": "https://github.com/spicyj/match-at"
|
8 |
+
},
|
9 |
+
"main": "lib/matchAt.js",
|
10 |
+
"files": [
|
11 |
+
"lib/"
|
12 |
+
],
|
13 |
+
"devDependencies": {
|
14 |
+
"babel": "^4.7.16",
|
15 |
+
"jest-cli": "^0.4.0",
|
16 |
+
"react-tools": "^0.13.1"
|
17 |
+
},
|
18 |
+
"jest": {
|
19 |
+
"scriptPreprocessor": "<rootDir>/jestSupport/preprocessor.js",
|
20 |
+
"unmockedModulePathPatterns": [
|
21 |
+
""
|
22 |
+
]
|
23 |
+
},
|
24 |
+
"scripts": {
|
25 |
+
"prepublish": "babel -d lib/ src/",
|
26 |
+
"test": "jest"
|
27 |
+
},
|
28 |
+
"gitHead": "4197daff69720734c72ba3321ed68a41c0527fb2",
|
29 |
+
"bugs": {
|
30 |
+
"url": "https://github.com/spicyj/match-at/issues"
|
31 |
+
},
|
32 |
+
"homepage": "https://github.com/spicyj/match-at",
|
33 |
+
"_id": "[email protected]",
|
34 |
+
"_shasum": "f561e7709ff9a105b85cc62c6b8ee7c15bf24f31",
|
35 |
+
"_from": "match-at@",
|
36 |
+
"_npmVersion": "2.2.0",
|
37 |
+
"_nodeVersion": "0.10.35",
|
38 |
+
"_npmUser": {
|
39 |
+
"name": "spicyj",
|
40 |
+
"email": "[email protected]"
|
41 |
+
},
|
42 |
+
"maintainers": [
|
43 |
+
{
|
44 |
+
"name": "spicyj",
|
45 |
+
"email": "[email protected]"
|
46 |
+
}
|
47 |
+
],
|
48 |
+
"dist": {
|
49 |
+
"shasum": "f561e7709ff9a105b85cc62c6b8ee7c15bf24f31",
|
50 |
+
"tarball": "https://registry.npmjs.org/match-at/-/match-at-0.1.0.tgz"
|
51 |
+
},
|
52 |
+
"directories": {},
|
53 |
+
"_resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.0.tgz"
|
54 |
+
}
|
modules/tokenize_latex/tokenize_latex.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# taken and modified from https://github.com/harvardnlp/im2markup
|
2 |
+
# tokenize latex formulas
|
3 |
+
import sys
|
4 |
+
import os
|
5 |
+
import re
|
6 |
+
import argparse
|
7 |
+
import subprocess
|
8 |
+
import shutil
|
9 |
+
from threading import Timer
|
10 |
+
from datetime import datetime
|
11 |
+
|
12 |
+
|
13 |
+
def run_cmd(cmd, timeout_sec=30):
|
14 |
+
proc = subprocess.Popen(cmd, shell=True)
|
15 |
+
kill_proc = lambda p: p.kill()
|
16 |
+
timer = Timer(timeout_sec, kill_proc, [proc])
|
17 |
+
try:
|
18 |
+
timer.start()
|
19 |
+
stdout,stderr = proc.communicate()
|
20 |
+
finally:
|
21 |
+
timer.cancel()
|
22 |
+
|
23 |
+
def tokenize_latex(latex_code, latex_type="", middle_file=""):
|
24 |
+
if not latex_code:
|
25 |
+
return False, latex_code
|
26 |
+
if not latex_type:
|
27 |
+
latex_type = "tabular" if "tabular" in latex_code else "formula"
|
28 |
+
if not middle_file:
|
29 |
+
middle_file = "out-" + datetime.now().strftime('%Y_%m_%d_%H_%M_%S') + ".txt"
|
30 |
+
temp_file = middle_file + '.tmp'
|
31 |
+
|
32 |
+
if latex_type == "formula":
|
33 |
+
with open(temp_file, 'w') as f:
|
34 |
+
prepre = latex_code
|
35 |
+
# replace split, align with aligned
|
36 |
+
prepre = re.sub(r'\\begin{(split|align|alignedat|alignat|eqnarray)\*?}(.+?)\\end{\1\*?}', r'\\begin{aligned}\2\\end{aligned}', prepre, flags=re.S)
|
37 |
+
prepre = re.sub(r'\\begin{(smallmatrix)\*?}(.+?)\\end{\1\*?}', r'\\begin{matrix}\2\\end{matrix}', prepre, flags=re.S)
|
38 |
+
f.write(prepre)
|
39 |
+
|
40 |
+
cmd = r"cat %s | node %s %s > %s " % (temp_file, os.path.join(os.path.dirname(__file__), 'preprocess_formula.js'), 'normalize', middle_file)
|
41 |
+
ret = subprocess.call(cmd, shell=True)
|
42 |
+
os.remove(temp_file)
|
43 |
+
if ret != 0:
|
44 |
+
return False, latex_code
|
45 |
+
|
46 |
+
operators = '\s?'.join('|'.join(['arccos', 'arcsin', 'arctan', 'arg', 'cos', 'cosh', 'cot', 'coth', 'csc', 'deg', 'det', 'dim', 'exp', 'gcd', 'hom', 'inf',
|
47 |
+
'injlim', 'ker', 'lg', 'lim', 'liminf', 'limsup', 'ln', 'log', 'max', 'min', 'Pr', 'projlim', 'sec', 'sin', 'sinh', 'sup', 'tan', 'tanh']))
|
48 |
+
ops = re.compile(r'\\operatorname {(%s)}' % operators)
|
49 |
+
with open(middle_file, 'r') as fin:
|
50 |
+
for line in fin:
|
51 |
+
tokens = line.strip().split()
|
52 |
+
tokens_out = []
|
53 |
+
for token in tokens:
|
54 |
+
tokens_out.append(token)
|
55 |
+
post = ' '.join(tokens_out)
|
56 |
+
# use \sin instead of \operatorname{sin}
|
57 |
+
names = ['\\'+x.replace(' ', '') for x in re.findall(ops, post)]
|
58 |
+
post = re.sub(ops, lambda match: str(names.pop(0)), post).replace(r'\\ \end{array}', r'\end{array}')
|
59 |
+
os.remove(middle_file)
|
60 |
+
return True, post
|
61 |
+
|
62 |
+
elif latex_type == "tabular":
|
63 |
+
latex_code = latex_code.replace("\\\\%", "\\\\ %")
|
64 |
+
latex_code = latex_code.replace("\%", "<PERCENTAGE_TOKEN>")
|
65 |
+
latex_code = latex_code.split('%')[0]
|
66 |
+
latex_code = latex_code.replace("<PERCENTAGE_TOKEN>", "\%")
|
67 |
+
if not "\\end{tabular}" in latex_code:
|
68 |
+
latex_code += "\\end{tabular}"
|
69 |
+
with open(middle_file, 'w') as f:
|
70 |
+
f.write(latex_code.replace('\r', ' ').replace('\n', ' '))
|
71 |
+
cmd = "perl -pe 's|hskip(.*?)(cm\\|in\\|pt\\|mm\\|em)|hspace{\\1\\2}|g' %s > %s"%(middle_file, temp_file)
|
72 |
+
ret = subprocess.call(cmd, shell=True)
|
73 |
+
if ret != 0:
|
74 |
+
return False, latex_code
|
75 |
+
os.remove(middle_file)
|
76 |
+
cmd = r"cat %s | node %s %s > %s " % (temp_file, os.path.join(os.path.dirname(__file__), 'preprocess_tabular.js'), 'tokenize', middle_file)
|
77 |
+
ret = subprocess.call(cmd, shell=True)
|
78 |
+
os.remove(temp_file)
|
79 |
+
if ret != 0:
|
80 |
+
return False, latex_code
|
81 |
+
with open(middle_file, 'r') as fin:
|
82 |
+
for line in fin:
|
83 |
+
tokens = line.strip().split()
|
84 |
+
tokens_out = []
|
85 |
+
for token in tokens:
|
86 |
+
tokens_out.append(token)
|
87 |
+
post = ' '.join(tokens_out)
|
88 |
+
os.remove(middle_file)
|
89 |
+
return True, post
|
90 |
+
else:
|
91 |
+
print(f"latex type{latex_type} unrecognized.")
|
92 |
+
return False, latex_code
|
93 |
+
|
94 |
+
if __name__ == '__main__':
|
95 |
+
latex_code = open("2.txt", 'r').read().replace('\r', ' ')
|
96 |
+
print("=>", latex_code)
|
97 |
+
new_code = tokenize_latex(latex_code)
|
98 |
+
print("=>", new_code)
|
modules/visual_matcher.py
ADDED
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import numpy as np
|
3 |
+
from PIL import Image
|
4 |
+
from scipy.spatial.distance import cdist
|
5 |
+
from scipy.optimize import linear_sum_assignment
|
6 |
+
|
7 |
+
|
8 |
+
class SimpleAffineTransform:
|
9 |
+
"""
|
10 |
+
simple affine transform, only translation and scale.
|
11 |
+
"""
|
12 |
+
def __init__(self, translation=(0, 0), scale=1.0):
|
13 |
+
self.translation = np.array(translation)
|
14 |
+
self.scale = scale
|
15 |
+
|
16 |
+
def estimate(self, src, dst):
|
17 |
+
src_center = np.mean(src, axis=0)
|
18 |
+
dst_center = np.mean(dst, axis=0)
|
19 |
+
self.translation = dst_center - src_center
|
20 |
+
|
21 |
+
src_dists = np.linalg.norm(src - src_center, axis=1)
|
22 |
+
dst_dists = np.linalg.norm(dst - dst_center, axis=1)
|
23 |
+
self.scale = np.mean(dst_dists) / (np.mean(src_dists) + 1e-10)
|
24 |
+
|
25 |
+
def inverse(self):
|
26 |
+
inverse_transform = AffineTransform(-self.translation, 1.0/self.scale)
|
27 |
+
return inverse_transform
|
28 |
+
|
29 |
+
def __call__(self, coords):
|
30 |
+
return self.scale * (coords - np.mean(coords, axis=0)) + np.mean(coords, axis=0) + self.translation
|
31 |
+
|
32 |
+
def residuals(self, src, dst):
|
33 |
+
return np.sqrt(np.sum((self(src) - dst) ** 2, axis=1))
|
34 |
+
|
35 |
+
|
36 |
+
def norm_coords(x, left, right):
|
37 |
+
if x < left:
|
38 |
+
return left
|
39 |
+
if x > right:
|
40 |
+
return right
|
41 |
+
return x
|
42 |
+
|
43 |
+
def norm_same_token(token):
|
44 |
+
special_map = {
|
45 |
+
"\\cdot": ".",
|
46 |
+
"\\mid": "|",
|
47 |
+
"\\to": "\\rightarrow",
|
48 |
+
"\\top": "T",
|
49 |
+
"\\Tilde": "\\tilde",
|
50 |
+
"\\cdots": "\\dots",
|
51 |
+
"\\prime": "'",
|
52 |
+
"\\ast": "*",
|
53 |
+
"\\left<": "\\langle",
|
54 |
+
"\\right>": "\\rangle"
|
55 |
+
}
|
56 |
+
if token in special_map.keys():
|
57 |
+
token = special_map[token]
|
58 |
+
if token.startswith('\\left') or token.startswith('\\right'):
|
59 |
+
token = token.replace("\\left", "").replace("\\right", "")
|
60 |
+
if token.startswith('\\big') or token.startswith('\\Big'):
|
61 |
+
if "\\" in token[4:]:
|
62 |
+
token = "\\"+token[4:].split("\\")[-1]
|
63 |
+
else:
|
64 |
+
token = token[-1]
|
65 |
+
|
66 |
+
if token in ['\\leq', '\\geq']:
|
67 |
+
return token[0:-1]
|
68 |
+
if token in ['\\lVert', '\\rVert', '\\Vert']:
|
69 |
+
return '\\|'
|
70 |
+
if token in ['\\lvert', '\\rvert', '\\vert']:
|
71 |
+
return '|'
|
72 |
+
if token.endswith("rightarrow"):
|
73 |
+
return "\\rightarrow"
|
74 |
+
if token.endswith("leftarrow"):
|
75 |
+
return "\\leftarrow"
|
76 |
+
if token.startswith('\\wide'):
|
77 |
+
return token.replace("wide", "")
|
78 |
+
if token.startswith('\\var'):
|
79 |
+
return token.replace("\\var", "")
|
80 |
+
return token
|
81 |
+
|
82 |
+
|
83 |
+
class HungarianMatcher:
|
84 |
+
def __init__(
|
85 |
+
self,
|
86 |
+
cost_token: float = 1,
|
87 |
+
cost_position: float = 0.05,
|
88 |
+
cost_order: float = 0.15,
|
89 |
+
):
|
90 |
+
self.cost_token = cost_token
|
91 |
+
self.cost_position = cost_position
|
92 |
+
self.cost_order = cost_order
|
93 |
+
self.cost = {}
|
94 |
+
|
95 |
+
def calculate_token_cost_old(self, box_gt, box_pred):
|
96 |
+
token_cost = np.ones((len(box_gt), len(box_pred)))
|
97 |
+
for i in range(token_cost.shape[0]):
|
98 |
+
box1 = box_gt[i]
|
99 |
+
for j in range(token_cost.shape[1]):
|
100 |
+
box2 = box_pred[j]
|
101 |
+
if box1['token'] == box2['token']:
|
102 |
+
token_cost[i, j] = 0
|
103 |
+
elif norm_same_token(box1['token']) == norm_same_token(box2['token']):
|
104 |
+
token_cost[i, j] = 0.05
|
105 |
+
return np.array(token_cost)
|
106 |
+
|
107 |
+
def calculate_token_cost(self, box_gt, box_pred):
|
108 |
+
token2id = {}
|
109 |
+
for data in box_gt+box_pred:
|
110 |
+
if data['token'] not in token2id:
|
111 |
+
token2id[data['token']] = len(token2id)
|
112 |
+
num_classes = len(token2id)
|
113 |
+
|
114 |
+
token2id_norm = {}
|
115 |
+
for data in box_gt+box_pred:
|
116 |
+
if norm_same_token(data['token']) not in token2id_norm:
|
117 |
+
token2id_norm[norm_same_token(data['token'])] = len(token2id_norm)
|
118 |
+
num_classes_norm = len(token2id_norm)
|
119 |
+
|
120 |
+
gt_token_array = []
|
121 |
+
norm_gt_token_array = []
|
122 |
+
for data in box_gt:
|
123 |
+
gt_token_array.append(token2id[data['token']])
|
124 |
+
norm_gt_token_array.append(token2id_norm[norm_same_token(data['token'])])
|
125 |
+
|
126 |
+
pred_token_logits = []
|
127 |
+
norm_pred_token_logits = []
|
128 |
+
for data in box_pred:
|
129 |
+
logits = [0] * num_classes
|
130 |
+
logits[token2id[data['token']]] = 1
|
131 |
+
pred_token_logits.append(logits)
|
132 |
+
|
133 |
+
logits_norm = [0] * num_classes_norm
|
134 |
+
logits_norm[token2id_norm[norm_same_token(data['token'])]] = 1
|
135 |
+
norm_pred_token_logits.append(logits_norm)
|
136 |
+
|
137 |
+
gt_token_array = np.array(gt_token_array)
|
138 |
+
pred_token_logits = np.array(pred_token_logits)
|
139 |
+
|
140 |
+
norm_gt_token_array = np.array(norm_gt_token_array)
|
141 |
+
norm_pred_token_logits = np.array(norm_pred_token_logits)
|
142 |
+
|
143 |
+
token_cost = 1.0 - pred_token_logits[:, gt_token_array]
|
144 |
+
norm_token_cost = 1.0 - norm_pred_token_logits[:, norm_gt_token_array]
|
145 |
+
|
146 |
+
token_cost[np.logical_and(token_cost==1, norm_token_cost==0)] = 0.05
|
147 |
+
return token_cost.T
|
148 |
+
|
149 |
+
|
150 |
+
def box2array(self, box_list, size):
|
151 |
+
W, H = size
|
152 |
+
box_array = []
|
153 |
+
for box in box_list:
|
154 |
+
x_min, y_min, x_max, y_max = box['bbox']
|
155 |
+
box_array.append([x_min/W, y_min/H, x_max/W, y_max/H])
|
156 |
+
return np.array(box_array)
|
157 |
+
|
158 |
+
def order2array(self, box_list):
|
159 |
+
order_array = []
|
160 |
+
for idx, box in enumerate(box_list):
|
161 |
+
order_array.append([idx / len(box_list)])
|
162 |
+
return np.array(order_array)
|
163 |
+
|
164 |
+
def calculate_l1_cost(self, gt_array, pred_array):
|
165 |
+
scale = gt_array.shape[-1]
|
166 |
+
l1_cost = cdist(gt_array, pred_array, 'minkowski', p=1)
|
167 |
+
return l1_cost / scale
|
168 |
+
|
169 |
+
def __call__(self, box_gt, box_pred, gt_size, pred_size):
|
170 |
+
aa = time.time()
|
171 |
+
gt_box_array = self.box2array(box_gt, gt_size)
|
172 |
+
pred_box_array = self.box2array(box_pred, pred_size)
|
173 |
+
gt_order_array = self.order2array(box_gt)
|
174 |
+
pred_order_array = self.order2array(box_pred)
|
175 |
+
|
176 |
+
token_cost = self.calculate_token_cost(box_gt, box_pred)
|
177 |
+
position_cost = self.calculate_l1_cost(gt_box_array, pred_box_array)
|
178 |
+
order_cost = self.calculate_l1_cost(gt_order_array, pred_order_array)
|
179 |
+
|
180 |
+
self.cost["token"] = token_cost
|
181 |
+
self.cost["position"] = position_cost
|
182 |
+
self.cost["order"] = order_cost
|
183 |
+
|
184 |
+
cost = self.cost_token * token_cost + self.cost_position * position_cost + self.cost_order * order_cost
|
185 |
+
cost[np.isnan(cost) | np.isinf(cost)] = 100
|
186 |
+
indexes = linear_sum_assignment(cost)
|
187 |
+
matched_idxes = []
|
188 |
+
for a, b in zip(*indexes):
|
189 |
+
matched_idxes.append((a, b))
|
190 |
+
|
191 |
+
return matched_idxes
|
requriements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
tqdm
|
2 |
+
matplotlib
|
3 |
+
gradio==4.16.0
|
4 |
+
numpy<2.0.0
|
5 |
+
scikit-image<=0.20.0
|