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

Side by Side Diff: content/renderer/date_time_formatter.cc

Issue 23623019: Support datalist for date/time input types on Android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Used double to transfer value Created 7 years, 2 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
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "content/renderer/date_time_formatter.h" 5 #include "content/renderer/date_time_formatter.h"
6 6
7 #include "base/strings/string_util.h" 7 #include "base/strings/string_util.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "third_party/WebKit/public/platform/WebCString.h" 9 #include "third_party/WebKit/public/platform/WebCString.h"
10 #include "third_party/WebKit/public/web/WebDateTimeChooserParams.h" 10 #include "third_party/WebKit/public/web/WebDateTimeChooserParams.h"
(...skipping 10 matching lines...) Expand all
21 patterns_[i] = ""; 21 patterns_[i] = "";
22 } 22 }
23 patterns_[ui::TEXT_INPUT_TYPE_DATE] = "yyyy-MM-dd"; 23 patterns_[ui::TEXT_INPUT_TYPE_DATE] = "yyyy-MM-dd";
24 patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME] = "yyyy-MM-dd'T'HH:mm'Z'"; 24 patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME] = "yyyy-MM-dd'T'HH:mm'Z'";
25 patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL] = "yyyy-MM-dd'T'HH:mm"; 25 patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL] = "yyyy-MM-dd'T'HH:mm";
26 patterns_[ui::TEXT_INPUT_TYPE_MONTH] = "yyyy-MM"; 26 patterns_[ui::TEXT_INPUT_TYPE_MONTH] = "yyyy-MM";
27 patterns_[ui::TEXT_INPUT_TYPE_TIME] = "HH:mm"; 27 patterns_[ui::TEXT_INPUT_TYPE_TIME] = "HH:mm";
28 patterns_[ui::TEXT_INPUT_TYPE_WEEK] = "Y-'W'ww"; 28 patterns_[ui::TEXT_INPUT_TYPE_WEEK] = "Y-'W'ww";
29 } 29 }
30 30
31 // Returns true if icu_value parses as a valid for the specified date/time
32 // pattern. The date/time pattern given is for icu::SimpleDateFormat.
33 static bool TryPattern(const char* pattern,
34 const icu::UnicodeString& icu_value) {
35 icu::UnicodeString time_pattern = pattern;
36 UErrorCode success = U_ZERO_ERROR;
37 icu::SimpleDateFormat formatter(time_pattern, success);
38 formatter.parse(icu_value, success);
39 return success == U_ZERO_ERROR;
40 }
41
42 // For a time value represented as a string find the longest time
43 // pattern which matches it. A valid time can have hours and minutes
44 // or hours, minutes and seconds or hour, minutes, seconds and upto 3
45 // digits of fractional seconds. Specify step in milliseconds, it is 1000
46 // times the value specified as "step" in the "<input type=time step=...>
47 // HTML fragment. A value of 60000 or more indicates that seconds
48 // are not expected and a value of 1000 or more indicates that fractional
49 // seconds are not expected.
50 static const char* FindLongestTimePatternWhichMatches(const std::string& value,
51 double step) {
52 const char* pattern = "HH:mm";
53 if (step >= 60000)
54 return pattern;
55
56 icu::UnicodeString icu_value = icu::UnicodeString::fromUTF8(
57 icu::StringPiece(value.data(), value.size()));
58 const char* last_pattern = pattern;
59 pattern = "HH:mm:ss";
60 if (!TryPattern(pattern, icu_value))
61 return last_pattern;
62 if (step >= 1000)
63 return pattern;
64 last_pattern = pattern;
65 pattern = "HH:mm:ss.S";
66 if (!TryPattern(pattern, icu_value))
67 return last_pattern;
68 last_pattern = pattern;
69 pattern = "HH:mm:ss.SS";
70 if (!TryPattern(pattern, icu_value))
71 return last_pattern;
72 last_pattern = pattern;
73 pattern = "HH:mm:ss.SSS";
74 if (!TryPattern(pattern, icu_value))
75 return last_pattern;
76 return pattern;
77 }
78
79 DateTimeFormatter::DateTimeFormatter(
80 const WebKit::WebDateTimeChooserParams& source)
81 : formatted_string_(source.currentValue.utf8()) {
82 CreatePatternMap();
83 if (source.type == WebKit::WebDateTimeInputTypeTime)
84 time_pattern_ =
85 FindLongestTimePatternWhichMatches(formatted_string_, source.step);
86 ExtractType(source);
87 if (!ParseValues()) {
88 type_ = ui::TEXT_INPUT_TYPE_NONE;
89 ClearAll();
90 LOG(WARNING) << "Problems parsing input <" << formatted_string_ << ">";
91 }
92 }
93
94 DateTimeFormatter::DateTimeFormatter(ui::TextInputType type, 31 DateTimeFormatter::DateTimeFormatter(ui::TextInputType type,
95 int year, 32 int year,
96 int month, 33 int month,
97 int day, 34 int day,
98 int hour, 35 int hour,
99 int minute, 36 int minute,
100 int second, 37 int second,
101 int milli, 38 int milli,
102 int week_year, 39 int week_year,
103 int week) 40 int week)
(...skipping 22 matching lines...) Expand all
126 pattern_ = type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX ? 63 pattern_ = type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX ?
127 &patterns_[type_] : &patterns_[ui::TEXT_INPUT_TYPE_NONE]; 64 &patterns_[type_] : &patterns_[ui::TEXT_INPUT_TYPE_NONE];
128 } 65 }
129 66
130 formatted_string_ = FormatString(); 67 formatted_string_ = FormatString();
131 } 68 }
132 69
133 DateTimeFormatter::~DateTimeFormatter() { 70 DateTimeFormatter::~DateTimeFormatter() {
134 } 71 }
135 72
136 int DateTimeFormatter::GetYear() const {
137 return year_;
138 }
139
140 int DateTimeFormatter::GetMonth() const {
141 return month_;
142 }
143
144 int DateTimeFormatter::GetDay() const {
145 return day_;
146 }
147
148 int DateTimeFormatter::GetHour() const {
149 return hour_;
150 }
151
152 int DateTimeFormatter::GetMinute() const {
153 return minute_;
154 }
155
156 int DateTimeFormatter::GetSecond() const {
157 return second_;
158 }
159
160 int DateTimeFormatter::GetMilli() const { return milli_; }
161
162 int DateTimeFormatter::GetWeekYear() const { return week_year_; }
163
164 int DateTimeFormatter::GetWeek() const {
165 return week_;
166 }
167
168 ui::TextInputType DateTimeFormatter::GetType() const {
169 return type_;
170 }
171
172 const std::string& DateTimeFormatter::GetFormattedValue() const { 73 const std::string& DateTimeFormatter::GetFormattedValue() const {
173 return formatted_string_; 74 return formatted_string_;
174 } 75 }
175 76
176 const std::string DateTimeFormatter::FormatString() const { 77 const std::string DateTimeFormatter::FormatString() const {
177 UErrorCode success = U_ZERO_ERROR; 78 UErrorCode success = U_ZERO_ERROR;
178 if (year_ == 0 && month_ == 0 && day_ == 0 && hour_ == 0 && minute_ == 0 && 79 if (type_ == ui::TEXT_INPUT_TYPE_NONE) {
179 second_ == 0 && milli_ == 0 && week_year_ == 0 && week_ == 0) {
180 return std::string(); 80 return std::string();
181 } 81 }
182 82
183 std::string result; 83 std::string result;
184 icu::GregorianCalendar calendar(success); 84 icu::GregorianCalendar calendar(success);
185 if (success <= U_ZERO_ERROR) { 85 if (success <= U_ZERO_ERROR) {
186 if (type_ == ui::TEXT_INPUT_TYPE_WEEK) { 86 switch (type_) {
187 // An ISO week starts with Monday. 87 case ui::TEXT_INPUT_TYPE_WEEK:
188 calendar.setFirstDayOfWeek(UCAL_MONDAY); 88 // An ISO week starts with Monday.
189 // ISO 8601 defines that the week with the year's first Thursday is the 89 calendar.setFirstDayOfWeek(UCAL_MONDAY);
190 // first week. 90 // ISO 8601 defines that the week with the year's first Thursday is the
191 calendar.setMinimalDaysInFirstWeek(4); 91 // first week.
192 calendar.set(UCAL_YEAR_WOY, week_year_); 92 calendar.setMinimalDaysInFirstWeek(4);
193 calendar.set(UCAL_WEEK_OF_YEAR, week_); 93 calendar.set(UCAL_YEAR_WOY, week_year_);
194 } else { 94 calendar.set(UCAL_WEEK_OF_YEAR, week_);
195 calendar.set(UCAL_YEAR, year_); 95 break;
196 calendar.set(UCAL_MONTH, month_); 96 case ui::TEXT_INPUT_TYPE_MONTH:
197 calendar.set(UCAL_DATE, day_); 97 calendar.set(UCAL_YEAR, year_);
198 calendar.set(UCAL_HOUR_OF_DAY, hour_); 98 calendar.set(UCAL_MONTH, month_);
199 calendar.set(UCAL_MINUTE, minute_); 99 break;
200 calendar.set(UCAL_SECOND, second_); 100 case ui::TEXT_INPUT_TYPE_DATE:
201 calendar.set(UCAL_MILLISECOND, milli_); 101 calendar.set(UCAL_YEAR, year_);
102 calendar.set(UCAL_MONTH, month_);
103 calendar.set(UCAL_DATE, day_);
104 break;
105 case ui::TEXT_INPUT_TYPE_TIME:
106 calendar.set(UCAL_HOUR_OF_DAY, hour_);
107 calendar.set(UCAL_MINUTE, minute_);
108 calendar.set(UCAL_SECOND, second_);
109 calendar.set(UCAL_MILLISECOND, milli_);
110 break;
111 case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL:
112 calendar.set(UCAL_YEAR, year_);
113 calendar.set(UCAL_MONTH, month_);
114 calendar.set(UCAL_DATE, day_);
115 calendar.set(UCAL_HOUR_OF_DAY, hour_);
116 calendar.set(UCAL_MINUTE, minute_);
117 calendar.set(UCAL_SECOND, second_);
118 calendar.set(UCAL_MILLISECOND, milli_);
119 break;
120 default:
121 NOTREACHED();
202 } 122 }
203 icu::SimpleDateFormat formatter(*pattern_, success); 123 icu::SimpleDateFormat formatter(*pattern_, success);
204 icu::UnicodeString formatted_time; 124 icu::UnicodeString formatted_time;
205 formatter.format(calendar, formatted_time, NULL, success); 125 formatter.format(calendar, formatted_time, NULL, success);
206 UTF16ToUTF8(formatted_time.getBuffer(), 126 UTF16ToUTF8(formatted_time.getBuffer(),
207 static_cast<size_t>(formatted_time.length()), 127 static_cast<size_t>(formatted_time.length()),
208 &result); 128 &result);
209 if (success <= U_ZERO_ERROR) 129 if (success <= U_ZERO_ERROR)
210 return result; 130 return result;
211 } 131 }
212 LOG(WARNING) << "Calendar not created: error " << success; 132 LOG(WARNING) << "Calendar not created: error " << success;
213 return std::string(); 133 return std::string();
214 } 134 }
215 135
216 void DateTimeFormatter::ExtractType(
217 const WebKit::WebDateTimeChooserParams& source) {
218 switch (source.type) {
219 case WebKit::WebDateTimeInputTypeDate:
220 type_ = ui::TEXT_INPUT_TYPE_DATE;
221 break;
222 case WebKit::WebDateTimeInputTypeDateTime:
223 type_ = ui::TEXT_INPUT_TYPE_DATE_TIME;
224 break;
225 case WebKit::WebDateTimeInputTypeDateTimeLocal:
226 type_ = ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL;
227 break;
228 case WebKit::WebDateTimeInputTypeMonth:
229 type_ = ui::TEXT_INPUT_TYPE_MONTH;
230 break;
231 case WebKit::WebDateTimeInputTypeTime:
232 type_ = ui::TEXT_INPUT_TYPE_TIME;
233 break;
234 case WebKit::WebDateTimeInputTypeWeek:
235 type_ = ui::TEXT_INPUT_TYPE_WEEK;
236 break;
237 case WebKit::WebDateTimeInputTypeNone:
238 default:
239 type_ = ui::TEXT_INPUT_TYPE_NONE;
240 }
241 }
242
243 // Not all fields are defined in all configurations and ICU might store
244 // garbage if success <= U_ZERO_ERROR so the output is sanitized here.
245 int DateTimeFormatter::ExtractValue(
246 const icu::Calendar* calendar, UCalendarDateFields value) const {
247 UErrorCode success = U_ZERO_ERROR;
248 int result = calendar->get(value, success);
249 return (success <= U_ZERO_ERROR) ? result : 0;
250 }
251
252 bool DateTimeFormatter::ParseValues() {
253 if (type_ == ui::TEXT_INPUT_TYPE_NONE) {
254 ClearAll();
255 return false;
256 }
257
258 if (formatted_string_.empty()) {
259 ClearAll();
260 return true;
261 }
262
263 UErrorCode success = U_ZERO_ERROR;
264 icu::UnicodeString icu_value = icu::UnicodeString::fromUTF8(
265 icu::StringPiece(formatted_string_.data(), formatted_string_.size()));
266 if (type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX) {
267 const icu::UnicodeString pattern =
268 type_ == ui::TEXT_INPUT_TYPE_TIME ? time_pattern_ : patterns_[type_];
269 icu::SimpleDateFormat formatter(pattern, success);
270 formatter.parse(icu_value, success);
271 if (success <= U_ZERO_ERROR) {
272 const icu::Calendar* cal = formatter.getCalendar();
273 year_ = ExtractValue(cal, UCAL_YEAR);
274 month_ = ExtractValue(cal, UCAL_MONTH);
275 day_ = ExtractValue(cal, UCAL_DATE);
276 hour_ = ExtractValue(cal, UCAL_HOUR_OF_DAY); // 24h format
277 minute_ = ExtractValue(cal, UCAL_MINUTE);
278 second_ = ExtractValue(cal, UCAL_SECOND);
279 milli_ = ExtractValue(cal, UCAL_MILLISECOND);
280 week_year_ = ExtractValue(cal, UCAL_YEAR_WOY);
281 week_ = ExtractValue(cal, UCAL_WEEK_OF_YEAR);
282 }
283 }
284
285 return (success <= U_ZERO_ERROR);
286 }
287
288 void DateTimeFormatter::ClearAll() {
289 year_ = 0;
290 month_ = 0;
291 day_ = 0;
292 hour_ = 0;
293 minute_ = 0;
294 second_ = 0;
295 milli_ = 0;
296 week_year_ = 0;
297 week_ = 0;
298 }
299
300 } // namespace content 136 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698