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

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

Powered by Google App Engine
This is Rietveld 408576698