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 23using content::BrowserThread; 24using extensions::Extension; 25 26// Maps scale factors (enum values) to file path. 27// A similar typedef in BrowserThemePack is private. 28typedef 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. 32typedef std::map<int, TestScaleFactorToFileMap> TestFilePathMap; 33 34class 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 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO)); 244 245 // Make sure we don't have phantom data. 246 EXPECT_FALSE(pack->GetColor(ThemeProperties::COLOR_CONTROL_BACKGROUND, 247 &color)); 248 EXPECT_FALSE(pack->GetTint(ThemeProperties::TINT_FRAME, &actual)); 249 } 250 251 void VerifyHiDpiTheme(BrowserThemePack* pack) { 252 // The high DPI theme defines the following images: 253 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME)); 254 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE)); 255 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO)); 256 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE)); 257 EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR)); 258 259 // The high DPI theme does not define the following images: 260 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND)); 261 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND)); 262 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO)); 263 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_V)); 264 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND)); 265 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY)); 266 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY_INACTIVE)); 267 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)); 268 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION)); 269 EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND)); 270 271 // Compare some known pixel colors at know locations for a theme 272 // image where two different PNG files were specified for scales 100% 273 // and 200% respectively. 274 int idr = IDR_THEME_FRAME; 275 gfx::Image image = pack->GetImageNamed(idr); 276 EXPECT_FALSE(image.IsEmpty()); 277 const gfx::ImageSkia* image_skia = image.ToImageSkia(); 278 ASSERT_TRUE(image_skia); 279 // Scale 100%. 280 const gfx::ImageSkiaRep& rep1 = image_skia->GetRepresentation(1.0f); 281 ASSERT_FALSE(rep1.is_null()); 282 EXPECT_EQ(80, rep1.sk_bitmap().width()); 283 EXPECT_EQ(80, rep1.sk_bitmap().height()); 284 rep1.sk_bitmap().lockPixels(); 285 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 4, 4)); 286 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 8, 8)); 287 EXPECT_EQ(SkColorSetRGB( 0, 241, 237), rep1.sk_bitmap().getColor(16, 16)); 288 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(24, 24)); 289 EXPECT_EQ(SkColorSetRGB( 0, 241, 237), rep1.sk_bitmap().getColor(32, 32)); 290 rep1.sk_bitmap().unlockPixels(); 291 // Scale 200%. 292 const gfx::ImageSkiaRep& rep2 = image_skia->GetRepresentation(2.0f); 293 ASSERT_FALSE(rep2.is_null()); 294 EXPECT_EQ(160, rep2.sk_bitmap().width()); 295 EXPECT_EQ(160, rep2.sk_bitmap().height()); 296 rep2.sk_bitmap().lockPixels(); 297 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor( 4, 4)); 298 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor( 8, 8)); 299 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(16, 16)); 300 EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(24, 24)); 301 EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(32, 32)); 302 rep2.sk_bitmap().unlockPixels(); 303 304 // TODO(sschmitz): I plan to remove the following (to the end of the fct) 305 // Reason: this test may be brittle. It depends on details of how we scale 306 // an 100% image to an 200% image. If there's filtering etc, this test would 307 // break. Also High DPI is new, but scaling from 100% to 200% is not new 308 // and need not be tested here. But in the interrim it is useful to verify 309 // that this image was scaled and did not appear in the input. 310 311 // Compare pixel colors and locations for a theme image that had 312 // only one PNG file specified (for scale 100%). The representation 313 // for scale of 200% was computed. 314 idr = IDR_THEME_FRAME_INCOGNITO_INACTIVE; 315 image = pack->GetImageNamed(idr); 316 EXPECT_FALSE(image.IsEmpty()); 317 image_skia = image.ToImageSkia(); 318 ASSERT_TRUE(image_skia); 319 // Scale 100%. 320 const gfx::ImageSkiaRep& rep3 = image_skia->GetRepresentation(1.0f); 321 ASSERT_FALSE(rep3.is_null()); 322 EXPECT_EQ(80, rep3.sk_bitmap().width()); 323 EXPECT_EQ(80, rep3.sk_bitmap().height()); 324 rep3.sk_bitmap().lockPixels(); 325 // We take samples of colors and locations along the diagonal whenever 326 // the color changes. Note these colors are slightly different from 327 // the input PNG file due to input processing. 328 std::vector<std::pair<int, SkColor> > normal; 329 int xy = 0; 330 SkColor color = rep3.sk_bitmap().getColor(xy, xy); 331 normal.push_back(std::make_pair(xy, color)); 332 for (int xy = 0; xy < 40; ++xy) { 333 SkColor next_color = rep3.sk_bitmap().getColor(xy, xy); 334 if (next_color != color) { 335 color = next_color; 336 normal.push_back(std::make_pair(xy, color)); 337 } 338 } 339 EXPECT_EQ(static_cast<size_t>(9), normal.size()); 340 rep3.sk_bitmap().unlockPixels(); 341 // Scale 200%. 342 const gfx::ImageSkiaRep& rep4 = image_skia->GetRepresentation(2.0f); 343 ASSERT_FALSE(rep4.is_null()); 344 EXPECT_EQ(160, rep4.sk_bitmap().width()); 345 EXPECT_EQ(160, rep4.sk_bitmap().height()); 346 rep4.sk_bitmap().lockPixels(); 347 // We expect the same colors and at locations scaled by 2 348 // since this bitmap was scaled by 2. 349 for (size_t i = 0; i < normal.size(); ++i) { 350 int xy = 2 * normal[i].first; 351 SkColor color = normal[i].second; 352 EXPECT_EQ(color, rep4.sk_bitmap().getColor(xy, xy)); 353 } 354 rep4.sk_bitmap().unlockPixels(); 355 } 356 357 base::MessageLoop message_loop; 358 content::TestBrowserThread fake_ui_thread; 359 content::TestBrowserThread fake_file_thread; 360 361 typedef scoped_ptr<ui::test::ScopedSetSupportedScaleFactors> 362 ScopedSetSupportedScaleFactors; 363 ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_; 364 scoped_refptr<BrowserThemePack> theme_pack_; 365}; 366 367 368TEST_F(BrowserThemePackTest, DeriveUnderlineLinkColor) { 369 // If we specify a link color, but don't specify the underline color, the 370 // theme provider should create one. 371 std::string color_json = "{ \"ntp_link\": [128, 128, 128]," 372 " \"ntp_section_link\": [128, 128, 128] }"; 373 LoadColorJSON(color_json); 374 375 std::map<int, SkColor> colors = GetDefaultColorMap(); 376 SkColor link_color = SkColorSetRGB(128, 128, 128); 377 colors[ThemeProperties::COLOR_NTP_LINK] = link_color; 378 colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = 379 BuildThirdOpacity(link_color); 380 colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; 381 colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = 382 BuildThirdOpacity(link_color); 383 384 VerifyColorMap(colors); 385} 386 387TEST_F(BrowserThemePackTest, ProvideUnderlineLinkColor) { 388 // If we specify the underline color, it shouldn't try to generate one. 389 std::string color_json = "{ \"ntp_link\": [128, 128, 128]," 390 " \"ntp_link_underline\": [255, 255, 255]," 391 " \"ntp_section_link\": [128, 128, 128]," 392 " \"ntp_section_link_underline\": [255, 255, 255]" 393 "}"; 394 LoadColorJSON(color_json); 395 396 std::map<int, SkColor> colors = GetDefaultColorMap(); 397 SkColor link_color = SkColorSetRGB(128, 128, 128); 398 SkColor underline_color = SkColorSetRGB(255, 255, 255); 399 colors[ThemeProperties::COLOR_NTP_LINK] = link_color; 400 colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = underline_color; 401 colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; 402 colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = 403 underline_color; 404 405 VerifyColorMap(colors); 406} 407 408TEST_F(BrowserThemePackTest, UseSectionColorAsNTPHeader) { 409 std::string color_json = "{ \"ntp_section\": [190, 190, 190] }"; 410 LoadColorJSON(color_json); 411 412 std::map<int, SkColor> colors = GetDefaultColorMap(); 413 SkColor ntp_color = SkColorSetRGB(190, 190, 190); 414 colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_color; 415 colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_color; 416 VerifyColorMap(colors); 417} 418 419TEST_F(BrowserThemePackTest, ProvideNtpHeaderColor) { 420 std::string color_json = "{ \"ntp_header\": [120, 120, 120], " 421 " \"ntp_section\": [190, 190, 190] }"; 422 LoadColorJSON(color_json); 423 424 std::map<int, SkColor> colors = GetDefaultColorMap(); 425 SkColor ntp_header = SkColorSetRGB(120, 120, 120); 426 SkColor ntp_section = SkColorSetRGB(190, 190, 190); 427 colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_header; 428 colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_section; 429 VerifyColorMap(colors); 430} 431 432TEST_F(BrowserThemePackTest, CanReadTints) { 433 std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }"; 434 LoadTintJSON(tint_json); 435 436 color_utils::HSL expected = { 0.5, 0.5, 0.5 }; 437 color_utils::HSL actual = { -1, -1, -1 }; 438 EXPECT_TRUE(theme_pack_->GetTint( 439 ThemeProperties::TINT_BUTTONS, &actual)); 440 EXPECT_DOUBLE_EQ(expected.h, actual.h); 441 EXPECT_DOUBLE_EQ(expected.s, actual.s); 442 EXPECT_DOUBLE_EQ(expected.l, actual.l); 443} 444 445TEST_F(BrowserThemePackTest, CanReadDisplayProperties) { 446 std::string json = "{ \"ntp_background_alignment\": \"bottom\", " 447 " \"ntp_background_repeat\": \"repeat-x\", " 448 " \"ntp_logo_alternate\": 0 }"; 449 LoadDisplayPropertiesJSON(json); 450 451 int out_val; 452 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 453 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val)); 454 EXPECT_EQ(ThemeProperties::ALIGN_BOTTOM, out_val); 455 456 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 457 ThemeProperties::NTP_BACKGROUND_TILING, &out_val)); 458 EXPECT_EQ(ThemeProperties::REPEAT_X, out_val); 459 460 EXPECT_TRUE(theme_pack_->GetDisplayProperty( 461 ThemeProperties::NTP_LOGO_ALTERNATE, &out_val)); 462 EXPECT_EQ(0, out_val); 463} 464 465TEST_F(BrowserThemePackTest, CanParsePaths) { 466 std::string path_json = "{ \"theme_button_background\": \"one\", " 467 " \"theme_toolbar\": \"two\" }"; 468 TestFilePathMap out_file_paths; 469 ParseImageNamesJSON(path_json, &out_file_paths); 470 471 size_t expected_file_paths = 2u; 472#if defined(USE_ASH) && !defined(OS_CHROMEOS) 473 // On desktop builds with ash, additional theme paths are generated to map to 474 // the special resource ids like IDR_THEME_FRAME_DESKTOP, etc 475 expected_file_paths = 3u; 476#endif 477 EXPECT_EQ(expected_file_paths, out_file_paths.size()); 478 // "12" and "5" are internal constants to BrowserThemePack and are 479 // PRS_THEME_BUTTON_BACKGROUND and PRS_THEME_TOOLBAR, but they are 480 // implementation details that shouldn't be exported. 481 // By default the scale factor is for 100%. 482 EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("one")) == 483 out_file_paths[12][ui::SCALE_FACTOR_100P]); 484 EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("two")) == 485 out_file_paths[5][ui::SCALE_FACTOR_100P]); 486} 487 488TEST_F(BrowserThemePackTest, InvalidPathNames) { 489 std::string path_json = "{ \"wrong\": [1], " 490 " \"theme_button_background\": \"one\", " 491 " \"not_a_thing\": \"blah\" }"; 492 TestFilePathMap out_file_paths; 493 ParseImageNamesJSON(path_json, &out_file_paths); 494 495 // We should have only parsed one valid path out of that mess above. 496 EXPECT_EQ(1u, out_file_paths.size()); 497} 498 499TEST_F(BrowserThemePackTest, InvalidColors) { 500 std::string invalid_color = "{ \"toolbar\": [\"dog\", \"cat\", [12]], " 501 " \"sound\": \"woof\" }"; 502 LoadColorJSON(invalid_color); 503 std::map<int, SkColor> colors = GetDefaultColorMap(); 504 VerifyColorMap(colors); 505} 506 507TEST_F(BrowserThemePackTest, InvalidTints) { 508 std::string invalid_tints = "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], " 509 " \"invalid\": \"entry\" }"; 510 LoadTintJSON(invalid_tints); 511 512 // We shouldn't have a buttons tint, as it was invalid. 513 color_utils::HSL actual = { -1, -1, -1 }; 514 EXPECT_FALSE(theme_pack_->GetTint(ThemeProperties::TINT_BUTTONS, 515 &actual)); 516} 517 518TEST_F(BrowserThemePackTest, InvalidDisplayProperties) { 519 std::string invalid_properties = "{ \"ntp_background_alignment\": [15], " 520 " \"junk\": [15.3] }"; 521 LoadDisplayPropertiesJSON(invalid_properties); 522 523 int out_val; 524 EXPECT_FALSE(theme_pack_->GetDisplayProperty( 525 ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val)); 526} 527 528// These three tests should just not cause a segmentation fault. 529TEST_F(BrowserThemePackTest, NullPaths) { 530 TestFilePathMap out_file_paths; 531 ParseImageNamesDictionary(NULL, &out_file_paths); 532} 533 534TEST_F(BrowserThemePackTest, NullTints) { 535 LoadTintDictionary(NULL); 536} 537 538TEST_F(BrowserThemePackTest, NullColors) { 539 LoadColorDictionary(NULL); 540} 541 542TEST_F(BrowserThemePackTest, NullDisplayProperties) { 543 LoadDisplayPropertiesDictionary(NULL); 544} 545 546TEST_F(BrowserThemePackTest, TestHasCustomImage) { 547 // HasCustomImage should only return true for images that exist in the 548 // extension and not for autogenerated images. 549 std::string images = "{ \"theme_frame\": \"one\" }"; 550 TestFilePathMap out_file_paths; 551 ParseImageNamesJSON(images, &out_file_paths); 552 553 EXPECT_TRUE(theme_pack_->HasCustomImage(IDR_THEME_FRAME)); 554 EXPECT_FALSE(theme_pack_->HasCustomImage(IDR_THEME_FRAME_INCOGNITO)); 555} 556 557TEST_F(BrowserThemePackTest, TestNonExistantImages) { 558 std::string images = "{ \"theme_frame\": \"does_not_exist\" }"; 559 TestFilePathMap out_file_paths; 560 ParseImageNamesJSON(images, &out_file_paths); 561 562 EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths)); 563} 564 565// TODO(erg): This test should actually test more of the built resources from 566// the extension data, but for now, exists so valgrind can test some of the 567// tricky memory stuff that BrowserThemePack does. 568TEST_F(BrowserThemePackTest, CanBuildAndReadPack) { 569 base::ScopedTempDir dir; 570 ASSERT_TRUE(dir.CreateUniqueTempDir()); 571 base::FilePath file = dir.path().AppendASCII("data.pak"); 572 573 // Part 1: Build the pack from an extension. 574 { 575 base::FilePath star_gazing_path = GetStarGazingPath(); 576 scoped_refptr<BrowserThemePack> pack; 577 BuildFromUnpackedExtension(star_gazing_path, pack); 578 ASSERT_TRUE(pack->WriteToDisk(file)); 579 VerifyStarGazing(pack.get()); 580 } 581 582 // Part 2: Try to read back the data pack that we just wrote to disk. 583 { 584 scoped_refptr<BrowserThemePack> pack = 585 BrowserThemePack::BuildFromDataPack( 586 file, "mblmlcbknbnfebdfjnolmcapmdofhmme"); 587 ASSERT_TRUE(pack.get()); 588 VerifyStarGazing(pack.get()); 589 } 590} 591 592TEST_F(BrowserThemePackTest, HiDpiThemeTest) { 593 base::ScopedTempDir dir; 594 ASSERT_TRUE(dir.CreateUniqueTempDir()); 595 base::FilePath file = dir.path().AppendASCII("theme_data.pak"); 596 597 // Part 1: Build the pack from an extension. 598 { 599 base::FilePath hidpi_path = GetHiDpiThemePath(); 600 scoped_refptr<BrowserThemePack> pack; 601 BuildFromUnpackedExtension(hidpi_path, pack); 602 ASSERT_TRUE(pack->WriteToDisk(file)); 603 VerifyHiDpiTheme(pack.get()); 604 } 605 606 // Part 2: Try to read back the data pack that we just wrote to disk. 607 { 608 scoped_refptr<BrowserThemePack> pack = 609 BrowserThemePack::BuildFromDataPack(file, "gllekhaobjnhgeag"); 610 ASSERT_TRUE(pack.get()); 611 VerifyHiDpiTheme(pack.get()); 612 } 613} 614