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 
AddBOMs(nsACString & aDest,const nsACString & aSource)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 
AdjustOffsets(gint * aStartOffset,gint * aEndOffset,gint count)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 
FinishUTF16toUTF8(nsCString & aStr)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 
ConvertAdjusted(const nsAString & aStr)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 
Convert(const nsAString & aStr)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 
ConvertTexttoAsterisks(nsAString & aString)148 void ConvertTexttoAsterisks(nsAString& aString) {
149   for (uint32_t i = 0; i < aString.Length(); i++) {
150     aString.ReplaceLiteral(i, 1, u"*");
151   }
152 }
153 
154 }  // namespace DOMtoATK
155 
156 }  // namespace a11y
157 }  // namespace mozilla
158