Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / character_encoding.cc
blob0a166a92d6f727483bc78c87906bd58d5d2e08fa
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/character_encoding.h"
7 #include <map>
8 #include <set>
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_tokenizer.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "third_party/icu/source/common/unicode/ucnv.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/l10n/l10n_util_collator.h"
22 using content::BrowserThread;
24 namespace {
26 // The maximum length of short list of recently user selected encodings is 3.
27 const size_t kUserSelectedEncodingsMaxLength = 3;
29 typedef struct {
30 int resource_id;
31 const char* name;
32 int category_string_id;
33 } CanonicalEncodingData;
35 // An array of all supported canonical encoding names.
36 const CanonicalEncodingData kCanonicalEncodingNames[] = {
37 { IDC_ENCODING_UTF8, "UTF-8", IDS_ENCODING_UNICODE },
38 { IDC_ENCODING_UTF16LE, "UTF-16LE", IDS_ENCODING_UNICODE },
39 { IDC_ENCODING_WINDOWS1252, "windows-1252", IDS_ENCODING_WESTERN },
40 { IDC_ENCODING_GBK, "GBK", IDS_ENCODING_SIMP_CHINESE },
41 { IDC_ENCODING_GB18030, "gb18030", IDS_ENCODING_SIMP_CHINESE },
42 { IDC_ENCODING_BIG5, "Big5", IDS_ENCODING_TRAD_CHINESE },
43 { IDC_ENCODING_KOREAN, "EUC-KR", IDS_ENCODING_KOREAN },
44 { IDC_ENCODING_SHIFTJIS, "Shift_JIS", IDS_ENCODING_JAPANESE },
45 { IDC_ENCODING_EUCJP, "EUC-JP", IDS_ENCODING_JAPANESE },
46 { IDC_ENCODING_ISO2022JP, "ISO-2022-JP", IDS_ENCODING_JAPANESE },
47 { IDC_ENCODING_THAI, "windows-874", IDS_ENCODING_THAI },
48 { IDC_ENCODING_ISO885915, "ISO-8859-15", IDS_ENCODING_WESTERN },
49 { IDC_ENCODING_MACINTOSH, "macintosh", IDS_ENCODING_WESTERN },
50 { IDC_ENCODING_ISO88592, "ISO-8859-2", IDS_ENCODING_CENTRAL_EUROPEAN },
51 { IDC_ENCODING_WINDOWS1250, "windows-1250", IDS_ENCODING_CENTRAL_EUROPEAN },
52 { IDC_ENCODING_ISO88595, "ISO-8859-5", IDS_ENCODING_CYRILLIC },
53 { IDC_ENCODING_WINDOWS1251, "windows-1251", IDS_ENCODING_CYRILLIC },
54 { IDC_ENCODING_KOI8R, "KOI8-R", IDS_ENCODING_CYRILLIC },
55 { IDC_ENCODING_KOI8U, "KOI8-U", IDS_ENCODING_CYRILLIC },
56 { IDC_ENCODING_IBM866, "IBM866", IDS_ENCODING_CYRILLIC },
57 { IDC_ENCODING_ISO88597, "ISO-8859-7", IDS_ENCODING_GREEK },
58 { IDC_ENCODING_WINDOWS1253, "windows-1253", IDS_ENCODING_GREEK },
59 { IDC_ENCODING_WINDOWS1254, "windows-1254", IDS_ENCODING_TURKISH },
60 { IDC_ENCODING_WINDOWS1256, "windows-1256", IDS_ENCODING_ARABIC },
61 { IDC_ENCODING_ISO88596, "ISO-8859-6", IDS_ENCODING_ARABIC },
62 { IDC_ENCODING_WINDOWS1255, "windows-1255", IDS_ENCODING_HEBREW },
63 { IDC_ENCODING_ISO88598I, "ISO-8859-8-I", IDS_ENCODING_HEBREW },
64 { IDC_ENCODING_ISO88598, "ISO-8859-8", IDS_ENCODING_HEBREW },
65 { IDC_ENCODING_WINDOWS1258, "windows-1258", IDS_ENCODING_VIETNAMESE },
66 { IDC_ENCODING_ISO88594, "ISO-8859-4", IDS_ENCODING_BALTIC },
67 { IDC_ENCODING_ISO885913, "ISO-8859-13", IDS_ENCODING_BALTIC },
68 { IDC_ENCODING_WINDOWS1257, "windows-1257", IDS_ENCODING_BALTIC },
69 { IDC_ENCODING_ISO88593, "ISO-8859-3", IDS_ENCODING_SOUTH_EUROPEAN },
70 { IDC_ENCODING_ISO885910, "ISO-8859-10", IDS_ENCODING_NORDIC },
71 { IDC_ENCODING_ISO885914, "ISO-8859-14", IDS_ENCODING_CELTIC },
72 { IDC_ENCODING_ISO885916, "ISO-8859-16", IDS_ENCODING_ROMANIAN },
75 const int kCanonicalEncodingNamesLength = arraysize(kCanonicalEncodingNames);
77 typedef std::map<int, std::pair<const char*, int> >
78 IdToCanonicalEncodingNameMapType;
79 typedef std::map<const std::string, int> CanonicalEncodingNameToIdMapType;
81 typedef struct {
82 const char* canonical_form;
83 const char* display_form;
84 } CanonicalEncodingDisplayNamePair;
86 const CanonicalEncodingDisplayNamePair kCanonicalDisplayNameOverrides[] = {
87 // Only lists the canonical names where we want a different form for display.
88 { "macintosh", "Macintosh" },
89 { "windows-874", "Windows-874" },
90 { "windows-1250", "Windows-1250" },
91 { "windows-1251", "Windows-1251" },
92 { "windows-1252", "Windows-1252" },
93 { "windows-1253", "Windows-1253" },
94 { "windows-1254", "Windows-1254" },
95 { "windows-1255", "Windows-1255" },
96 { "windows-1256", "Windows-1256" },
97 { "windows-1257", "Windows-1257" },
98 { "windows-1258", "Windows-1258" },
101 const int kCanonicalDisplayNameOverridesLength =
102 arraysize(kCanonicalDisplayNameOverrides);
104 typedef std::map<std::string, const char*> CanonicalNameDisplayNameMapType;
106 class CanonicalEncodingMap {
107 public:
108 CanonicalEncodingMap() {}
109 const IdToCanonicalEncodingNameMapType* GetIdToCanonicalEncodingNameMapData();
110 const CanonicalEncodingNameToIdMapType* GetCanonicalEncodingNameToIdMapData();
111 const CanonicalNameDisplayNameMapType* GetCanonicalNameDisplayNameMapData();
112 std::vector<int>* locale_dependent_encoding_ids() {
113 return &locale_dependent_encoding_ids_;
116 std::vector<CharacterEncoding::EncodingInfo>* current_display_encodings() {
117 return &current_display_encodings_;
120 private:
121 scoped_ptr<IdToCanonicalEncodingNameMapType> id_to_encoding_name_map_;
122 scoped_ptr<CanonicalEncodingNameToIdMapType> encoding_name_to_id_map_;
123 scoped_ptr<CanonicalNameDisplayNameMapType>
124 encoding_name_to_display_name_map_;
125 std::vector<int> locale_dependent_encoding_ids_;
126 std::vector<CharacterEncoding::EncodingInfo> current_display_encodings_;
128 DISALLOW_COPY_AND_ASSIGN(CanonicalEncodingMap);
131 const IdToCanonicalEncodingNameMapType*
132 CanonicalEncodingMap::GetIdToCanonicalEncodingNameMapData() {
133 // Testing and building map is not thread safe, this function is supposed to
134 // only run in UI thread. Myabe I should add a lock in here for making it as
135 // thread safe.
136 if (!id_to_encoding_name_map_.get()) {
137 id_to_encoding_name_map_.reset(new IdToCanonicalEncodingNameMapType);
138 for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
139 int resource_id = kCanonicalEncodingNames[i].resource_id;
140 (*id_to_encoding_name_map_)[resource_id] =
141 std::make_pair(kCanonicalEncodingNames[i].name,
142 kCanonicalEncodingNames[i].category_string_id);
145 return id_to_encoding_name_map_.get();
148 const CanonicalEncodingNameToIdMapType*
149 CanonicalEncodingMap::GetCanonicalEncodingNameToIdMapData() {
150 if (!encoding_name_to_id_map_.get()) {
151 encoding_name_to_id_map_.reset(new CanonicalEncodingNameToIdMapType);
152 for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
153 (*encoding_name_to_id_map_)[kCanonicalEncodingNames[i].name] =
154 kCanonicalEncodingNames[i].resource_id;
157 return encoding_name_to_id_map_.get();
160 const CanonicalNameDisplayNameMapType*
161 CanonicalEncodingMap::GetCanonicalNameDisplayNameMapData() {
162 if (!encoding_name_to_display_name_map_.get()) {
163 encoding_name_to_display_name_map_.reset(
164 new CanonicalNameDisplayNameMapType);
165 // First store the names in the kCanonicalEncodingNames list.
166 for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
167 (*encoding_name_to_display_name_map_)[kCanonicalEncodingNames[i].name] =
168 kCanonicalEncodingNames[i].name;
170 // Then save in the overrides.
171 for (int i = 0; i < kCanonicalDisplayNameOverridesLength; ++i) {
172 (*encoding_name_to_display_name_map_)
173 [kCanonicalDisplayNameOverrides[i].canonical_form] =
174 kCanonicalDisplayNameOverrides[i].display_form;
176 DCHECK(static_cast<int>(encoding_name_to_display_name_map_->size()) ==
177 kCanonicalEncodingNamesLength)
178 << "Got an override that wasn't in the encoding list";
180 return encoding_name_to_display_name_map_.get();
183 // A static map object which contains all resourceid-nonsequenced canonical
184 // encoding names.
185 CanonicalEncodingMap* CanonicalEncodingMapSingleton() {
186 DCHECK_CURRENTLY_ON(BrowserThread::UI);
187 static CanonicalEncodingMap* singleton = new CanonicalEncodingMap;
188 return singleton;
191 const int kDefaultEncodingMenus[] = {
192 IDC_ENCODING_UTF16LE,
193 IDC_ENCODING_WINDOWS1252,
194 IDC_ENCODING_GBK,
195 IDC_ENCODING_GB18030,
196 IDC_ENCODING_BIG5,
197 IDC_ENCODING_KOREAN,
198 IDC_ENCODING_SHIFTJIS,
199 IDC_ENCODING_EUCJP,
200 IDC_ENCODING_ISO2022JP,
201 IDC_ENCODING_THAI,
202 IDC_ENCODING_ISO885915,
203 IDC_ENCODING_MACINTOSH,
204 IDC_ENCODING_ISO88592,
205 IDC_ENCODING_WINDOWS1250,
206 IDC_ENCODING_ISO88595,
207 IDC_ENCODING_WINDOWS1251,
208 IDC_ENCODING_KOI8R,
209 IDC_ENCODING_KOI8U,
210 IDC_ENCODING_IBM866,
211 IDC_ENCODING_ISO88597,
212 IDC_ENCODING_WINDOWS1253,
213 IDC_ENCODING_WINDOWS1254,
214 IDC_ENCODING_WINDOWS1256,
215 IDC_ENCODING_ISO88596,
216 IDC_ENCODING_WINDOWS1255,
217 IDC_ENCODING_ISO88598I,
218 IDC_ENCODING_ISO88598,
219 IDC_ENCODING_WINDOWS1258,
220 IDC_ENCODING_ISO88594,
221 IDC_ENCODING_ISO885913,
222 IDC_ENCODING_WINDOWS1257,
223 IDC_ENCODING_ISO88593,
224 IDC_ENCODING_ISO885910,
225 IDC_ENCODING_ISO885914,
226 IDC_ENCODING_ISO885916,
229 const int kDefaultEncodingMenusLength = arraysize(kDefaultEncodingMenus);
231 // Parse the input |encoding_list| which is a encoding list separated with
232 // comma, get available encoding ids and save them to |available_list|.
233 // The parameter |maximum_size| indicates maximum size of encoding items we
234 // want to get from the |encoding_list|.
235 void ParseEncodingListSeparatedWithComma(
236 const std::string& encoding_list, std::vector<int>* const available_list,
237 size_t maximum_size) {
238 base::StringTokenizer tokenizer(encoding_list, ",");
239 while (tokenizer.GetNext()) {
240 int id = CharacterEncoding::GetCommandIdByCanonicalEncodingName(
241 tokenizer.token());
242 // Ignore invalid encoding.
243 if (!id)
244 continue;
245 available_list->push_back(id);
246 if (available_list->size() == maximum_size)
247 return;
251 base::string16 GetEncodingDisplayName(const std::string& encoding_name,
252 int category_string_id) {
253 base::string16 category_name = l10n_util::GetStringUTF16(category_string_id);
254 if (category_string_id != IDS_ENCODING_KOREAN &&
255 category_string_id != IDS_ENCODING_THAI &&
256 category_string_id != IDS_ENCODING_TURKISH &&
257 category_string_id != IDS_ENCODING_VIETNAMESE &&
258 category_string_id != IDS_ENCODING_ROMANIAN) {
259 const CanonicalNameDisplayNameMapType* map =
260 CanonicalEncodingMapSingleton()->GetCanonicalNameDisplayNameMapData();
261 DCHECK(map);
263 CanonicalNameDisplayNameMapType::const_iterator found_name =
264 map->find(encoding_name);
265 DCHECK(found_name != map->end());
266 return l10n_util::GetStringFUTF16(IDS_ENCODING_DISPLAY_TEMPLATE,
267 category_name,
268 base::ASCIIToUTF16(found_name->second));
270 return category_name;
273 int GetEncodingCategoryStringIdByCommandId(int id) {
274 const IdToCanonicalEncodingNameMapType* map =
275 CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
276 DCHECK(map);
278 IdToCanonicalEncodingNameMapType::const_iterator found_name = map->find(id);
279 if (found_name != map->end())
280 return found_name->second.second;
281 return 0;
284 std::string GetEncodingCategoryStringByCommandId(int id) {
285 int category_id = GetEncodingCategoryStringIdByCommandId(id);
286 if (category_id)
287 return l10n_util::GetStringUTF8(category_id);
288 return std::string();
291 } // namespace
293 CharacterEncoding::EncodingInfo::EncodingInfo(int id)
294 : encoding_id(id) {
295 encoding_category_name =
296 base::UTF8ToUTF16(GetEncodingCategoryStringByCommandId(id));
297 encoding_display_name = GetCanonicalEncodingDisplayNameByCommandId(id);
300 // Static.
301 int CharacterEncoding::GetCommandIdByCanonicalEncodingName(
302 const std::string& encoding_name) {
303 const CanonicalEncodingNameToIdMapType* map =
304 CanonicalEncodingMapSingleton()->GetCanonicalEncodingNameToIdMapData();
305 DCHECK(map);
307 CanonicalEncodingNameToIdMapType::const_iterator found_id =
308 map->find(encoding_name);
309 if (found_id != map->end())
310 return found_id->second;
311 return 0;
314 // Static.
315 std::string CharacterEncoding::GetCanonicalEncodingNameByCommandId(int id) {
316 const IdToCanonicalEncodingNameMapType* map =
317 CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
318 DCHECK(map);
320 IdToCanonicalEncodingNameMapType::const_iterator found_name = map->find(id);
321 if (found_name != map->end())
322 return found_name->second.first;
323 return std::string();
326 // Static.
327 base::string16 CharacterEncoding::GetCanonicalEncodingDisplayNameByCommandId(
328 int id) {
329 const IdToCanonicalEncodingNameMapType* map =
330 CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
331 DCHECK(map);
333 IdToCanonicalEncodingNameMapType::const_iterator found_name = map->find(id);
334 if (found_name != map->end())
335 return GetEncodingDisplayName(found_name->second.first,
336 found_name->second.second);
337 return base::string16();
340 // Static.
341 // Return count number of all supported canonical encoding.
342 int CharacterEncoding::GetSupportCanonicalEncodingCount() {
343 return kCanonicalEncodingNamesLength;
346 // Static.
347 std::string CharacterEncoding::GetCanonicalEncodingNameByIndex(int index) {
348 if (index < kCanonicalEncodingNamesLength)
349 return kCanonicalEncodingNames[index].name;
350 return std::string();
353 // Static.
354 base::string16 CharacterEncoding::GetCanonicalEncodingDisplayNameByIndex(
355 int index) {
356 if (index < kCanonicalEncodingNamesLength)
357 return GetEncodingDisplayName(kCanonicalEncodingNames[index].name,
358 kCanonicalEncodingNames[index].category_string_id);
359 return base::string16();
362 // Static.
363 int CharacterEncoding::GetEncodingCommandIdByIndex(int index) {
364 if (index < kCanonicalEncodingNamesLength)
365 return kCanonicalEncodingNames[index].resource_id;
366 return 0;
369 // Static.
370 std::string CharacterEncoding::GetCanonicalEncodingNameByAliasName(
371 const std::string& alias_name) {
372 // If the input alias_name is already canonical encoding name, just return it.
373 const CanonicalEncodingNameToIdMapType* map =
374 CanonicalEncodingMapSingleton()->GetCanonicalEncodingNameToIdMapData();
375 DCHECK(map);
377 CanonicalEncodingNameToIdMapType::const_iterator found_id =
378 map->find(alias_name);
379 if (found_id != map->end())
380 return alias_name;
382 const char* standards[3] = { "HTML", "MIME", "IANA" };
383 for (size_t i = 0; i < arraysize(standards); ++i) {
384 UErrorCode error_code = U_ZERO_ERROR;
385 const char* canonical_name = ucnv_getCanonicalName(
386 alias_name.c_str(), standards[i], &error_code);
387 if (U_SUCCESS(error_code) && canonical_name)
388 return canonical_name;
390 return std::string();
393 // Static
394 // According to the behavior of user recently selected encoding short list in
395 // Firefox, we always put UTF-8 as top position, after then put user
396 // recent selected encodings, then put local dependent encoding items.
397 // At last, we put all remaining encoding items.
398 const std::vector<CharacterEncoding::EncodingInfo>*
399 CharacterEncoding::GetCurrentDisplayEncodings(
400 const std::string& locale,
401 const std::string& locale_encodings,
402 const std::string& recently_select_encodings) {
403 std::vector<int>* const locale_dependent_encoding_list =
404 CanonicalEncodingMapSingleton()->locale_dependent_encoding_ids();
405 std::vector<CharacterEncoding::EncodingInfo>* const encoding_list =
406 CanonicalEncodingMapSingleton()->current_display_encodings();
408 // Initialize locale dependent static encoding list.
409 if (locale_dependent_encoding_list->empty() && !locale_encodings.empty())
410 ParseEncodingListSeparatedWithComma(locale_encodings,
411 locale_dependent_encoding_list,
412 kUserSelectedEncodingsMaxLength);
414 CR_DEFINE_STATIC_LOCAL(std::string, cached_user_selected_encodings, ());
415 // Build current display encoding list.
416 if (encoding_list->empty() ||
417 cached_user_selected_encodings != recently_select_encodings) {
418 // Update user recently selected encodings.
419 cached_user_selected_encodings = recently_select_encodings;
420 // Clear old encoding list since user recently selected encodings changed.
421 encoding_list->clear();
422 // Always add UTF-8 to first encoding position.
423 encoding_list->push_back(EncodingInfo(IDC_ENCODING_UTF8));
424 std::set<int> inserted_encoding;
425 inserted_encoding.insert(IDC_ENCODING_UTF8);
427 // Parse user recently selected encodings and get list
428 std::vector<int> recently_select_encoding_list;
429 ParseEncodingListSeparatedWithComma(recently_select_encodings,
430 &recently_select_encoding_list,
431 kUserSelectedEncodingsMaxLength);
433 // Put 'cached encodings' (dynamic encoding list) after 'local dependent
434 // encoding list'.
435 recently_select_encoding_list.insert(recently_select_encoding_list.begin(),
436 locale_dependent_encoding_list->begin(),
437 locale_dependent_encoding_list->end());
438 for (std::vector<int>::iterator it = recently_select_encoding_list.begin();
439 it != recently_select_encoding_list.end(); ++it) {
440 // Test whether we have met this encoding id.
441 bool ok = inserted_encoding.insert(*it).second;
442 // Duplicated encoding, ignore it. Ideally, this situation should not
443 // happened, but just in case some one manually edit preference file.
444 if (!ok)
445 continue;
446 encoding_list->push_back(EncodingInfo(*it));
448 // Append a separator;
449 encoding_list->push_back(EncodingInfo(0));
451 // We need to keep "Unicode (UTF-16LE)" always at the top (among the rest
452 // of encodings) instead of being sorted along with other encodings. So if
453 // "Unicode (UTF-16LE)" is already in previous encodings, sort the rest
454 // of encodings. Otherwise Put "Unicode (UTF-16LE)" on the first of the
455 // rest of encodings, skip "Unicode (UTF-16LE)" and sort all left encodings.
456 int start_sorted_index = encoding_list->size();
457 if (inserted_encoding.find(IDC_ENCODING_UTF16LE) ==
458 inserted_encoding.end()) {
459 encoding_list->push_back(EncodingInfo(IDC_ENCODING_UTF16LE));
460 inserted_encoding.insert(IDC_ENCODING_UTF16LE);
461 start_sorted_index++;
464 // Add the rest of encodings that are neither in the static encoding list
465 // nor in the list of recently selected encodings.
466 // Build the encoding list sorted in the current locale sorting order.
467 for (int i = 0; i < kDefaultEncodingMenusLength; ++i) {
468 int id = kDefaultEncodingMenus[i];
469 // We have inserted this encoding, skip it.
470 if (inserted_encoding.find(id) != inserted_encoding.end())
471 continue;
472 encoding_list->push_back(EncodingInfo(id));
474 // Sort the encoding list.
475 l10n_util::SortVectorWithStringKey(locale,
476 encoding_list,
477 start_sorted_index,
478 encoding_list->size(),
479 true);
481 DCHECK(!encoding_list->empty());
482 return encoding_list;
485 // Static
486 bool CharacterEncoding::UpdateRecentlySelectedEncoding(
487 const std::string& original_selected_encodings,
488 int new_selected_encoding_id,
489 std::string* selected_encodings) {
490 // Get encoding name.
491 std::string encoding_name =
492 GetCanonicalEncodingNameByCommandId(new_selected_encoding_id);
493 DCHECK(!encoding_name.empty());
494 // Check whether the new encoding is in local dependent encodings or original
495 // recently selected encodings. If yes, do not add it.
496 std::vector<int>* locale_dependent_encoding_list =
497 CanonicalEncodingMapSingleton()->locale_dependent_encoding_ids();
498 DCHECK(locale_dependent_encoding_list);
499 std::vector<int> selected_encoding_list;
500 ParseEncodingListSeparatedWithComma(original_selected_encodings,
501 &selected_encoding_list,
502 kUserSelectedEncodingsMaxLength);
503 // Put 'cached encodings' (dynamic encoding list) after 'local dependent
504 // encoding list' for check.
505 std::vector<int> top_encoding_list(*locale_dependent_encoding_list);
506 // UTF8 is always in our optimized encoding list.
507 top_encoding_list.insert(top_encoding_list.begin(), IDC_ENCODING_UTF8);
508 top_encoding_list.insert(top_encoding_list.end(),
509 selected_encoding_list.begin(),
510 selected_encoding_list.end());
511 for (std::vector<int>::const_iterator it = top_encoding_list.begin();
512 it != top_encoding_list.end(); ++it)
513 if (*it == new_selected_encoding_id)
514 return false;
515 // Need to add the encoding id to recently selected encoding list.
516 // Remove the last encoding in original list.
517 if (selected_encoding_list.size() == kUserSelectedEncodingsMaxLength)
518 selected_encoding_list.pop_back();
519 // Insert new encoding to head of selected encoding list.
520 *selected_encodings = encoding_name;
521 // Generate the string for rest selected encoding list.
522 for (std::vector<int>::const_iterator it = selected_encoding_list.begin();
523 it != selected_encoding_list.end(); ++it) {
524 selected_encodings->append(1, L',');
525 selected_encodings->append(GetCanonicalEncodingNameByCommandId(*it));
527 return true;