| 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 "base/json/json_reader.h" | 7 #include "base/json/json_reader.h" |
| 8 #include "base/strings/nullable_string16.h" | 8 #include "base/strings/nullable_string16.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "content/public/common/content_client.h" |
| 14 #include "content/public/common/manifest.h" | 15 #include "content/public/common/manifest.h" |
| 16 #include "content/public/renderer/content_renderer_client.h" |
| 15 #include "content/renderer/manifest/manifest_uma_util.h" | 17 #include "content/renderer/manifest/manifest_uma_util.h" |
| 16 #include "ui/gfx/geometry/size.h" | 18 #include "ui/gfx/geometry/size.h" |
| 17 | 19 |
| 18 namespace content { | 20 namespace content { |
| 19 | 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 // Helper function that returns whether the given |str| is a valid width or | 24 // Helper function that returns whether the given |str| is a valid width or |
| 23 // height value for an icon sizes per: | 25 // height value for an icon sizes per: |
| 24 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes | 26 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 } | 80 } |
| 79 | 81 |
| 80 const std::string& GetErrorPrefix() { | 82 const std::string& GetErrorPrefix() { |
| 81 CR_DEFINE_STATIC_LOCAL(std::string, error_prefix, | 83 CR_DEFINE_STATIC_LOCAL(std::string, error_prefix, |
| 82 ("Manifest parsing error: ")); | 84 ("Manifest parsing error: ")); |
| 83 return error_prefix; | 85 return error_prefix; |
| 84 } | 86 } |
| 85 | 87 |
| 86 } // anonymous namespace | 88 } // anonymous namespace |
| 87 | 89 |
| 88 | |
| 89 ManifestParser::ManifestParser(const base::StringPiece& data, | 90 ManifestParser::ManifestParser(const base::StringPiece& data, |
| 90 const GURL& manifest_url, | 91 const GURL& manifest_url, |
| 91 const GURL& document_url) | 92 const GURL& document_url) |
| 92 : data_(data), | 93 : data_(data), |
| 93 manifest_url_(manifest_url), | 94 manifest_url_(manifest_url), |
| 94 document_url_(document_url), | 95 document_url_(document_url), |
| 95 failed_(false) { | 96 failed_(false) { |
| 97 DCHECK(manifest_url_.is_valid()); |
| 98 DCHECK(document_url_.is_valid()); |
| 96 } | 99 } |
| 97 | 100 |
| 98 ManifestParser::~ManifestParser() { | 101 ManifestParser::~ManifestParser() { |
| 99 } | 102 } |
| 100 | 103 |
| 101 void ManifestParser::Parse() { | 104 void ManifestParser::Parse() { |
| 102 std::string parse_error; | 105 std::string parse_error; |
| 103 scoped_ptr<base::Value> value( | 106 scoped_ptr<base::Value> value( |
| 104 base::JSONReader::ReadAndReturnError(data_, base::JSON_PARSE_RFC, | 107 base::JSONReader::ReadAndReturnError(data_, base::JSON_PARSE_RFC, |
| 105 nullptr, &parse_error)); | 108 nullptr, &parse_error)); |
| 106 | 109 |
| 107 if (!value) { | 110 if (!value) { |
| 108 errors_.push_back(GetErrorPrefix() + parse_error); | 111 errors_.push_back(GetErrorPrefix() + parse_error); |
| 109 ManifestUmaUtil::ParseFailed(); | 112 ManifestUmaUtil::ParseFailed(); |
| 110 failed_ = true; | 113 failed_ = true; |
| 111 return; | 114 return; |
| 112 } | 115 } |
| 113 | 116 |
| 114 base::DictionaryValue* dictionary = nullptr; | 117 base::DictionaryValue* dictionary = nullptr; |
| 115 if (!value->GetAsDictionary(&dictionary)) { | 118 if (!value->GetAsDictionary(&dictionary)) { |
| 116 errors_.push_back(GetErrorPrefix() + | 119 errors_.push_back(GetErrorPrefix() + |
| 117 "root element must be a valid JSON object."); | 120 "root element must be a valid JSON object."); |
| 118 ManifestUmaUtil::ParseFailed(); | 121 ManifestUmaUtil::ParseFailed(); |
| 119 failed_ = true; | 122 failed_ = true; |
| 120 return; | 123 return; |
| 121 } | 124 } |
| 122 DCHECK(dictionary); | 125 DCHECK(dictionary); |
| 123 | 126 |
| 124 manifest_.name = ParseName(*dictionary); | 127 for (base::DictionaryValue::Iterator iterator(*dictionary); |
| 125 manifest_.short_name = ParseShortName(*dictionary); | 128 !iterator.IsAtEnd(); iterator.Advance()) { |
| 126 manifest_.start_url = ParseStartURL(*dictionary); | 129 const std::string& key = iterator.key(); |
| 127 manifest_.display = ParseDisplay(*dictionary); | 130 const base::Value& value = iterator.value(); |
| 128 manifest_.orientation = ParseOrientation(*dictionary); | 131 |
| 129 manifest_.icons = ParseIcons(*dictionary); | 132 bool handled = Parse(key, value); |
| 130 manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary); | 133 if (!handled) { |
| 131 manifest_.gcm_user_visible_only = ParseGCMUserVisibleOnly(*dictionary); | 134 handled = GetContentClient()->renderer()->ParseManifestProperty(key, |
| 135 value); |
| 136 } |
| 137 |
| 138 if (!handled) |
| 139 errors_.push_back(GetErrorPrefix() + "unknown property '" + key + "'."); |
| 140 } |
| 132 | 141 |
| 133 ManifestUmaUtil::ParseSucceeded(manifest_); | 142 ManifestUmaUtil::ParseSucceeded(manifest_); |
| 134 } | 143 } |
| 135 | 144 |
| 145 bool ManifestParser::Parse(const std::string& key, const base::Value& value) { |
| 146 if (key == "name") |
| 147 manifest_.name = ParseName(key, value); |
| 148 else if (key == "short_name") |
| 149 manifest_.short_name = ParseShortName(key, value); |
| 150 else if (key == "start_url") |
| 151 manifest_.start_url = ParseStartURL(key, value); |
| 152 else if (key == "display") |
| 153 manifest_.display = ParseDisplay(key, value); |
| 154 else if (key == "orientation") |
| 155 manifest_.orientation = ParseOrientation(key, value); |
| 156 else if (key == "icons") |
| 157 manifest_.icons = ParseIcons(key, value); |
| 158 else |
| 159 return false; |
| 160 |
| 161 return true; |
| 162 } |
| 163 |
| 136 const Manifest& ManifestParser::manifest() const { | 164 const Manifest& ManifestParser::manifest() const { |
| 137 return manifest_; | 165 return manifest_; |
| 138 } | 166 } |
| 139 | 167 |
| 140 const std::vector<std::string>& ManifestParser::errors() const { | 168 const std::vector<std::string>& ManifestParser::errors() const { |
| 141 return errors_; | 169 return errors_; |
| 142 } | 170 } |
| 143 | 171 |
| 144 bool ManifestParser::failed() const { | 172 bool ManifestParser::failed() const { |
| 145 return failed_; | 173 return failed_; |
| 146 } | 174 } |
| 147 | 175 |
| 148 bool ManifestParser::ParseBoolean(const base::DictionaryValue& dictionary, | 176 bool ManifestParser::ParseBoolean( |
| 149 const std::string& key, | 177 const std::string& key, const base::Value& value, bool default_value) { |
| 150 bool default_value) { | 178 bool bool_value; |
| 151 if (!dictionary.HasKey(key)) | 179 if (!value.GetAsBoolean(&bool_value)) { |
| 152 return default_value; | |
| 153 | |
| 154 bool value; | |
| 155 if (!dictionary.GetBoolean(key, &value)) { | |
| 156 errors_.push_back(GetErrorPrefix() + | 180 errors_.push_back(GetErrorPrefix() + |
| 157 "property '" + key + "' ignored, type boolean expected."); | 181 "property '" + key + "' ignored, type boolean expected."); |
| 158 return default_value; | 182 return default_value; |
| 159 } | 183 } |
| 160 | 184 |
| 161 return value; | 185 return bool_value; |
| 162 } | 186 } |
| 163 | 187 |
| 164 base::NullableString16 ManifestParser::ParseString( | 188 base::NullableString16 ManifestParser::ParseString( |
| 165 const base::DictionaryValue& dictionary, | 189 const std::string& key, const base::Value& value, TrimType trim) { |
| 166 const std::string& key, | 190 base::string16 string_value; |
| 167 TrimType trim) { | 191 if (!value.GetAsString(&string_value)) { |
| 168 if (!dictionary.HasKey(key)) | |
| 169 return base::NullableString16(); | |
| 170 | |
| 171 base::string16 value; | |
| 172 if (!dictionary.GetString(key, &value)) { | |
| 173 errors_.push_back(GetErrorPrefix() + | 192 errors_.push_back(GetErrorPrefix() + |
| 174 "property '" + key + "' ignored, type string expected."); | 193 "property '" + key + "' ignored, type string expected."); |
| 175 return base::NullableString16(); | 194 return base::NullableString16(); |
| 176 } | 195 } |
| 177 | 196 |
| 178 if (trim == Trim) | 197 if (trim == Trim) |
| 179 base::TrimWhitespace(value, base::TRIM_ALL, &value); | 198 base::TrimWhitespace(string_value, base::TRIM_ALL, &string_value); |
| 180 return base::NullableString16(value, false); | 199 return base::NullableString16(string_value, false); |
| 181 } | 200 } |
| 182 | 201 |
| 183 GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary, | 202 GURL ManifestParser::ParseURL( |
| 184 const std::string& key, | 203 const std::string& key, const base::Value& value, const GURL& base_url) { |
| 185 const GURL& base_url) { | 204 base::NullableString16 url_str = ParseString(key, value, NoTrim); |
| 186 base::NullableString16 url_str = ParseString(dictionary, key, NoTrim); | |
| 187 if (url_str.is_null()) | 205 if (url_str.is_null()) |
| 188 return GURL(); | 206 return GURL(); |
| 189 | 207 |
| 190 return base_url.Resolve(url_str.string()); | 208 return base_url.Resolve(url_str.string()); |
| 191 } | 209 } |
| 192 | 210 |
| 193 base::NullableString16 ManifestParser::ParseName( | 211 base::NullableString16 ManifestParser::ParseName( |
| 194 const base::DictionaryValue& dictionary) { | 212 const std::string& key, const base::Value& value) { |
| 195 return ParseString(dictionary, "name", Trim); | 213 return ParseString(key, value, Trim); |
| 196 } | 214 } |
| 197 | 215 |
| 198 base::NullableString16 ManifestParser::ParseShortName( | 216 base::NullableString16 ManifestParser::ParseShortName( |
| 199 const base::DictionaryValue& dictionary) { | 217 const std::string& key, const base::Value& value) { |
| 200 return ParseString(dictionary, "short_name", Trim); | 218 return ParseString(key, value, Trim); |
| 201 } | 219 } |
| 202 | 220 |
| 203 GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) { | 221 GURL ManifestParser::ParseStartURL( |
| 204 GURL start_url = ParseURL(dictionary, "start_url", manifest_url_); | 222 const std::string& key, const base::Value& value) { |
| 223 GURL start_url = ParseURL(key, value, manifest_url_); |
| 205 if (!start_url.is_valid()) | 224 if (!start_url.is_valid()) |
| 206 return GURL(); | 225 return GURL(); |
| 207 | 226 |
| 208 if (start_url.GetOrigin() != document_url_.GetOrigin()) { | 227 if (start_url.GetOrigin() != document_url_.GetOrigin()) { |
| 209 errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should " | 228 errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should " |
| 210 "be same origin as document."); | 229 "be same origin as document."); |
| 211 return GURL(); | 230 return GURL(); |
| 212 } | 231 } |
| 213 | 232 |
| 214 return start_url; | 233 return start_url; |
| 215 } | 234 } |
| 216 | 235 |
| 217 Manifest::DisplayMode ManifestParser::ParseDisplay( | 236 Manifest::DisplayMode ManifestParser::ParseDisplay( |
| 218 const base::DictionaryValue& dictionary) { | 237 const std::string& key, const base::Value& value) { |
| 219 base::NullableString16 display = ParseString(dictionary, "display", Trim); | 238 base::NullableString16 display = ParseString(key, value, Trim); |
| 220 if (display.is_null()) | 239 if (display.is_null()) |
| 221 return Manifest::DISPLAY_MODE_UNSPECIFIED; | 240 return Manifest::DISPLAY_MODE_UNSPECIFIED; |
| 222 | 241 |
| 223 if (LowerCaseEqualsASCII(display.string(), "fullscreen")) | 242 if (LowerCaseEqualsASCII(display.string(), "fullscreen")) |
| 224 return Manifest::DISPLAY_MODE_FULLSCREEN; | 243 return Manifest::DISPLAY_MODE_FULLSCREEN; |
| 225 else if (LowerCaseEqualsASCII(display.string(), "standalone")) | 244 else if (LowerCaseEqualsASCII(display.string(), "standalone")) |
| 226 return Manifest::DISPLAY_MODE_STANDALONE; | 245 return Manifest::DISPLAY_MODE_STANDALONE; |
| 227 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui")) | 246 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui")) |
| 228 return Manifest::DISPLAY_MODE_MINIMAL_UI; | 247 return Manifest::DISPLAY_MODE_MINIMAL_UI; |
| 229 else if (LowerCaseEqualsASCII(display.string(), "browser")) | 248 else if (LowerCaseEqualsASCII(display.string(), "browser")) |
| 230 return Manifest::DISPLAY_MODE_BROWSER; | 249 return Manifest::DISPLAY_MODE_BROWSER; |
| 231 else { | 250 else { |
| 232 errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored."); | 251 errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored."); |
| 233 return Manifest::DISPLAY_MODE_UNSPECIFIED; | 252 return Manifest::DISPLAY_MODE_UNSPECIFIED; |
| 234 } | 253 } |
| 235 } | 254 } |
| 236 | 255 |
| 237 blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( | 256 blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( |
| 238 const base::DictionaryValue& dictionary) { | 257 const std::string& key, const base::Value& value) { |
| 239 base::NullableString16 orientation = | 258 base::NullableString16 orientation = ParseString(key, value, Trim); |
| 240 ParseString(dictionary, "orientation", Trim); | |
| 241 | |
| 242 if (orientation.is_null()) | 259 if (orientation.is_null()) |
| 243 return blink::WebScreenOrientationLockDefault; | 260 return blink::WebScreenOrientationLockDefault; |
| 244 | 261 |
| 245 if (LowerCaseEqualsASCII(orientation.string(), "any")) | 262 if (LowerCaseEqualsASCII(orientation.string(), "any")) |
| 246 return blink::WebScreenOrientationLockAny; | 263 return blink::WebScreenOrientationLockAny; |
| 247 else if (LowerCaseEqualsASCII(orientation.string(), "natural")) | 264 else if (LowerCaseEqualsASCII(orientation.string(), "natural")) |
| 248 return blink::WebScreenOrientationLockNatural; | 265 return blink::WebScreenOrientationLockNatural; |
| 249 else if (LowerCaseEqualsASCII(orientation.string(), "landscape")) | 266 else if (LowerCaseEqualsASCII(orientation.string(), "landscape")) |
| 250 return blink::WebScreenOrientationLockLandscape; | 267 return blink::WebScreenOrientationLockLandscape; |
| 251 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary")) | 268 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary")) |
| 252 return blink::WebScreenOrientationLockLandscapePrimary; | 269 return blink::WebScreenOrientationLockLandscapePrimary; |
| 253 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary")) | 270 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary")) |
| 254 return blink::WebScreenOrientationLockLandscapeSecondary; | 271 return blink::WebScreenOrientationLockLandscapeSecondary; |
| 255 else if (LowerCaseEqualsASCII(orientation.string(), "portrait")) | 272 else if (LowerCaseEqualsASCII(orientation.string(), "portrait")) |
| 256 return blink::WebScreenOrientationLockPortrait; | 273 return blink::WebScreenOrientationLockPortrait; |
| 257 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary")) | 274 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary")) |
| 258 return blink::WebScreenOrientationLockPortraitPrimary; | 275 return blink::WebScreenOrientationLockPortraitPrimary; |
| 259 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary")) | 276 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary")) |
| 260 return blink::WebScreenOrientationLockPortraitSecondary; | 277 return blink::WebScreenOrientationLockPortraitSecondary; |
| 261 else { | 278 else { |
| 262 errors_.push_back(GetErrorPrefix() + | 279 errors_.push_back(GetErrorPrefix() + |
| 263 "unknown 'orientation' value ignored."); | 280 "unknown 'orientation' value ignored."); |
| 264 return blink::WebScreenOrientationLockDefault; | 281 return blink::WebScreenOrientationLockDefault; |
| 265 } | 282 } |
| 266 } | 283 } |
| 267 | 284 |
| 268 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) { | 285 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) { |
| 269 return ParseURL(icon, "src", manifest_url_); | 286 const std::string key = "src"; |
| 287 const base::Value* value; |
| 288 |
| 289 if (!icon.Get(key, &value)) |
| 290 return GURL(); |
| 291 return ParseURL(key, *value, manifest_url_); |
| 270 } | 292 } |
| 271 | 293 |
| 272 base::NullableString16 ManifestParser::ParseIconType( | 294 base::NullableString16 ManifestParser::ParseIconType( |
| 273 const base::DictionaryValue& icon) { | 295 const base::DictionaryValue& icon) { |
| 274 return ParseString(icon, "type", Trim); | 296 const std::string key = "type"; |
| 297 const base::Value* value; |
| 298 |
| 299 if (!icon.Get(key, &value)) |
| 300 return base::NullableString16(); |
| 301 return ParseString(key, *value, Trim); |
| 275 } | 302 } |
| 276 | 303 |
| 277 double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) { | 304 double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) { |
| 278 double density; | 305 double density; |
| 279 if (!icon.HasKey("density")) | 306 if (!icon.HasKey("density")) |
| 280 return Manifest::Icon::kDefaultDensity; | 307 return Manifest::Icon::kDefaultDensity; |
| 281 | 308 |
| 282 if (!icon.GetDouble("density", &density) || density <= 0) { | 309 if (!icon.GetDouble("density", &density) || density <= 0) { |
| 283 errors_.push_back(GetErrorPrefix() + | 310 errors_.push_back(GetErrorPrefix() + |
| 284 "icon 'density' ignored, must be float greater than 0."); | 311 "icon 'density' ignored, must be float greater than 0."); |
| 285 return Manifest::Icon::kDefaultDensity; | 312 return Manifest::Icon::kDefaultDensity; |
| 286 } | 313 } |
| 287 return density; | 314 return density; |
| 288 } | 315 } |
| 289 | 316 |
| 290 std::vector<gfx::Size> ManifestParser::ParseIconSizes( | 317 std::vector<gfx::Size> ManifestParser::ParseIconSizes( |
| 291 const base::DictionaryValue& icon) { | 318 const base::DictionaryValue& icon) { |
| 292 base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); | 319 const std::string key = "sizes"; |
| 320 const base::Value* value; |
| 293 | 321 |
| 322 if (!icon.Get(key, &value)) |
| 323 return std::vector<gfx::Size>(); |
| 324 |
| 325 base::NullableString16 sizes_str = ParseString(key, *value, NoTrim); |
| 294 if (sizes_str.is_null()) | 326 if (sizes_str.is_null()) |
| 295 return std::vector<gfx::Size>(); | 327 return std::vector<gfx::Size>(); |
| 296 | 328 |
| 297 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); | 329 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); |
| 298 if (sizes.empty()) { | 330 if (sizes.empty()) { |
| 299 errors_.push_back(GetErrorPrefix() + "found icon with no valid size."); | 331 errors_.push_back(GetErrorPrefix() + "found icon with no valid size."); |
| 300 } | 332 } |
| 301 return sizes; | 333 return sizes; |
| 302 } | 334 } |
| 303 | 335 |
| 304 std::vector<Manifest::Icon> ManifestParser::ParseIcons( | 336 std::vector<Manifest::Icon> ManifestParser::ParseIcons( |
| 305 const base::DictionaryValue& dictionary) { | 337 const std::string& key, const base::Value& value) { |
| 306 std::vector<Manifest::Icon> icons; | 338 std::vector<Manifest::Icon> icons; |
| 307 if (!dictionary.HasKey("icons")) | |
| 308 return icons; | |
| 309 | 339 |
| 310 const base::ListValue* icons_list = nullptr; | 340 const base::ListValue* icons_list = nullptr; |
| 311 if (!dictionary.GetList("icons", &icons_list)) { | 341 if (!value.GetAsList(&icons_list)) { |
| 312 errors_.push_back(GetErrorPrefix() + | 342 errors_.push_back(GetErrorPrefix() + |
| 313 "property 'icons' ignored, type array expected."); | 343 "property 'icons' ignored, type array expected."); |
| 314 return icons; | 344 return icons; |
| 315 } | 345 } |
| 316 | 346 |
| 317 for (size_t i = 0; i < icons_list->GetSize(); ++i) { | 347 for (size_t i = 0; i < icons_list->GetSize(); ++i) { |
| 318 const base::DictionaryValue* icon_dictionary = nullptr; | 348 const base::DictionaryValue* icon_dictionary = nullptr; |
| 319 if (!icons_list->GetDictionary(i, &icon_dictionary)) | 349 if (!icons_list->GetDictionary(i, &icon_dictionary)) |
| 320 continue; | 350 continue; |
| 321 | 351 |
| 322 Manifest::Icon icon; | 352 Manifest::Icon icon; |
| 323 icon.src = ParseIconSrc(*icon_dictionary); | 353 icon.src = ParseIconSrc(*icon_dictionary); |
| 324 // An icon MUST have a valid src. If it does not, it MUST be ignored. | 354 // An icon MUST have a valid src. If it does not, it MUST be ignored. |
| 325 if (!icon.src.is_valid()) | 355 if (!icon.src.is_valid()) |
| 326 continue; | 356 continue; |
| 327 icon.type = ParseIconType(*icon_dictionary); | 357 icon.type = ParseIconType(*icon_dictionary); |
| 328 icon.density = ParseIconDensity(*icon_dictionary); | 358 icon.density = ParseIconDensity(*icon_dictionary); |
| 329 icon.sizes = ParseIconSizes(*icon_dictionary); | 359 icon.sizes = ParseIconSizes(*icon_dictionary); |
| 330 | 360 |
| 331 icons.push_back(icon); | 361 icons.push_back(icon); |
| 332 } | 362 } |
| 333 | 363 |
| 334 return icons; | 364 return icons; |
| 335 } | 365 } |
| 336 | 366 |
| 337 base::NullableString16 ManifestParser::ParseGCMSenderID( | |
| 338 const base::DictionaryValue& dictionary) { | |
| 339 return ParseString(dictionary, "gcm_sender_id", Trim); | |
| 340 } | |
| 341 | |
| 342 bool ManifestParser::ParseGCMUserVisibleOnly( | |
| 343 const base::DictionaryValue& dictionary) { | |
| 344 return ParseBoolean(dictionary, "gcm_user_visible_only", false); | |
| 345 } | |
| 346 | |
| 347 } // namespace content | 367 } // namespace content |
| OLD | NEW |