DOMtoATK.cpp (4299B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=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 "DOMtoATK.h" 8 #include "nsUTF8Utils.h" 9 10 namespace mozilla { 11 namespace a11y { 12 13 namespace DOMtoATK { 14 15 void AddBOMs(nsACString& aDest, const nsACString& aSource) { 16 uint32_t destlength = 0; 17 18 // First compute how much room we will need. 19 for (uint32_t srci = 0; srci < aSource.Length();) { 20 int bytes = UTF8traits::bytes(aSource[srci]); 21 if (bytes >= 4) { 22 // Non-BMP character, will add a BOM after it. 23 destlength += 3; 24 } 25 // Skip whole character encoding. 26 srci += bytes; 27 destlength += bytes; 28 } 29 30 uint32_t desti = 0; // Index within aDest. 31 32 // Add BOMs after non-BMP characters. 33 aDest.SetLength(destlength); 34 for (uint32_t srci = 0; srci < aSource.Length();) { 35 uint32_t bytes = UTF8traits::bytes(aSource[srci]); 36 37 MOZ_ASSERT(bytes <= aSource.Length() - srci, 38 "We should have the whole sequence"); 39 40 // Copy whole sequence. 41 aDest.Replace(desti, bytes, Substring(aSource, srci, bytes)); 42 desti += bytes; 43 srci += bytes; 44 45 if (bytes >= 4) { 46 // More than 4 bytes in UTF-8 encoding exactly means more than 16 encoded 47 // bits. This is thus a non-BMP character which needed a surrogate 48 // pair to get encoded in UTF-16, add a BOM after it. 49 50 // And add a BOM after it. 51 aDest.Replace(desti, 3, "\xEF\xBB\xBF"); 52 desti += 3; 53 } 54 } 55 MOZ_ASSERT(desti == destlength, 56 "Incoherency between computed length" 57 "and actually translated length"); 58 } 59 60 void ATKStringConverterHelper::AdjustOffsets(gint* aStartOffset, 61 gint* aEndOffset, gint count) { 62 MOZ_ASSERT(!mAdjusted, 63 "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be " 64 "called only once"); 65 66 if (*aStartOffset > 0) { 67 (*aStartOffset)--; 68 mStartShifted = true; 69 } 70 71 if (*aEndOffset >= 0 && *aEndOffset < count) { 72 (*aEndOffset)++; 73 mEndShifted = true; 74 } 75 76 #ifdef DEBUG 77 mAdjusted = true; 78 #endif 79 } 80 81 gchar* ATKStringConverterHelper::FinishUTF16toUTF8(nsCString& aStr) { 82 int skip = 0; 83 84 if (mStartShifted) { 85 // AdjustOffsets added a leading character. 86 87 MOZ_ASSERT(aStr.Length() > 0, "There should be a leading character"); 88 MOZ_ASSERT( 89 static_cast<int>(aStr.Length()) >= UTF8traits::bytes(aStr.CharAt(0)), 90 "The leading character should be complete"); 91 92 // drop first character 93 skip = UTF8traits::bytes(aStr.CharAt(0)); 94 } 95 96 if (mEndShifted) { 97 // AdjustOffsets added a trailing character. 98 99 MOZ_ASSERT(aStr.Length() > 0, "There should be a trailing character"); 100 101 int trail = -1; 102 // Find beginning of last character. 103 for (trail = aStr.Length() - 1; trail >= 0; trail--) { 104 if (!UTF8traits::isInSeq(aStr.CharAt(trail))) { 105 break; 106 } 107 } 108 MOZ_ASSERT(trail >= 0, 109 "There should be at least a whole trailing character"); 110 MOZ_ASSERT(trail + UTF8traits::bytes(aStr.CharAt(trail)) == 111 static_cast<int>(aStr.Length()), 112 "The trailing character should be complete"); 113 114 // Drop the last character. 115 aStr.Truncate(trail); 116 } 117 118 // copy and return, libspi will free it 119 return g_strdup(aStr.get() + skip); 120 } 121 122 gchar* ATKStringConverterHelper::ConvertAdjusted(const nsAString& aStr) { 123 MOZ_ASSERT(mAdjusted, 124 "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be " 125 "called before ATKStringConverterHelper::ConvertAdjusted"); 126 127 NS_ConvertUTF16toUTF8 cautoStr(aStr); 128 if (!cautoStr.get()) { 129 return nullptr; 130 } 131 132 nsAutoCString cautoStrBOMs; 133 AddBOMs(cautoStrBOMs, cautoStr); 134 return FinishUTF16toUTF8(cautoStrBOMs); 135 } 136 137 gchar* Convert(const nsAString& aStr) { 138 NS_ConvertUTF16toUTF8 cautoStr(aStr); 139 if (!cautoStr.get()) { 140 return nullptr; 141 } 142 143 nsAutoCString cautoStrBOMs; 144 AddBOMs(cautoStrBOMs, cautoStr); 145 return g_strdup(cautoStrBOMs.get()); 146 } 147 148 } // namespace DOMtoATK 149 150 } // namespace a11y 151 } // namespace mozilla