OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/manifest/manifest_parser.h" | 5 #include "content/renderer/manifest/manifest_parser.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/strings/nullable_string16.h" | 10 #include "base/strings/nullable_string16.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 : data_(data), | 98 : data_(data), |
99 manifest_url_(manifest_url), | 99 manifest_url_(manifest_url), |
100 document_url_(document_url), | 100 document_url_(document_url), |
101 failed_(false) { | 101 failed_(false) { |
102 } | 102 } |
103 | 103 |
104 ManifestParser::~ManifestParser() { | 104 ManifestParser::~ManifestParser() { |
105 } | 105 } |
106 | 106 |
107 void ManifestParser::Parse() { | 107 void ManifestParser::Parse() { |
108 std::string parse_error; | 108 std::string error_msg; |
| 109 int error_line = 0; |
| 110 int error_column = 0; |
109 scoped_ptr<base::Value> value = base::JSONReader::ReadAndReturnError( | 111 scoped_ptr<base::Value> value = base::JSONReader::ReadAndReturnError( |
110 data_, base::JSON_PARSE_RFC, nullptr, &parse_error); | 112 data_, base::JSON_PARSE_RFC, nullptr, &error_msg, &error_line, |
| 113 &error_column); |
111 | 114 |
112 if (!value) { | 115 if (!value) { |
113 errors_.push_back(GetErrorPrefix() + parse_error); | 116 AddErrorInfo(GetErrorPrefix() + error_msg, error_line, error_column); |
114 ManifestUmaUtil::ParseFailed(); | 117 ManifestUmaUtil::ParseFailed(); |
115 failed_ = true; | 118 failed_ = true; |
116 return; | 119 return; |
117 } | 120 } |
118 | 121 |
119 base::DictionaryValue* dictionary = nullptr; | 122 base::DictionaryValue* dictionary = nullptr; |
120 if (!value->GetAsDictionary(&dictionary)) { | 123 if (!value->GetAsDictionary(&dictionary)) { |
121 errors_.push_back(GetErrorPrefix() + | 124 AddErrorInfo(GetErrorPrefix() + |
122 "root element must be a valid JSON object."); | 125 "root element must be a valid JSON object."); |
123 ManifestUmaUtil::ParseFailed(); | 126 ManifestUmaUtil::ParseFailed(); |
124 failed_ = true; | 127 failed_ = true; |
125 return; | 128 return; |
126 } | 129 } |
127 DCHECK(dictionary); | 130 DCHECK(dictionary); |
128 | 131 |
129 manifest_.name = ParseName(*dictionary); | 132 manifest_.name = ParseName(*dictionary); |
130 manifest_.short_name = ParseShortName(*dictionary); | 133 manifest_.short_name = ParseShortName(*dictionary); |
131 manifest_.start_url = ParseStartURL(*dictionary); | 134 manifest_.start_url = ParseStartURL(*dictionary); |
132 manifest_.display = ParseDisplay(*dictionary); | 135 manifest_.display = ParseDisplay(*dictionary); |
133 manifest_.orientation = ParseOrientation(*dictionary); | 136 manifest_.orientation = ParseOrientation(*dictionary); |
134 manifest_.icons = ParseIcons(*dictionary); | 137 manifest_.icons = ParseIcons(*dictionary); |
135 manifest_.related_applications = ParseRelatedApplications(*dictionary); | 138 manifest_.related_applications = ParseRelatedApplications(*dictionary); |
136 manifest_.prefer_related_applications = | 139 manifest_.prefer_related_applications = |
137 ParsePreferRelatedApplications(*dictionary); | 140 ParsePreferRelatedApplications(*dictionary); |
138 manifest_.theme_color = ParseThemeColor(*dictionary); | 141 manifest_.theme_color = ParseThemeColor(*dictionary); |
139 manifest_.background_color = ParseBackgroundColor(*dictionary); | 142 manifest_.background_color = ParseBackgroundColor(*dictionary); |
140 manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary); | 143 manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary); |
141 | 144 |
142 ManifestUmaUtil::ParseSucceeded(manifest_); | 145 ManifestUmaUtil::ParseSucceeded(manifest_); |
143 } | 146 } |
144 | 147 |
145 const Manifest& ManifestParser::manifest() const { | 148 const Manifest& ManifestParser::manifest() const { |
146 return manifest_; | 149 return manifest_; |
147 } | 150 } |
148 | 151 |
149 const std::vector<std::string>& ManifestParser::errors() const { | 152 const std::vector<scoped_ptr<ManifestParser::ErrorInfo>>& |
| 153 ManifestParser::errors() const { |
150 return errors_; | 154 return errors_; |
151 } | 155 } |
152 | 156 |
153 bool ManifestParser::failed() const { | 157 bool ManifestParser::failed() const { |
154 return failed_; | 158 return failed_; |
155 } | 159 } |
156 | 160 |
157 bool ManifestParser::ParseBoolean(const base::DictionaryValue& dictionary, | 161 bool ManifestParser::ParseBoolean(const base::DictionaryValue& dictionary, |
158 const std::string& key, | 162 const std::string& key, |
159 bool default_value) { | 163 bool default_value) { |
160 if (!dictionary.HasKey(key)) | 164 if (!dictionary.HasKey(key)) |
161 return default_value; | 165 return default_value; |
162 | 166 |
163 bool value; | 167 bool value; |
164 if (!dictionary.GetBoolean(key, &value)) { | 168 if (!dictionary.GetBoolean(key, &value)) { |
165 errors_.push_back(GetErrorPrefix() + | 169 AddErrorInfo(GetErrorPrefix() + "property '" + key + "' ignored, type " + |
166 "property '" + key + "' ignored, type boolean expected."); | 170 "boolean expected."); |
167 return default_value; | 171 return default_value; |
168 } | 172 } |
169 | 173 |
170 return value; | 174 return value; |
171 } | 175 } |
172 | 176 |
173 base::NullableString16 ManifestParser::ParseString( | 177 base::NullableString16 ManifestParser::ParseString( |
174 const base::DictionaryValue& dictionary, | 178 const base::DictionaryValue& dictionary, |
175 const std::string& key, | 179 const std::string& key, |
176 TrimType trim) { | 180 TrimType trim) { |
177 if (!dictionary.HasKey(key)) | 181 if (!dictionary.HasKey(key)) |
178 return base::NullableString16(); | 182 return base::NullableString16(); |
179 | 183 |
180 base::string16 value; | 184 base::string16 value; |
181 if (!dictionary.GetString(key, &value)) { | 185 if (!dictionary.GetString(key, &value)) { |
182 errors_.push_back(GetErrorPrefix() + | 186 AddErrorInfo(GetErrorPrefix() + "property '" + key + "' ignored, type " + |
183 "property '" + key + "' ignored, type string expected."); | 187 "string expected."); |
184 return base::NullableString16(); | 188 return base::NullableString16(); |
185 } | 189 } |
186 | 190 |
187 if (trim == Trim) | 191 if (trim == Trim) |
188 base::TrimWhitespace(value, base::TRIM_ALL, &value); | 192 base::TrimWhitespace(value, base::TRIM_ALL, &value); |
189 return base::NullableString16(value, false); | 193 return base::NullableString16(value, false); |
190 } | 194 } |
191 | 195 |
192 int64_t ManifestParser::ParseColor( | 196 int64_t ManifestParser::ParseColor( |
193 const base::DictionaryValue& dictionary, | 197 const base::DictionaryValue& dictionary, |
194 const std::string& key) { | 198 const std::string& key) { |
195 base::NullableString16 parsed_color = ParseString(dictionary, key, Trim); | 199 base::NullableString16 parsed_color = ParseString(dictionary, key, Trim); |
196 if (parsed_color.is_null()) | 200 if (parsed_color.is_null()) |
197 return Manifest::kInvalidOrMissingColor; | 201 return Manifest::kInvalidOrMissingColor; |
198 | 202 |
199 blink::WebColor color; | 203 blink::WebColor color; |
200 if (!blink::WebCSSParser::parseColor(&color, parsed_color.string())) { | 204 if (!blink::WebCSSParser::parseColor(&color, parsed_color.string())) { |
201 errors_.push_back(GetErrorPrefix() + | 205 AddErrorInfo(GetErrorPrefix() + "property '" + key + "' ignored, '" + |
202 "property '" + key + "' ignored, '" + | 206 base::UTF16ToUTF8(parsed_color.string()) + "' is not a " + |
203 base::UTF16ToUTF8(parsed_color.string()) + | 207 "valid color."); |
204 "' is not a valid color."); | |
205 return Manifest::kInvalidOrMissingColor; | 208 return Manifest::kInvalidOrMissingColor; |
206 } | 209 } |
207 | 210 |
208 // We do this here because Java does not have an unsigned int32_t type so | 211 // We do this here because Java does not have an unsigned int32_t type so |
209 // colors with high alpha values will be negative. Instead of doing the | 212 // colors with high alpha values will be negative. Instead of doing the |
210 // conversion after we pass over to Java, we do it here as it is easier and | 213 // conversion after we pass over to Java, we do it here as it is easier and |
211 // clearer. | 214 // clearer. |
212 int32_t signed_color = reinterpret_cast<int32_t&>(color); | 215 int32_t signed_color = reinterpret_cast<int32_t&>(color); |
213 return static_cast<int64_t>(signed_color); | 216 return static_cast<int64_t>(signed_color); |
214 } | 217 } |
(...skipping 17 matching lines...) Expand all Loading... |
232 const base::DictionaryValue& dictionary) { | 235 const base::DictionaryValue& dictionary) { |
233 return ParseString(dictionary, "short_name", Trim); | 236 return ParseString(dictionary, "short_name", Trim); |
234 } | 237 } |
235 | 238 |
236 GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) { | 239 GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) { |
237 GURL start_url = ParseURL(dictionary, "start_url", manifest_url_); | 240 GURL start_url = ParseURL(dictionary, "start_url", manifest_url_); |
238 if (!start_url.is_valid()) | 241 if (!start_url.is_valid()) |
239 return GURL(); | 242 return GURL(); |
240 | 243 |
241 if (start_url.GetOrigin() != document_url_.GetOrigin()) { | 244 if (start_url.GetOrigin() != document_url_.GetOrigin()) { |
242 errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should " | 245 AddErrorInfo(GetErrorPrefix() + "property 'start_url' ignored, should be " + |
243 "be same origin as document."); | 246 "same origin as document."); |
244 return GURL(); | 247 return GURL(); |
245 } | 248 } |
246 | 249 |
247 return start_url; | 250 return start_url; |
248 } | 251 } |
249 | 252 |
250 blink::WebDisplayMode ManifestParser::ParseDisplay( | 253 blink::WebDisplayMode ManifestParser::ParseDisplay( |
251 const base::DictionaryValue& dictionary) { | 254 const base::DictionaryValue& dictionary) { |
252 base::NullableString16 display = ParseString(dictionary, "display", Trim); | 255 base::NullableString16 display = ParseString(dictionary, "display", Trim); |
253 if (display.is_null()) | 256 if (display.is_null()) |
254 return blink::WebDisplayModeUndefined; | 257 return blink::WebDisplayModeUndefined; |
255 | 258 |
256 if (base::LowerCaseEqualsASCII(display.string(), "fullscreen")) | 259 if (base::LowerCaseEqualsASCII(display.string(), "fullscreen")) |
257 return blink::WebDisplayModeFullscreen; | 260 return blink::WebDisplayModeFullscreen; |
258 else if (base::LowerCaseEqualsASCII(display.string(), "standalone")) | 261 else if (base::LowerCaseEqualsASCII(display.string(), "standalone")) |
259 return blink::WebDisplayModeStandalone; | 262 return blink::WebDisplayModeStandalone; |
260 else if (base::LowerCaseEqualsASCII(display.string(), "minimal-ui")) | 263 else if (base::LowerCaseEqualsASCII(display.string(), "minimal-ui")) |
261 return blink::WebDisplayModeMinimalUi; | 264 return blink::WebDisplayModeMinimalUi; |
262 else if (base::LowerCaseEqualsASCII(display.string(), "browser")) | 265 else if (base::LowerCaseEqualsASCII(display.string(), "browser")) |
263 return blink::WebDisplayModeBrowser; | 266 return blink::WebDisplayModeBrowser; |
264 else { | 267 else { |
265 errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored."); | 268 AddErrorInfo(GetErrorPrefix() + "unknown 'display' value ignored."); |
266 return blink::WebDisplayModeUndefined; | 269 return blink::WebDisplayModeUndefined; |
267 } | 270 } |
268 } | 271 } |
269 | 272 |
270 blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( | 273 blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( |
271 const base::DictionaryValue& dictionary) { | 274 const base::DictionaryValue& dictionary) { |
272 base::NullableString16 orientation = | 275 base::NullableString16 orientation = |
273 ParseString(dictionary, "orientation", Trim); | 276 ParseString(dictionary, "orientation", Trim); |
274 | 277 |
275 if (orientation.is_null()) | 278 if (orientation.is_null()) |
(...skipping 13 matching lines...) Expand all Loading... |
289 return blink::WebScreenOrientationLockLandscapeSecondary; | 292 return blink::WebScreenOrientationLockLandscapeSecondary; |
290 else if (base::LowerCaseEqualsASCII(orientation.string(), "portrait")) | 293 else if (base::LowerCaseEqualsASCII(orientation.string(), "portrait")) |
291 return blink::WebScreenOrientationLockPortrait; | 294 return blink::WebScreenOrientationLockPortrait; |
292 else if (base::LowerCaseEqualsASCII(orientation.string(), | 295 else if (base::LowerCaseEqualsASCII(orientation.string(), |
293 "portrait-primary")) | 296 "portrait-primary")) |
294 return blink::WebScreenOrientationLockPortraitPrimary; | 297 return blink::WebScreenOrientationLockPortraitPrimary; |
295 else if (base::LowerCaseEqualsASCII(orientation.string(), | 298 else if (base::LowerCaseEqualsASCII(orientation.string(), |
296 "portrait-secondary")) | 299 "portrait-secondary")) |
297 return blink::WebScreenOrientationLockPortraitSecondary; | 300 return blink::WebScreenOrientationLockPortraitSecondary; |
298 else { | 301 else { |
299 errors_.push_back(GetErrorPrefix() + | 302 AddErrorInfo(GetErrorPrefix() + "unknown 'orientation' value ignored."); |
300 "unknown 'orientation' value ignored."); | |
301 return blink::WebScreenOrientationLockDefault; | 303 return blink::WebScreenOrientationLockDefault; |
302 } | 304 } |
303 } | 305 } |
304 | 306 |
305 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) { | 307 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) { |
306 return ParseURL(icon, "src", manifest_url_); | 308 return ParseURL(icon, "src", manifest_url_); |
307 } | 309 } |
308 | 310 |
309 base::NullableString16 ManifestParser::ParseIconType( | 311 base::NullableString16 ManifestParser::ParseIconType( |
310 const base::DictionaryValue& icon) { | 312 const base::DictionaryValue& icon) { |
311 return ParseString(icon, "type", Trim); | 313 return ParseString(icon, "type", Trim); |
312 } | 314 } |
313 | 315 |
314 double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) { | 316 double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) { |
315 double density; | 317 double density; |
316 if (!icon.HasKey("density")) | 318 if (!icon.HasKey("density")) |
317 return Manifest::Icon::kDefaultDensity; | 319 return Manifest::Icon::kDefaultDensity; |
318 | 320 |
319 if (!icon.GetDouble("density", &density) || density <= 0) { | 321 if (!icon.GetDouble("density", &density) || density <= 0) { |
320 errors_.push_back(GetErrorPrefix() + | 322 AddErrorInfo(GetErrorPrefix() + |
321 "icon 'density' ignored, must be float greater than 0."); | 323 "icon 'density' ignored, must be float greater than 0."); |
322 return Manifest::Icon::kDefaultDensity; | 324 return Manifest::Icon::kDefaultDensity; |
323 } | 325 } |
324 return density; | 326 return density; |
325 } | 327 } |
326 | 328 |
327 std::vector<gfx::Size> ManifestParser::ParseIconSizes( | 329 std::vector<gfx::Size> ManifestParser::ParseIconSizes( |
328 const base::DictionaryValue& icon) { | 330 const base::DictionaryValue& icon) { |
329 base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); | 331 base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); |
330 | 332 |
331 if (sizes_str.is_null()) | 333 if (sizes_str.is_null()) |
332 return std::vector<gfx::Size>(); | 334 return std::vector<gfx::Size>(); |
333 | 335 |
334 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); | 336 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); |
335 if (sizes.empty()) { | 337 if (sizes.empty()) { |
336 errors_.push_back(GetErrorPrefix() + "found icon with no valid size."); | 338 AddErrorInfo(GetErrorPrefix() + "found icon with no valid size."); |
337 } | 339 } |
338 return sizes; | 340 return sizes; |
339 } | 341 } |
340 | 342 |
341 std::vector<Manifest::Icon> ManifestParser::ParseIcons( | 343 std::vector<Manifest::Icon> ManifestParser::ParseIcons( |
342 const base::DictionaryValue& dictionary) { | 344 const base::DictionaryValue& dictionary) { |
343 std::vector<Manifest::Icon> icons; | 345 std::vector<Manifest::Icon> icons; |
344 if (!dictionary.HasKey("icons")) | 346 if (!dictionary.HasKey("icons")) |
345 return icons; | 347 return icons; |
346 | 348 |
347 const base::ListValue* icons_list = nullptr; | 349 const base::ListValue* icons_list = nullptr; |
348 if (!dictionary.GetList("icons", &icons_list)) { | 350 if (!dictionary.GetList("icons", &icons_list)) { |
349 errors_.push_back(GetErrorPrefix() + | 351 AddErrorInfo(GetErrorPrefix() + |
350 "property 'icons' ignored, type array expected."); | 352 "property 'icons' ignored, type array expected."); |
351 return icons; | 353 return icons; |
352 } | 354 } |
353 | 355 |
354 for (size_t i = 0; i < icons_list->GetSize(); ++i) { | 356 for (size_t i = 0; i < icons_list->GetSize(); ++i) { |
355 const base::DictionaryValue* icon_dictionary = nullptr; | 357 const base::DictionaryValue* icon_dictionary = nullptr; |
356 if (!icons_list->GetDictionary(i, &icon_dictionary)) | 358 if (!icons_list->GetDictionary(i, &icon_dictionary)) |
357 continue; | 359 continue; |
358 | 360 |
359 Manifest::Icon icon; | 361 Manifest::Icon icon; |
360 icon.src = ParseIconSrc(*icon_dictionary); | 362 icon.src = ParseIconSrc(*icon_dictionary); |
(...skipping 27 matching lines...) Expand all Loading... |
388 | 390 |
389 std::vector<Manifest::RelatedApplication> | 391 std::vector<Manifest::RelatedApplication> |
390 ManifestParser::ParseRelatedApplications( | 392 ManifestParser::ParseRelatedApplications( |
391 const base::DictionaryValue& dictionary) { | 393 const base::DictionaryValue& dictionary) { |
392 std::vector<Manifest::RelatedApplication> applications; | 394 std::vector<Manifest::RelatedApplication> applications; |
393 if (!dictionary.HasKey("related_applications")) | 395 if (!dictionary.HasKey("related_applications")) |
394 return applications; | 396 return applications; |
395 | 397 |
396 const base::ListValue* applications_list = nullptr; | 398 const base::ListValue* applications_list = nullptr; |
397 if (!dictionary.GetList("related_applications", &applications_list)) { | 399 if (!dictionary.GetList("related_applications", &applications_list)) { |
398 errors_.push_back( | 400 AddErrorInfo( |
399 GetErrorPrefix() + | 401 GetErrorPrefix() + |
400 "property 'related_applications' ignored, type array expected."); | 402 "property 'related_applications' ignored, type array expected."); |
401 return applications; | 403 return applications; |
402 } | 404 } |
403 | 405 |
404 for (size_t i = 0; i < applications_list->GetSize(); ++i) { | 406 for (size_t i = 0; i < applications_list->GetSize(); ++i) { |
405 const base::DictionaryValue* application_dictionary = nullptr; | 407 const base::DictionaryValue* application_dictionary = nullptr; |
406 if (!applications_list->GetDictionary(i, &application_dictionary)) | 408 if (!applications_list->GetDictionary(i, &application_dictionary)) |
407 continue; | 409 continue; |
408 | 410 |
409 Manifest::RelatedApplication application; | 411 Manifest::RelatedApplication application; |
410 application.platform = | 412 application.platform = |
411 ParseRelatedApplicationPlatform(*application_dictionary); | 413 ParseRelatedApplicationPlatform(*application_dictionary); |
412 // "If platform is undefined, move onto the next item if any are left." | 414 // "If platform is undefined, move onto the next item if any are left." |
413 if (application.platform.is_null()) { | 415 if (application.platform.is_null()) { |
414 errors_.push_back( | 416 AddErrorInfo( |
415 GetErrorPrefix() + | 417 GetErrorPrefix() + |
416 "'platform' is a required field, related application ignored."); | 418 "'platform' is a required field, related application ignored."); |
417 continue; | 419 continue; |
418 } | 420 } |
419 | 421 |
420 application.id = ParseRelatedApplicationId(*application_dictionary); | 422 application.id = ParseRelatedApplicationId(*application_dictionary); |
421 application.url = ParseRelatedApplicationURL(*application_dictionary); | 423 application.url = ParseRelatedApplicationURL(*application_dictionary); |
422 // "If both id and url are undefined, move onto the next item if any are | 424 // "If both id and url are undefined, move onto the next item if any are |
423 // left." | 425 // left." |
424 if (application.url.is_empty() && application.id.is_null()) { | 426 if (application.url.is_empty() && application.id.is_null()) { |
425 errors_.push_back( | 427 AddErrorInfo( |
426 GetErrorPrefix() + | 428 GetErrorPrefix() + |
427 "one of 'url' or 'id' is required, related application ignored."); | 429 "one of 'url' or 'id' is required, related application ignored."); |
428 continue; | 430 continue; |
429 } | 431 } |
430 | 432 |
431 applications.push_back(application); | 433 applications.push_back(application); |
432 } | 434 } |
433 | 435 |
434 return applications; | 436 return applications; |
435 } | 437 } |
(...skipping 11 matching lines...) Expand all Loading... |
447 int64_t ManifestParser::ParseBackgroundColor( | 449 int64_t ManifestParser::ParseBackgroundColor( |
448 const base::DictionaryValue& dictionary) { | 450 const base::DictionaryValue& dictionary) { |
449 return ParseColor(dictionary, "background_color"); | 451 return ParseColor(dictionary, "background_color"); |
450 } | 452 } |
451 | 453 |
452 base::NullableString16 ManifestParser::ParseGCMSenderID( | 454 base::NullableString16 ManifestParser::ParseGCMSenderID( |
453 const base::DictionaryValue& dictionary) { | 455 const base::DictionaryValue& dictionary) { |
454 return ParseString(dictionary, "gcm_sender_id", Trim); | 456 return ParseString(dictionary, "gcm_sender_id", Trim); |
455 } | 457 } |
456 | 458 |
| 459 void ManifestParser::AddErrorInfo(const std::string& error_msg, |
| 460 int error_line, |
| 461 int error_column) { |
| 462 errors_.push_back( |
| 463 make_scoped_ptr(new ErrorInfo(error_msg, error_line, error_column))); |
| 464 } |
457 } // namespace content | 465 } // namespace content |
OLD | NEW |