Prepare Chromium and Blink for ICU 59

ICU 59 uses char16_t as UChar instead of {wchar_t, uint16_t}.
As a result, char16_t is not compatible with char16 any more.
When constructing string16 from UnicodeString/UChar buffer, we need to
reinterpret_cast with a barrier (to avoid an anti-aliasing optimzation
by some compilers).

Add UnicodeStringToString16() to base/i18n that utilizes ICU 59-to-be's
helper for the casting regardless of anti-aliasing optimization.

And, refactor UnicodeString->string16->UTF8 string to UnicodeString->UTF8
in a few places.

For ICU C API "clients", UChar will be configured to be {wchar_t, uint16_t}
so that there's little to be changed.

This was tested with an ICU branch with char16_t as UChar.

http://source.icu-project.org/repos/icu/branches/markus/ucharptr2/

BUG=693640
TEST=trybots are all green.

Review-Url: https://codereview.chromium.org/2740673002
Cr-Commit-Position: refs/heads/master@{#459034}
diff --git a/ash/common/system/date/date_view.cc b/ash/common/system/date/date_view.cc
index 6a09517..3cbd0bd 100644
--- a/ash/common/system/date/date_view.cc
+++ b/ash/common/system/date/date_view.cc
@@ -57,43 +57,19 @@
   return MaterialDesignController::IsSystemTrayMenuMaterial();
 }
 
-base::string16 FormatDateWithPattern(const base::Time& time,
-                                     const char* pattern) {
-  UErrorCode status = U_ZERO_ERROR;
-  std::unique_ptr<icu::DateTimePatternGenerator> generator(
-      icu::DateTimePatternGenerator::createInstance(status));
-  DCHECK(U_SUCCESS(status));
-  icu::UnicodeString generated_pattern =
-      generator->getBestPattern(icu::UnicodeString(pattern), status);
-  DCHECK(U_SUCCESS(status));
-  icu::SimpleDateFormat simple_formatter(generated_pattern, status);
-  DCHECK(U_SUCCESS(status));
-  icu::UnicodeString date_string;
-  simple_formatter.format(static_cast<UDate>(time.ToDoubleT() * 1000),
-                          date_string, status);
-  DCHECK(U_SUCCESS(status));
-  return base::string16(date_string.getBuffer(),
-                        static_cast<size_t>(date_string.length()));
-}
-
 base::string16 FormatDate(const base::Time& time) {
   if (UseMd()) {
     // Use 'short' month format (e.g., "Oct") followed by non-padded day of
     // month (e.g., "2", "10").
-    return FormatDateWithPattern(time, "LLLd");
+    return base::TimeFormatWithPattern(time, "LLLd");
   } else {
-    icu::UnicodeString date_string;
-    std::unique_ptr<icu::DateFormat> formatter(
-        icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
-    formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
-    return base::string16(date_string.getBuffer(),
-                          static_cast<size_t>(date_string.length()));
+    return base::TimeFormatShortDate(time);
   }
 }
 
 base::string16 FormatDayOfWeek(const base::Time& time) {
   // Use 'short' day of week format (e.g., "Wed").
-  return FormatDateWithPattern(time, "EEE");
+  return base::TimeFormatWithPattern(time, "EEE");
 }
 
 }  // namespace
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 9d2afd8..c367a61 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1702,6 +1702,7 @@
     "i18n/time_formatting.h",
     "i18n/timezone.cc",
     "i18n/timezone.h",
+    "i18n/unicodestring.h",
     "i18n/utf8_validator_tables.cc",
     "i18n/utf8_validator_tables.h",
   ]
diff --git a/base/i18n/message_formatter.cc b/base/i18n/message_formatter.cc
index 702e51b..6962a28 100644
--- a/base/i18n/message_formatter.cc
+++ b/base/i18n/message_formatter.cc
@@ -4,6 +4,7 @@
 
 #include "base/i18n/message_formatter.h"
 
+#include "base/i18n/unicodestring.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/time/time.h"
@@ -91,7 +92,7 @@
                << u_errorName(error);
     return string16();
   }
-  return string16(formatted.getBuffer(), formatted.length());
+  return i18n::UnicodeStringToString16(formatted);
 }
 
 string16 MessageFormatter::FormatWithNamedArgs(
@@ -134,7 +135,7 @@
                << u_errorName(error);
     return string16();
   }
-  return string16(formatted.getBuffer(), formatted.length());
+  return i18n::UnicodeStringToString16(formatted);
 }
 
 }  // namespace i18n
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
index 0365f2c..0ab031ec 100644
--- a/base/i18n/number_formatting.cc
+++ b/base/i18n/number_formatting.cc
@@ -10,6 +10,7 @@
 
 #include "base/format_macros.h"
 #include "base/i18n/message_formatter.h"
+#include "base/i18n/unicodestring.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
@@ -60,7 +61,7 @@
   icu::UnicodeString ustr;
   number_format->format(number, ustr);
 
-  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+  return i18n::UnicodeStringToString16(ustr);
 }
 
 string16 FormatDouble(double number, int fractional_digits) {
@@ -76,7 +77,7 @@
   icu::UnicodeString ustr;
   number_format->format(number, ustr);
 
-  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+  return i18n::UnicodeStringToString16(ustr);
 }
 
 string16 FormatPercent(int number) {
diff --git a/base/i18n/string_compare.cc b/base/i18n/string_compare.cc
index 2851e7d..649c281 100644
--- a/base/i18n/string_compare.cc
+++ b/base/i18n/string_compare.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
 
 namespace base {
 namespace i18n {
@@ -17,8 +18,8 @@
                                              const string16& rhs) {
   UErrorCode error = U_ZERO_ERROR;
   UCollationResult result = collator.compare(
-      static_cast<const UChar*>(lhs.c_str()), static_cast<int>(lhs.length()),
-      static_cast<const UChar*>(rhs.c_str()), static_cast<int>(rhs.length()),
+      icu::UnicodeString(FALSE, lhs.c_str(), static_cast<int>(lhs.length())),
+      icu::UnicodeString(FALSE, rhs.c_str(), static_cast<int>(rhs.length())),
       error);
   DCHECK(U_SUCCESS(error));
   return result;
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 4755bdd..3a5394a 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/i18n/unicodestring.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -28,8 +29,7 @@
   icu::UnicodeString date_string;
 
   formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
-  return string16(date_string.getBuffer(),
-                  static_cast<size_t>(date_string.length()));
+  return i18n::UnicodeStringToString16(date_string);
 }
 
 string16 TimeFormatWithoutAmPm(const icu::DateFormat* formatter,
@@ -48,8 +48,7 @@
       begin--;
     time_string.removeBetween(begin, ampm_field.getEndIndex());
   }
-  return string16(time_string.getBuffer(),
-                  static_cast<size_t>(time_string.length()));
+  return i18n::UnicodeStringToString16(time_string);
 }
 
 icu::SimpleDateFormat CreateSimpleDateFormatter(const char* pattern) {
@@ -214,7 +213,7 @@
     return false;
   }
 
-  *out = base::string16(formatted.getBuffer(), formatted.length());
+  *out = i18n::UnicodeStringToString16(formatted);
   return true;
 }
 
@@ -237,7 +236,7 @@
   icu::UnicodeString formatted;
   icu::FieldPosition ignore(icu::FieldPosition::DONT_CARE);
   measure_format.formatMeasures(measures, 3, formatted, ignore, status);
-  *out = base::string16(formatted.getBuffer(), formatted.length());
+  *out = i18n::UnicodeStringToString16(formatted);
   return U_SUCCESS(status) == TRUE;
 }
 
@@ -256,8 +255,7 @@
   icu::DateInterval interval(start_date, end_date);
   icu::UnicodeString formatted;
   formatter->format(&interval, formatted, pos, status);
-  return string16(formatted.getBuffer(),
-                  static_cast<size_t>(formatted.length()));
+  return i18n::UnicodeStringToString16(formatted);
 }
 
 HourClockType GetHourClockType() {
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
index aa6fe6e..98b6a20 100644
--- a/base/i18n/time_formatting_unittest.cc
+++ b/base/i18n/time_formatting_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/i18n/rtl.h"
+#include "base/i18n/unicodestring.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
 #include "base/time/time.h"
@@ -37,7 +38,7 @@
   zone_formatter->format(UTZFMT_STYLE_SPECIFIC_SHORT, *zone,
                          static_cast<UDate>(time.ToDoubleT() * 1000),
                          name, nullptr);
-  return string16(name.getBuffer(), name.length());
+  return i18n::UnicodeStringToString16(name);
 }
 
 // Calls TimeDurationFormat() with |delta| and |width| and returns the resulting
diff --git a/base/i18n/timezone.cc b/base/i18n/timezone.cc
index e881c9d..95e7aee 100644
--- a/base/i18n/timezone.cc
+++ b/base/i18n/timezone.cc
@@ -610,9 +610,9 @@
   std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
   icu::UnicodeString id;
   zone->getID(id);
-  string16 olson_code(id.getBuffer(), id.length());
+  std::string olson_code;
   return TimezoneMap::GetInstance()->CountryCodeForTimezone(
-      UTF16ToUTF8(olson_code));
+      id.toUTF8String(olson_code));
 }
 
 }  // namespace base
diff --git a/base/i18n/unicodestring.h b/base/i18n/unicodestring.h
new file mode 100644
index 0000000..b62c526
--- /dev/null
+++ b/base/i18n/unicodestring.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_UNICODESTRING_H_
+#define BASE_I18N_UNICODESTRING_H_
+
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/common/unicode/uvernum.h"
+
+#if U_ICU_VERSION_MAJOR_NUM >= 59
+#include "third_party/icu/source/common/unicode/char16ptr.h"
+#endif
+
+namespace base {
+namespace i18n {
+
+inline string16 UnicodeStringToString16(const icu::UnicodeString& unistr) {
+#if U_ICU_VERSION_MAJOR_NUM >= 59
+  return base::string16(icu::toUCharPtr(unistr.getBuffer()),
+                        static_cast<size_t>(unistr.length()));
+#else
+  return base::string16(unistr.getBuffer(),
+                        static_cast<size_t>(unistr.length()));
+#endif
+}
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_UNICODESTRING_H_
diff --git a/chrome/browser/chromeos/system/timezone_util.cc b/chrome/browser/chromeos/system/timezone_util.cc
index 6c41a05..d01f60e 100644
--- a/chrome/browser/chromeos/system/timezone_util.cc
+++ b/chrome/browser/chromeos/system/timezone_util.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/i18n/rtl.h"
+#include "base/i18n/unicodestring.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
@@ -77,7 +78,7 @@
   if (!U_FAILURE(status)) {
     city = icu::ures_getUnicodeStringByKey(zone_item.get(), "ec", &status);
     if (U_SUCCESS(status))
-      return base::string16(city.getBuffer(), city.length());
+      return base::i18n::UnicodeStringToString16(city);
   }
 
   // Fallback case in case of failure.
@@ -135,8 +136,7 @@
   }
   base::string16 result(l10n_util::GetStringFUTF16(
       IDS_OPTIONS_SETTINGS_TIMEZONE_DISPLAY_TEMPLATE,
-      base::ASCIIToUTF16(offset_str),
-      base::string16(name.getBuffer(), name.length()),
+      base::ASCIIToUTF16(offset_str), base::i18n::UnicodeStringToString16(name),
       GetExemplarCity(timezone)));
   base::i18n::AdjustStringForLocaleDirection(&result);
   return result;
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
index f9ea586..b85f153 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/i18n/rtl.h"
+#include "base/i18n/unicodestring.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
@@ -74,8 +75,7 @@
       icu::DateFormat::createDateInstance(icu::DateFormat::kLong));
   icu::UnicodeString date_string;
   formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
-  return base::string16(date_string.getBuffer(),
-                        static_cast<size_t>(date_string.length()));
+  return base::i18n::UnicodeStringToString16(date_string);
 }
 
 }  // namespace
diff --git a/chromeos/settings/timezone_settings.cc b/chromeos/settings/timezone_settings.cc
index 496e887..9c3a371 100644
--- a/chromeos/settings/timezone_settings.cc
+++ b/chromeos/settings/timezone_settings.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/i18n/unicodestring.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -483,8 +484,7 @@
 // static
 base::string16 TimezoneSettings::GetTimezoneID(const icu::TimeZone& timezone) {
   icu::UnicodeString id;
-  timezone.getID(id);
-  return base::string16(id.getBuffer(), id.length());
+  return base::i18n::UnicodeStringToString16(timezone.getID(id));
 }
 
 }  // namespace system
diff --git a/components/autofill/core/browser/autofill_profile_comparator.cc b/components/autofill/core/browser/autofill_profile_comparator.cc
index c3e8709..fd103d3 100644
--- a/components/autofill/core/browser/autofill_profile_comparator.cc
+++ b/components/autofill/core/browser/autofill_profile_comparator.cc
@@ -9,6 +9,7 @@
 
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/char_iterator.h"
+#include "base/i18n/unicodestring.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -128,7 +129,7 @@
 
   icu::UnicodeString value = icu::UnicodeString(result.data(), result.length());
   transliterator_->transliterate(value);
-  return base::string16(value.getBuffer(), value.length());
+  return base::i18n::UnicodeStringToString16(value);
 }
 
 bool AutofillProfileComparator::AreMergeable(const AutofillProfile& p1,
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index bd5110e..0e54c44 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -13,6 +13,7 @@
 
 #include "base/guid.h"
 #include "base/i18n/time_formatting.h"
+#include "base/i18n/unicodestring.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -870,7 +871,8 @@
   int32_t num_months;
   const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
   for (int32_t i = 0; i < num_months; ++i) {
-    const base::string16 icu_month(months[i].getBuffer(), months[i].length());
+    const base::string16 icu_month(
+        base::i18n::UnicodeStringToString16(months[i]));
     if (compare.StringsEqual(icu_month, month)) {
       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
       return true;
@@ -883,7 +885,7 @@
   base::string16 trimmed_month;
   base::TrimString(month, ASCIIToUTF16("."), &trimmed_month);
   for (int32_t i = 0; i < num_months; ++i) {
-    base::string16 icu_month(months[i].getBuffer(), months[i].length());
+    base::string16 icu_month(base::i18n::UnicodeStringToString16(months[i]));
     base::TrimString(icu_month, ASCIIToUTF16("."), &icu_month);
     if (compare.StringsEqual(icu_month, trimmed_month)) {
       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
diff --git a/components/bookmarks/browser/titled_url_index.cc b/components/bookmarks/browser/titled_url_index.cc
index abde1aa..fa9ed76 100644
--- a/components/bookmarks/browser/titled_url_index.cc
+++ b/components/bookmarks/browser/titled_url_index.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/i18n/case_conversion.h"
+#include "base/i18n/unicodestring.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_offset_string_conversions.h"
@@ -42,8 +43,7 @@
     LOG(ERROR) << "normalization failed: " << u_errorName(status);
     return text;
   }
-  return base::string16(unicode_normalized_text.getBuffer(),
-                        unicode_normalized_text.length());
+  return base::i18n::UnicodeStringToString16(unicode_normalized_text);
 }
 
 }  // namespace
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc
index ba20ad5..28b6d03 100644
--- a/content/browser/android/date_time_chooser_android.cc
+++ b/content/browser/android/date_time_chooser_android.cc
@@ -9,6 +9,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/i18n/char_iterator.h"
+#include "base/i18n/unicodestring.h"
 #include "content/common/date_time_suggestion.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/render_view_host.h"
@@ -36,8 +37,7 @@
       sanitized.append(c);
     sanitized_iterator.Advance();
   }
-  return base::string16(sanitized.getBuffer(),
-                        static_cast<size_t>(sanitized.length()));
+  return base::i18n::UnicodeStringToString16(sanitized);
 }
 
 }  // namespace
diff --git a/content/renderer/android/email_detector.cc b/content/renderer/android/email_detector.cc
index 564f341..1a0db8b 100644
--- a/content/renderer/android/email_detector.cc
+++ b/content/renderer/android/email_detector.cc
@@ -62,8 +62,8 @@
     DCHECK(U_SUCCESS(status));
     icu::UnicodeString content_ustr(matcher->group(status));
     DCHECK(U_SUCCESS(status));
-    base::UTF16ToUTF8(content_ustr.getBuffer(), content_ustr.length(),
-        content_text);
+    content_text->clear();
+    content_ustr.toUTF8String(*content_text);
     return true;
   }
 
diff --git a/ios/chrome/browser/notification_promo_unittest.cc b/ios/chrome/browser/notification_promo_unittest.cc
index 830d9c5..d5356e8 100644
--- a/ios/chrome/browser/notification_promo_unittest.cc
+++ b/ios/chrome/browser/notification_promo_unittest.cc
@@ -34,18 +34,14 @@
   UErrorCode status = U_ZERO_ERROR;
   icu::SimpleDateFormat simple_formatter(icu::UnicodeString(kDateFormat),
                                          icu::Locale("en_US"), status);
-  if (!U_SUCCESS(status))
-    return false;
-
   icu::UnicodeString date_unicode_string;
   simple_formatter.format(static_cast<UDate>(*date_epoch * 1000),
                           date_unicode_string, status);
-  if (!U_SUCCESS(status))
+  if (U_FAILURE(status))
     return false;
 
-  return base::UTF16ToUTF8(date_unicode_string.getBuffer(),
-                           static_cast<size_t>(date_unicode_string.length()),
-                           date_string);
+  date_unicode_string.toUTF8String(*date_string);
+  return true;
 }
 
 }  // namespace
diff --git a/net/ftp/ftp_util.cc b/net/ftp/ftp_util.cc
index a668453..4af3603 100644
--- a/net/ftp/ftp_util.cc
+++ b/net/ftp/ftp_util.cc
@@ -9,6 +9,7 @@
 
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/char_iterator.h"
+#include "base/i18n/unicodestring.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
@@ -175,8 +176,8 @@
           format_symbols.getShortMonths(months_count);
 
       for (int32_t month = 0; month < months_count; month++) {
-        base::string16 month_name(months[month].getBuffer(),
-                            static_cast<size_t>(months[month].length()));
+        base::string16 month_name(
+            base::i18n::UnicodeStringToString16(months[month]));
 
         // Ignore the case of the month names. The simplest way to handle that
         // is to make everything lowercase.
diff --git a/third_party/WebKit/Source/core/html/forms/EmailInputType.cpp b/third_party/WebKit/Source/core/html/forms/EmailInputType.cpp
index 755ae39..52be833 100644
--- a/third_party/WebKit/Source/core/html/forms/EmailInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/EmailInputType.cpp
@@ -23,6 +23,9 @@
 
 #include "core/html/forms/EmailInputType.h"
 
+#include <unicode/idna.h>
+#include <unicode/unistr.h>
+#include <unicode/uvernum.h>
 #include "bindings/core/v8/ScriptRegexp.h"
 #include "core/InputTypeNames.h"
 #include "core/html/HTMLInputElement.h"
@@ -31,8 +34,10 @@
 #include "platform/text/PlatformLocale.h"
 #include "public/platform/Platform.h"
 #include "wtf/text/StringBuilder.h"
-#include <unicode/idna.h>
-#include <unicode/unistr.h>
+
+#if U_ICU_VERSION_MAJOR_NUM >= 59
+#include <unicode/char16ptr.h>
+#endif
 
 namespace blink {
 
@@ -87,7 +92,11 @@
 
   StringBuilder builder;
   builder.append(address, 0, atPosition + 1);
+#if U_ICU_VERSION_MAJOR_NUM >= 59
+  builder.append(icu::toUCharPtr(domainName.getBuffer()), domainName.length());
+#else
   builder.append(domainName.getBuffer(), domainName.length());
+#endif
   String asciiEmail = builder.toString();
   return isValidEmailAddress(regexp, asciiEmail) ? asciiEmail : address;
 }