Home | History | Annotate | Download | only in browser
      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 }
    543