Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/mathml/./../../../layout/mathml/nsMathMLOperators.cpp
Warning:line 191, column 13
Value stored to 'end' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_layout_mathml0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/mathml -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/mathml -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/layout/mathml -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/mathml -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/painting -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/tables -I /root/firefox-clang/layout/xul -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/mathml -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_layout_mathml0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsMathMLOperators.h"
6
7#include "mozilla/StaticPrefs_mathml.h"
8#include "mozilla/Utf16.h"
9#include "mozilla/intl/UnicodeProperties.h"
10#include "nsCOMPtr.h"
11#include "nsCRT.h"
12#include "nsHashKeys.h"
13#include "nsIPersistentProperties2.h"
14#include "nsISimpleEnumerator.h"
15#include "nsNetUtil.h"
16#include "nsTArray.h"
17#include "nsTHashMap.h"
18
19using namespace mozilla;
20
21// operator dictionary entry
22struct OperatorData {
23 OperatorData(void) : mLeadingSpace(0.0f), mTrailingSpace(0.0f) {}
24
25 // member data
26 nsString mStr;
27 nsOperatorFlags mFlags;
28 float mLeadingSpace; // unit is em
29 float mTrailingSpace; // unit is em
30};
31
32static int32_t gTableRefCount = 0;
33static uint32_t gOperatorCount = 0;
34static OperatorData* gOperatorArray = nullptr;
35static nsTHashMap<nsStringHashKey, OperatorData*>* gOperatorTable = nullptr;
36static bool gGlobalsInitialized = false;
37
38static const char16_t kDashCh = char16_t('#');
39static const char16_t kColonCh = char16_t(':');
40
41static uint32_t ToUnicodeCodePoint(const nsString& aOperator) {
42 if (aOperator.Length() == 1) {
43 return aOperator[0];
44 }
45 if (aOperator.Length() == 2 &&
46 mozilla::IsSurrogatePair(aOperator[0], aOperator[1])) {
47 return mozilla::SurrogateToUCS4(aOperator[0], aOperator[1]);
48 }
49 return 0;
50}
51
52static void SetBooleanProperty(OperatorData* aOperatorData, nsString aName) {
53 if (aName.IsEmpty()) {
54 return;
55 }
56
57 if (aName.EqualsLiteral("stretchy") && (1 == aOperatorData->mStr.Length())) {
58 aOperatorData->mFlags.Booleans() += OperatorBoolean::Stretchy;
59 } else if (aName.EqualsLiteral("fence")) {
60 aOperatorData->mFlags.Booleans() += OperatorBoolean::Fence;
61 } else if (!StaticPrefs::mathml_operator_dictionary_accent_disabled() &&
62 aName.EqualsLiteral("accent")) {
63 aOperatorData->mFlags.Booleans() += OperatorBoolean::Accent;
64 } else if (aName.EqualsLiteral("largeop")) {
65 aOperatorData->mFlags.Booleans() += OperatorBoolean::LargeOperator;
66 } else if (aName.EqualsLiteral("separator")) {
67 aOperatorData->mFlags.Booleans() += OperatorBoolean::Separator;
68 } else if (aName.EqualsLiteral("movablelimits")) {
69 aOperatorData->mFlags.Booleans() += OperatorBoolean::MovableLimits;
70 } else if (aName.EqualsLiteral("symmetric")) {
71 aOperatorData->mFlags.Booleans() += OperatorBoolean::Symmetric;
72 }
73}
74
75static void SetProperty(OperatorData* aOperatorData, nsString aName,
76 nsString aValue) {
77 if (aName.IsEmpty() || aValue.IsEmpty()) {
78 return;
79 }
80
81 if (aName.EqualsLiteral("direction")) {
82 if (aValue.EqualsLiteral("vertical")) {
83 aOperatorData->mFlags.SetDirection(OperatorDirection::Vertical);
84 } else if (aValue.EqualsLiteral("horizontal")) {
85 aOperatorData->mFlags.SetDirection(OperatorDirection::Horizontal);
86 } else {
87 return; // invalid value
88 }
89 } else {
90 bool isLeadingSpace;
91 if (aName.EqualsLiteral("lspace")) {
92 isLeadingSpace = true;
93 } else if (aName.EqualsLiteral("rspace")) {
94 isLeadingSpace = false;
95 } else {
96 return; // input is not applicable
97 }
98
99 // aValue is assumed to be a digit from 0 to 7
100 nsresult error = NS_OK;
101 float space = aValue.ToFloat(&error) / 18.0;
102 if (NS_FAILED(error)((bool)(__builtin_expect(!!(NS_FAILED_impl(error)), 0)))) {
103 return;
104 }
105
106 if (isLeadingSpace) {
107 aOperatorData->mLeadingSpace = space;
108 } else {
109 aOperatorData->mTrailingSpace = space;
110 }
111 }
112}
113
114static bool SetOperator(OperatorData* aOperatorData, OperatorForm aForm,
115 const nsCString& aOperator, nsString& aAttributes)
116
117{
118 static const char16_t kNullCh = char16_t('\0');
119
120 // aOperator is in the expanded format \uNNNN\uNNNN ...
121 // First compress these Unicode points to the internal nsString format
122 int32_t i = 0;
123 nsAutoString name, value;
124 int32_t len = aOperator.Length();
125 char16_t c = aOperator[i++];
126 uint32_t state = 0;
127 char16_t uchar = 0;
128 while (i <= len) {
129 if (0 == state) {
130 if (c != '\\') {
131 return false;
132 }
133 if (i < len) {
134 c = aOperator[i];
135 }
136 i++;
137 if (('u' != c) && ('U' != c)) {
138 return false;
139 }
140 if (i < len) {
141 c = aOperator[i];
142 }
143 i++;
144 state++;
145 } else {
146 if (('0' <= c) && (c <= '9')) {
147 uchar = (uchar << 4) | (c - '0');
148 } else if (('a' <= c) && (c <= 'f')) {
149 uchar = (uchar << 4) | (c - 'a' + 0x0a);
150 } else if (('A' <= c) && (c <= 'F')) {
151 uchar = (uchar << 4) | (c - 'A' + 0x0a);
152 } else {
153 return false;
154 }
155 if (i < len) {
156 c = aOperator[i];
157 }
158 i++;
159 state++;
160 if (5 == state) {
161 value.Append(uchar);
162 uchar = 0;
163 state = 0;
164 }
165 }
166 }
167 if (0 != state) {
168 return false;
169 }
170
171 // Quick return when the caller doesn't care about the attributes and just
172 // wants to know if this is a valid operator (this is the case at the first
173 // pass of the parsing of the dictionary in InitOperators())
174 if (aForm == OperatorForm::Unknown) {
175 return true;
176 }
177
178 // Add operator to hash table
179 aOperatorData->mFlags.SetForm(aForm);
180 aOperatorData->mStr.Assign(value);
181 value.AppendInt(static_cast<uint32_t>(aForm), 10);
182 gOperatorTable->InsertOrUpdate(value, aOperatorData);
183
184#ifdef DEBUG1
185 NS_LossyConvertUTF16toASCII str(aAttributes);
186#endif
187 // Loop over the space-delimited list of attributes to get the name:value
188 // pairs
189 aAttributes.Append(kNullCh); // put an extra null at the end
190 char16_t* start = aAttributes.BeginWriting();
191 char16_t* end = start;
Value stored to 'end' during its initialization is never read
192 while ((kNullCh != *start) && (kDashCh != *start)) {
193 name.SetLength(0);
194 value.SetLength(0);
195 // skip leading space, the dash amounts to the end of the line
196 while ((kNullCh != *start) && (kDashCh != *start) &&
197 nsCRT::IsAsciiSpace(*start)) {
198 ++start;
199 }
200 end = start;
201 // look for ':'
202 while ((kNullCh != *end) && (kDashCh != *end) &&
203 !nsCRT::IsAsciiSpace(*end) && (kColonCh != *end)) {
204 ++end;
205 }
206 // If ':' is not found, then it's a boolean property
207 bool IsBooleanProperty = (kColonCh != *end);
208 *end = kNullCh; // end segment here
209 // this segment is the name
210 if (start < end) {
211 name.Assign(start);
212 }
213 if (IsBooleanProperty) {
214 SetBooleanProperty(aOperatorData, name);
215 } else {
216 start = ++end;
217 // look for space or end of line
218 while ((kNullCh != *end) && (kDashCh != *end) &&
219 !nsCRT::IsAsciiSpace(*end)) {
220 ++end;
221 }
222 *end = kNullCh; // end segment here
223 if (start < end) {
224 // this segment is the value
225 value.Assign(start);
226 }
227 SetProperty(aOperatorData, name, value);
228 }
229 start = ++end;
230 }
231 return true;
232}
233
234static nsresult InitOperators(void) {
235 // Load the property file containing the Operator Dictionary
236 nsresult rv;
237 nsCOMPtr<nsIPersistentProperties> mathfontProp;
238 rv = NS_LoadPersistentPropertiesFromURISpec(
239 getter_AddRefs(mathfontProp),
240 "resource://gre/res/fonts/mathfont.properties"_ns);
241
242 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
243 return rv;
244 }
245
246 // Parse the Operator Dictionary in two passes.
247 // The first pass is to count the number of operators; the second pass is to
248 // allocate the necessary space for them and to add them in the hash table.
249 for (int32_t pass = 1; pass <= 2; pass++) {
250 OperatorData dummyData;
251 OperatorData* operatorData = &dummyData;
252 nsCOMPtr<nsISimpleEnumerator> iterator;
253 if (NS_SUCCEEDED(mathfontProp->Enumerate(getter_AddRefs(iterator)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mathfontProp->
Enumerate(getter_AddRefs(iterator)))), 1)))
) {
254 bool more;
255 uint32_t index = 0;
256 nsAutoCString name;
257 nsAutoString attributes;
258 while ((NS_SUCCEEDED(iterator->HasMoreElements(&more))((bool)(__builtin_expect(!!(!NS_FAILED_impl(iterator->HasMoreElements
(&more))), 1)))
) && more) {
259 nsCOMPtr<nsISupports> supports;
260 nsCOMPtr<nsIPropertyElement> element;
261 if (NS_SUCCEEDED(iterator->GetNext(getter_AddRefs(supports)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(iterator->GetNext
(getter_AddRefs(supports)))), 1)))
) {
262 element = do_QueryInterface(supports);
263 if (NS_SUCCEEDED(element->GetKey(name))((bool)(__builtin_expect(!!(!NS_FAILED_impl(element->GetKey
(name))), 1)))
&&
264 NS_SUCCEEDED(element->GetValue(attributes))((bool)(__builtin_expect(!!(!NS_FAILED_impl(element->GetValue
(attributes))), 1)))
) {
265 // expected key: operator.\uNNNN.{infix,postfix,prefix}
266 if ((21 <= name.Length()) && (0 == name.Find("operator.\\u"))) {
267 name.Cut(0, 9); // 9 is the length of "operator.";
268 int32_t len = name.Length();
269 OperatorForm form;
270 if (kNotFound != name.RFind(".infix")) {
271 form = OperatorForm::Infix;
272 len -= 6; // 6 is the length of ".infix";
273 } else if (kNotFound != name.RFind(".postfix")) {
274 form = OperatorForm::Postfix;
275 len -= 8; // 8 is the length of ".postfix";
276 } else if (kNotFound != name.RFind(".prefix")) {
277 form = OperatorForm::Prefix;
278 len -= 7; // 7 is the length of ".prefix";
279 } else {
280 continue; // input is not applicable
281 }
282 name.SetLength(len);
283 if (2 == pass) { // allocate space and start the storage
284 if (!gOperatorArray) {
285 if (0 == gOperatorCount) {
286 return NS_ERROR_UNEXPECTED;
287 }
288 gOperatorArray = new OperatorData[gOperatorCount];
289 }
290 operatorData = &gOperatorArray[index];
291 } else {
292 form = OperatorForm::Unknown; // to quickly return from
293 // SetOperator() at pass 1
294 }
295 // See if the operator should be retained
296 if (SetOperator(operatorData, form, name, attributes)) {
297 index++;
298 if (1 == pass) {
299 gOperatorCount = index;
300 }
301 }
302 }
303 }
304 }
305 }
306 }
307 }
308 return NS_OK;
309}
310
311static nsresult InitOperatorGlobals() {
312 gGlobalsInitialized = true;
313 nsresult rv = NS_ERROR_OUT_OF_MEMORY;
314 gOperatorTable = new nsTHashMap<nsStringHashKey, OperatorData*>();
315 if (gOperatorTable) {
316 rv = InitOperators();
317 }
318 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
319 nsMathMLOperators::CleanUp();
320 }
321 return rv;
322}
323
324void nsMathMLOperators::CleanUp() {
325 if (gOperatorArray) {
326 delete[] gOperatorArray;
327 gOperatorArray = nullptr;
328 }
329 if (gOperatorTable) {
330 delete gOperatorTable;
331 gOperatorTable = nullptr;
332 }
333}
334
335void nsMathMLOperators::AddRefTable(void) { gTableRefCount++; }
336
337void nsMathMLOperators::ReleaseTable(void) {
338 if (0 == --gTableRefCount) {
339 CleanUp();
340 }
341}
342
343static OperatorData* GetOperatorData(const nsString& aOperator,
344 const OperatorForm aForm) {
345 nsAutoString key(aOperator);
346 key.AppendInt(static_cast<uint32_t>(aForm));
347 return gOperatorTable->Get(key);
348}
349
350bool nsMathMLOperators::LookupOperator(const nsString& aOperator,
351 OperatorForm aForm,
352 nsOperatorFlags* aFlags,
353 float* aLeadingSpace,
354 float* aTrailingSpace) {
355 NS_ASSERTION(aFlags && aLeadingSpace && aTrailingSpace, "bad usage")do { if (!(aFlags && aLeadingSpace && aTrailingSpace
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad usage", "aFlags && aLeadingSpace && aTrailingSpace"
, "./../../../layout/mathml/nsMathMLOperators.cpp", 355); MOZ_PretendNoReturn
(); } } while (0)
;
356 NS_ASSERTION(aForm != OperatorForm::Unknown, "*** invalid call ***")do { if (!(aForm != OperatorForm::Unknown)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "*** invalid call ***", "aForm != OperatorForm::Unknown", "./../../../layout/mathml/nsMathMLOperators.cpp"
, 356); MOZ_PretendNoReturn(); } } while (0)
;
357
358 // Operator strings must be of length 1 or 2 in UTF-16.
359 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
360 if (aOperator.IsEmpty() || aOperator.Length() > 2) {
361 return false;
362 }
363
364 if (aOperator.Length() == 2) {
365 // Try and handle Arabic operators.
366 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
367 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
368 if (aForm == OperatorForm::Postfix &&
369 (codePoint == 0x1EEF0 || codePoint == 0x1EEF1)) {
370 // Use category I.
371 // https://w3c.github.io/mathml-core/#operator-dictionary-categories-values
372 aFlags->SetForm(OperatorForm::Postfix);
373 aFlags->Booleans() = OperatorBoolean::Stretchy;
374 aFlags->SetDirection(OperatorDirection::Horizontal);
375 *aLeadingSpace = 0;
376 *aTrailingSpace = 0;
377 return true;
378 }
379 return false;
380 }
381
382 // Ignore the combining "negation" suffix for 2-character strings.
383 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
384 if (aOperator[1] == 0x0338 || aOperator[1] == 0x20D2) {
385 nsAutoString newOperator;
386 newOperator.Append(aOperator[0]);
387 return LookupOperator(newOperator, aForm, aFlags, aLeadingSpace,
388 aTrailingSpace);
389 }
390 }
391
392 if (!gGlobalsInitialized) {
393 InitOperatorGlobals();
394 }
395 if (gOperatorTable) {
396 if (OperatorData* data = GetOperatorData(aOperator, aForm)) {
397 NS_ASSERTION(data->mStr.Equals(aOperator), "bad setup")do { if (!(data->mStr.Equals(aOperator))) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "bad setup", "data->mStr.Equals(aOperator)"
, "./../../../layout/mathml/nsMathMLOperators.cpp", 397); MOZ_PretendNoReturn
(); } } while (0)
;
398 *aFlags = data->mFlags;
399 *aLeadingSpace = data->mLeadingSpace;
400 *aTrailingSpace = data->mTrailingSpace;
401 return true;
402 }
403 }
404
405 return false;
406}
407
408bool nsMathMLOperators::LookupOperatorWithFallback(const nsString& aOperator,
409 OperatorForm aForm,
410 nsOperatorFlags* aFlags,
411 float* aLeadingSpace,
412 float* aTrailingSpace) {
413 if (LookupOperator(aOperator, aForm, aFlags, aLeadingSpace, aTrailingSpace)) {
414 return true;
415 }
416 for (const auto& form :
417 {OperatorForm::Infix, OperatorForm::Postfix, OperatorForm::Prefix}) {
418 if (form == aForm) {
419 // This form was tried above, skip it.
420 continue;
421 }
422 if (LookupOperator(aOperator, form, aFlags, aLeadingSpace,
423 aTrailingSpace)) {
424 return true;
425 }
426 }
427 return false;
428}
429
430/* static */
431bool nsMathMLOperators::IsMirrorableOperator(const nsString& aOperator) {
432 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
433 return intl::UnicodeProperties::IsMirrored(codePoint);
434 }
435 return false;
436}
437
438/* static */
439nsString nsMathMLOperators::GetMirroredOperator(const nsString& aOperator) {
440 nsString result;
441 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
442 result.Assign(intl::UnicodeProperties::CharMirror(codePoint));
443 }
444 return result;
445}
446
447/* static */
448bool nsMathMLOperators::IsIntegralOperator(const nsString& aOperator) {
449 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
450 return (0x222B <= codePoint && codePoint <= 0x2233) ||
451 (0x2A0B <= codePoint && codePoint <= 0x2A1C);
452 }
453 return false;
454}
455
456/* static */
457StretchDirection nsMathMLOperators::GetStretchyDirection(
458 const nsString& aOperator) {
459 // Search any entry for that operator and return the corresponding direction.
460 // It is assumed that all the forms have same direction.
461 for (const auto& form :
462 {OperatorForm::Infix, OperatorForm::Postfix, OperatorForm::Prefix}) {
463 nsOperatorFlags flags;
464 float dummy;
465 if (nsMathMLOperators::LookupOperator(aOperator, form, &flags, &dummy,
466 &dummy)) {
467 if (flags.Direction() == OperatorDirection::Vertical) {
468 return StretchDirection::Vertical;
469 }
470 if (flags.Direction() == OperatorDirection::Horizontal) {
471 return StretchDirection::Horizontal;
472 }
473 }
474 }
475 return StretchDirection::Unsupported;
476}