diff options
Diffstat (limited to 'accessible/atk/DOMtoATK.cpp')
-rw-r--r-- | accessible/atk/DOMtoATK.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/accessible/atk/DOMtoATK.cpp b/accessible/atk/DOMtoATK.cpp new file mode 100644 index 0000000000..2c23731bba --- /dev/null +++ b/accessible/atk/DOMtoATK.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 "DOMtoATK.h" +#include "nsUTF8Utils.h" + +namespace mozilla { +namespace a11y { + +namespace DOMtoATK { + +void AddBOMs(nsACString& aDest, const nsACString& aSource) { + uint32_t destlength = 0; + + // First compute how much room we will need. + for (uint32_t srci = 0; srci < aSource.Length();) { + int bytes = UTF8traits::bytes(aSource[srci]); + if (bytes >= 4) { + // Non-BMP character, will add a BOM after it. + destlength += 3; + } + // Skip whole character encoding. + srci += bytes; + destlength += bytes; + } + + uint32_t desti = 0; // Index within aDest. + + // Add BOMs after non-BMP characters. + aDest.SetLength(destlength); + for (uint32_t srci = 0; srci < aSource.Length();) { + uint32_t bytes = UTF8traits::bytes(aSource[srci]); + + MOZ_ASSERT(bytes <= aSource.Length() - srci, + "We should have the whole sequence"); + + // Copy whole sequence. + aDest.Replace(desti, bytes, Substring(aSource, srci, bytes)); + desti += bytes; + srci += bytes; + + if (bytes >= 4) { + // More than 4 bytes in UTF-8 encoding exactly means more than 16 encoded + // bits. This is thus a non-BMP character which needed a surrogate + // pair to get encoded in UTF-16, add a BOM after it. + + // And add a BOM after it. + aDest.Replace(desti, 3, "\xEF\xBB\xBF"); + desti += 3; + } + } + MOZ_ASSERT(desti == destlength, + "Incoherency between computed length" + "and actually translated length"); +} + +void ATKStringConverterHelper::AdjustOffsets(gint* aStartOffset, + gint* aEndOffset, gint count) { + MOZ_ASSERT(!mAdjusted, + "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be " + "called only once"); + + if (*aStartOffset > 0) { + (*aStartOffset)--; + mStartShifted = true; + } + + if (*aEndOffset >= 0 && *aEndOffset < count) { + (*aEndOffset)++; + mEndShifted = true; + } + +#ifdef DEBUG + mAdjusted = true; +#endif +} + +gchar* ATKStringConverterHelper::FinishUTF16toUTF8(nsCString& aStr) { + int skip = 0; + + if (mStartShifted) { + // AdjustOffsets added a leading character. + + MOZ_ASSERT(aStr.Length() > 0, "There should be a leading character"); + MOZ_ASSERT( + static_cast<int>(aStr.Length()) >= UTF8traits::bytes(aStr.CharAt(0)), + "The leading character should be complete"); + + // drop first character + skip = UTF8traits::bytes(aStr.CharAt(0)); + } + + if (mEndShifted) { + // AdjustOffsets added a trailing character. + + MOZ_ASSERT(aStr.Length() > 0, "There should be a trailing character"); + + int trail = -1; + // Find beginning of last character. + for (trail = aStr.Length() - 1; trail >= 0; trail--) { + if (!UTF8traits::isInSeq(aStr.CharAt(trail))) { + break; + } + } + MOZ_ASSERT(trail >= 0, + "There should be at least a whole trailing character"); + MOZ_ASSERT(trail + UTF8traits::bytes(aStr.CharAt(trail)) == + static_cast<int>(aStr.Length()), + "The trailing character should be complete"); + + // Drop the last character. + aStr.Truncate(trail); + } + + // copy and return, libspi will free it + return g_strdup(aStr.get() + skip); +} + +gchar* ATKStringConverterHelper::ConvertAdjusted(const nsAString& aStr) { + MOZ_ASSERT(mAdjusted, + "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be " + "called before ATKStringConverterHelper::ConvertAdjusted"); + + NS_ConvertUTF16toUTF8 cautoStr(aStr); + if (!cautoStr.get()) { + return nullptr; + } + + nsAutoCString cautoStrBOMs; + AddBOMs(cautoStrBOMs, cautoStr); + return FinishUTF16toUTF8(cautoStrBOMs); +} + +gchar* Convert(const nsAString& aStr) { + NS_ConvertUTF16toUTF8 cautoStr(aStr); + if (!cautoStr.get()) { + return nullptr; + } + + nsAutoCString cautoStrBOMs; + AddBOMs(cautoStrBOMs, cautoStr); + return g_strdup(cautoStrBOMs.get()); +} + +} // namespace DOMtoATK + +} // namespace a11y +} // namespace mozilla |