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