Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/layout/mathml/nsMathMLOperators.cpp
Warning:line 188, 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 -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=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/mathml -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/mathml -resource-dir /usr/lib/llvm-20/lib/clang/20 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/layout/mathml -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/mathml -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/painting -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/tables -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/mathml -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -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-deprecated-this-capture -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 -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 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-20-090804-167946-1 -x c++ Unified_cpp_layout_mathml0.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "nsMathMLOperators.h"
8#include "nsCOMPtr.h"
9#include "nsTHashMap.h"
10#include "nsHashKeys.h"
11#include "nsNetUtil.h"
12#include "nsTArray.h"
13
14#include "mozilla/intl/UnicodeProperties.h"
15#include "nsIPersistentProperties2.h"
16#include "nsISimpleEnumerator.h"
17#include "nsCRT.h"
18
19// operator dictionary entry
20struct OperatorData {
21 OperatorData(void) : mFlags(0), mLeadingSpace(0.0f), mTrailingSpace(0.0f) {}
22
23 // member data
24 nsString mStr;
25 nsOperatorFlags mFlags;
26 float mLeadingSpace; // unit is em
27 float mTrailingSpace; // unit is em
28};
29
30static int32_t gTableRefCount = 0;
31static uint32_t gOperatorCount = 0;
32static OperatorData* gOperatorArray = nullptr;
33static nsTHashMap<nsStringHashKey, OperatorData*>* gOperatorTable = nullptr;
34static bool gGlobalsInitialized = false;
35
36static const char16_t kDashCh = char16_t('#');
37static const char16_t kColonCh = char16_t(':');
38
39static uint32_t ToUnicodeCodePoint(const nsString& aOperator) {
40 if (aOperator.Length() == 1) {
41 return aOperator[0];
42 }
43 if (aOperator.Length() == 2 &&
44 NS_IS_SURROGATE_PAIR(aOperator[0], aOperator[1])(((uint32_t(aOperator[0]) & 0xFFFFFC00) == 0xD800) &&
((uint32_t(aOperator[1]) & 0xFFFFFC00) == 0xDC00))
) {
45 return SURROGATE_TO_UCS4(aOperator[0], aOperator[1])(((uint32_t(aOperator[0]) & 0x03FF) << 10) + (uint32_t
(aOperator[1]) & 0x03FF) + uint32_t(0x00010000))
;
46 }
47 return 0;
48}
49
50static void SetBooleanProperty(OperatorData* aOperatorData, nsString aName) {
51 if (aName.IsEmpty()) {
52 return;
53 }
54
55 if (aName.EqualsLiteral("stretchy") && (1 == aOperatorData->mStr.Length())) {
56 aOperatorData->mFlags |= NS_MATHML_OPERATOR_STRETCHY;
57 } else if (aName.EqualsLiteral("fence")) {
58 aOperatorData->mFlags |= NS_MATHML_OPERATOR_FENCE;
59 } else if (aName.EqualsLiteral("accent")) {
60 aOperatorData->mFlags |= NS_MATHML_OPERATOR_ACCENT;
61 } else if (aName.EqualsLiteral("largeop")) {
62 aOperatorData->mFlags |= NS_MATHML_OPERATOR_LARGEOP;
63 } else if (aName.EqualsLiteral("separator")) {
64 aOperatorData->mFlags |= NS_MATHML_OPERATOR_SEPARATOR;
65 } else if (aName.EqualsLiteral("movablelimits")) {
66 aOperatorData->mFlags |= NS_MATHML_OPERATOR_MOVABLELIMITS;
67 } else if (aName.EqualsLiteral("symmetric")) {
68 aOperatorData->mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
69 }
70}
71
72static void SetProperty(OperatorData* aOperatorData, nsString aName,
73 nsString aValue) {
74 if (aName.IsEmpty() || aValue.IsEmpty()) {
75 return;
76 }
77
78 if (aName.EqualsLiteral("direction")) {
79 if (aValue.EqualsLiteral("vertical")) {
80 aOperatorData->mFlags |= NS_MATHML_OPERATOR_DIRECTION_VERTICAL;
81 } else if (aValue.EqualsLiteral("horizontal")) {
82 aOperatorData->mFlags |= NS_MATHML_OPERATOR_DIRECTION_HORIZONTAL;
83 } else {
84 return; // invalid value
85 }
86 } else {
87 bool isLeadingSpace;
88 if (aName.EqualsLiteral("lspace")) {
89 isLeadingSpace = true;
90 } else if (aName.EqualsLiteral("rspace")) {
91 isLeadingSpace = false;
92 } else {
93 return; // input is not applicable
94 }
95
96 // aValue is assumed to be a digit from 0 to 7
97 nsresult error = NS_OK;
98 float space = aValue.ToFloat(&error) / 18.0;
99 if (NS_FAILED(error)((bool)(__builtin_expect(!!(NS_FAILED_impl(error)), 0)))) {
100 return;
101 }
102
103 if (isLeadingSpace) {
104 aOperatorData->mLeadingSpace = space;
105 } else {
106 aOperatorData->mTrailingSpace = space;
107 }
108 }
109}
110
111static bool SetOperator(OperatorData* aOperatorData, nsOperatorFlags aForm,
112 const nsCString& aOperator, nsString& aAttributes)
113
114{
115 static const char16_t kNullCh = char16_t('\0');
116
117 // aOperator is in the expanded format \uNNNN\uNNNN ...
118 // First compress these Unicode points to the internal nsString format
119 int32_t i = 0;
120 nsAutoString name, value;
121 int32_t len = aOperator.Length();
122 char16_t c = aOperator[i++];
123 uint32_t state = 0;
124 char16_t uchar = 0;
125 while (i <= len) {
126 if (0 == state) {
127 if (c != '\\') {
128 return false;
129 }
130 if (i < len) {
131 c = aOperator[i];
132 }
133 i++;
134 if (('u' != c) && ('U' != c)) {
135 return false;
136 }
137 if (i < len) {
138 c = aOperator[i];
139 }
140 i++;
141 state++;
142 } else {
143 if (('0' <= c) && (c <= '9')) {
144 uchar = (uchar << 4) | (c - '0');
145 } else if (('a' <= c) && (c <= 'f')) {
146 uchar = (uchar << 4) | (c - 'a' + 0x0a);
147 } else if (('A' <= c) && (c <= 'F')) {
148 uchar = (uchar << 4) | (c - 'A' + 0x0a);
149 } else {
150 return false;
151 }
152 if (i < len) {
153 c = aOperator[i];
154 }
155 i++;
156 state++;
157 if (5 == state) {
158 value.Append(uchar);
159 uchar = 0;
160 state = 0;
161 }
162 }
163 }
164 if (0 != state) {
165 return false;
166 }
167
168 // Quick return when the caller doesn't care about the attributes and just
169 // wants to know if this is a valid operator (this is the case at the first
170 // pass of the parsing of the dictionary in InitOperators())
171 if (!aForm) {
172 return true;
173 }
174
175 // Add operator to hash table
176 aOperatorData->mFlags |= aForm;
177 aOperatorData->mStr.Assign(value);
178 value.AppendInt(aForm, 10);
179 gOperatorTable->InsertOrUpdate(value, aOperatorData);
180
181#ifdef DEBUG1
182 NS_LossyConvertUTF16toASCII str(aAttributes);
183#endif
184 // Loop over the space-delimited list of attributes to get the name:value
185 // pairs
186 aAttributes.Append(kNullCh); // put an extra null at the end
187 char16_t* start = aAttributes.BeginWriting();
188 char16_t* end = start;
Value stored to 'end' during its initialization is never read
189 while ((kNullCh != *start) && (kDashCh != *start)) {
190 name.SetLength(0);
191 value.SetLength(0);
192 // skip leading space, the dash amounts to the end of the line
193 while ((kNullCh != *start) && (kDashCh != *start) &&
194 nsCRT::IsAsciiSpace(*start)) {
195 ++start;
196 }
197 end = start;
198 // look for ':'
199 while ((kNullCh != *end) && (kDashCh != *end) &&
200 !nsCRT::IsAsciiSpace(*end) && (kColonCh != *end)) {
201 ++end;
202 }
203 // If ':' is not found, then it's a boolean property
204 bool IsBooleanProperty = (kColonCh != *end);
205 *end = kNullCh; // end segment here
206 // this segment is the name
207 if (start < end) {
208 name.Assign(start);
209 }
210 if (IsBooleanProperty) {
211 SetBooleanProperty(aOperatorData, name);
212 } else {
213 start = ++end;
214 // look for space or end of line
215 while ((kNullCh != *end) && (kDashCh != *end) &&
216 !nsCRT::IsAsciiSpace(*end)) {
217 ++end;
218 }
219 *end = kNullCh; // end segment here
220 if (start < end) {
221 // this segment is the value
222 value.Assign(start);
223 }
224 SetProperty(aOperatorData, name, value);
225 }
226 start = ++end;
227 }
228 return true;
229}
230
231static nsresult InitOperators(void) {
232 // Load the property file containing the Operator Dictionary
233 nsresult rv;
234 nsCOMPtr<nsIPersistentProperties> mathfontProp;
235 rv = NS_LoadPersistentPropertiesFromURISpec(
236 getter_AddRefs(mathfontProp),
237 "resource://gre/res/fonts/mathfont.properties"_ns);
238
239 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
240 return rv;
241 }
242
243 // Parse the Operator Dictionary in two passes.
244 // The first pass is to count the number of operators; the second pass is to
245 // allocate the necessary space for them and to add them in the hash table.
246 for (int32_t pass = 1; pass <= 2; pass++) {
247 OperatorData dummyData;
248 OperatorData* operatorData = &dummyData;
249 nsCOMPtr<nsISimpleEnumerator> iterator;
250 if (NS_SUCCEEDED(mathfontProp->Enumerate(getter_AddRefs(iterator)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mathfontProp->
Enumerate(getter_AddRefs(iterator)))), 1)))
) {
251 bool more;
252 uint32_t index = 0;
253 nsAutoCString name;
254 nsAutoString attributes;
255 while ((NS_SUCCEEDED(iterator->HasMoreElements(&more))((bool)(__builtin_expect(!!(!NS_FAILED_impl(iterator->HasMoreElements
(&more))), 1)))
) && more) {
256 nsCOMPtr<nsISupports> supports;
257 nsCOMPtr<nsIPropertyElement> element;
258 if (NS_SUCCEEDED(iterator->GetNext(getter_AddRefs(supports)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(iterator->GetNext
(getter_AddRefs(supports)))), 1)))
) {
259 element = do_QueryInterface(supports);
260 if (NS_SUCCEEDED(element->GetKey(name))((bool)(__builtin_expect(!!(!NS_FAILED_impl(element->GetKey
(name))), 1)))
&&
261 NS_SUCCEEDED(element->GetValue(attributes))((bool)(__builtin_expect(!!(!NS_FAILED_impl(element->GetValue
(attributes))), 1)))
) {
262 // expected key: operator.\uNNNN.{infix,postfix,prefix}
263 if ((21 <= name.Length()) && (0 == name.Find("operator.\\u"))) {
264 name.Cut(0, 9); // 9 is the length of "operator.";
265 int32_t len = name.Length();
266 nsOperatorFlags form = 0;
267 if (kNotFound != name.RFind(".infix")) {
268 form = NS_MATHML_OPERATOR_FORM_INFIX;
269 len -= 6; // 6 is the length of ".infix";
270 } else if (kNotFound != name.RFind(".postfix")) {
271 form = NS_MATHML_OPERATOR_FORM_POSTFIX;
272 len -= 8; // 8 is the length of ".postfix";
273 } else if (kNotFound != name.RFind(".prefix")) {
274 form = NS_MATHML_OPERATOR_FORM_PREFIX;
275 len -= 7; // 7 is the length of ".prefix";
276 } else {
277 continue; // input is not applicable
278 }
279 name.SetLength(len);
280 if (2 == pass) { // allocate space and start the storage
281 if (!gOperatorArray) {
282 if (0 == gOperatorCount) {
283 return NS_ERROR_UNEXPECTED;
284 }
285 gOperatorArray = new OperatorData[gOperatorCount];
286 }
287 operatorData = &gOperatorArray[index];
288 } else {
289 form = 0; // to quickly return from SetOperator() at pass 1
290 }
291 // See if the operator should be retained
292 if (SetOperator(operatorData, form, name, attributes)) {
293 index++;
294 if (1 == pass) {
295 gOperatorCount = index;
296 }
297 }
298 }
299 }
300 }
301 }
302 }
303 }
304 return NS_OK;
305}
306
307static nsresult InitOperatorGlobals() {
308 gGlobalsInitialized = true;
309 nsresult rv = NS_ERROR_OUT_OF_MEMORY;
310 gOperatorTable = new nsTHashMap<nsStringHashKey, OperatorData*>();
311 if (gOperatorTable) {
312 rv = InitOperators();
313 }
314 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
315 nsMathMLOperators::CleanUp();
316 }
317 return rv;
318}
319
320void nsMathMLOperators::CleanUp() {
321 if (gOperatorArray) {
322 delete[] gOperatorArray;
323 gOperatorArray = nullptr;
324 }
325 if (gOperatorTable) {
326 delete gOperatorTable;
327 gOperatorTable = nullptr;
328 }
329}
330
331void nsMathMLOperators::AddRefTable(void) { gTableRefCount++; }
332
333void nsMathMLOperators::ReleaseTable(void) {
334 if (0 == --gTableRefCount) {
335 CleanUp();
336 }
337}
338
339static OperatorData* GetOperatorData(const nsString& aOperator,
340 const uint8_t aForm) {
341 nsAutoString key(aOperator);
342 key.AppendInt(aForm);
343 return gOperatorTable->Get(key);
344}
345
346bool nsMathMLOperators::LookupOperator(const nsString& aOperator,
347 const uint8_t aForm,
348 nsOperatorFlags* aFlags,
349 float* aLeadingSpace,
350 float* aTrailingSpace) {
351 NS_ASSERTION(aFlags && aLeadingSpace && aTrailingSpace, "bad usage")do { if (!(aFlags && aLeadingSpace && aTrailingSpace
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad usage", "aFlags && aLeadingSpace && aTrailingSpace"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/mathml/nsMathMLOperators.cpp"
, 351); MOZ_PretendNoReturn(); } } while (0)
;
352 NS_ASSERTION(aForm > 0 && aForm < 4, "*** invalid call ***")do { if (!(aForm > 0 && aForm < 4)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "*** invalid call ***", "aForm > 0 && aForm < 4"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/mathml/nsMathMLOperators.cpp"
, 352); MOZ_PretendNoReturn(); } } while (0)
;
353
354 // Operator strings must be of length 1 or 2 in UTF-16.
355 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
356 if (aOperator.IsEmpty() || aOperator.Length() > 2) {
357 return false;
358 }
359
360 if (aOperator.Length() == 2) {
361 // Try and handle Arabic operators.
362 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
363 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
364 if (aForm == NS_MATHML_OPERATOR_FORM_POSTFIX &&
365 (codePoint == 0x1EEF0 || codePoint == 0x1EEF1)) {
366 // Use category I.
367 // https://w3c.github.io/mathml-core/#operator-dictionary-categories-values
368 *aFlags = NS_MATHML_OPERATOR_FORM_POSTFIX |
369 NS_MATHML_OPERATOR_STRETCHY |
370 NS_MATHML_OPERATOR_DIRECTION_HORIZONTAL;
371 *aLeadingSpace = 0;
372 *aTrailingSpace = 0;
373 return true;
374 }
375 return false;
376 }
377
378 // Ignore the combining "negation" suffix for 2-character strings.
379 // https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
380 if (aOperator[1] == 0x0338 || aOperator[1] == 0x20D2) {
381 nsAutoString newOperator;
382 newOperator.Append(aOperator[0]);
383 return LookupOperator(newOperator, aForm, aFlags, aLeadingSpace,
384 aTrailingSpace);
385 }
386 }
387
388 if (!gGlobalsInitialized) {
389 InitOperatorGlobals();
390 }
391 if (gOperatorTable) {
392 if (OperatorData* data = GetOperatorData(aOperator, aForm)) {
393 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)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/mathml/nsMathMLOperators.cpp"
, 393); MOZ_PretendNoReturn(); } } while (0)
;
394 *aFlags = data->mFlags;
395 *aLeadingSpace = data->mLeadingSpace;
396 *aTrailingSpace = data->mTrailingSpace;
397 return true;
398 }
399 }
400
401 return false;
402}
403
404bool nsMathMLOperators::LookupOperatorWithFallback(const nsString& aOperator,
405 const uint8_t aForm,
406 nsOperatorFlags* aFlags,
407 float* aLeadingSpace,
408 float* aTrailingSpace) {
409 if (LookupOperator(aOperator, aForm, aFlags, aLeadingSpace, aTrailingSpace)) {
410 return true;
411 }
412 for (const auto& form :
413 {NS_MATHML_OPERATOR_FORM_INFIX, NS_MATHML_OPERATOR_FORM_POSTFIX,
414 NS_MATHML_OPERATOR_FORM_PREFIX}) {
415 if (form == aForm) {
416 // This form was tried above, skip it.
417 continue;
418 }
419 if (LookupOperator(aOperator, form, aFlags, aLeadingSpace,
420 aTrailingSpace)) {
421 return true;
422 }
423 }
424 return false;
425}
426
427/* static */
428bool nsMathMLOperators::IsMirrorableOperator(const nsString& aOperator) {
429 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
430 return mozilla::intl::UnicodeProperties::IsMirrored(codePoint);
431 }
432 return false;
433}
434
435/* static */
436bool nsMathMLOperators::IsIntegralOperator(const nsString& aOperator) {
437 if (auto codePoint = ToUnicodeCodePoint(aOperator)) {
438 return (0x222B <= codePoint && codePoint <= 0x2233) ||
439 (0x2A0B <= codePoint && codePoint <= 0x2A1C);
440 }
441 return false;
442}
443
444/* static */
445nsStretchDirection nsMathMLOperators::GetStretchyDirection(
446 const nsString& aOperator) {
447 // Search any entry for that operator and return the corresponding direction.
448 // It is assumed that all the forms have same direction.
449 for (const auto& form :
450 {NS_MATHML_OPERATOR_FORM_INFIX, NS_MATHML_OPERATOR_FORM_POSTFIX,
451 NS_MATHML_OPERATOR_FORM_PREFIX}) {
452 nsOperatorFlags flags;
453 float dummy;
454 if (nsMathMLOperators::LookupOperator(aOperator, form, &flags, &dummy,
455 &dummy)) {
456 if (NS_MATHML_OPERATOR_IS_DIRECTION_VERTICAL(flags)(NS_MATHML_OPERATOR_DIRECTION_VERTICAL == ((flags) & NS_MATHML_OPERATOR_DIRECTION
))
) {
457 return NS_STRETCH_DIRECTION_VERTICAL;
458 }
459 if (NS_MATHML_OPERATOR_IS_DIRECTION_HORIZONTAL(flags)(NS_MATHML_OPERATOR_DIRECTION_HORIZONTAL == ((flags) & NS_MATHML_OPERATOR_DIRECTION
))
) {
460 return NS_STRETCH_DIRECTION_HORIZONTAL;
461 }
462 }
463 }
464 return NS_STRETCH_DIRECTION_UNSUPPORTED;
465}