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