@simonklee/opentui-tex-native-source 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,825 @@
1
+ --- a/build.zig
2
+ +++ b/build.zig
3
+ @@ -27,7 +27,7 @@
4
+ );
5
+
6
+ const install_config = b.addInstallFileWithDir(
7
+ - conf_header.getOutput(),
8
+ + conf_header.getOutputFile(),
9
+ .header,
10
+ "microtexconfig.h",
11
+ );
12
+ @@ -38,18 +38,19 @@
13
+ .root_module = b.createModule(.{
14
+ .target = target,
15
+ .optimize = optimize,
16
+ + .pic = true,
17
+ }),
18
+ });
19
+
20
+ // also install the configuration header into the include directory
21
+ lib.step.dependOn(&install_config.step);
22
+
23
+ - lib.linkLibCpp();
24
+ - lib.addConfigHeader(conf_header);
25
+ + lib.root_module.link_libcpp = true;
26
+ + lib.root_module.addConfigHeader(conf_header);
27
+
28
+ - lib.addIncludePath(b.path("lib"));
29
+ + lib.root_module.addIncludePath(b.path("lib"));
30
+ lib.root_module.addCMacro("GLYPH_RENDER_TYPE", glyph_render_type);
31
+ - lib.addCSourceFiles(.{
32
+ + lib.root_module.addCSourceFiles(.{
33
+ .root = b.path("lib"),
34
+ .files = SOURCE_FILES,
35
+ .flags = COMPILE_FLAGS,
36
+ @@ -60,7 +61,7 @@
37
+ }
38
+
39
+ // include the C wrapper
40
+ - lib.addCSourceFiles(.{
41
+ + lib.root_module.addCSourceFiles(.{
42
+ .root = b.path("lib"),
43
+ .files = CWRAPPER_FILES,
44
+ .flags = COMPILE_FLAGS,
45
+ @@ -78,21 +79,22 @@
46
+ .root_module = b.createModule(.{
47
+ .target = target,
48
+ .optimize = optimize,
49
+ + .pic = true,
50
+ }),
51
+ });
52
+
53
+ - exe.linkLibrary(lib);
54
+ - exe.addIncludePath(b.path("zig-out/include"));
55
+ - exe.addIncludePath(b.path("example/samples"));
56
+ - exe.addIncludePath(b.path("example/memcheck"));
57
+ - exe.addCSourceFiles(.{
58
+ + exe.root_module.linkLibrary(lib);
59
+ + exe.root_module.addIncludePath(b.path("zig-out/include"));
60
+ + exe.root_module.addIncludePath(b.path("example/samples"));
61
+ + exe.root_module.addIncludePath(b.path("example/memcheck"));
62
+ + exe.root_module.addCSourceFiles(.{
63
+ .files = &.{
64
+ "example/samples/samples.cpp",
65
+ "example/memcheck/mem_check_main.cpp",
66
+ },
67
+ .flags = COMPILE_FLAGS,
68
+ });
69
+ - exe.addIncludePath(b.path("lib"));
70
+ + exe.root_module.addIncludePath(b.path("lib"));
71
+
72
+ const memcheck_step = b.step("memcheck", "Build the memcheck binary.");
73
+ memcheck_step.dependOn(&b.addInstallArtifact(exe, .{}).step);
74
+ --- /dev/null
75
+ +++ b/lib/core/parse_limits.h
76
+ @@ -0,0 +1,54 @@
77
+ +#ifndef MICROTEX_PARSE_LIMITS_H
78
+ +#define MICROTEX_PARSE_LIMITS_H
79
+ +
80
+ +#include <cstddef>
81
+ +#include <string>
82
+ +
83
+ +namespace microtex {
84
+ +
85
+ +// Deliberately not std::exception: partial parsing must not swallow limit failures.
86
+ +struct ParseLimitExceeded {};
87
+ +
88
+ +struct ParseLimits {
89
+ + // Allow expansion beyond the 4 KiB public input limit, but bound synchronous work.
90
+ + static constexpr size_t bytes_max = 64 * 1024;
91
+ + size_t work_left = 1024 * 1024;
92
+ + size_t replacements_left = 1024;
93
+ + size_t depth = 0;
94
+ +
95
+ + void spend(size_t work = 1) {
96
+ + if (work > work_left) throw ParseLimitExceeded{};
97
+ + work_left -= work;
98
+ + }
99
+ +
100
+ + void input(size_t bytes) {
101
+ + if (bytes > bytes_max) throw ParseLimitExceeded{};
102
+ + spend(bytes);
103
+ + }
104
+ +
105
+ + void replace(std::string& source, size_t pos, size_t count, const std::string& text) {
106
+ + if (replacements_left == 0 || text.size() > bytes_max ||
107
+ + source.size() > bytes_max - text.size()) throw ParseLimitExceeded{};
108
+ + --replacements_left;
109
+ + spend(source.size() + text.size());
110
+ + source.replace(pos, count, text);
111
+ + }
112
+ +};
113
+ +
114
+ +// Nested parsers and macro argument substitutions share the caller's budget.
115
+ +inline thread_local ParseLimits parse_limits;
116
+ +
117
+ +struct ParseDepth {
118
+ + ParseDepth() {
119
+ + parse_limits.spend();
120
+ + if (parse_limits.depth >= 64) throw ParseLimitExceeded{};
121
+ + ++parse_limits.depth;
122
+ + }
123
+ + ~ParseDepth() { --parse_limits.depth; }
124
+ + ParseDepth(const ParseDepth&) = delete;
125
+ + ParseDepth& operator=(const ParseDepth&) = delete;
126
+ +};
127
+ +
128
+ +} // namespace microtex
129
+ +
130
+ +#endif
131
+ --- a/lib/core/parser.cpp
132
+ +++ b/lib/core/parser.cpp
133
+ @@ -1,4 +1,5 @@
134
+ #include "core/parser.h"
135
+ +#include "core/parse_limits.h"
136
+
137
+ #include "atom/atom.h"
138
+ #include "atom/atom_basic.h"
139
+ @@ -39,6 +40,7 @@
140
+ } // namespace
141
+
142
+ void Parser::init(bool isPartial, const string& latex, Formula* formula, bool firstPass) {
143
+ + parse_limits.input(latex.size());
144
+ _pos = _spos = _len = 0;
145
+ _group = 0;
146
+ _atIsLetter = 0;
147
+ @@ -62,6 +64,7 @@
148
+ }
149
+
150
+ void Parser::reset(const string& latex) {
151
+ + parse_limits.input(latex.size());
152
+ _latex = latex;
153
+ _len = latex.length();
154
+ _formula->_root = nullptr;
155
+ @@ -284,7 +287,7 @@
156
+ }
157
+
158
+ void Parser::insert(int beg, int end, const string& formula) {
159
+ - _latex.replace(beg, end - beg, formula);
160
+ + parse_limits.replace(_latex, beg, end - beg, formula);
161
+ _len = _latex.length();
162
+ _pos = beg;
163
+ _insertion = true;
164
+ @@ -363,6 +366,8 @@
165
+ }
166
+
167
+ void Parser::getOptsArgs(int argc, int opts, Args& args) {
168
+ + ParseDepth depth;
169
+ + if (argc < 0 || argc > 10) throw ParseLimitExceeded{};
170
+ // A maximum of 10 options can be passed to a command,
171
+ // the value will be added at the tail of the args if found any,
172
+ // the last (maximum to 12th) value is reserved for returned value
173
+ @@ -536,6 +541,7 @@
174
+ }
175
+
176
+ sptr<Atom> Parser::getArgument() {
177
+ + ParseDepth depth;
178
+ skipWhiteSpace();
179
+ char ch;
180
+ if (_pos < _len)
181
+ @@ -619,7 +625,7 @@
182
+ auto mac = MacroInfo::get(cmd);
183
+ getOptsArgs(mac->argc, mac->opt, args);
184
+ mac->invoke(*this, args);
185
+ - _latex.erase(pos, _pos - pos);
186
+ + parse_limits.replace(_latex, pos, _pos - pos, "");
187
+ _len = _latex.length();
188
+ _pos = pos;
189
+ }
190
+ @@ -632,7 +638,7 @@
191
+ try {
192
+ mac->invoke(*this, args);
193
+ // The last element is the returned value (after inflated macro)
194
+ - _latex.replace(pos, _pos - pos, args.back());
195
+ + parse_limits.replace(_latex, pos, _pos - pos, args.back());
196
+ } catch (ex_parse& e) {
197
+ if (!_isPartial) throw e;
198
+ pos += cmd.length() + 1;
199
+ @@ -654,7 +660,7 @@
200
+ string expr = "{\\makeatletter \\" + args[1] + "@env";
201
+ for (int i = 1; i <= mac->argc - 1; i++) expr += "{" + optargs[i] + "}";
202
+ expr += "{" + grp + "}\\makeatother}";
203
+ - _latex.replace(pos, _pos - pos, expr);
204
+ + parse_limits.replace(_latex, pos, _pos - pos, expr);
205
+ _len = _latex.length();
206
+ _pos = pos;
207
+ }
208
+ @@ -666,6 +672,7 @@
209
+ int spos;
210
+ vector<string> args;
211
+ while (_pos < _len) {
212
+ + parse_limits.spend();
213
+ ch = _latex[_pos];
214
+ switch (ch) {
215
+ case ESCAPE: {
216
+ @@ -687,7 +694,7 @@
217
+ if (chr == '\r' || chr == '\n') break;
218
+ }
219
+ if (_pos < _len) _pos--;
220
+ - _latex.replace(spos, _pos - spos, "");
221
+ + parse_limits.replace(_latex, spos, _pos - spos, "");
222
+ _len = _latex.length();
223
+ _pos = spos;
224
+ break;
225
+ @@ -700,6 +707,7 @@
226
+ }
227
+
228
+ void Parser::parse() {
229
+ + ParseDepth depth;
230
+ if (_len == 0) {
231
+ if (_formula->_root == nullptr && !_arrayMode) _formula->add(sptrOf<EmptyAtom>());
232
+ return;
233
+ @@ -707,6 +715,7 @@
234
+
235
+ char ch;
236
+ while (_pos < _len) {
237
+ + parse_limits.spend();
238
+ ch = _latex[_pos];
239
+
240
+ switch (ch) {
241
+ --- a/lib/utils/string_utils.h
242
+ +++ b/lib/utils/string_utils.h
243
+ @@ -8,6 +8,7 @@
244
+ #include <map>
245
+ #include <string>
246
+ #include <vector>
247
+ +#include "core/parse_limits.h"
248
+
249
+ namespace microtex {
250
+
251
+ @@ -119,7 +120,7 @@
252
+ if (from.empty()) return src;
253
+ size_t start = 0;
254
+ while ((start = src.find(from, start)) != std::string::npos) {
255
+ - src.replace(start, from.length(), to);
256
+ + parse_limits.replace(src, start, from.length(), to);
257
+ start += to.length();
258
+ }
259
+ return src;
260
+ --- a/lib/wrapper/byte_seq.cpp
261
+ +++ b/lib/wrapper/byte_seq.cpp
262
+ @@ -3,6 +3,7 @@
263
+ #include "wrapper/byte_seq.h"
264
+
265
+ #include <cstdlib>
266
+ +#include <new>
267
+
268
+ #include "utils/log.h"
269
+
270
+ @@ -10,11 +11,16 @@
271
+
272
+ ByteSeq::ByteSeq() {
273
+ _data = malloc(CHUNK_SIZE);
274
+ + if (_data == nullptr) throw std::bad_alloc();
275
+ // the first 4 bytes is the bytes size used
276
+ _index = 4;
277
+ _capacity = CHUNK_SIZE;
278
+ }
279
+
280
+ +ByteSeq::~ByteSeq() {
281
+ + free(_data);
282
+ +}
283
+ +
284
+ void ByteSeq::_put(const char* str) {
285
+ auto l = sizeOf(str);
286
+ strcpy((char*)_data + _index, str);
287
+ @@ -28,8 +34,11 @@
288
+ #ifdef HAVE_LOG
289
+ logv("grow buffer, _capacity: %u, to be add: %u\n", _capacity, required);
290
+ #endif
291
+ - _data = realloc(_data, _capacity + CHUNK_SIZE);
292
+ - _capacity += CHUNK_SIZE;
293
+ + const auto capacity = _index + required + CHUNK_SIZE;
294
+ + auto data = realloc(_data, capacity);
295
+ + if (data == nullptr) throw std::bad_alloc();
296
+ + _data = data;
297
+ + _capacity = capacity;
298
+ }
299
+
300
+ void* ByteSeq::finish() {
301
+ @@ -38,7 +47,8 @@
302
+ #endif
303
+ auto ptr = (unsigned int*)_data;
304
+ *ptr = _index;
305
+ - return _data;
306
+ + _data = nullptr;
307
+ + return ptr;
308
+ }
309
+
310
+ } // namespace microtex
311
+ --- a/lib/wrapper/byte_seq.h
312
+ +++ b/lib/wrapper/byte_seq.h
313
+ @@ -52,6 +52,7 @@
314
+ no_copy_assign(ByteSeq);
315
+
316
+ ByteSeq();
317
+ + ~ByteSeq();
318
+
319
+ template <typename T, typename... Ts>
320
+ void put(T t, Ts... ts) {
321
+ --- a/lib/wrapper/cwrapper.cpp
322
+ +++ b/lib/wrapper/cwrapper.cpp
323
+ @@ -3,6 +3,7 @@
324
+ #include "wrapper/cwrapper.h"
325
+
326
+ #include "microtex.h"
327
+ +#include "core/parse_limits.h"
328
+ #include "utils/log.h"
329
+ #include "wrapper/graphic_wrapper.h"
330
+
331
+ @@ -136,16 +137,22 @@
332
+ #ifdef HAVE_LOG
333
+ logv("parse: %s\n", tex);
334
+ #endif
335
+ - auto r = MicroTeX::parse(
336
+ - tex,
337
+ - width,
338
+ - textSize,
339
+ - lineSpace,
340
+ - color,
341
+ - fillWidth,
342
+ - {enableOverrideTeXStyle, static_cast<TexStyle>(texStyle)}
343
+ - );
344
+ - return reinterpret_cast<RenderPtr>(r);
345
+ + try {
346
+ + parse_limits = {};
347
+ + auto r = MicroTeX::parse(
348
+ + tex,
349
+ + width,
350
+ + textSize,
351
+ + lineSpace,
352
+ + color,
353
+ + fillWidth,
354
+ + {enableOverrideTeXStyle, static_cast<TexStyle>(texStyle)}
355
+ + );
356
+ + return reinterpret_cast<RenderPtr>(r);
357
+ + } catch (...) {
358
+ + // C++ exceptions cannot unwind through the Zig/C ABI.
359
+ + return nullptr;
360
+ + }
361
+ }
362
+
363
+ MICROTEX_CAPI void microtex_deleteRender(RenderPtr render) {
364
+ @@ -154,10 +161,14 @@
365
+ }
366
+
367
+ MICROTEX_CAPI DrawingData microtex_getDrawingData(RenderPtr render, int x, int y) {
368
+ - auto r = reinterpret_cast<Render*>(render);
369
+ - Graphics2D_wrapper g2;
370
+ - r->draw(g2, x, y);
371
+ - return g2.getDrawingData();
372
+ + try {
373
+ + auto r = reinterpret_cast<Render*>(render);
374
+ + Graphics2D_wrapper g2;
375
+ + r->draw(g2, x, y);
376
+ + return g2.getDrawingData();
377
+ + } catch (...) {
378
+ + return nullptr;
379
+ + }
380
+ }
381
+
382
+ MICROTEX_CAPI void microtex_freeDrawingData(DrawingData data) {
383
+ --- a/lib/atom/atom_matrix.cpp
384
+ +++ b/lib/atom/atom_matrix.cpp
385
+ @@ -1,11 +1,13 @@
386
+ #include "atom/atom_matrix.h"
387
+
388
+ +#include <charconv>
389
+ #include <memory>
390
+
391
+ #include "atom/atom_basic.h"
392
+ #include "atom/atom_row.h"
393
+ #include "core/formula.h"
394
+ #include "core/glue.h"
395
+ +#include "core/parse_limits.h"
396
+ #include "env/env.h"
397
+ #include "utils/exceptions.h"
398
+ #include "utils/string_utils.h"
399
+ @@ -31,6 +33,8 @@
400
+ }
401
+
402
+ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
403
+ + ParseDepth depth;
404
+ + parse_limits.input(opt.size());
405
+ int len = opt.length();
406
+ int pos = 0;
407
+ char ch;
408
+ @@ -39,6 +43,7 @@
409
+ // clear first
410
+ lpos.clear();
411
+ while (pos < len) {
412
+ + parse_limits.spend();
413
+ ch = opt[pos];
414
+ switch (ch) {
415
+ case 'l': lpos.push_back(Alignment::left); break;
416
+ @@ -79,11 +84,22 @@
417
+ vector<string> args;
418
+ tp->getOptsArgs(2, 0, args);
419
+ pos += tp->getPos();
420
+ - int nrep = 0;
421
+ - valueOf(args[1], nrep);
422
+ + size_t nrep = 0;
423
+ + const auto& count = trim(args[1]);
424
+ + auto first = count.data();
425
+ + if (!count.empty() && count.front() == '+') ++first;
426
+ + const auto parsed = from_chars(first, count.data() + count.size(), nrep);
427
+ + if (parsed.ec != errc{} || parsed.ptr != count.data() + count.size() ||
428
+ + nrep > ParseLimits::bytes_max ||
429
+ + (!args[2].empty() && nrep > (ParseLimits::bytes_max - opt.size()) / args[2].size())) {
430
+ + throw ParseLimitExceeded{};
431
+ + }
432
+ + const auto bytes = nrep * args[2].size();
433
+ + parse_limits.spend(nrep + bytes);
434
+ string str;
435
+ - for (int j = 0; j < nrep; j++) str += args[2];
436
+ - opt.insert(pos, str);
437
+ + str.reserve(bytes);
438
+ + for (size_t j = 0; j < nrep; j++) str += args[2];
439
+ + parse_limits.replace(opt, pos, 0, str);
440
+ len = opt.length();
441
+ pos--;
442
+ } break;
443
+ @@ -102,10 +118,11 @@
444
+ int spos = len + 1;
445
+ bool hasrep = false;
446
+ while (--spos > pos) {
447
+ + parse_limits.spend(spos - pos);
448
+ auto it = _colspeReplacement.find(opt.substr(pos, spos - pos));
449
+ if (it != _colspeReplacement.end()) {
450
+ hasrep = true;
451
+ - opt.insert(spos, it->second);
452
+ + parse_limits.replace(opt, spos, 0, it->second);
453
+ len = opt.length();
454
+ pos = spos - 1;
455
+ break;
456
+ @@ -127,9 +144,9 @@
457
+ if (lpos.empty()) lpos.push_back(Alignment::center);
458
+ }
459
+
460
+ -float* MatrixAtom::getColumnSep(Env& env, float width) {
461
+ +vector<float> MatrixAtom::getColumnSep(Env& env, float width) {
462
+ const int cols = _matrix->cols();
463
+ - auto* arr = new float[cols + 1]();
464
+ + vector<float> arr(cols + 1);
465
+ sptr<Box> Align, AlignSep, Hsep;
466
+ float h, w = env.textWidth();
467
+ int i = 0;
468
+ @@ -234,7 +251,7 @@
469
+
470
+ void MatrixAtom::recalculateLine(
471
+ const int rows,
472
+ - sptr<Box>** boxarr,
473
+ + vector<vector<sptr<Box>>>& boxarr,
474
+ vector<sptr<Atom>>& multiRows,
475
+ float* height,
476
+ float* depth,
477
+ @@ -406,11 +423,11 @@
478
+ const int rows = _matrix->rows();
479
+ const int cols = _matrix->cols();
480
+
481
+ - auto lineDepth = new float[rows]();
482
+ - auto lineHeight = new float[rows]();
483
+ - auto colWidth = new float[cols]();
484
+ - auto boxarr = new sptr<Box>*[rows]();
485
+ - for (int i = 0; i < rows; i++) boxarr[i] = new sptr<Box>[cols]();
486
+ + vector<float> lineDepth(rows);
487
+ + vector<float> lineHeight(rows);
488
+ + vector<float> colWidth(cols);
489
+ + vector<vector<sptr<Box>>> boxarr(rows);
490
+ + for (auto& row : boxarr) row.resize(cols);
491
+
492
+ float matW = 0;
493
+ const auto drt = env.ruleThickness();
494
+ @@ -459,7 +476,7 @@
495
+ for (int j = 0; j < cols; j++) matW += colWidth[j];
496
+
497
+ // The horizontal separator's width
498
+ - float* Hsep = getColumnSep(env, matW);
499
+ + auto Hsep = getColumnSep(env, matW);
500
+
501
+ for (auto& i : multiCols) {
502
+ auto* multi = (MulticolumnAtom*)i.get();
503
+ @@ -486,9 +503,9 @@
504
+
505
+ auto Vsep = _vsep_in.createBox(env);
506
+ // Recalculate the height of the row
507
+ - recalculateLine(rows, boxarr, multiRows, lineHeight, lineDepth, drt, Vsep->_height);
508
+ + recalculateLine(rows, boxarr, multiRows, lineHeight.data(), lineDepth.data(), drt, Vsep->_height);
509
+
510
+ - auto* vb = new VBox();
511
+ + auto vb = sptrOf<VBox>();
512
+ float totalHeight = 0;
513
+ float Vspace = Vsep->_height / 2;
514
+
515
+ @@ -511,11 +528,11 @@
516
+
517
+ bool isLastVline = true;
518
+
519
+ - WrapperBox* wb = nullptr;
520
+ + sptr<WrapperBox> wb;
521
+ int tj = j;
522
+ float l = j == 0 ? Hsep[j] : Hsep[j] / 2;
523
+ if (boxarr[i][j]->_type == AtomType::none) {
524
+ - wb = new WrapperBox(
525
+ + wb = sptrOf<WrapperBox>(
526
+ boxarr[i][j],
527
+ colWidth[j],
528
+ lineHeight[i],
529
+ @@ -523,18 +540,17 @@
530
+ _position[j] //
531
+ );
532
+ } else {
533
+ - auto b = generateMulticolumn(env, boxarr[i][j], Hsep, colWidth, i, j);
534
+ + auto b = generateMulticolumn(env, boxarr[i][j], Hsep.data(), colWidth.data(), i, j);
535
+ auto* matom = (MulticolumnAtom*)_matrix->_array[i][j].get();
536
+ j += matom->skipped() - 1;
537
+ - wb = new WrapperBox(b, b->_width, lineHeight[i], lineDepth[i], Alignment::left);
538
+ + wb = sptrOf<WrapperBox>(b, b->_width, lineHeight[i], lineDepth[i], Alignment::left);
539
+ isLastVline = matom->hasRightVline();
540
+ }
541
+ float r = j == cols - 1 ? Hsep[j + 1] : Hsep[j + 1] / 2;
542
+ wb->addInsets(l, Vspace, r, Vspace);
543
+ applyCell(*wb, i, j);
544
+ - sptr<Box> swb(wb);
545
+ - boxarr[i][tj] = swb;
546
+ - hb->add(swb);
547
+ + boxarr[i][tj] = wb;
548
+ + hb->add(wb);
549
+
550
+ auto it = _vlines.find(j + 1);
551
+ if (isLastVline && it != _vlines.end()) {
552
+ @@ -582,14 +598,7 @@
553
+ vb->_height = totalHeight / 2 + axis;
554
+ vb->_depth = totalHeight / 2 - axis;
555
+
556
+ - delete[] Hsep;
557
+ - delete[] lineDepth;
558
+ - delete[] lineHeight;
559
+ - delete[] colWidth;
560
+ - for (int i = 0; i < rows; i++) delete[] boxarr[i];
561
+ - delete[] boxarr;
562
+ -
563
+ - return sptr<Box>(vb);
564
+ + return vb;
565
+ }
566
+
567
+ sptr<Box> MatrixAtom::createBox(Env& env) {
568
+ @@ -709,13 +718,13 @@
569
+ const auto drt = env.ruleThickness();
570
+ auto rb = sptrOf<RuleBox>(_height, drt, _shift, MatrixAtom::LINE_COLOR, true);
571
+ auto sep = sptrOf<StrutBox>(2 * drt, 0.f, 0.f, 0.f);
572
+ - auto hb = new HBox();
573
+ + auto hb = sptrOf<HBox>();
574
+ for (int i = 0; i < _n - 1; i++) {
575
+ hb->add(rb);
576
+ hb->add(sep);
577
+ }
578
+ if (_n > 0) hb->add(rb);
579
+ - return sptr<Box>(hb);
580
+ + return hb;
581
+ }
582
+
583
+ SpaceAtom MultlineAtom::_vsep_in(UnitType::ex, 0.f, 1.f, 0.f);
584
+ @@ -725,7 +734,7 @@
585
+ if (tw == POS_INF || _lineType == MultiLineType::gathered)
586
+ return MatrixAtom(_isPartial, _column, "").createBox(env);
587
+
588
+ - auto* vb = new VBox();
589
+ + auto vb = sptrOf<VBox>();
590
+ auto atom = _column->_array[0][0];
591
+ Alignment alignment = _lineType == MultiLineType::gather ? Alignment::center : Alignment::left;
592
+ if (atom->_alignment != Alignment::none) alignment = atom->_alignment;
593
+ @@ -752,5 +761,5 @@
594
+ vb->_height = h / 2;
595
+ vb->_depth = h / 2;
596
+
597
+ - return sptr<Box>(vb);
598
+ + return vb;
599
+ }
600
+ --- a/lib/macro/macro_env.h
601
+ +++ b/lib/macro/macro_env.h
602
+ @@ -11,68 +11,68 @@
603
+ namespace microtex {
604
+
605
+ inline macro(smallmatrixATATenv) {
606
+ - auto* arr = new ArrayFormula();
607
+ - Parser parser(tp.isPartial(), args[1], arr, false);
608
+ + auto arr = sptrOf<ArrayFormula>();
609
+ + Parser parser(tp.isPartial(), args[1], arr.get(), false);
610
+ parser.parse();
611
+ arr->checkDimensions();
612
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::smallMatrix);
613
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::smallMatrix);
614
+ }
615
+
616
+ inline macro(matrixATATenv) {
617
+ - auto* arr = new ArrayFormula();
618
+ - Parser parser(tp.isPartial(), args[1], arr, false);
619
+ + auto arr = sptrOf<ArrayFormula>();
620
+ + Parser parser(tp.isPartial(), args[1], arr.get(), false);
621
+ parser.parse();
622
+ arr->checkDimensions();
623
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::matrix);
624
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::matrix);
625
+ }
626
+
627
+ inline macro(arrayATATenv) {
628
+ - auto* arr = new ArrayFormula();
629
+ - Parser parser(tp.isPartial(), args[2], arr, false);
630
+ + auto arr = sptrOf<ArrayFormula>();
631
+ + Parser parser(tp.isPartial(), args[2], arr.get(), false);
632
+ parser.parse();
633
+ arr->checkDimensions();
634
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), args[1], true);
635
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, args[1], true);
636
+ }
637
+
638
+ inline macro(alignATATenv) {
639
+ - auto* arr = new ArrayFormula();
640
+ - Parser parser(tp.isPartial(), args[1], arr, false);
641
+ + auto arr = sptrOf<ArrayFormula>();
642
+ + Parser parser(tp.isPartial(), args[1], arr.get(), false);
643
+ parser.parse();
644
+ arr->checkDimensions();
645
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::align);
646
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::align);
647
+ }
648
+
649
+ inline macro(flalignATATenv) {
650
+ - auto* arr = new ArrayFormula();
651
+ - Parser parser(tp.isPartial(), args[1], arr, false);
652
+ + auto arr = sptrOf<ArrayFormula>();
653
+ + Parser parser(tp.isPartial(), args[1], arr.get(), false);
654
+ parser.parse();
655
+ arr->checkDimensions();
656
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::flAlign);
657
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::flAlign);
658
+ }
659
+
660
+ inline macro(alignatATATenv) {
661
+ - auto* arr = new ArrayFormula();
662
+ - Parser par(tp.isPartial(), args[2], arr, false);
663
+ + auto arr = sptrOf<ArrayFormula>();
664
+ + Parser par(tp.isPartial(), args[2], arr.get(), false);
665
+ par.parse();
666
+ arr->checkDimensions();
667
+ size_t n = 0;
668
+ valueOf(args[1], n);
669
+ if (arr->cols() != 2 * n) throw ex_parse("Bad number of equations in alignat environment!");
670
+
671
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::alignAt);
672
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignAt);
673
+ }
674
+
675
+ inline macro(alignedATATenv) {
676
+ - auto* arr = new ArrayFormula();
677
+ - Parser p(tp.isPartial(), args[1], arr, false);
678
+ + auto arr = sptrOf<ArrayFormula>();
679
+ + Parser p(tp.isPartial(), args[1], arr.get(), false);
680
+ p.parse();
681
+ arr->checkDimensions();
682
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::aligned);
683
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::aligned);
684
+ }
685
+
686
+ inline macro(alignedatATATenv) {
687
+ - auto* arr = new ArrayFormula();
688
+ - Parser p(tp.isPartial(), args[2], arr, false);
689
+ + auto arr = sptrOf<ArrayFormula>();
690
+ + Parser p(tp.isPartial(), args[2], arr.get(), false);
691
+ p.parse();
692
+ arr->checkDimensions();
693
+ size_t n = 0;
694
+ @@ -81,12 +81,12 @@
695
+ throw ex_parse("Bad number of equations in alignedat environment!");
696
+ }
697
+
698
+ - return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::alignedAt);
699
+ + return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignedAt);
700
+ }
701
+
702
+ inline macro(multlineATATenv) {
703
+ - auto* arr = new ArrayFormula();
704
+ - Parser p(tp.isPartial(), args[1], arr, false);
705
+ + auto arr = sptrOf<ArrayFormula>();
706
+ + Parser p(tp.isPartial(), args[1], arr.get(), false);
707
+ p.parse();
708
+ arr->checkDimensions();
709
+ if (arr->cols() > 1) {
710
+ @@ -94,29 +94,29 @@
711
+ }
712
+ if (arr->cols() == 0) return nullptr;
713
+
714
+ - return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::multiline);
715
+ + return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::multiline);
716
+ }
717
+
718
+ inline macro(gatherATATenv) {
719
+ - auto* arr = new ArrayFormula();
720
+ - Parser p(tp.isPartial(), args[1], arr, false);
721
+ + auto arr = sptrOf<ArrayFormula>();
722
+ + Parser p(tp.isPartial(), args[1], arr.get(), false);
723
+ p.parse();
724
+ arr->checkDimensions();
725
+ if (arr->cols() > 1) throw ex_parse("Requires exact one column in gather environment!");
726
+ if (arr->cols() == 0) return nullptr;
727
+
728
+ - return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::gather);
729
+ + return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gather);
730
+ }
731
+
732
+ inline macro(gatheredATATenv) {
733
+ - auto* arr = new ArrayFormula();
734
+ - Parser p(tp.isPartial(), args[1], arr, false);
735
+ + auto arr = sptrOf<ArrayFormula>();
736
+ + Parser p(tp.isPartial(), args[1], arr.get(), false);
737
+ p.parse();
738
+ arr->checkDimensions();
739
+ if (arr->cols() > 1) throw ex_parse("Requires exact one column in gathered environment!");
740
+ if (arr->cols() == 0) return nullptr;
741
+
742
+ - return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::gathered);
743
+ + return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gathered);
744
+ }
745
+
746
+ inline macro(multicolumn) {
747
+ --- a/lib/atom/atom_matrix.h
748
+ +++ b/lib/atom/atom_matrix.h
749
+ @@ -87,7 +87,7 @@
750
+
751
+ static void recalculateLine(
752
+ int rows,
753
+ - sptr<Box>** boxarr,
754
+ + std::vector<std::vector<sptr<Box>>>& boxarr,
755
+ std::vector<sptr<Atom>>& multiRows,
756
+ float* height,
757
+ float* depth,
758
+ @@ -95,7 +95,7 @@
759
+ float vspace
760
+ );
761
+
762
+ - float* getColumnSep(Env& env, float width);
763
+ + std::vector<float> getColumnSep(Env& env, float width);
764
+
765
+ void applyCell(WrapperBox& box, int i, int j);
766
+
767
+ --- a/lib/atom/atom_row.cpp
768
+ +++ b/lib/atom/atom_row.cpp
769
+ @@ -172,7 +172,7 @@
770
+ }
771
+
772
+ sptr<Box> RowAtom::createBox(Env& env) {
773
+ - auto hbox = new HBox();
774
+ + auto hbox = sptrOf<HBox>();
775
+ // convert atoms to boxes and add to the horizontal box
776
+ const int end = _elements.size() - 1;
777
+ for (int i = -1; i < end;) {
778
+ @@ -326,7 +326,7 @@
779
+ }
780
+ // reset previous atom
781
+ _previousAtom = nullptr;
782
+ - return sptr<Box>(hbox);
783
+ + return hbox;
784
+ }
785
+
786
+ void RowAtom::setPreviousAtom(const sptr<AtomDecor>& prev) {
787
+ --- a/lib/macro/macro_delims.cpp
788
+ +++ b/lib/macro/macro_delims.cpp
789
+ @@ -13,18 +13,18 @@
790
+ StackArgs::autoSpace(Formula(tp, args[1], false, tp.isMathMode())._root, false);
791
+ const auto& under =
792
+ StackArgs::autoSpace(Formula(tp, args[2], false, tp.isMathMode())._root, false);
793
+ - const auto stack = new StackAtom(nullptr, over, under);
794
+ + const auto stack = sptrOf<StackAtom>(nullptr, over, under);
795
+ const auto& arrow = sptrOf<ExtensibleAtom>(
796
+ name,
797
+ // capture raw pointer to avoid cycle reference
798
+ - [stack](const Env& env) -> float {
799
+ + [stack = stack.get()](const Env& env) -> float {
800
+ return stack->getMaxWidth() + Units::fsize(UnitType::ex, 1.f, env);
801
+ },
802
+ false
803
+ );
804
+ arrow->_type = AtomType::relation;
805
+ stack->setBaseAtom(arrow);
806
+ - return sptr<StackAtom>(stack);
807
+ + return stack;
808
+ }
809
+
810
+ macro(left) {
811
+ @@ -45,12 +45,12 @@
812
+ return sptrOf<FencedAtom>(tf._root, sl->name(), sr->name(), tf.middle());
813
+ }
814
+
815
+ - auto* ra = new RowAtom();
816
+ + auto ra = sptrOf<RowAtom>();
817
+ ra->add(left);
818
+ ra->add(Formula(tp, grep, false)._root);
819
+ ra->add(right);
820
+
821
+ - return sptr<Atom>(ra);
822
+ + return ra;
823
+ }
824
+
825
+ } // namespace microtex