diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/xslt/xslt/txXSLTNumberCounters.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/xslt/xslt/txXSLTNumberCounters.cpp')
-rw-r--r-- | dom/xslt/xslt/txXSLTNumberCounters.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txXSLTNumberCounters.cpp b/dom/xslt/xslt/txXSLTNumberCounters.cpp new file mode 100644 index 0000000000..de1de46556 --- /dev/null +++ b/dom/xslt/xslt/txXSLTNumberCounters.cpp @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "txXSLTNumber.h" +#include "nsReadableUtils.h" +#include "txCore.h" + +class txDecimalCounter : public txFormattedCounter { + public: + txDecimalCounter() : mMinLength(1), mGroupSize(50) {} + + txDecimalCounter(int32_t aMinLength, int32_t aGroupSize, + const nsAString& mGroupSeparator); + + virtual void appendNumber(int32_t aNumber, nsAString& aDest) override; + + private: + int32_t mMinLength; + int32_t mGroupSize; + nsString mGroupSeparator; +}; + +class txAlphaCounter : public txFormattedCounter { + public: + explicit txAlphaCounter(char16_t aOffset) : mOffset(aOffset) {} + + virtual void appendNumber(int32_t aNumber, nsAString& aDest) override; + + private: + char16_t mOffset; +}; + +class txRomanCounter : public txFormattedCounter { + public: + explicit txRomanCounter(bool aUpper) : mTableOffset(aUpper ? 30 : 0) {} + + void appendNumber(int32_t aNumber, nsAString& aDest) override; + + private: + int32_t mTableOffset; +}; + +nsresult txFormattedCounter::getCounterFor(const nsString& aToken, + int32_t aGroupSize, + const nsAString& aGroupSeparator, + txFormattedCounter*& aCounter) { + int32_t length = aToken.Length(); + NS_ASSERTION(length, "getting counter for empty token"); + aCounter = 0; + + if (length == 1) { + char16_t ch = aToken.CharAt(0); + switch (ch) { + case 'i': + case 'I': + aCounter = new txRomanCounter(ch == 'I'); + break; + + case 'a': + case 'A': + aCounter = new txAlphaCounter(ch); + break; + + case '1': + default: + // if we don't recognize the token then use "1" + aCounter = new txDecimalCounter(1, aGroupSize, aGroupSeparator); + break; + } + MOZ_ASSERT(aCounter); + return NS_OK; + } + + // for now, the only multi-char token we support are decimals + int32_t i; + for (i = 0; i < length - 1; ++i) { + if (aToken.CharAt(i) != '0') break; + } + if (i == length - 1 && aToken.CharAt(i) == '1') { + aCounter = new txDecimalCounter(length, aGroupSize, aGroupSeparator); + } else { + // if we don't recognize the token then use '1' + aCounter = new txDecimalCounter(1, aGroupSize, aGroupSeparator); + } + MOZ_ASSERT(aCounter); + return NS_OK; +} + +txDecimalCounter::txDecimalCounter(int32_t aMinLength, int32_t aGroupSize, + const nsAString& aGroupSeparator) + : mMinLength(aMinLength), + mGroupSize(aGroupSize), + mGroupSeparator(aGroupSeparator) { + if (mGroupSize <= 0) { + mGroupSize = aMinLength + 10; + } +} + +void txDecimalCounter::appendNumber(int32_t aNumber, nsAString& aDest) { + const int32_t bufsize = 10; // must be able to fit an int32_t + char16_t buf[bufsize]; + int32_t pos = bufsize; + while (aNumber > 0) { + int32_t ch = aNumber % 10; + aNumber /= 10; + buf[--pos] = ch + '0'; + } + + // in case we didn't get a long enough string + int32_t end = (bufsize > mMinLength) ? bufsize - mMinLength : 0; + while (pos > end) { + buf[--pos] = '0'; + } + + // in case we *still* didn't get a long enough string. + // this should be very rare since it only happens if mMinLength is bigger + // then the length of any int32_t. + // pos will always be zero + int32_t extraPos = mMinLength; + while (extraPos > bufsize) { + aDest.Append(char16_t('0')); + --extraPos; + if (extraPos % mGroupSize == 0) { + aDest.Append(mGroupSeparator); + } + } + + // copy string to buffer + if (mGroupSize >= bufsize - pos) { + // no grouping will occur + aDest.Append(buf + pos, (uint32_t)(bufsize - pos)); + } else { + // append chars up to first grouping separator + int32_t len = ((bufsize - pos - 1) % mGroupSize) + 1; + aDest.Append(buf + pos, len); + pos += len; + while (bufsize - pos > 0) { + aDest.Append(mGroupSeparator); + aDest.Append(buf + pos, mGroupSize); + pos += mGroupSize; + } + NS_ASSERTION(bufsize == pos, "error while grouping"); + } +} + +void txAlphaCounter::appendNumber(int32_t aNumber, nsAString& aDest) { + char16_t buf[12]; + buf[11] = 0; + int32_t pos = 11; + while (aNumber > 0) { + --aNumber; + int32_t ch = aNumber % 26; + aNumber /= 26; + buf[--pos] = ch + mOffset; + } + + aDest.Append(buf + pos, (uint32_t)(11 - pos)); +} + +const char* const kTxRomanNumbers[] = { + "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm", + "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc", + "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", + "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", + "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", + "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; + +void txRomanCounter::appendNumber(int32_t aNumber, nsAString& aDest) { + // Numbers bigger then 3999 and negative numbers can't be done in roman + if (uint32_t(aNumber) >= 4000) { + txDecimalCounter().appendNumber(aNumber, aDest); + return; + } + + while (aNumber >= 1000) { + aDest.Append(!mTableOffset ? char16_t('m') : char16_t('M')); + aNumber -= 1000; + } + + int32_t posValue; + + // Hundreds + posValue = aNumber / 100; + aNumber %= 100; + AppendASCIItoUTF16( + mozilla::MakeStringSpan(kTxRomanNumbers[posValue + mTableOffset]), aDest); + // Tens + posValue = aNumber / 10; + aNumber %= 10; + AppendASCIItoUTF16( + mozilla::MakeStringSpan(kTxRomanNumbers[10 + posValue + mTableOffset]), + aDest); + // Ones + AppendASCIItoUTF16( + mozilla::MakeStringSpan(kTxRomanNumbers[20 + aNumber + mTableOffset]), + aDest); +} |