Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / character_encoding.cc
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.
4
5 #include "chrome/browser/character_encoding.h"
6
7 #include <map>
8 #include <set>
9
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"
21
22 using content::BrowserThread;
23
24 namespace {
25
26 // The maximum length of short list of recently user selected encodings is 3.
27 const size_t kUserSelectedEncodingsMaxLength = 3;
28
29 typedef struct {
30   int resource_id;
31   const char* name;
32   int category_string_id;
33 } CanonicalEncodingData;
34
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_ISO88591, "ISO-8859-1", IDS_ENCODING_WESTERN },
40   { IDC_ENCODING_WINDOWS1252, "windows-1252", IDS_ENCODING_WESTERN },
41   { IDC_ENCODING_GBK, "GBK", IDS_ENCODING_SIMP_CHINESE },
42   { IDC_ENCODING_GB18030, "gb18030", IDS_ENCODING_SIMP_CHINESE },
43   { IDC_ENCODING_BIG5, "Big5", IDS_ENCODING_TRAD_CHINESE },
44   { IDC_ENCODING_BIG5HKSCS, "Big5-HKSCS", IDS_ENCODING_TRAD_CHINESE },
45   { IDC_ENCODING_KOREAN, "EUC-KR", IDS_ENCODING_KOREAN },
46   { IDC_ENCODING_SHIFTJIS, "Shift_JIS", IDS_ENCODING_JAPANESE },
47   { IDC_ENCODING_EUCJP, "EUC-JP", IDS_ENCODING_JAPANESE },
48   { IDC_ENCODING_ISO2022JP, "ISO-2022-JP", IDS_ENCODING_JAPANESE },
49   { IDC_ENCODING_THAI, "windows-874", IDS_ENCODING_THAI },
50   { IDC_ENCODING_ISO885915, "ISO-8859-15", IDS_ENCODING_WESTERN },
51   { IDC_ENCODING_MACINTOSH, "macintosh", IDS_ENCODING_WESTERN },
52   { IDC_ENCODING_ISO88592, "ISO-8859-2", IDS_ENCODING_CENTRAL_EUROPEAN },
53   { IDC_ENCODING_WINDOWS1250, "windows-1250", IDS_ENCODING_CENTRAL_EUROPEAN },
54   { IDC_ENCODING_ISO88595, "ISO-8859-5", IDS_ENCODING_CYRILLIC },
55   { IDC_ENCODING_WINDOWS1251, "windows-1251", IDS_ENCODING_CYRILLIC },
56   { IDC_ENCODING_KOI8R, "KOI8-R", IDS_ENCODING_CYRILLIC },
57   { IDC_ENCODING_KOI8U, "KOI8-U", IDS_ENCODING_CYRILLIC },
58   { IDC_ENCODING_ISO88597, "ISO-8859-7", IDS_ENCODING_GREEK },
59   { IDC_ENCODING_WINDOWS1253, "windows-1253", IDS_ENCODING_GREEK },
60   { IDC_ENCODING_WINDOWS1254, "windows-1254", IDS_ENCODING_TURKISH },
61   { IDC_ENCODING_WINDOWS1256, "windows-1256", IDS_ENCODING_ARABIC },
62   { IDC_ENCODING_ISO88596, "ISO-8859-6", IDS_ENCODING_ARABIC },
63   { IDC_ENCODING_WINDOWS1255, "windows-1255", IDS_ENCODING_HEBREW },
64   { IDC_ENCODING_ISO88598I, "ISO-8859-8-I", IDS_ENCODING_HEBREW },
65   { IDC_ENCODING_ISO88598, "ISO-8859-8", IDS_ENCODING_HEBREW },
66   { IDC_ENCODING_WINDOWS1258, "windows-1258", IDS_ENCODING_VIETNAMESE },
67   { IDC_ENCODING_ISO88594, "ISO-8859-4", IDS_ENCODING_BALTIC },
68   { IDC_ENCODING_ISO885913, "ISO-8859-13", IDS_ENCODING_BALTIC },
69   { IDC_ENCODING_WINDOWS1257, "windows-1257", IDS_ENCODING_BALTIC },
70   { IDC_ENCODING_ISO88593, "ISO-8859-3", IDS_ENCODING_SOUTH_EUROPEAN },
71   { IDC_ENCODING_ISO885910, "ISO-8859-10", IDS_ENCODING_NORDIC },
72   { IDC_ENCODING_ISO885914, "ISO-8859-14", IDS_ENCODING_CELTIC },
73   { IDC_ENCODING_ISO885916, "ISO-8859-16", IDS_ENCODING_ROMANIAN },
74 };
75
76 const int kCanonicalEncodingNamesLength = arraysize(kCanonicalEncodingNames);
77
78 typedef std::map<int, std::pair<const char*, int> >
79     IdToCanonicalEncodingNameMapType;
80 typedef std::map<const std::string, int> CanonicalEncodingNameToIdMapType;
81
82 typedef struct {
83   const char* canonical_form;
84   const char* display_form;
85 } CanonicalEncodingDisplayNamePair;
86
87 const CanonicalEncodingDisplayNamePair kCanonicalDisplayNameOverrides[] = {
88   // Only lists the canonical names where we want a different form for display.
89   { "macintosh", "Macintosh" },
90   { "windows-874", "Windows-874" },
91   { "windows-1250", "Windows-1250" },
92   { "windows-1251", "Windows-1251" },
93   { "windows-1252", "Windows-1252" },
94   { "windows-1253", "Windows-1253" },
95   { "windows-1254", "Windows-1254" },
96   { "windows-1255", "Windows-1255" },
97   { "windows-1256", "Windows-1256" },
98   { "windows-1257", "Windows-1257" },
99   { "windows-1258", "Windows-1258" },
100 };
101
102 const int kCanonicalDisplayNameOverridesLength =
103     arraysize(kCanonicalDisplayNameOverrides);
104
105 typedef std::map<std::string, const char*> CanonicalNameDisplayNameMapType;
106
107 class CanonicalEncodingMap {
108  public:
109   CanonicalEncodingMap() {}
110   const IdToCanonicalEncodingNameMapType* GetIdToCanonicalEncodingNameMapData();
111   const CanonicalEncodingNameToIdMapType* GetCanonicalEncodingNameToIdMapData();
112   const CanonicalNameDisplayNameMapType* GetCanonicalNameDisplayNameMapData();
113   std::vector<int>* locale_dependent_encoding_ids() {
114     return &locale_dependent_encoding_ids_;
115   }
116
117   std::vector<CharacterEncoding::EncodingInfo>* current_display_encodings() {
118     return &current_display_encodings_;
119   }
120
121  private:
122   scoped_ptr<IdToCanonicalEncodingNameMapType> id_to_encoding_name_map_;
123   scoped_ptr<CanonicalEncodingNameToIdMapType> encoding_name_to_id_map_;
124   scoped_ptr<CanonicalNameDisplayNameMapType>
125       encoding_name_to_display_name_map_;
126   std::vector<int> locale_dependent_encoding_ids_;
127   std::vector<CharacterEncoding::EncodingInfo> current_display_encodings_;
128
129   DISALLOW_COPY_AND_ASSIGN(CanonicalEncodingMap);
130 };
131
132 const IdToCanonicalEncodingNameMapType*
133     CanonicalEncodingMap::GetIdToCanonicalEncodingNameMapData() {
134   // Testing and building map is not thread safe, this function is supposed to
135   // only run in UI thread. Myabe I should add a lock in here for making it as
136   // thread safe.
137   if (!id_to_encoding_name_map_.get()) {
138     id_to_encoding_name_map_.reset(new IdToCanonicalEncodingNameMapType);
139     for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
140       int resource_id = kCanonicalEncodingNames[i].resource_id;
141       (*id_to_encoding_name_map_)[resource_id] =
142         std::make_pair(kCanonicalEncodingNames[i].name,
143                        kCanonicalEncodingNames[i].category_string_id);
144     }
145   }
146   return id_to_encoding_name_map_.get();
147 }
148
149 const CanonicalEncodingNameToIdMapType*
150     CanonicalEncodingMap::GetCanonicalEncodingNameToIdMapData() {
151   if (!encoding_name_to_id_map_.get()) {
152     encoding_name_to_id_map_.reset(new CanonicalEncodingNameToIdMapType);
153     for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
154       (*encoding_name_to_id_map_)[kCanonicalEncodingNames[i].name] =
155           kCanonicalEncodingNames[i].resource_id;
156     }
157   }
158   return encoding_name_to_id_map_.get();
159 }
160
161 const CanonicalNameDisplayNameMapType*
162     CanonicalEncodingMap::GetCanonicalNameDisplayNameMapData() {
163   if (!encoding_name_to_display_name_map_.get()) {
164     encoding_name_to_display_name_map_.reset(
165         new CanonicalNameDisplayNameMapType);
166     // First store the names in the kCanonicalEncodingNames list.
167     for (int i = 0; i < kCanonicalEncodingNamesLength; ++i) {
168       (*encoding_name_to_display_name_map_)[kCanonicalEncodingNames[i].name] =
169           kCanonicalEncodingNames[i].name;
170     }
171     // Then save in the overrides.
172     for (int i = 0; i < kCanonicalDisplayNameOverridesLength; ++i) {
173       (*encoding_name_to_display_name_map_)
174           [kCanonicalDisplayNameOverrides[i].canonical_form] =
175           kCanonicalDisplayNameOverrides[i].display_form;
176     }
177     DCHECK(static_cast<int>(encoding_name_to_display_name_map_->size()) ==
178            kCanonicalEncodingNamesLength)
179         << "Got an override that wasn't in the encoding list";
180   }
181   return encoding_name_to_display_name_map_.get();
182 }
183
184 // A static map object which contains all resourceid-nonsequenced canonical
185 // encoding names.
186 CanonicalEncodingMap* CanonicalEncodingMapSingleton() {
187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
188   static CanonicalEncodingMap* singleton = new CanonicalEncodingMap;
189   return singleton;
190 }
191
192 const int kDefaultEncodingMenus[] = {
193   IDC_ENCODING_UTF16LE,
194   IDC_ENCODING_ISO88591,
195   IDC_ENCODING_WINDOWS1252,
196   IDC_ENCODING_GBK,
197   IDC_ENCODING_GB18030,
198   IDC_ENCODING_BIG5,
199   IDC_ENCODING_BIG5HKSCS,
200   IDC_ENCODING_KOREAN,
201   IDC_ENCODING_SHIFTJIS,
202   IDC_ENCODING_EUCJP,
203   IDC_ENCODING_ISO2022JP,
204   IDC_ENCODING_THAI,
205   IDC_ENCODING_ISO885915,
206   IDC_ENCODING_MACINTOSH,
207   IDC_ENCODING_ISO88592,
208   IDC_ENCODING_WINDOWS1250,
209   IDC_ENCODING_ISO88595,
210   IDC_ENCODING_WINDOWS1251,
211   IDC_ENCODING_KOI8R,
212   IDC_ENCODING_KOI8U,
213   IDC_ENCODING_ISO88597,
214   IDC_ENCODING_WINDOWS1253,
215   IDC_ENCODING_WINDOWS1254,
216   IDC_ENCODING_WINDOWS1256,
217   IDC_ENCODING_ISO88596,
218   IDC_ENCODING_WINDOWS1255,
219   IDC_ENCODING_ISO88598I,
220   IDC_ENCODING_ISO88598,
221   IDC_ENCODING_WINDOWS1258,
222   IDC_ENCODING_ISO88594,
223   IDC_ENCODING_ISO885913,
224   IDC_ENCODING_WINDOWS1257,
225   IDC_ENCODING_ISO88593,
226   IDC_ENCODING_ISO885910,
227   IDC_ENCODING_ISO885914,
228   IDC_ENCODING_ISO885916,
229 };
230
231 const int kDefaultEncodingMenusLength = arraysize(kDefaultEncodingMenus);
232
233 // Parse the input |encoding_list| which is a encoding list separated with
234 // comma, get available encoding ids and save them to |available_list|.
235 // The parameter |maximum_size| indicates maximum size of encoding items we
236 // want to get from the |encoding_list|.
237 void ParseEncodingListSeparatedWithComma(
238     const std::string& encoding_list, std::vector<int>* const available_list,
239     size_t maximum_size) {
240   base::StringTokenizer tokenizer(encoding_list, ",");
241   while (tokenizer.GetNext()) {
242     int id = CharacterEncoding::GetCommandIdByCanonicalEncodingName(
243         tokenizer.token());
244     // Ignore invalid encoding.
245     if (!id)
246       continue;
247     available_list->push_back(id);
248     if (available_list->size() == maximum_size)
249       return;
250   }
251 }
252
253 base::string16 GetEncodingDisplayName(const std::string& encoding_name,
254                                       int category_string_id) {
255   base::string16 category_name = l10n_util::GetStringUTF16(category_string_id);
256   if (category_string_id != IDS_ENCODING_KOREAN &&
257       category_string_id != IDS_ENCODING_THAI &&
258       category_string_id != IDS_ENCODING_TURKISH) {
259     const CanonicalNameDisplayNameMapType* map =
260         CanonicalEncodingMapSingleton()->GetCanonicalNameDisplayNameMapData();
261     DCHECK(map);
262
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));
269   }
270   return category_name;
271 }
272
273 int GetEncodingCategoryStringIdByCommandId(int id) {
274   const IdToCanonicalEncodingNameMapType* map =
275       CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
276   DCHECK(map);
277
278   IdToCanonicalEncodingNameMapType::const_iterator found_name = map->find(id);
279   if (found_name != map->end())
280     return found_name->second.second;
281   return 0;
282 }
283
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();
289 }
290
291 }  // namespace
292
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);
298 }
299
300 // Static.
301 int CharacterEncoding::GetCommandIdByCanonicalEncodingName(
302     const std::string& encoding_name) {
303   const CanonicalEncodingNameToIdMapType* map =
304       CanonicalEncodingMapSingleton()->GetCanonicalEncodingNameToIdMapData();
305   DCHECK(map);
306
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;
312 }
313
314 // Static.
315 std::string CharacterEncoding::GetCanonicalEncodingNameByCommandId(int id) {
316   const IdToCanonicalEncodingNameMapType* map =
317       CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
318   DCHECK(map);
319
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();
324 }
325
326 // Static.
327 base::string16 CharacterEncoding::GetCanonicalEncodingDisplayNameByCommandId(
328     int id) {
329   const IdToCanonicalEncodingNameMapType* map =
330       CanonicalEncodingMapSingleton()->GetIdToCanonicalEncodingNameMapData();
331   DCHECK(map);
332
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();
338 }
339
340 // Static.
341 // Return count number of all supported canonical encoding.
342 int CharacterEncoding::GetSupportCanonicalEncodingCount() {
343   return kCanonicalEncodingNamesLength;
344 }
345
346 // Static.
347 std::string CharacterEncoding::GetCanonicalEncodingNameByIndex(int index) {
348   if (index < kCanonicalEncodingNamesLength)
349     return kCanonicalEncodingNames[index].name;
350   return std::string();
351 }
352
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();
360 }
361
362 // Static.
363 int CharacterEncoding::GetEncodingCommandIdByIndex(int index) {
364   if (index < kCanonicalEncodingNamesLength)
365     return kCanonicalEncodingNames[index].resource_id;
366   return 0;
367 }
368
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);
376
377   CanonicalEncodingNameToIdMapType::const_iterator found_id =
378       map->find(alias_name);
379   if (found_id != map->end())
380     return alias_name;
381
382   UErrorCode error_code = U_ZERO_ERROR;
383
384   const char* canonical_name = ucnv_getCanonicalName(
385       alias_name.c_str(), "MIME", &error_code);
386   // If failed,  then try IANA next.
387   if (U_FAILURE(error_code) || !canonical_name) {
388     error_code = U_ZERO_ERROR;
389     canonical_name = ucnv_getCanonicalName(
390       alias_name.c_str(), "IANA", &error_code);
391   }
392
393   if (canonical_name) {
394     // TODO(jnd) use a map to handle all customized {alias, canonical}
395     // encoding mappings if we have more than one pair.
396     // We don't want to add an unnecessary charset to the encoding menu, so we
397     // alias 'US-ASCII' to 'ISO-8859-1' in our UI without touching WebKit.
398     // http://crbug.com/15801.
399     if (alias_name == "US-ASCII")
400       return GetCanonicalEncodingNameByCommandId(IDC_ENCODING_ISO88591);
401     return canonical_name;
402   } else {
403     return std::string();
404   }
405 }
406
407 // Static
408 // According to the behavior of user recently selected encoding short list in
409 // Firefox, we always put UTF-8 as top position, after then put user
410 // recent selected encodings, then put local dependent encoding items.
411 // At last, we put all remaining encoding items.
412 const std::vector<CharacterEncoding::EncodingInfo>*
413     CharacterEncoding::GetCurrentDisplayEncodings(
414     const std::string& locale,
415     const std::string& locale_encodings,
416     const std::string& recently_select_encodings) {
417   std::vector<int>* const locale_dependent_encoding_list =
418       CanonicalEncodingMapSingleton()->locale_dependent_encoding_ids();
419   std::vector<CharacterEncoding::EncodingInfo>* const encoding_list =
420       CanonicalEncodingMapSingleton()->current_display_encodings();
421
422   // Initialize locale dependent static encoding list.
423   if (locale_dependent_encoding_list->empty() && !locale_encodings.empty())
424     ParseEncodingListSeparatedWithComma(locale_encodings,
425                                         locale_dependent_encoding_list,
426                                         kUserSelectedEncodingsMaxLength);
427
428   CR_DEFINE_STATIC_LOCAL(std::string, cached_user_selected_encodings, ());
429   // Build current display encoding list.
430   if (encoding_list->empty() ||
431       cached_user_selected_encodings != recently_select_encodings) {
432     // Update user recently selected encodings.
433     cached_user_selected_encodings = recently_select_encodings;
434     // Clear old encoding list since user recently selected encodings changed.
435     encoding_list->clear();
436     // Always add UTF-8 to first encoding position.
437     encoding_list->push_back(EncodingInfo(IDC_ENCODING_UTF8));
438     std::set<int> inserted_encoding;
439     inserted_encoding.insert(IDC_ENCODING_UTF8);
440
441     // Parse user recently selected encodings and get list
442     std::vector<int> recently_select_encoding_list;
443     ParseEncodingListSeparatedWithComma(recently_select_encodings,
444                                         &recently_select_encoding_list,
445                                         kUserSelectedEncodingsMaxLength);
446
447     // Put 'cached encodings' (dynamic encoding list) after 'local dependent
448     // encoding list'.
449     recently_select_encoding_list.insert(recently_select_encoding_list.begin(),
450         locale_dependent_encoding_list->begin(),
451         locale_dependent_encoding_list->end());
452     for (std::vector<int>::iterator it = recently_select_encoding_list.begin();
453          it != recently_select_encoding_list.end(); ++it) {
454         // Test whether we have met this encoding id.
455         bool ok = inserted_encoding.insert(*it).second;
456         // Duplicated encoding, ignore it. Ideally, this situation should not
457         // happened, but just in case some one manually edit preference file.
458         if (!ok)
459           continue;
460         encoding_list->push_back(EncodingInfo(*it));
461     }
462     // Append a separator;
463     encoding_list->push_back(EncodingInfo(0));
464
465     // We need to keep "Unicode (UTF-16LE)" always at the top (among the rest
466     // of encodings) instead of being sorted along with other encodings. So if
467     // "Unicode (UTF-16LE)" is already in previous encodings, sort the rest
468     // of encodings. Otherwise Put "Unicode (UTF-16LE)" on the first of the
469     // rest of encodings, skip "Unicode (UTF-16LE)" and sort all left encodings.
470     int start_sorted_index = encoding_list->size();
471     if (inserted_encoding.find(IDC_ENCODING_UTF16LE) ==
472         inserted_encoding.end()) {
473       encoding_list->push_back(EncodingInfo(IDC_ENCODING_UTF16LE));
474       inserted_encoding.insert(IDC_ENCODING_UTF16LE);
475       start_sorted_index++;
476     }
477
478     // Add the rest of encodings that are neither in the static encoding list
479     // nor in the list of recently selected encodings.
480     // Build the encoding list sorted in the current locale sorting order.
481     for (int i = 0; i < kDefaultEncodingMenusLength; ++i) {
482       int id = kDefaultEncodingMenus[i];
483       // We have inserted this encoding, skip it.
484       if (inserted_encoding.find(id) != inserted_encoding.end())
485         continue;
486       encoding_list->push_back(EncodingInfo(id));
487     }
488     // Sort the encoding list.
489     l10n_util::SortVectorWithStringKey(locale,
490                                        encoding_list,
491                                        start_sorted_index,
492                                        encoding_list->size(),
493                                        true);
494   }
495   DCHECK(!encoding_list->empty());
496   return encoding_list;
497 }
498
499 // Static
500 bool CharacterEncoding::UpdateRecentlySelectedEncoding(
501     const std::string& original_selected_encodings,
502     int new_selected_encoding_id,
503     std::string* selected_encodings) {
504   // Get encoding name.
505   std::string encoding_name =
506       GetCanonicalEncodingNameByCommandId(new_selected_encoding_id);
507   DCHECK(!encoding_name.empty());
508   // Check whether the new encoding is in local dependent encodings or original
509   // recently selected encodings. If yes, do not add it.
510   std::vector<int>* locale_dependent_encoding_list =
511       CanonicalEncodingMapSingleton()->locale_dependent_encoding_ids();
512   DCHECK(locale_dependent_encoding_list);
513   std::vector<int> selected_encoding_list;
514   ParseEncodingListSeparatedWithComma(original_selected_encodings,
515                                       &selected_encoding_list,
516                                       kUserSelectedEncodingsMaxLength);
517   // Put 'cached encodings' (dynamic encoding list) after 'local dependent
518   // encoding list' for check.
519   std::vector<int> top_encoding_list(*locale_dependent_encoding_list);
520   // UTF8 is always in our optimized encoding list.
521   top_encoding_list.insert(top_encoding_list.begin(), IDC_ENCODING_UTF8);
522   top_encoding_list.insert(top_encoding_list.end(),
523                            selected_encoding_list.begin(),
524                            selected_encoding_list.end());
525   for (std::vector<int>::const_iterator it = top_encoding_list.begin();
526        it != top_encoding_list.end(); ++it)
527     if (*it == new_selected_encoding_id)
528       return false;
529   // Need to add the encoding id to recently selected encoding list.
530   // Remove the last encoding in original list.
531   if (selected_encoding_list.size() == kUserSelectedEncodingsMaxLength)
532     selected_encoding_list.pop_back();
533   // Insert new encoding to head of selected encoding list.
534   *selected_encodings = encoding_name;
535   // Generate the string for rest selected encoding list.
536   for (std::vector<int>::const_iterator it = selected_encoding_list.begin();
537        it != selected_encoding_list.end(); ++it) {
538     selected_encodings->append(1, L',');
539     selected_encodings->append(GetCanonicalEncodingNameByCommandId(*it));
540   }
541   return true;
542 }