2017-10-27 20:33:53 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-09-21 06:12:01 +04:00
|
|
|
|
2013-08-31 01:37:12 +04:00
|
|
|
#include "nsMathMLOperators.h"
|
2001-02-02 12:34:15 +03:00
|
|
|
#include "nsCOMPtr.h"
|
2014-03-19 01:25:40 +04:00
|
|
|
#include "nsDataHashtable.h"
|
|
|
|
#include "nsHashKeys.h"
|
2018-11-13 01:20:52 +03:00
|
|
|
#include "nsNetUtil.h"
|
2009-01-18 23:14:14 +03:00
|
|
|
#include "nsTArray.h"
|
1999-09-21 06:12:01 +04:00
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
#include "nsIPersistentProperties2.h"
|
2015-07-07 05:17:00 +03:00
|
|
|
#include "nsISimpleEnumerator.h"
|
2002-05-15 22:55:21 +04:00
|
|
|
#include "nsCRT.h"
|
1999-09-21 06:12:01 +04:00
|
|
|
|
|
|
|
// operator dictionary entry
|
2001-02-02 12:34:15 +03:00
|
|
|
struct OperatorData {
|
2011-12-22 02:21:59 +04:00
|
|
|
OperatorData(void) : mFlags(0), mLeadingSpace(0.0f), mTrailingSpace(0.0f) {}
|
1999-09-21 06:12:01 +04:00
|
|
|
|
|
|
|
// member data
|
|
|
|
nsString mStr;
|
|
|
|
nsOperatorFlags mFlags;
|
2011-12-22 02:21:59 +04:00
|
|
|
float mLeadingSpace; // unit is em
|
|
|
|
float mTrailingSpace; // unit is em
|
1999-09-21 06:12:01 +04:00
|
|
|
};
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
static int32_t gTableRefCount = 0;
|
|
|
|
static uint32_t gOperatorCount = 0;
|
2012-07-30 18:20:58 +04:00
|
|
|
static OperatorData* gOperatorArray = nullptr;
|
2014-03-19 01:25:40 +04:00
|
|
|
static nsDataHashtable<nsStringHashKey, OperatorData*>* gOperatorTable =
|
|
|
|
nullptr;
|
2013-11-15 06:45:38 +04:00
|
|
|
static bool gGlobalsInitialized = false;
|
2000-03-23 12:56:50 +03:00
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
static const char16_t kDashCh = char16_t('#');
|
|
|
|
static const char16_t kColonCh = char16_t(':');
|
1999-09-21 06:12:01 +04:00
|
|
|
|
2009-09-28 00:32:54 +04:00
|
|
|
static void SetBooleanProperty(OperatorData* aOperatorData, nsString aName) {
|
|
|
|
if (aName.IsEmpty()) return;
|
|
|
|
|
2009-11-22 00:11:05 +03:00
|
|
|
if (aName.EqualsLiteral("stretchy") && (1 == aOperatorData->mStr.Length()))
|
2009-09-28 00:32:54 +04:00
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_STRETCHY;
|
2009-11-22 00:11:05 +03:00
|
|
|
else if (aName.EqualsLiteral("fence"))
|
2009-09-28 00:32:54 +04:00
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_FENCE;
|
|
|
|
else if (aName.EqualsLiteral("accent"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_ACCENT;
|
|
|
|
else if (aName.EqualsLiteral("largeop"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_LARGEOP;
|
|
|
|
else if (aName.EqualsLiteral("separator"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_SEPARATOR;
|
|
|
|
else if (aName.EqualsLiteral("movablelimits"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_MOVABLELIMITS;
|
|
|
|
else if (aName.EqualsLiteral("symmetric"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
|
2010-08-20 07:44:07 +04:00
|
|
|
else if (aName.EqualsLiteral("integral"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_INTEGRAL;
|
2011-12-22 02:22:00 +04:00
|
|
|
else if (aName.EqualsLiteral("mirrorable"))
|
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_MIRRORABLE;
|
2009-09-28 00:32:54 +04:00
|
|
|
}
|
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
static void SetProperty(OperatorData* aOperatorData, nsString aName,
|
|
|
|
nsString aValue) {
|
2009-09-28 00:32:54 +04:00
|
|
|
if (aName.IsEmpty() || aValue.IsEmpty()) return;
|
2001-02-02 12:34:15 +03:00
|
|
|
|
|
|
|
// XXX These ones are not kept in the dictionary
|
|
|
|
// Support for these requires nsString member variables
|
|
|
|
// maxsize (default: infinity)
|
|
|
|
// minsize (default: 1)
|
|
|
|
|
2009-09-28 00:32:54 +04:00
|
|
|
if (aName.EqualsLiteral("direction")) {
|
2004-04-30 17:23:43 +04:00
|
|
|
if (aValue.EqualsLiteral("vertical"))
|
2009-09-28 00:32:54 +04:00
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_DIRECTION_VERTICAL;
|
2004-04-30 17:23:43 +04:00
|
|
|
else if (aValue.EqualsLiteral("horizontal"))
|
2009-09-28 00:32:54 +04:00
|
|
|
aOperatorData->mFlags |= NS_MATHML_OPERATOR_DIRECTION_HORIZONTAL;
|
2001-02-02 12:34:15 +03:00
|
|
|
else
|
|
|
|
return; // invalid value
|
2009-09-28 00:32:54 +04:00
|
|
|
} else {
|
2011-12-22 02:21:59 +04:00
|
|
|
bool isLeadingSpace;
|
2004-04-30 17:23:43 +04:00
|
|
|
if (aName.EqualsLiteral("lspace"))
|
2011-12-22 02:21:59 +04:00
|
|
|
isLeadingSpace = true;
|
2004-04-30 17:23:43 +04:00
|
|
|
else if (aName.EqualsLiteral("rspace"))
|
2011-12-22 02:21:59 +04:00
|
|
|
isLeadingSpace = false;
|
2001-02-02 12:34:15 +03:00
|
|
|
else
|
|
|
|
return; // input is not applicable
|
|
|
|
|
2009-09-28 00:32:54 +04:00
|
|
|
// aValue is assumed to be a digit from 0 to 7
|
2012-07-27 17:59:29 +04:00
|
|
|
nsresult error = NS_OK;
|
2009-09-28 00:32:54 +04:00
|
|
|
float space = aValue.ToFloat(&error) / 18.0;
|
2012-08-13 17:49:48 +04:00
|
|
|
if (NS_FAILED(error)) return;
|
2001-02-02 12:34:15 +03:00
|
|
|
|
2011-12-22 02:21:59 +04:00
|
|
|
if (isLeadingSpace)
|
|
|
|
aOperatorData->mLeadingSpace = space;
|
2001-02-02 12:34:15 +03:00
|
|
|
else
|
2011-12-22 02:21:59 +04:00
|
|
|
aOperatorData->mTrailingSpace = space;
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
}
|
1999-09-21 06:12:01 +04:00
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
static bool SetOperator(OperatorData* aOperatorData, nsOperatorFlags aForm,
|
2002-08-30 21:13:34 +04:00
|
|
|
const nsCString& aOperator, nsString& aAttributes)
|
1999-09-21 06:12:01 +04:00
|
|
|
|
|
|
|
{
|
2014-01-04 19:02:17 +04:00
|
|
|
static const char16_t kNullCh = char16_t('\0');
|
2013-11-15 06:45:38 +04:00
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
// aOperator is in the expanded format \uNNNN\uNNNN ...
|
|
|
|
// First compress these Unicode points to the internal nsString format
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i = 0;
|
2001-02-02 12:34:15 +03:00
|
|
|
nsAutoString name, value;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t len = aOperator.Length();
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t c = aOperator[i++];
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t state = 0;
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t uchar = 0;
|
2001-02-02 12:34:15 +03:00
|
|
|
while (i <= len) {
|
|
|
|
if (0 == state) {
|
|
|
|
if (c != '\\') return false;
|
|
|
|
if (i < len) c = aOperator[i];
|
|
|
|
i++;
|
|
|
|
if (('u' != c) && ('U' != c)) return false;
|
|
|
|
if (i < len) c = aOperator[i];
|
|
|
|
i++;
|
|
|
|
state++;
|
|
|
|
} else {
|
|
|
|
if (('0' <= c) && (c <= '9'))
|
|
|
|
uchar = (uchar << 4) | (c - '0');
|
|
|
|
else if (('a' <= c) && (c <= 'f'))
|
|
|
|
uchar = (uchar << 4) | (c - 'a' + 0x0a);
|
|
|
|
else if (('A' <= c) && (c <= 'F'))
|
|
|
|
uchar = (uchar << 4) | (c - 'A' + 0x0a);
|
2011-10-17 18:59:28 +04:00
|
|
|
else
|
|
|
|
return false;
|
2001-02-02 12:34:15 +03:00
|
|
|
if (i < len) c = aOperator[i];
|
|
|
|
i++;
|
|
|
|
state++;
|
|
|
|
if (5 == state) {
|
|
|
|
value.Append(uchar);
|
|
|
|
uchar = 0;
|
|
|
|
state = 0;
|
1999-09-21 06:12:01 +04:00
|
|
|
}
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
if (0 != state) return false;
|
2001-02-02 12:34:15 +03:00
|
|
|
|
|
|
|
// Quick return when the caller doesn't care about the attributes and just
|
|
|
|
// wants to know if this is a valid operator (this is the case at the first
|
|
|
|
// pass of the parsing of the dictionary in InitOperators())
|
2011-10-17 18:59:28 +04:00
|
|
|
if (!aForm) return true;
|
2001-02-02 12:34:15 +03:00
|
|
|
|
2009-09-28 00:32:54 +04:00
|
|
|
// Add operator to hash table
|
|
|
|
aOperatorData->mFlags |= aForm;
|
2001-02-02 12:34:15 +03:00
|
|
|
aOperatorData->mStr.Assign(value);
|
|
|
|
value.AppendInt(aForm, 10);
|
2014-03-19 01:25:40 +04:00
|
|
|
gOperatorTable->Put(value, aOperatorData);
|
2001-02-02 12:34:15 +03:00
|
|
|
|
2012-06-25 23:59:42 +04:00
|
|
|
#ifdef DEBUG
|
2006-02-03 17:18:39 +03:00
|
|
|
NS_LossyConvertUTF16toASCII str(aAttributes);
|
2001-02-02 12:34:15 +03:00
|
|
|
#endif
|
|
|
|
// Loop over the space-delimited list of attributes to get the name:value
|
|
|
|
// pairs
|
|
|
|
aAttributes.Append(kNullCh); // put an extra null at the end
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t* start = aAttributes.BeginWriting();
|
|
|
|
char16_t* end = start;
|
2001-02-02 12:34:15 +03:00
|
|
|
while ((kNullCh != *start) && (kDashCh != *start)) {
|
|
|
|
name.SetLength(0);
|
|
|
|
value.SetLength(0);
|
|
|
|
// skip leading space, the dash amounts to the end of the line
|
|
|
|
while ((kNullCh != *start) && (kDashCh != *start) &&
|
|
|
|
nsCRT::IsAsciiSpace(*start)) {
|
|
|
|
++start;
|
|
|
|
}
|
|
|
|
end = start;
|
2009-09-28 00:32:54 +04:00
|
|
|
// look for ':'
|
|
|
|
while ((kNullCh != *end) && (kDashCh != *end) &&
|
|
|
|
!nsCRT::IsAsciiSpace(*end) && (kColonCh != *end)) {
|
2001-02-02 12:34:15 +03:00
|
|
|
++end;
|
|
|
|
}
|
2009-09-28 00:32:54 +04:00
|
|
|
// If ':' is not found, then it's a boolean property
|
2011-09-29 10:19:26 +04:00
|
|
|
bool IsBooleanProperty = (kColonCh != *end);
|
2001-02-02 12:34:15 +03:00
|
|
|
*end = kNullCh; // end segment here
|
|
|
|
// this segment is the name
|
|
|
|
if (start < end) {
|
|
|
|
name.Assign(start);
|
|
|
|
}
|
2009-09-28 00:32:54 +04:00
|
|
|
if (IsBooleanProperty) {
|
|
|
|
SetBooleanProperty(aOperatorData, name);
|
|
|
|
} else {
|
|
|
|
start = ++end;
|
|
|
|
// look for space or end of line
|
|
|
|
while ((kNullCh != *end) && (kDashCh != *end) &&
|
|
|
|
!nsCRT::IsAsciiSpace(*end)) {
|
|
|
|
++end;
|
|
|
|
}
|
|
|
|
*end = kNullCh; // end segment here
|
|
|
|
if (start < end) {
|
|
|
|
// this segment is the value
|
|
|
|
value.Assign(start);
|
|
|
|
}
|
|
|
|
SetProperty(aOperatorData, name, value);
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
start = ++end;
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult InitOperators(void) {
|
|
|
|
// Load the property file containing the Operator Dictionary
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIPersistentProperties> mathfontProp;
|
2014-09-21 20:41:03 +04:00
|
|
|
rv = NS_LoadPersistentPropertiesFromURISpec(
|
|
|
|
getter_AddRefs(mathfontProp),
|
2020-07-01 11:29:29 +03:00
|
|
|
"resource://gre/res/fonts/mathfont.properties"_ns);
|
2014-09-21 20:41:03 +04:00
|
|
|
|
2005-09-16 03:17:17 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2001-02-02 12:34:15 +03:00
|
|
|
|
|
|
|
// Parse the Operator Dictionary in two passes.
|
|
|
|
// The first pass is to count the number of operators; the second pass is to
|
|
|
|
// allocate the necessary space for them and to add them in the hash table.
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t pass = 1; pass <= 2; pass++) {
|
2001-02-02 12:34:15 +03:00
|
|
|
OperatorData dummyData;
|
|
|
|
OperatorData* operatorData = &dummyData;
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> iterator;
|
2002-08-30 21:13:34 +04:00
|
|
|
if (NS_SUCCEEDED(mathfontProp->Enumerate(getter_AddRefs(iterator)))) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool more;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t index = 0;
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString name;
|
2002-08-30 21:13:34 +04:00
|
|
|
nsAutoString attributes;
|
2001-02-02 12:34:15 +03:00
|
|
|
while ((NS_SUCCEEDED(iterator->HasMoreElements(&more))) && more) {
|
2014-03-15 23:00:17 +04:00
|
|
|
nsCOMPtr<nsISupports> supports;
|
2001-02-02 12:34:15 +03:00
|
|
|
nsCOMPtr<nsIPropertyElement> element;
|
2014-03-15 23:00:17 +04:00
|
|
|
if (NS_SUCCEEDED(iterator->GetNext(getter_AddRefs(supports)))) {
|
|
|
|
element = do_QueryInterface(supports);
|
2002-08-30 21:13:34 +04:00
|
|
|
if (NS_SUCCEEDED(element->GetKey(name)) &&
|
|
|
|
NS_SUCCEEDED(element->GetValue(attributes))) {
|
2001-02-02 12:34:15 +03:00
|
|
|
// expected key: operator.\uNNNN.{infix,postfix,prefix}
|
|
|
|
if ((21 <= name.Length()) && (0 == name.Find("operator.\\u"))) {
|
|
|
|
name.Cut(0, 9); // 9 is the length of "operator.";
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t len = name.Length();
|
2001-02-02 12:34:15 +03:00
|
|
|
nsOperatorFlags form = 0;
|
|
|
|
if (kNotFound != name.RFind(".infix")) {
|
|
|
|
form = NS_MATHML_OPERATOR_FORM_INFIX;
|
|
|
|
len -= 6; // 6 is the length of ".infix";
|
|
|
|
} else if (kNotFound != name.RFind(".postfix")) {
|
|
|
|
form = NS_MATHML_OPERATOR_FORM_POSTFIX;
|
|
|
|
len -= 8; // 8 is the length of ".postfix";
|
|
|
|
} else if (kNotFound != name.RFind(".prefix")) {
|
|
|
|
form = NS_MATHML_OPERATOR_FORM_PREFIX;
|
|
|
|
len -= 7; // 7 is the length of ".prefix";
|
|
|
|
} else
|
|
|
|
continue; // input is not applicable
|
|
|
|
name.SetLength(len);
|
|
|
|
if (2 == pass) { // allocate space and start the storage
|
|
|
|
if (!gOperatorArray) {
|
|
|
|
if (0 == gOperatorCount) return NS_ERROR_UNEXPECTED;
|
|
|
|
gOperatorArray = new OperatorData[gOperatorCount];
|
|
|
|
if (!gOperatorArray) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
operatorData = &gOperatorArray[index];
|
|
|
|
} else {
|
|
|
|
form = 0; // to quickly return from SetOperator() at pass 1
|
|
|
|
}
|
|
|
|
// See if the operator should be retained
|
|
|
|
if (SetOperator(operatorData, form, name, attributes)) {
|
|
|
|
index++;
|
|
|
|
if (1 == pass) gOperatorCount = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-21 06:12:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-02-02 12:34:15 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-12-07 04:15:53 +03:00
|
|
|
static nsresult InitOperatorGlobals() {
|
2013-11-15 06:45:38 +04:00
|
|
|
gGlobalsInitialized = true;
|
2001-02-02 12:34:15 +03:00
|
|
|
nsresult rv = NS_ERROR_OUT_OF_MEMORY;
|
2014-03-19 01:25:40 +04:00
|
|
|
gOperatorTable = new nsDataHashtable<nsStringHashKey, OperatorData*>();
|
2013-12-02 20:50:27 +04:00
|
|
|
if (gOperatorTable) {
|
|
|
|
rv = InitOperators();
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
2007-08-14 22:42:24 +04:00
|
|
|
if (NS_FAILED(rv)) nsMathMLOperators::CleanUp();
|
2001-02-02 12:34:15 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-08-14 22:42:24 +04:00
|
|
|
void nsMathMLOperators::CleanUp() {
|
|
|
|
if (gOperatorArray) {
|
|
|
|
delete[] gOperatorArray;
|
2012-07-30 18:20:58 +04:00
|
|
|
gOperatorArray = nullptr;
|
2007-08-14 22:42:24 +04:00
|
|
|
}
|
|
|
|
if (gOperatorTable) {
|
|
|
|
delete gOperatorTable;
|
2012-07-30 18:20:58 +04:00
|
|
|
gOperatorTable = nullptr;
|
2007-08-14 22:42:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
void nsMathMLOperators::AddRefTable(void) { gTableRefCount++; }
|
1999-09-21 06:12:01 +04:00
|
|
|
|
|
|
|
void nsMathMLOperators::ReleaseTable(void) {
|
|
|
|
if (0 == --gTableRefCount) {
|
2007-08-14 22:42:24 +04:00
|
|
|
CleanUp();
|
1999-09-21 06:12:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-22 01:25:55 +03:00
|
|
|
static OperatorData* GetOperatorData(const nsString& aOperator,
|
|
|
|
nsOperatorFlags aForm) {
|
|
|
|
nsAutoString key(aOperator);
|
|
|
|
key.AppendInt(aForm);
|
2014-03-19 01:25:40 +04:00
|
|
|
return gOperatorTable->Get(key);
|
2009-11-22 01:25:55 +03:00
|
|
|
}
|
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
bool nsMathMLOperators::LookupOperator(const nsString& aOperator,
|
1999-09-21 06:12:01 +04:00
|
|
|
const nsOperatorFlags aForm,
|
|
|
|
nsOperatorFlags* aFlags,
|
2011-12-22 02:21:59 +04:00
|
|
|
float* aLeadingSpace,
|
|
|
|
float* aTrailingSpace) {
|
2013-11-15 06:45:38 +04:00
|
|
|
if (!gGlobalsInitialized) {
|
2015-12-07 04:15:53 +03:00
|
|
|
InitOperatorGlobals();
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
if (gOperatorTable) {
|
2011-12-22 02:21:59 +04:00
|
|
|
NS_ASSERTION(aFlags && aLeadingSpace && aTrailingSpace, "bad usage");
|
2009-11-22 01:25:55 +03:00
|
|
|
NS_ASSERTION(aForm > 0 && aForm < 4, "*** invalid call ***");
|
|
|
|
|
|
|
|
// The MathML REC says:
|
|
|
|
// If the operator does not occur in the dictionary with the specified form,
|
|
|
|
// the renderer should use one of the forms which is available there, in the
|
|
|
|
// order of preference: infix, postfix, prefix.
|
1999-12-10 15:47:24 +03:00
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
OperatorData* found;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t form = NS_MATHML_OPERATOR_GET_FORM(aForm);
|
2009-11-22 01:25:55 +03:00
|
|
|
if (!(found = GetOperatorData(aOperator, form))) {
|
|
|
|
if (form == NS_MATHML_OPERATOR_FORM_INFIX ||
|
|
|
|
!(found =
|
|
|
|
GetOperatorData(aOperator, NS_MATHML_OPERATOR_FORM_INFIX))) {
|
|
|
|
if (form == NS_MATHML_OPERATOR_FORM_POSTFIX ||
|
|
|
|
!(found = GetOperatorData(aOperator,
|
|
|
|
NS_MATHML_OPERATOR_FORM_POSTFIX))) {
|
2001-02-02 12:34:15 +03:00
|
|
|
if (form != NS_MATHML_OPERATOR_FORM_PREFIX) {
|
2009-11-22 01:25:55 +03:00
|
|
|
found = GetOperatorData(aOperator, NS_MATHML_OPERATOR_FORM_PREFIX);
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-21 06:12:01 +04:00
|
|
|
if (found) {
|
2001-02-02 12:34:15 +03:00
|
|
|
NS_ASSERTION(found->mStr.Equals(aOperator), "bad setup");
|
2011-12-22 02:21:59 +04:00
|
|
|
*aLeadingSpace = found->mLeadingSpace;
|
|
|
|
*aTrailingSpace = found->mTrailingSpace;
|
2001-02-02 12:34:15 +03:00
|
|
|
*aFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the form bits
|
2000-05-08 11:12:39 +04:00
|
|
|
*aFlags |= found->mFlags; // just add bits without overwriting
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-09-21 06:12:01 +04:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-09-21 06:12:01 +04:00
|
|
|
}
|
|
|
|
|
2002-02-06 23:48:35 +03:00
|
|
|
void nsMathMLOperators::LookupOperators(const nsString& aOperator,
|
|
|
|
nsOperatorFlags* aFlags,
|
2011-12-22 02:21:59 +04:00
|
|
|
float* aLeadingSpace,
|
|
|
|
float* aTrailingSpace) {
|
2013-11-15 06:45:38 +04:00
|
|
|
if (!gGlobalsInitialized) {
|
2015-12-07 04:15:53 +03:00
|
|
|
InitOperatorGlobals();
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
2002-02-06 23:48:35 +03:00
|
|
|
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_INFIX] = 0;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_INFIX] = 0.0f;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_INFIX] = 0.0f;
|
2002-02-06 23:48:35 +03:00
|
|
|
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_POSTFIX] = 0;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_POSTFIX] = 0.0f;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_POSTFIX] = 0.0f;
|
2002-02-06 23:48:35 +03:00
|
|
|
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_PREFIX] = 0;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = 0.0f;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = 0.0f;
|
2002-02-06 23:48:35 +03:00
|
|
|
|
2001-02-02 12:34:15 +03:00
|
|
|
if (gOperatorTable) {
|
|
|
|
OperatorData* found;
|
2009-11-22 01:25:55 +03:00
|
|
|
found = GetOperatorData(aOperator, NS_MATHML_OPERATOR_FORM_INFIX);
|
2002-02-06 23:48:35 +03:00
|
|
|
if (found) {
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_INFIX] = found->mFlags;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_INFIX] = found->mLeadingSpace;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_INFIX] = found->mTrailingSpace;
|
2000-05-08 11:12:39 +04:00
|
|
|
}
|
2009-11-22 01:25:55 +03:00
|
|
|
found = GetOperatorData(aOperator, NS_MATHML_OPERATOR_FORM_POSTFIX);
|
2002-02-06 23:48:35 +03:00
|
|
|
if (found) {
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_POSTFIX] = found->mFlags;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_POSTFIX] = found->mLeadingSpace;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_POSTFIX] = found->mTrailingSpace;
|
2000-05-08 11:12:39 +04:00
|
|
|
}
|
2009-11-22 01:25:55 +03:00
|
|
|
found = GetOperatorData(aOperator, NS_MATHML_OPERATOR_FORM_PREFIX);
|
2002-02-06 23:48:35 +03:00
|
|
|
if (found) {
|
|
|
|
aFlags[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mFlags;
|
2011-12-22 02:21:59 +04:00
|
|
|
aLeadingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mLeadingSpace;
|
|
|
|
aTrailingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mTrailingSpace;
|
2000-05-08 11:12:39 +04:00
|
|
|
}
|
2000-03-23 12:56:50 +03:00
|
|
|
}
|
2002-02-06 23:48:35 +03:00
|
|
|
}
|
|
|
|
|
2019-02-26 01:09:24 +03:00
|
|
|
/* static */
|
|
|
|
bool nsMathMLOperators::IsMirrorableOperator(const nsString& aOperator) {
|
2011-12-22 02:22:00 +04:00
|
|
|
// LookupOperator will search infix, postfix and prefix forms of aOperator and
|
|
|
|
// return the first form found. It is assumed that all these forms have same
|
|
|
|
// mirrorability.
|
|
|
|
nsOperatorFlags flags = 0;
|
|
|
|
float dummy;
|
|
|
|
nsMathMLOperators::LookupOperator(aOperator, NS_MATHML_OPERATOR_FORM_INFIX,
|
|
|
|
&flags, &dummy, &dummy);
|
|
|
|
return NS_MATHML_OPERATOR_IS_MIRRORABLE(flags);
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:09:24 +03:00
|
|
|
/* static */
|
|
|
|
nsStretchDirection nsMathMLOperators::GetStretchyDirection(
|
2009-11-22 00:11:05 +03:00
|
|
|
const nsString& aOperator) {
|
|
|
|
// LookupOperator will search infix, postfix and prefix forms of aOperator and
|
|
|
|
// return the first form found. It is assumed that all these forms have same
|
|
|
|
// direction.
|
|
|
|
nsOperatorFlags flags = 0;
|
|
|
|
float dummy;
|
|
|
|
nsMathMLOperators::LookupOperator(aOperator, NS_MATHML_OPERATOR_FORM_INFIX,
|
|
|
|
&flags, &dummy, &dummy);
|
|
|
|
|
|
|
|
if (NS_MATHML_OPERATOR_IS_DIRECTION_VERTICAL(flags)) {
|
|
|
|
return NS_STRETCH_DIRECTION_VERTICAL;
|
|
|
|
} else if (NS_MATHML_OPERATOR_IS_DIRECTION_HORIZONTAL(flags)) {
|
|
|
|
return NS_STRETCH_DIRECTION_HORIZONTAL;
|
|
|
|
} else {
|
|
|
|
return NS_STRETCH_DIRECTION_UNSUPPORTED;
|
2001-02-02 12:34:15 +03:00
|
|
|
}
|
|
|
|
}
|