1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/themes/browser_theme_pack.h" 6 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/json/json_file_value_serializer.h" 9 #include "base/json/json_reader.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/path_service.h" 12 #include "base/values.h" 13 #include "chrome/browser/themes/theme_properties.h" 14 #include "chrome/common/chrome_paths.h" 15 #include "content/public/test/test_browser_thread.h" 16 #include "grit/theme_resources.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "ui/gfx/color_utils.h" 19 #include "ui/gfx/image/image.h" 20 #include "ui/gfx/image/image_skia.h" 21 #include "ui/gfx/image/image_skia_rep.h" 22 23 using content::BrowserThread; 24 using extensions::Extension; 25 26 // Maps scale factors (enum values) to file path. 27 // A similar typedef in BrowserThemePack is private. 28 typedef std::map<ui::ScaleFactor, base::FilePath> TestScaleFactorToFileMap; 29 30 // Maps image ids to maps of scale factors to file paths. 31 // A similar typedef in BrowserThemePack is private. 32 typedef std::map<int, TestScaleFactorToFileMap> TestFilePathMap; 33 34 class BrowserThemePackTest : public ::testing::Test { 35 public: 36 BrowserThemePackTest() 37 : message_loop(), 38 fake_ui_thread(BrowserThread::UI, &message_loop), 39 fake_file_thread(BrowserThread::FILE, &message_loop) { 40 std::vector<ui::ScaleFactor> scale_factors; 41 scale_factors.push_back(ui::SCALE_FACTOR_100P); 42 scale_factors.push_back(ui::SCALE_FACTOR_200P); 43 scoped_set_supported_scale_factors_.reset( 44 new ui::test::ScopedSetSupportedScaleFactors(scale_factors)); 45 theme_pack_ = new BrowserThemePack(); 46 } 47 48 // Transformation for link underline colors. 49 SkColor BuildThirdOpacity(SkColor color_link) { 50 return SkColorSetA(color_link, SkColorGetA(color_link) / 3); 51 } 52 53 void GenerateDefaultFrameColor(std::map<int, SkColor>* colors, 54 int color, int tint) { 55 (*colors)[color] = HSLShift( 56 ThemeProperties::GetDefaultColor( 57 ThemeProperties::COLOR_FRAME), 58 ThemeProperties::GetDefaultTint(tint)); 59 } 60 61 // Returns a mapping from each COLOR_* constant to the default value for this 62 // constant. Callers get this map, and then modify expected values and then 63 // run the resulting thing through VerifyColorMap(). 64 std::map<int, SkColor> GetDefaultColorMap() { 65 std::map<int, SkColor> colors; 66 for (int i = ThemeProperties::COLOR_FRAME; 67 i <= ThemeProperties::COLOR_BUTTON_BACKGROUND; ++i) { 68 colors[i] = ThemeProperties::GetDefaultColor(i); 69 } 70 71 GenerateDefaultFrameColor(&colors, ThemeProperties::COLOR_FRAME, 72 ThemeProperties::TINT_FRAME); 73 GenerateDefaultFrameColor(&colors, 74 ThemeProperties::COLOR_FRAME_INACTIVE, 75 ThemeProperties::TINT_FRAME_INACTIVE); 76 GenerateDefaultFrameColor(&colors, 77 ThemeProperties::COLOR_FRAME_INCOGNITO, 78 ThemeProperties::TINT_FRAME_INCOGNITO); 79 GenerateDefaultFrameColor( 80 &colors, 81 ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE, 82 ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE); 83 84 return colors; 85 } 86 87 void VerifyColorMap(const std::map<int, SkColor>& color_map) { 88 for (std::map<int, SkColor>::const_iterator it = color_map.begin(); 89 it != color_map.end(); ++it) { 90 SkColor color = ThemeProperties::GetDefaultColor(it->first); 91 theme_pack_->GetColor(it->first, &color); 92 EXPECT_EQ(it->second, color) << "Color id = " << it->first; 93 } 94 } 95 96 void LoadColorJSON(const std::string& json) { 97 scoped_ptr<base::Value> value(base::JSONReader::Read(json)); 98 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); 99 LoadColorDictionary(static_cast<base::DictionaryValue*>(value.get())); 100 } 101 102 void LoadColorDictionary(base::DictionaryValue* value) { 103 theme_pack_->BuildColorsFromJSON(value); 104 } 105 106 void LoadTintJSON(const std::string& json) { 107 scoped_ptr<base::Value> value(base::JSONReader::Read(json)); 108 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); 109 LoadTintDictionary(static_cast<base::DictionaryValue*>(value.get())); 110 } 111 112 void LoadTintDictionary(base::DictionaryValue* value) { 113 theme_pack_->BuildTintsFromJSON(value); 114 } 115 116 void LoadDisplayPropertiesJSON(const std::string& json) { 117 scoped_ptr<base::Value> value(base::JSONReader::Read(json)); 118 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); 119 LoadDisplayPropertiesDictionary( 120 static_cast<base::DictionaryValue*>(value.get())); 121 } 122 123 void LoadDisplayPropertiesDictionary(base::DictionaryValue* value) { 124 theme_pack_->BuildDisplayPropertiesFromJSON(value); 125 } 126 127 void ParseImageNamesJSON(const std::string& json, 128 TestFilePathMap* out_file_paths) { 129 scoped_ptr<base::Value> value(base::JSONReader::Read(json)); 130 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); 131 ParseImageNamesDictionary(static_cast<base::DictionaryValue*>(value.get()), 132 out_file_paths); 133 } 134 135 void ParseImageNamesDictionary( 136 base::DictionaryValue* value, 137 TestFilePathMap* out_file_paths) { 138 theme_pack_->ParseImageNamesFromJSON(value, base::FilePath(), 139 out_file_paths); 140 141 // Build the source image list for HasCustomImage(). 142 theme_pack_->BuildSourceImagesArray(*out_file_paths); 143 } 144 145 bool LoadRawBitmapsTo(const TestFilePathMap& out_file_paths) { 146 return theme_pack_->LoadRawBitmapsTo(out_file_paths, 147 &theme_pack_->images_on_ui_thread_); 148 } 149 150 // This function returns void in order to be able use ASSERT_... 151 // The BrowserThemePack is returned in |pack|. 152 void BuildFromUnpackedExtension(const base::FilePath& extension_path, 153 scoped_refptr<BrowserThemePack>& pack) { 154 base::FilePath manifest_path = 155 extension_path.AppendASCII("manifest.json"); 156 std::string error; 157 JSONFileValueSerializer serializer(manifest_path); 158 scoped_ptr<base::DictionaryValue> valid_value( 159 static_cast<base::DictionaryValue*>( 160 serializer.Deserialize(NULL, &error))); 161 EXPECT_EQ("", error); 162 ASSERT_TRUE(valid_value.get()); 163 scoped_refptr<Extension> extension( 164 Extension::Create( 165 extension_path, 166 extensions::Manifest::INVALID_LOCATION, 167 *valid_value, 168 Extension::REQUIRE_KEY, 169 &error)); 170 ASSERT_TRUE(extension.get()); 171 ASSERT_EQ("", error); 172 pack = BrowserThemePack::BuildFromExtension(extension.get()); 173 ASSERT_TRUE(pack.get()); 174 } 175 176 base::FilePath GetStarGazingPath() { 177 base::FilePath test_path; 178 if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) { 179 NOTREACHED(); 180 return test_path; 181 } 182 183 test_path = test_path.AppendASCII("profiles"); 184 test_path = test_path.AppendASCII("profile_with_complex_theme"); 185 test_path = test_path.AppendASCII("Default"); 186 test_path = test_path.AppendASCII("Extensions"); 187 test_path = test_path.AppendASCII("mblmlcbknbnfebdfjnolmcapmdofhmme"); 188 test_path = test_path.AppendASCII("1.1"); 189 return base::FilePath(test_path); 190 } 191 192 base::FilePath GetHiDpiThemePath() { 193 base::FilePath test_path; 194 if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) { 195 NOTREACHED(); 196 return test_path; 197 } 198 test_path = test_path.AppendASCII("extensions"); 199 test_path = test_path.AppendASCII("theme_hidpi"); 200 return base::FilePath(test_path); 201 } 202 203 // Verifies the data in star gazing. We do this multiple times for different 204 // BrowserThemePack objects to make sure it works in generated and mmapped 205 // mode correctly. 206 void VerifyStarGazing(BrowserThemePack* pack) { 207 // First check that values we know exist, exist. 208 SkColor color; 209 EXPECT_TRUE(pack->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, 210 &color)); 211 EXPECT_EQ(SK_ColorBLACK, color); 212 213 EXPECT_TRUE(pack->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND, 214 &color)); 215 EXPECT_EQ(SkColorSetRGB(57, 137, 194), color); 216 217 color_utils::HSL expected = { 0.6, 0.553, 0.5 }; 218 color_utils::HSL actual; 219 EXPECT_TRUE(pack->GetTint(ThemeProperties::TINT_BUTTONS, &actual)); 220 EXPECT_DOUBLE_EQ(expected.h, actual.h); 221 EXPECT_DOUBLE_EQ(expected.s, actual.s); 222 EXPECT_DOUBLE_EQ(expected.l, actual.l); 223 224 int val; 225 EXPECT_TRUE(pack->GetDisplayProperty( 226 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &val)); 227 EXPECT_EQ(ThemeProperties::ALIGN_TOP, val); 228 229 // The stargazing theme defines the following images: 230 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)); 231 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME)); 232 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND)); 233 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND)); 234 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR)); 235 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND)); 236 237 // Here are a few images that we shouldn't expect because even though 238 // they're included in the theme pack, they were autogenerated and 239 // therefore shouldn't show up when calling HasCustomImage(). 240 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE)); 241 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO)); 242 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE)); 243 #if !defined(OS_MACOSX) 244 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO)); 245 #endif 246 247 // Make sure we don't have phantom data. 248 EXPECT_FALSE(pack->GetColor(ThemeProperties::COLOR_CONTROL_BACKGROUND, 249 &color)); 250 EXPECT_FALSE(pack->GetTint(ThemeProperties::TINT_FRAME, &actual)); 251 } 252 253 void VerifyHiDpiTheme(BrowserThemePack* pack) { 254 // The high DPI theme defines the following images: 255 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME)); 256 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE)); 257 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO)); 258 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE)); 259 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR)); 260 261 // The high DPI theme does not define the following images: 262 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND)); 263 #if !defined(OS_MACOSX) 264 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO)); 265 #endif 266 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_V)); 267 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND)); 268 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY)); 269 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY_INACTIVE)); 270 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)); 271 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION)); 272 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND)); 273 274 // Compare some known pixel colors at know locations for a theme 275 // image where two different PNG files were specified for scales 100% 276 // and 200% respectively. 277 int idr = IDR_THEME_FRAME; 278 gfx::Image image = pack->GetImageNamed(idr); 279 EXPECT_FALSE(image.IsEmpty()); 280 const gfx::ImageSkia* image_skia = image.ToImageSkia(); 281 ASSERT_TRUE(image_skia); 282 // Scale 100%. 283 const gfx::ImageSkiaRep& rep1 = image_skia->GetRepresentation(1.0f); 284 ASSERT_FALSE(rep1.is_null()); 285 EXPECT_EQ(80, rep1.sk_bitmap().width()); 286 EXPECT_EQ(80, rep1.sk_bitmap().height()); 287 rep1.sk_bitmap().lockPixels(); 288 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 4, 4)); 289 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 8, 8)); 290 EXPECT_EQ(SkColorSetRGB( 0, 241, 237), rep1.sk_bitmap().getColor(16, 16)); 291 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(24, 24)); 292 EXPECT_EQ(SkColorSetRGB( 0, 241, 237), rep1.sk_bitmap().getColor(32, 32)); 293 rep1.sk_bitmap().unlockPixels(); 294 // Scale 200%. 295 const gfx::ImageSkiaRep& rep2 = image_skia->GetRepresentation(2.0f); 296 ASSERT_FALSE(rep2.is_null()); 297 EXPECT_EQ(160, rep2.sk_bitmap().width()); 298 EXPECT_EQ(160, rep2.sk_bitmap().height()); 299 rep2.sk_bitmap().lockPixels(); 300 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor( 4, 4)); 301 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor( 8, 8)); 302 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(16, 16)); 303 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(24, 24)); 304 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(32, 32)); 305 rep2.sk_bitmap().unlockPixels(); 306 307 // TODO(sschmitz): I plan to remove the following (to the end of the fct) 308 // Reason: this test may be brittle. It depends on details of how we scale 309 // an 100% image to an 200% image. If there's filtering etc, this test would 310 // break. Also High DPI is new, but scaling from 100% to 200% is not new 311 // and need not be tested here. But in the interrim it is useful to verify 312 // that this image was scaled and did not appear in the input. 313 314 // Compare pixel colors and locations for a theme image that had 315 // only one PNG file specified (for scale 100%). The representation 316 // for scale of 200% was computed. 317 idr = IDR_THEME_FRAME_INCOGNITO_INACTIVE; 318 image = pack->GetImageNamed(idr); 319 EXPECT_FALSE(image.IsEmpty()); 320 image_skia = image.ToImageSkia(); 321 ASSERT_TRUE(image_skia); 322 // Scale 100%. 323 const gfx::ImageSkiaRep& rep3 = image_skia->GetRepresentation(1.0f); 324 ASSERT_FALSE(rep3.is_null()); 325 EXPECT_EQ(80, rep3.sk_bitmap().width()); 326 EXPECT_EQ(80, rep3.sk_bitmap().height()); 327 rep3.sk_bitmap().lockPixels(); 328 // We take samples of colors and locations along the diagonal whenever 329 // the color changes. Note these colors are slightly different from 330 // the input PNG file due to input processing. 331 std::vector<std::pair<int, SkColor> > normal; 332 int xy = 0; 333 SkColor color = rep3.sk_bitmap().getColor(xy, xy); 334 normal.push_back(std::make_pair(xy, color)); 335 for (int xy = 0; xy < 40; ++xy) { 336 SkColor next_color = rep3.sk_bitmap().getColor(xy, xy); 337 if (next_color != color) { 338 color = next_color; 339 normal.push_back(std::make_pair(xy, color)); 340 } 341 } 342 EXPECT_EQ(static_cast<size_t>(9), normal.size()); 343 rep3.sk_bitmap().unlockPixels(); 344 // Scale 200%. 345 const gfx::ImageSkiaRep& rep4 = image_skia->GetRepresentation(2.0f); 346 ASSERT_FALSE(rep4.is_null()); 347 EXPECT_EQ(160, rep4.sk_bitmap().width()); 348 EXPECT_EQ(160, rep4.sk_bitmap().height()); 349 rep4.sk_bitmap().lockPixels(); 350 // We expect the same colors and at locations scaled by 2 351 // since this bitmap was scaled by 2. 352 for (size_t i = 0; i < normal.size(); ++i) { 353 int xy = 2 * normal[i].first; 354 SkColor color = normal[i].second; 355 EXPECT_EQ(color, rep4.sk_bitmap().getColor(xy, xy)); 356 } 357 rep4.sk_bitmap().unlockPixels(); 358 } 359 360 base::MessageLoop message_loop; 361 content::TestBrowserThread fake_ui_thread; 362 content::TestBrowserThread fake_file_thread; 363 364 typedef scoped_ptr<ui::test::ScopedSetSupportedScaleFactors> 365 ScopedSetSupportedScaleFactors; 366 ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_; 367 scoped_refptr<BrowserThemePack> theme_pack_; 368 }; 369 370 371 TEST_F(BrowserThemePackTest, DeriveUnderlineLinkColor) { 372 // If we specify a link color, but don't specify the underline color, the 373 // theme provider should create one. 374 std::string color_json = "{ \"ntp_link\": [128, 128, 128]," 375 " \"ntp_section_link\": [128, 128, 128] }"; 376 LoadColorJSON(color_json); 377 378 std::map<int, SkColor> colors = GetDefaultColorMap(); 379 SkColor link_color = SkColorSetRGB(128, 128, 128); 380 colors[ThemeProperties::COLOR_NTP_LINK] = link_color; 381 colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = 382 BuildThirdOpacity(link_color); 383 colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; 384 colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = 385 BuildThirdOpacity(link_color); 386 387 VerifyColorMap(colors); 388 } 389 390 TEST_F(BrowserThemePackTest, ProvideUnderlineLinkColor) { 391 // If we specify the underline color, it shouldn't try to generate one. 392 std::string color_json = "{ \"ntp_link\": [128, 128, 128]," 393 " \"ntp_link_underline\": [255, 255, 255]," 394 " \"ntp_section_link\": [128, 128, 128]," 395 " \"ntp_section_link_underline\": [255, 255, 255]" 396 "}"; 397 LoadColorJSON(color_json); 398 399 std::map<int, SkColor> colors = GetDefaultColorMap(); 400 SkColor link_color = SkColorSetRGB(128, 128, 128); 401 SkColor underline_color = SkColorSetRGB(255, 255, 255); 402 colors[ThemeProperties::COLOR_NTP_LINK] = link_color; 403 colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = underline_color; 404 colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; 405 colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = 406 underline_color; 407 408 VerifyColorMap(colors); 409 } 410 411 TEST_F(BrowserThemePackTest, UseSectionColorAsNTPHeader) { 412 std::string color_json = "{ \"ntp_section\": [190, 190, 190] }"; 413 LoadColorJSON(color_json); 414 415 std::map<int, SkColor> colors = GetDefaultColorMap(); 416 SkColor ntp_color = SkColorSetRGB(190, 190, 190); 417 colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_color; 418 colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_color; 419 VerifyColorMap(colors); 420 } 421 422 TEST_F(BrowserThemePackTest, ProvideNtpHeaderColor) { 423 std::string color_json = "{ \"ntp_header\": [120, 120, 120], " 424 " \"ntp_section\": [190, 190, 190] }"; 425 LoadColorJSON(color_json); 426 427 std::map<int, SkColor> colors = GetDefaultColorMap(); 428 SkColor ntp_header = SkColorSetRGB(120, 120, 120); 429 SkColor ntp_section = SkColorSetRGB(190, 190, 190); 430 colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_header; 431 colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_section; 432 VerifyColorMap(colors); 433 } 434 435 TEST_F(BrowserThemePackTest, CanReadTints) { 436 std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }"; 437 LoadTintJSON(tint_json); 438 439 color_utils::HSL expected = { 0.5, 0.5, 0.5 }; 440 color_utils::HSL actual = { -1, -1, -1 }; 441 EXPECT_TRUE(theme_pack_->GetTint( 442 ThemeProperties::TINT_BUTTONS, &actual)); 443 EXPECT_DOUBLE_EQ(expected.h, actual.h); 444 EXPECT_DOUBLE_EQ(expected.s, actual.s); 445 EXPECT_DOUBLE_EQ(expected.l, actual.l); 446 } 447 448 TEST_F(BrowserThemePackTest, CanReadDisplayProperties) { 449 std::string json = "{ \"ntp_background_alignment\": \"bottom\", " 450 " \"ntp_background_repeat\": \"repeat-x\", " 451 " \"ntp_logo_alternate\": 0 }"; 452 LoadDisplayPropertiesJSON(json); 453 454 int out_val; 455 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 456 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val)); 457 EXPECT_EQ(ThemeProperties::ALIGN_BOTTOM, out_val); 458 459 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 460 ThemeProperties::NTP_BACKGROUND_TILING, &out_val)); 461 EXPECT_EQ(ThemeProperties::REPEAT_X, out_val); 462 463 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 464 ThemeProperties::NTP_LOGO_ALTERNATE, &out_val)); 465 EXPECT_EQ(0, out_val); 466 } 467 468 TEST_F(BrowserThemePackTest, CanParsePaths) { 469 std::string path_json = "{ \"theme_button_background\": \"one\", " 470 " \"theme_toolbar\": \"two\" }"; 471 TestFilePathMap out_file_paths; 472 ParseImageNamesJSON(path_json, &out_file_paths); 473 474 size_t expected_file_paths = 2u; 475 #if defined(USE_ASH) && !defined(OS_CHROMEOS) 476 // On desktop builds with ash, additional theme paths are generated to map to 477 // the special resource ids like IDR_THEME_FRAME_DESKTOP, etc 478 expected_file_paths = 3u; 479 #endif 480 EXPECT_EQ(expected_file_paths, out_file_paths.size()); 481 // "12" and "5" are internal constants to BrowserThemePack and are 482 // PRS_THEME_BUTTON_BACKGROUND and PRS_THEME_TOOLBAR, but they are 483 // implementation details that shouldn't be exported. 484 // By default the scale factor is for 100%. 485 EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("one")) == 486 out_file_paths[12][ui::SCALE_FACTOR_100P]); 487 EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("two")) == 488 out_file_paths[5][ui::SCALE_FACTOR_100P]); 489 } 490 491 TEST_F(BrowserThemePackTest, InvalidPathNames) { 492 std::string path_json = "{ \"wrong\": [1], " 493 " \"theme_button_background\": \"one\", " 494 " \"not_a_thing\": \"blah\" }"; 495 TestFilePathMap out_file_paths; 496 ParseImageNamesJSON(path_json, &out_file_paths); 497 498 // We should have only parsed one valid path out of that mess above. 499 EXPECT_EQ(1u, out_file_paths.size()); 500 } 501 502 TEST_F(BrowserThemePackTest, InvalidColors) { 503 std::string invalid_color = "{ \"toolbar\": [\"dog\", \"cat\", [12]], " 504 " \"sound\": \"woof\" }"; 505 LoadColorJSON(invalid_color); 506 std::map<int, SkColor> colors = GetDefaultColorMap(); 507 VerifyColorMap(colors); 508 } 509 510 TEST_F(BrowserThemePackTest, InvalidTints) { 511 std::string invalid_tints = "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], " 512 " \"invalid\": \"entry\" }"; 513 LoadTintJSON(invalid_tints); 514 515 // We shouldn't have a buttons tint, as it was invalid. 516 color_utils::HSL actual = { -1, -1, -1 }; 517 EXPECT_FALSE(theme_pack_->GetTint(ThemeProperties::TINT_BUTTONS, 518 &actual)); 519 } 520 521 TEST_F(BrowserThemePackTest, InvalidDisplayProperties) { 522 std::string invalid_properties = "{ \"ntp_background_alignment\": [15], " 523 " \"junk\": [15.3] }"; 524 LoadDisplayPropertiesJSON(invalid_properties); 525 526 int out_val; 527 EXPECT_FALSE(theme_pack_->GetDisplayProperty( 528 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val)); 529 } 530 531 // These three tests should just not cause a segmentation fault. 532 TEST_F(BrowserThemePackTest, NullPaths) { 533 TestFilePathMap out_file_paths; 534 ParseImageNamesDictionary(NULL, &out_file_paths); 535 } 536 537 TEST_F(BrowserThemePackTest, NullTints) { 538 LoadTintDictionary(NULL); 539 } 540 541 TEST_F(BrowserThemePackTest, NullColors) { 542 LoadColorDictionary(NULL); 543 } 544 545 TEST_F(BrowserThemePackTest, NullDisplayProperties) { 546 LoadDisplayPropertiesDictionary(NULL); 547 } 548 549 TEST_F(BrowserThemePackTest, TestHasCustomImage) { 550 // HasCustomImage should only return true for images that exist in the 551 // extension and not for autogenerated images. 552 std::string images = "{ \"theme_frame\": \"one\" }"; 553 TestFilePathMap out_file_paths; 554 ParseImageNamesJSON(images, &out_file_paths); 555 556 EXPECT_TRUE(theme_pack_->HasCustomImage(IDR_THEME_FRAME)); 557 EXPECT_FALSE(theme_pack_->HasCustomImage(IDR_THEME_FRAME_INCOGNITO)); 558 } 559 560 TEST_F(BrowserThemePackTest, TestNonExistantImages) { 561 std::string images = "{ \"theme_frame\": \"does_not_exist\" }"; 562 TestFilePathMap out_file_paths; 563 ParseImageNamesJSON(images, &out_file_paths); 564 565 EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths)); 566 } 567 568 // TODO(erg): This test should actually test more of the built resources from 569 // the extension data, but for now, exists so valgrind can test some of the 570 // tricky memory stuff that BrowserThemePack does. 571 TEST_F(BrowserThemePackTest, CanBuildAndReadPack) { 572 base::ScopedTempDir dir; 573 ASSERT_TRUE(dir.CreateUniqueTempDir()); 574 base::FilePath file = dir.path().AppendASCII("data.pak"); 575 576 // Part 1: Build the pack from an extension. 577 { 578 base::FilePath star_gazing_path = GetStarGazingPath(); 579 scoped_refptr<BrowserThemePack> pack; 580 BuildFromUnpackedExtension(star_gazing_path, pack); 581 ASSERT_TRUE(pack->WriteToDisk(file)); 582 VerifyStarGazing(pack.get()); 583 } 584 585 // Part 2: Try to read back the data pack that we just wrote to disk. 586 { 587 scoped_refptr<BrowserThemePack> pack = 588 BrowserThemePack::BuildFromDataPack( 589 file, "mblmlcbknbnfebdfjnolmcapmdofhmme"); 590 ASSERT_TRUE(pack.get()); 591 VerifyStarGazing(pack.get()); 592 } 593 } 594 595 TEST_F(BrowserThemePackTest, HiDpiThemeTest) { 596 base::ScopedTempDir dir; 597 ASSERT_TRUE(dir.CreateUniqueTempDir()); 598 base::FilePath file = dir.path().AppendASCII("theme_data.pak"); 599 600 // Part 1: Build the pack from an extension. 601 { 602 base::FilePath hidpi_path = GetHiDpiThemePath(); 603 scoped_refptr<BrowserThemePack> pack; 604 BuildFromUnpackedExtension(hidpi_path, pack); 605 ASSERT_TRUE(pack->WriteToDisk(file)); 606 VerifyHiDpiTheme(pack.get()); 607 } 608 609 // Part 2: Try to read back the data pack that we just wrote to disk. 610 { 611 scoped_refptr<BrowserThemePack> pack = 612 BrowserThemePack::BuildFromDataPack(file, "gllekhaobjnhgeag"); 613 ASSERT_TRUE(pack.get()); 614 VerifyHiDpiTheme(pack.get()); 615 } 616 } 617