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.
5 #include "chrome/browser/themes/browser_theme_pack.h"
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"
23 using content::BrowserThread
;
24 using extensions::Extension
;
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
;
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
;
34 class BrowserThemePackTest
: public ::testing::Test
{
36 BrowserThemePackTest()
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();
48 // Transformation for link underline colors.
49 SkColor
BuildThirdOpacity(SkColor color_link
) {
50 return SkColorSetA(color_link
, SkColorGetA(color_link
) / 3);
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
));
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
);
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(
81 ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE
,
82 ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE
);
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
;
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()));
102 void LoadColorDictionary(base::DictionaryValue
* value
) {
103 theme_pack_
->BuildColorsFromJSON(value
);
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()));
112 void LoadTintDictionary(base::DictionaryValue
* value
) {
113 theme_pack_
->BuildTintsFromJSON(value
);
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()));
123 void LoadDisplayPropertiesDictionary(base::DictionaryValue
* value
) {
124 theme_pack_
->BuildDisplayPropertiesFromJSON(value
);
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()),
135 void ParseImageNamesDictionary(
136 base::DictionaryValue
* value
,
137 TestFilePathMap
* out_file_paths
) {
138 theme_pack_
->ParseImageNamesFromJSON(value
, base::FilePath(),
141 // Build the source image list for HasCustomImage().
142 theme_pack_
->BuildSourceImagesArray(*out_file_paths
);
145 bool LoadRawBitmapsTo(const TestFilePathMap
& out_file_paths
) {
146 return theme_pack_
->LoadRawBitmapsTo(out_file_paths
,
147 &theme_pack_
->images_on_ui_thread_
);
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");
157 JSONFileValueDeserializer
deserializer(manifest_path
);
158 scoped_ptr
<base::DictionaryValue
> valid_value(
159 static_cast<base::DictionaryValue
*>(
160 deserializer
.Deserialize(NULL
, &error
)));
161 EXPECT_EQ("", error
);
162 ASSERT_TRUE(valid_value
.get());
163 scoped_refptr
<Extension
> extension(
166 extensions::Manifest::INVALID_LOCATION
,
168 Extension::REQUIRE_KEY
,
170 ASSERT_TRUE(extension
.get());
171 ASSERT_EQ("", error
);
172 pack
= BrowserThemePack::BuildFromExtension(extension
.get());
173 ASSERT_TRUE(pack
.get());
176 base::FilePath
GetStarGazingPath() {
177 base::FilePath test_path
;
178 if (!PathService::Get(chrome::DIR_TEST_DATA
, &test_path
)) {
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
);
192 base::FilePath
GetHiDpiThemePath() {
193 base::FilePath test_path
;
194 if (!PathService::Get(chrome::DIR_TEST_DATA
, &test_path
)) {
198 test_path
= test_path
.AppendASCII("extensions");
199 test_path
= test_path
.AppendASCII("theme_hidpi");
200 return base::FilePath(test_path
);
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
206 void VerifyStarGazing(BrowserThemePack
* pack
) {
207 // First check that values we know exist, exist.
209 EXPECT_TRUE(pack
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
,
211 EXPECT_EQ(SK_ColorBLACK
, color
);
213 EXPECT_TRUE(pack
->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND
,
215 EXPECT_EQ(SkColorSetRGB(57, 137, 194), color
);
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
);
225 EXPECT_TRUE(pack
->GetDisplayProperty(
226 ThemeProperties::NTP_BACKGROUND_ALIGNMENT
, &val
));
227 EXPECT_EQ(ThemeProperties::ALIGN_TOP
, val
);
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
));
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
));
247 // Make sure we don't have phantom data.
248 EXPECT_FALSE(pack
->GetColor(ThemeProperties::COLOR_CONTROL_BACKGROUND
,
250 EXPECT_FALSE(pack
->GetTint(ThemeProperties::TINT_FRAME
, &actual
));
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
));
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
));
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
));
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
);
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();
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();
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.
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
);
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
;
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
) {
339 normal
.push_back(std::make_pair(xy
, color
));
342 EXPECT_EQ(static_cast<size_t>(9), normal
.size());
343 rep3
.sk_bitmap().unlockPixels();
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
));
357 rep4
.sk_bitmap().unlockPixels();
360 base::MessageLoop message_loop
;
361 content::TestBrowserThread fake_ui_thread
;
362 content::TestBrowserThread fake_file_thread
;
364 typedef scoped_ptr
<ui::test::ScopedSetSupportedScaleFactors
>
365 ScopedSetSupportedScaleFactors
;
366 ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_
;
367 scoped_refptr
<BrowserThemePack
> theme_pack_
;
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
);
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
);
387 VerifyColorMap(colors
);
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]"
397 LoadColorJSON(color_json
);
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
] =
408 VerifyColorMap(colors
);
411 TEST_F(BrowserThemePackTest
, UseSectionColorAsNTPHeader
) {
412 std::string color_json
= "{ \"ntp_section\": [190, 190, 190] }";
413 LoadColorJSON(color_json
);
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
);
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
);
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
);
435 TEST_F(BrowserThemePackTest
, CanReadTints
) {
436 std::string tint_json
= "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }";
437 LoadTintJSON(tint_json
);
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
);
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
);
455 EXPECT_TRUE(theme_pack_
->GetDisplayProperty(
456 ThemeProperties::NTP_BACKGROUND_ALIGNMENT
, &out_val
));
457 EXPECT_EQ(ThemeProperties::ALIGN_BOTTOM
, out_val
);
459 EXPECT_TRUE(theme_pack_
->GetDisplayProperty(
460 ThemeProperties::NTP_BACKGROUND_TILING
, &out_val
));
461 EXPECT_EQ(ThemeProperties::REPEAT_X
, out_val
);
463 EXPECT_TRUE(theme_pack_
->GetDisplayProperty(
464 ThemeProperties::NTP_LOGO_ALTERNATE
, &out_val
));
465 EXPECT_EQ(0, out_val
);
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
);
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;
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
]);
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
);
498 // We should have only parsed one valid path out of that mess above.
499 EXPECT_EQ(1u, out_file_paths
.size());
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
);
510 TEST_F(BrowserThemePackTest
, InvalidTints
) {
511 std::string tints
= "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], "
512 " \"frame\": [-2, 2, 3],"
513 " \"frame_incognito_inactive\": [-1, 2, 0.6],"
514 " \"invalid\": \"entry\" }";
517 // We should ignore completely invalid (non-numeric) tints.
518 color_utils::HSL actual
= { -1, -1, -1 };
519 EXPECT_FALSE(theme_pack_
->GetTint(ThemeProperties::TINT_BUTTONS
, &actual
));
521 // We should change invalid numeric HSL tint components to the special -1 "no
523 EXPECT_TRUE(theme_pack_
->GetTint(ThemeProperties::TINT_FRAME
, &actual
));
524 EXPECT_EQ(-1, actual
.h
);
525 EXPECT_EQ(-1, actual
.s
);
526 EXPECT_EQ(-1, actual
.l
);
528 // We should correct partially incorrect inputs as well.
529 EXPECT_TRUE(theme_pack_
->GetTint(
530 ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE
, &actual
));
531 EXPECT_EQ(-1, actual
.h
);
532 EXPECT_EQ(-1, actual
.s
);
533 EXPECT_EQ(0.6, actual
.l
);
536 TEST_F(BrowserThemePackTest
, InvalidDisplayProperties
) {
537 std::string invalid_properties
= "{ \"ntp_background_alignment\": [15], "
538 " \"junk\": [15.3] }";
539 LoadDisplayPropertiesJSON(invalid_properties
);
542 EXPECT_FALSE(theme_pack_
->GetDisplayProperty(
543 ThemeProperties::NTP_BACKGROUND_ALIGNMENT
, &out_val
));
546 // These three tests should just not cause a segmentation fault.
547 TEST_F(BrowserThemePackTest
, NullPaths
) {
548 TestFilePathMap out_file_paths
;
549 ParseImageNamesDictionary(NULL
, &out_file_paths
);
552 TEST_F(BrowserThemePackTest
, NullTints
) {
553 LoadTintDictionary(NULL
);
556 TEST_F(BrowserThemePackTest
, NullColors
) {
557 LoadColorDictionary(NULL
);
560 TEST_F(BrowserThemePackTest
, NullDisplayProperties
) {
561 LoadDisplayPropertiesDictionary(NULL
);
564 TEST_F(BrowserThemePackTest
, TestHasCustomImage
) {
565 // HasCustomImage should only return true for images that exist in the
566 // extension and not for autogenerated images.
567 std::string images
= "{ \"theme_frame\": \"one\" }";
568 TestFilePathMap out_file_paths
;
569 ParseImageNamesJSON(images
, &out_file_paths
);
571 EXPECT_TRUE(theme_pack_
->HasCustomImage(IDR_THEME_FRAME
));
572 EXPECT_FALSE(theme_pack_
->HasCustomImage(IDR_THEME_FRAME_INCOGNITO
));
575 TEST_F(BrowserThemePackTest
, TestNonExistantImages
) {
576 std::string images
= "{ \"theme_frame\": \"does_not_exist\" }";
577 TestFilePathMap out_file_paths
;
578 ParseImageNamesJSON(images
, &out_file_paths
);
580 EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths
));
583 // TODO(erg): This test should actually test more of the built resources from
584 // the extension data, but for now, exists so valgrind can test some of the
585 // tricky memory stuff that BrowserThemePack does.
586 TEST_F(BrowserThemePackTest
, CanBuildAndReadPack
) {
587 base::ScopedTempDir dir
;
588 ASSERT_TRUE(dir
.CreateUniqueTempDir());
589 base::FilePath file
= dir
.path().AppendASCII("data.pak");
591 // Part 1: Build the pack from an extension.
593 base::FilePath star_gazing_path
= GetStarGazingPath();
594 scoped_refptr
<BrowserThemePack
> pack
;
595 BuildFromUnpackedExtension(star_gazing_path
, pack
);
596 ASSERT_TRUE(pack
->WriteToDisk(file
));
597 VerifyStarGazing(pack
.get());
600 // Part 2: Try to read back the data pack that we just wrote to disk.
602 scoped_refptr
<BrowserThemePack
> pack
=
603 BrowserThemePack::BuildFromDataPack(
604 file
, "mblmlcbknbnfebdfjnolmcapmdofhmme");
605 ASSERT_TRUE(pack
.get());
606 VerifyStarGazing(pack
.get());
610 TEST_F(BrowserThemePackTest
, HiDpiThemeTest
) {
611 base::ScopedTempDir dir
;
612 ASSERT_TRUE(dir
.CreateUniqueTempDir());
613 base::FilePath file
= dir
.path().AppendASCII("theme_data.pak");
615 // Part 1: Build the pack from an extension.
617 base::FilePath hidpi_path
= GetHiDpiThemePath();
618 scoped_refptr
<BrowserThemePack
> pack
;
619 BuildFromUnpackedExtension(hidpi_path
, pack
);
620 ASSERT_TRUE(pack
->WriteToDisk(file
));
621 VerifyHiDpiTheme(pack
.get());
624 // Part 2: Try to read back the data pack that we just wrote to disk.
626 scoped_refptr
<BrowserThemePack
> pack
=
627 BrowserThemePack::BuildFromDataPack(file
, "gllekhaobjnhgeag");
628 ASSERT_TRUE(pack
.get());
629 VerifyHiDpiTheme(pack
.get());