Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: chrome/browser/autofill/phone_number_i18n.cc

Issue 7044102: Another performance improvement for phone library - at least +25% to previous cl (982ms for 100 i... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autofill/phone_number_i18n.h" 5 #include "chrome/browser/autofill/phone_number_i18n.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/stringprintf.h" 9 #include "base/stringprintf.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
(...skipping 20 matching lines...) Expand all
31 case autofill_i18n::NATIONAL: 31 case autofill_i18n::NATIONAL:
32 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 32 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
33 case autofill_i18n::RFC3966: 33 case autofill_i18n::RFC3966:
34 return i18n::phonenumbers::PhoneNumberUtil::RFC3966; 34 return i18n::phonenumbers::PhoneNumberUtil::RFC3966;
35 default: 35 default:
36 NOTREACHED(); 36 NOTREACHED();
37 } 37 }
38 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 38 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
39 } 39 }
40 40
41 } // namespace 41 bool ParsePhoneNumberInternal(const string16& value,
42 42 const std::string& locale,
43 namespace autofill_i18n { 43 string16* country_code,
44 44 string16* city_code,
45 string16 NormalizePhoneNumber(const string16& value, 45 string16* number,
46 std::string const& locale) { 46 i18n::phonenumbers::PhoneNumber* i18n_number) {
47 string16 number;
48 string16 city_code;
49 string16 country_code;
50 string16 result;
51 // Full number - parse it, split it and re-combine into canonical form.
52 if (!ParsePhoneNumber(value, locale, &country_code, &city_code, &number))
53 return string16(); // Parsing failed - do not store phone.
54 if (!autofill_i18n::ConstructPhoneNumber(
55 country_code, city_code, number,
56 locale,
57 (country_code.empty() ?
58 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
59 &result)) {
60 // Reconstruction failed - do not store phone.
61 return string16();
62 }
63 std::string result_utf8(UTF16ToUTF8(result));
64 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&result_utf8);
65 return UTF8ToUTF16(result_utf8);
66 }
67
68 bool ParsePhoneNumber(const string16& value,
69 const std::string& locale,
70 string16* country_code,
71 string16* city_code,
72 string16* number) {
73 DCHECK(number); 47 DCHECK(number);
74 DCHECK(city_code); 48 DCHECK(city_code);
75 DCHECK(country_code); 49 DCHECK(country_code);
50 DCHECK(i18n_number);
76 51
77 number->clear(); 52 number->clear();
78 city_code->clear(); 53 city_code->clear();
79 country_code->clear(); 54 country_code->clear();
80 55
81 std::string number_text(UTF16ToUTF8(value)); 56 std::string number_text(UTF16ToUTF8(value));
82 57
83 // Parse phone number based on the locale. 58 // Parse phone number based on the locale.
84 i18n::phonenumbers::PhoneNumber i18n_number;
85 i18n::phonenumbers::PhoneNumberUtil* phone_util = 59 i18n::phonenumbers::PhoneNumberUtil* phone_util =
86 i18n::phonenumbers::PhoneNumberUtil::GetInstance(); 60 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
87 DCHECK(phone_util); 61 DCHECK(phone_util);
88 62
89 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(), 63 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(),
90 &i18n_number) != 64 i18n_number) !=
91 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) { 65 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) {
92 return false; 66 return false;
93 } 67 }
94 68
95 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation = 69 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation =
96 phone_util->IsPossibleNumberWithReason(i18n_number); 70 phone_util->IsPossibleNumberWithReason(*i18n_number);
97 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE) 71 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE)
98 return false; 72 return false;
99 73
100 // This verifies that number has a valid area code (that in some cases could 74 // This verifies that number has a valid area code (that in some cases could
101 // be empty) for parsed country code. Also verifies that this is a valid 75 // be empty) for parsed country code. Also verifies that this is a valid
102 // number (in US 1234567 is not valid, because numbers do not start with 1). 76 // number (in US 1234567 is not valid, because numbers do not start with 1).
103 if (!phone_util->IsValidNumber(i18n_number)) 77 if (!phone_util->IsValidNumber(*i18n_number))
104 return false; 78 return false;
105 79
106 std::string national_significant_number; 80 std::string national_significant_number;
107 phone_util->GetNationalSignificantNumber(i18n_number, 81 phone_util->GetNationalSignificantNumber(*i18n_number,
108 &national_significant_number); 82 &national_significant_number);
109 83
110 std::string area_code; 84 std::string area_code;
111 std::string subscriber_number; 85 std::string subscriber_number;
112 86
113 int area_length = phone_util->GetLengthOfGeographicalAreaCode(i18n_number); 87 int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
114 int destination_length = 88 int destination_length =
115 phone_util->GetLengthOfNationalDestinationCode(i18n_number); 89 phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
116 // Some phones have a destination code in lieu of area code: mobile operators 90 // Some phones have a destination code in lieu of area code: mobile operators
117 // in Europe, toll and toll-free numbers in USA, etc. From our point of view 91 // in Europe, toll and toll-free numbers in USA, etc. From our point of view
118 // these two types of codes are the same. 92 // these two types of codes are the same.
119 if (destination_length > area_length) 93 if (destination_length > area_length)
120 area_length = destination_length; 94 area_length = destination_length;
121 if (area_length > 0) { 95 if (area_length > 0) {
122 area_code = national_significant_number.substr(0, area_length); 96 area_code = national_significant_number.substr(0, area_length);
123 subscriber_number = national_significant_number.substr(area_length); 97 subscriber_number = national_significant_number.substr(area_length);
124 } else { 98 } else {
125 subscriber_number = national_significant_number; 99 subscriber_number = national_significant_number;
126 } 100 }
127 *number = UTF8ToUTF16(subscriber_number); 101 *number = UTF8ToUTF16(subscriber_number);
128 *city_code = UTF8ToUTF16(area_code); 102 *city_code = UTF8ToUTF16(area_code);
129 *country_code = string16(); 103 *country_code = string16();
130 104
131 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text); 105 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text);
132 string16 normalized_number(UTF8ToUTF16(number_text)); 106 string16 normalized_number(UTF8ToUTF16(number_text));
133 // Check if parsed number has country code and it was not inferred from the 107 // Check if parsed number has country code and it was not inferred from the
134 // locale. 108 // locale.
135 if (i18n_number.has_country_code()) { 109 if (i18n_number->has_country_code()) {
136 *country_code = UTF8ToUTF16(base::StringPrintf("%d", 110 *country_code = UTF8ToUTF16(
137 i18n_number.country_code())); 111 base::StringPrintf("%d", i18n_number->country_code()));
138 if (normalized_number.length() <= national_significant_number.length() && 112 if (normalized_number.length() <= national_significant_number.length() &&
139 (normalized_number.length() < country_code->length() || 113 (normalized_number.length() < country_code->length() ||
140 normalized_number.compare(0, country_code->length(), *country_code))) { 114 normalized_number.compare(0, country_code->length(), *country_code))) {
141 country_code->clear(); 115 country_code->clear();
142 } 116 }
143 } 117 }
144 118
145 return true; 119 return true;
146 } 120 }
147 121
122 } // namespace
123
124 namespace autofill_i18n {
125
126 string16 NormalizePhoneNumber(const string16& value,
127 std::string const& locale) {
128 string16 number;
129 string16 city_code;
130 string16 country_code;
131 string16 result;
132 // Full number - parse it, split it and re-combine into canonical form.
133 if (!ParsePhoneNumber(value, locale, &country_code, &city_code, &number))
134 return string16(); // Parsing failed - do not store phone.
135 if (!autofill_i18n::ConstructPhoneNumber(
136 country_code, city_code, number,
137 locale,
138 (country_code.empty() ?
139 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
140 &result)) {
141 // Reconstruction failed - do not store phone.
142 return string16();
143 }
144 std::string result_utf8(UTF16ToUTF8(result));
145 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&result_utf8);
146 return UTF8ToUTF16(result_utf8);
147 }
148
149 bool ParsePhoneNumber(const string16& value,
150 const std::string& locale,
151 string16* country_code,
152 string16* city_code,
153 string16* number) {
154 i18n::phonenumbers::PhoneNumber i18n_number;
155 return ParsePhoneNumberInternal(value, locale, country_code, city_code,
156 number, &i18n_number);
157 }
158
148 bool ConstructPhoneNumber(const string16& country_code, 159 bool ConstructPhoneNumber(const string16& country_code,
149 const string16& city_code, 160 const string16& city_code,
150 const string16& number, 161 const string16& number,
151 const std::string& locale, 162 const std::string& locale,
152 FullPhoneFormat phone_format, 163 FullPhoneFormat phone_format,
153 string16* whole_number) { 164 string16* whole_number) {
154 DCHECK(whole_number); 165 DCHECK(whole_number);
155 166
156 whole_number->clear(); 167 whole_number->clear();
157 168
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 } 269 }
259 return PHONES_NOT_EQUAL; 270 return PHONES_NOT_EQUAL;
260 } 271 }
261 272
262 bool PhoneNumbersMatch(const string16& number_a, 273 bool PhoneNumbersMatch(const string16& number_a,
263 const string16& number_b, 274 const string16& number_b,
264 const std::string& country_code) { 275 const std::string& country_code) {
265 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL; 276 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL;
266 } 277 }
267 278
279 PhoneObject::PhoneObject(const string16& number, const std::string& locale)
280 : locale_(SanitizeLocaleCode(locale)),
281 i18n_number_(NULL) {
282 scoped_ptr<i18n::phonenumbers::PhoneNumber>
283 i18n_number(new i18n::phonenumbers::PhoneNumber);
284 if (ParsePhoneNumberInternal(number, locale_, &country_code_, &city_code_,
285 &number_, i18n_number.get())) {
286 // Phone successfully parsed - set |i18n_number_| object, |whole_number_|
287 // will be set on the first call to GetWholeNumber().
288 i18n_number_.reset(i18n_number.release());
289 } else {
290 // Parsing failed. Store passed phone "as is" into |whole_number_|.
291 whole_number_ = number;
292 }
293 }
294
295 PhoneObject::PhoneObject(const PhoneObject& other)
296 : i18n_number_(NULL) {
297 *this = other;
298 }
299
300 PhoneObject::PhoneObject()
301 : i18n_number_(NULL) {
302 }
303
304 PhoneObject::~PhoneObject() {
305 }
306
307 string16 PhoneObject::GetCountryCode() const {
308 return country_code_;
309 }
310
311 string16 PhoneObject::GetCityCode() const {
312 return city_code_;
313 }
314
315 string16 PhoneObject::GetNumber() const {
316 return number_;
317 }
318
319 string16 PhoneObject::GetWholeNumber() const {
320 if (i18n_number_.get() && whole_number_.empty()) {
321 i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat format =
322 i18n::phonenumbers::PhoneNumberUtil::INTERNATIONAL;
323 if (country_code_.empty())
324 format = i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
325
326 std::string formatted_number;
327 i18n::phonenumbers::PhoneNumberUtil* phone_util =
328 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
329 phone_util->Format(*i18n_number_, format, &formatted_number);
330 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&formatted_number);
331 whole_number_ = UTF8ToUTF16(formatted_number);
332 }
333 return whole_number_;
334 }
335
336 PhoneMatch PhoneObject::ComparePhones(const string16& phone_number) const {
337 PhoneObject phone(phone_number, locale_);
338 if (!i18n_number_.get() || !phone.i18n_number_.get()) {
339 if (GetWholeNumber().empty())
340 return PHONES_NOT_EQUAL;
341 return (GetWholeNumber() == phone.GetWholeNumber()) ? PHONES_EQUAL :
342 PHONES_NOT_EQUAL;
343 }
344
345 i18n::phonenumbers::PhoneNumberUtil* phone_util =
346 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
347 switch (phone_util->IsNumberMatch(*i18n_number_, *(phone.i18n_number_))) {
348 case i18n::phonenumbers::PhoneNumberUtil::INVALID_NUMBER:
349 case i18n::phonenumbers::PhoneNumberUtil::NO_MATCH:
350 return PHONES_NOT_EQUAL;
351 case i18n::phonenumbers::PhoneNumberUtil::SHORT_NSN_MATCH:
352 return PHONES_SUBMATCH;
353 case i18n::phonenumbers::PhoneNumberUtil::NSN_MATCH:
354 case i18n::phonenumbers::PhoneNumberUtil::EXACT_MATCH:
355 return PHONES_EQUAL;
356 default:
357 NOTREACHED();
358 }
359 return PHONES_NOT_EQUAL;
360 }
361
362 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
363 if (this == &other)
364 return *this;
365 country_code_ = other.country_code_;
366 city_code_ = other.city_code_;
367 number_ = other.number_;
368 locale_ = other.locale_;
369 if (other.i18n_number_.get()) {
370 i18n_number_.reset(new i18n::phonenumbers::PhoneNumber(
371 *other.i18n_number_));
372 }
373 return *this;
374 }
375
268 } // namespace autofill_i18n 376 } // namespace autofill_i18n
269 377
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698