OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/test/integration/bookmarks_helper.h" | 5 #include "chrome/browser/sync/test/integration/bookmarks_helper.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
11 #include "base/synchronization/waitable_event.h" | 11 #include "base/synchronization/waitable_event.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "chrome/browser/bookmarks/bookmark_model.h" | 13 #include "chrome/browser/bookmarks/bookmark_model.h" |
14 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 14 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
15 #include "chrome/browser/bookmarks/bookmark_model_observer.h" | 15 #include "chrome/browser/bookmarks/bookmark_model_observer.h" |
16 #include "chrome/browser/bookmarks/bookmark_utils.h" | 16 #include "chrome/browser/bookmarks/bookmark_utils.h" |
17 #include "chrome/browser/favicon/favicon_service_factory.h" | 17 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 18 #include "chrome/browser/favicon/favicon_util.h" |
18 #include "chrome/browser/history/history_service_factory.h" | 19 #include "chrome/browser/history/history_service_factory.h" |
19 #include "chrome/browser/history/history_types.h" | 20 #include "chrome/browser/history/history_types.h" |
20 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
21 #include "chrome/browser/sync/profile_sync_service_harness.h" | 22 #include "chrome/browser/sync/profile_sync_service_harness.h" |
22 #include "chrome/browser/sync/test/integration/sync_test.h" | 23 #include "chrome/browser/sync/test/integration/sync_test.h" |
23 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" | 24 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" |
24 #include "chrome/test/base/ui_test_utils.h" | 25 #include "chrome/test/base/ui_test_utils.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
26 #include "third_party/skia/include/core/SkBitmap.h" | 27 #include "third_party/skia/include/core/SkBitmap.h" |
27 #include "ui/base/models/tree_node_iterator.h" | 28 #include "ui/base/models/tree_node_iterator.h" |
28 #include "ui/gfx/codec/png_codec.h" | 29 #include "ui/gfx/image/image_skia.h" |
29 | 30 |
30 using sync_datatype_helper::test; | 31 using sync_datatype_helper::test; |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 // History task which runs all pending tasks on the history thread and | 35 // History task which runs all pending tasks on the history thread and |
35 // signals when the tasks have completed. | 36 // signals when the tasks have completed. |
36 class HistoryEmptyTask : public HistoryDBTask { | 37 class HistoryEmptyTask : public HistoryDBTask { |
37 public: | 38 public: |
38 explicit HistoryEmptyTask(base::WaitableEvent* done) : done_(done) {} | 39 explicit HistoryEmptyTask(base::WaitableEvent* done) : done_(done) {} |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 void* node_pixel_addr_b = bitmap_b.getPixels(); | 157 void* node_pixel_addr_b = bitmap_b.getPixels(); |
157 EXPECT_TRUE(node_pixel_addr_b); | 158 EXPECT_TRUE(node_pixel_addr_b); |
158 if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) { | 159 if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) { |
159 LOG(ERROR) << "Favicon bitmap mismatch"; | 160 LOG(ERROR) << "Favicon bitmap mismatch"; |
160 return false; | 161 return false; |
161 } else { | 162 } else { |
162 return true; | 163 return true; |
163 } | 164 } |
164 } | 165 } |
165 | 166 |
166 // Gets the favicon associated with |node| in |model|. | 167 // Represents a favicon image and the icon URL associated with it. |
167 gfx::Image GetFavicon(BookmarkModel* model, const BookmarkNode* node) { | 168 struct FaviconData { |
| 169 FaviconData() { |
| 170 } |
| 171 |
| 172 FaviconData(const gfx::Image& favicon_image, |
| 173 const GURL& favicon_url) |
| 174 : image(favicon_image), |
| 175 icon_url(favicon_url) { |
| 176 } |
| 177 |
| 178 ~FaviconData() { |
| 179 } |
| 180 |
| 181 gfx::Image image; |
| 182 GURL icon_url; |
| 183 }; |
| 184 |
| 185 // Gets the favicon and icon URL associated with |node| in |model|. |
| 186 FaviconData GetFaviconData(BookmarkModel* model, |
| 187 const BookmarkNode* node) { |
168 // If a favicon wasn't explicitly set for a particular URL, simply return its | 188 // If a favicon wasn't explicitly set for a particular URL, simply return its |
169 // blank favicon. | 189 // blank favicon. |
170 if (!urls_with_favicons_ || | 190 if (!urls_with_favicons_ || |
171 urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) { | 191 urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) { |
172 return gfx::Image(); | 192 return FaviconData(); |
173 } | 193 } |
174 // If a favicon was explicitly set, we may need to wait for it to be loaded | 194 // If a favicon was explicitly set, we may need to wait for it to be loaded |
175 // via BookmarkModel::GetFavicon(), which is an asynchronous operation. | 195 // via BookmarkModel::GetFavicon(), which is an asynchronous operation. |
176 if (!node->is_favicon_loaded()) { | 196 if (!node->is_favicon_loaded()) { |
177 FaviconChangeObserver observer(model, node); | 197 FaviconChangeObserver observer(model, node); |
178 model->GetFavicon(node); | 198 model->GetFavicon(node); |
179 observer.WaitForGetFavicon(); | 199 observer.WaitForGetFavicon(); |
180 } | 200 } |
181 EXPECT_TRUE(node->is_favicon_loaded()); | 201 EXPECT_TRUE(node->is_favicon_loaded()); |
182 EXPECT_FALSE(model->GetFavicon(node).IsEmpty()); | 202 EXPECT_FALSE(model->GetFavicon(node).IsEmpty()); |
183 return model->GetFavicon(node); | 203 return FaviconData(model->GetFavicon(node), node->icon_url()); |
184 } | 204 } |
185 | 205 |
186 // Sets the favicon for |profile| and |node|. |profile| may be | 206 // Sets the favicon for |profile| and |node|. |profile| may be |
187 // |test()->verifier()|. | 207 // |test()->verifier()|. |
188 void SetFaviconImpl(Profile* profile, | 208 void SetFaviconImpl(Profile* profile, |
189 const BookmarkNode* node, | 209 const BookmarkNode* node, |
| 210 const GURL& icon_url, |
190 const gfx::Image& image) { | 211 const gfx::Image& image) { |
191 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); | 212 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); |
192 | 213 |
193 FaviconChangeObserver observer(model, node); | 214 FaviconChangeObserver observer(model, node); |
194 FaviconService* favicon_service = | 215 FaviconService* favicon_service = |
195 FaviconServiceFactory::GetForProfile(profile, | 216 FaviconServiceFactory::GetForProfile(profile, |
196 Profile::EXPLICIT_ACCESS); | 217 Profile::EXPLICIT_ACCESS); |
197 favicon_service->SetFavicons(node->url(), | 218 favicon_service->SetFavicons(node->url(), |
198 node->url(), | 219 icon_url, |
199 history::FAVICON, | 220 history::FAVICON, |
200 image); | 221 image); |
201 | 222 |
202 // Wait for the favicon for |node| to be invalidated. | 223 // Wait for the favicon for |node| to be invalidated. |
203 observer.WaitForSetFavicon(); | 224 observer.WaitForSetFavicon(); |
204 // Wait for the BookmarkModel to fetch the updated favicon and for the new | 225 // Wait for the BookmarkModel to fetch the updated favicon and for the new |
205 // favicon to be sent to BookmarkChangeProcessor. | 226 // favicon to be sent to BookmarkChangeProcessor. |
206 GetFavicon(model, node); | 227 GetFaviconData(model, node); |
207 } | 228 } |
208 | 229 |
209 // Wait for all currently scheduled tasks on the history thread for all | 230 // Wait for all currently scheduled tasks on the history thread for all |
210 // profiles to complete and any notifications sent to the UI thread to have | 231 // profiles to complete and any notifications sent to the UI thread to have |
211 // finished processing. | 232 // finished processing. |
212 void WaitForHistoryToProcessPendingTasks() { | 233 void WaitForHistoryToProcessPendingTasks() { |
213 // Skip waiting for history to complete for tests without favicons. | 234 // Skip waiting for history to complete for tests without favicons. |
214 if (!urls_with_favicons_) | 235 if (!urls_with_favicons_) |
215 return; | 236 return; |
216 | 237 |
(...skipping 17 matching lines...) Expand all Loading... |
234 // to the UI thread are processed. | 255 // to the UI thread are processed. |
235 content::RunAllPendingInMessageLoop(); | 256 content::RunAllPendingInMessageLoop(); |
236 } | 257 } |
237 | 258 |
238 // Checks if the favicon in |node_a| from |model_a| matches that of |node_b| | 259 // Checks if the favicon in |node_a| from |model_a| matches that of |node_b| |
239 // from |model_b|. Returns true if they match. | 260 // from |model_b|. Returns true if they match. |
240 bool FaviconsMatch(BookmarkModel* model_a, | 261 bool FaviconsMatch(BookmarkModel* model_a, |
241 BookmarkModel* model_b, | 262 BookmarkModel* model_b, |
242 const BookmarkNode* node_a, | 263 const BookmarkNode* node_a, |
243 const BookmarkNode* node_b) { | 264 const BookmarkNode* node_b) { |
244 const gfx::Image& bitmap_a = GetFavicon(model_a, node_a); | 265 FaviconData favicon_data_a = GetFaviconData(model_a, node_a); |
245 const gfx::Image& bitmap_b = GetFavicon(model_b, node_b); | 266 FaviconData favicon_data_b = GetFaviconData(model_b, node_b); |
246 | 267 |
247 if (bitmap_a.IsEmpty() && bitmap_b.IsEmpty()) | 268 if (favicon_data_a.icon_url != favicon_data_b.icon_url) |
| 269 return false; |
| 270 |
| 271 gfx::Image image_a = favicon_data_a.image; |
| 272 gfx::Image image_b = favicon_data_b.image; |
| 273 |
| 274 if (image_a.IsEmpty() && image_b.IsEmpty()) |
248 return true; // Two empty images are equivalent. | 275 return true; // Two empty images are equivalent. |
249 return !bitmap_a.IsEmpty() && !bitmap_b.IsEmpty() && | 276 |
250 FaviconBitmapsMatch(*bitmap_a.ToSkBitmap(), *bitmap_b.ToSkBitmap()); | 277 if (image_a.IsEmpty() != image_b.IsEmpty()) |
| 278 return false; |
| 279 |
| 280 // Compare only the 1x bitmaps as only those are synced. |
| 281 SkBitmap bitmap_a = image_a.AsImageSkia().GetRepresentation( |
| 282 ui::SCALE_FACTOR_100P).sk_bitmap(); |
| 283 SkBitmap bitmap_b = image_b.AsImageSkia().GetRepresentation( |
| 284 ui::SCALE_FACTOR_100P).sk_bitmap(); |
| 285 return FaviconBitmapsMatch(bitmap_a, bitmap_b); |
251 } | 286 } |
252 | 287 |
253 // Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. | 288 // Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. |
254 // Returns true if they are all equal. | 289 // Returns true if they are all equal. |
255 bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { | 290 bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { |
256 if (node_a == NULL || node_b == NULL) | 291 if (node_a == NULL || node_b == NULL) |
257 return node_a == node_b; | 292 return node_a == node_b; |
258 if (node_a->is_folder() != node_b->is_folder()) { | 293 if (node_a->is_folder() != node_b->is_folder()) { |
259 LOG(ERROR) << "Cannot compare folder with bookmark"; | 294 LOG(ERROR) << "Cannot compare folder with bookmark"; |
260 return false; | 295 return false; |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 if (test()->use_verifier()) { | 485 if (test()->use_verifier()) { |
451 const BookmarkNode* v_node = NULL; | 486 const BookmarkNode* v_node = NULL; |
452 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); | 487 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
453 GetVerifierBookmarkModel()->SetTitle(v_node, WideToUTF16(new_title)); | 488 GetVerifierBookmarkModel()->SetTitle(v_node, WideToUTF16(new_title)); |
454 } | 489 } |
455 GetBookmarkModel(profile)->SetTitle(node, WideToUTF16(new_title)); | 490 GetBookmarkModel(profile)->SetTitle(node, WideToUTF16(new_title)); |
456 } | 491 } |
457 | 492 |
458 void SetFavicon(int profile, | 493 void SetFavicon(int profile, |
459 const BookmarkNode* node, | 494 const BookmarkNode* node, |
460 const std::vector<unsigned char>& icon_bytes_vector) { | 495 const GURL& icon_url, |
461 scoped_refptr<base::RefCountedBytes> bitmap_data( | 496 const gfx::Image& image) { |
462 new base::RefCountedBytes(icon_bytes_vector)); | |
463 gfx::Image image(bitmap_data->front(), bitmap_data->size()); | |
464 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) | 497 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) |
465 << "Node " << node->GetTitle() << " does not belong to " | 498 << "Node " << node->GetTitle() << " does not belong to " |
466 << "Profile " << profile; | 499 << "Profile " << profile; |
467 ASSERT_EQ(BookmarkNode::URL, node->type()) | 500 ASSERT_EQ(BookmarkNode::URL, node->type()) |
468 << "Node " << node->GetTitle() << " must be a url."; | 501 << "Node " << node->GetTitle() << " must be a url."; |
469 if (urls_with_favicons_ == NULL) | 502 if (urls_with_favicons_ == NULL) |
470 urls_with_favicons_ = new std::set<GURL>(); | 503 urls_with_favicons_ = new std::set<GURL>(); |
471 urls_with_favicons_->insert(node->url()); | 504 urls_with_favicons_->insert(node->url()); |
472 if (test()->use_verifier()) { | 505 if (test()->use_verifier()) { |
473 const BookmarkNode* v_node = NULL; | 506 const BookmarkNode* v_node = NULL; |
474 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); | 507 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
475 SetFaviconImpl(test()->verifier(), v_node, image); | 508 SetFaviconImpl(test()->verifier(), v_node, icon_url, image); |
476 } | 509 } |
477 SetFaviconImpl(test()->GetProfile(profile), node, image); | 510 SetFaviconImpl(test()->GetProfile(profile), node, icon_url, image); |
478 } | 511 } |
479 | 512 |
480 const BookmarkNode* SetURL(int profile, | 513 const BookmarkNode* SetURL(int profile, |
481 const BookmarkNode* node, | 514 const BookmarkNode* node, |
482 const GURL& new_url) { | 515 const GURL& new_url) { |
483 if (GetBookmarkModel(profile)->GetNodeByID(node->id()) != node) { | 516 if (GetBookmarkModel(profile)->GetNodeByID(node->id()) != node) { |
484 LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to " | 517 LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to " |
485 << "Profile " << profile; | 518 << "Profile " << profile; |
486 return NULL; | 519 return NULL; |
487 } | 520 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 BookmarkNode::URL, | 679 BookmarkNode::URL, |
647 WideToUTF16(title)); | 680 WideToUTF16(title)); |
648 } | 681 } |
649 | 682 |
650 int CountFoldersWithTitlesMatching(int profile, const std::wstring& title) { | 683 int CountFoldersWithTitlesMatching(int profile, const std::wstring& title) { |
651 return CountNodesWithTitlesMatching(GetBookmarkModel(profile), | 684 return CountNodesWithTitlesMatching(GetBookmarkModel(profile), |
652 BookmarkNode::FOLDER, | 685 BookmarkNode::FOLDER, |
653 WideToUTF16(title)); | 686 WideToUTF16(title)); |
654 } | 687 } |
655 | 688 |
656 std::vector<unsigned char> CreateFavicon(int seed) { | 689 gfx::Image CreateFavicon(SkColor color) { |
657 const int w = 16; | 690 const int dip_width = 16; |
658 const int h = 16; | 691 const int dip_height = 16; |
659 SkBitmap bmp; | 692 std::vector<ui::ScaleFactor> favicon_scale_factors = |
660 bmp.setConfig(SkBitmap::kARGB_8888_Config, w, h); | 693 FaviconUtil::GetFaviconScaleFactors(); |
661 bmp.allocPixels(); | 694 gfx::ImageSkia favicon; |
662 uint32_t* src_data = bmp.getAddr32(0, 0); | 695 for (size_t i = 0; i < favicon_scale_factors.size(); ++i) { |
663 for (int i = 0; i < w * h; ++i) { | 696 float scale = ui::GetScaleFactorScale(favicon_scale_factors[i]); |
664 src_data[i] = SkPreMultiplyARGB((seed + i) % 255, | 697 int pixel_width = dip_width * scale; |
665 (seed + i) % 250, | 698 int pixel_height = dip_height * scale; |
666 (seed + i) % 245, | 699 SkBitmap bmp; |
667 (seed + i) % 240); | 700 bmp.setConfig(SkBitmap::kARGB_8888_Config, pixel_width, pixel_height); |
| 701 bmp.allocPixels(); |
| 702 bmp.eraseColor(color); |
| 703 favicon.AddRepresentation(gfx::ImageSkiaRep(bmp, favicon_scale_factors[i])); |
668 } | 704 } |
669 std::vector<unsigned char> favicon; | 705 return gfx::Image(favicon); |
670 gfx::PNGCodec::EncodeBGRASkBitmap(bmp, false, &favicon); | |
671 return favicon; | |
672 } | 706 } |
673 | 707 |
674 std::string IndexedURL(int i) { | 708 std::string IndexedURL(int i) { |
675 return StringPrintf("http://www.host.ext:1234/path/filename/%d", i); | 709 return StringPrintf("http://www.host.ext:1234/path/filename/%d", i); |
676 } | 710 } |
677 | 711 |
678 std::wstring IndexedURLTitle(int i) { | 712 std::wstring IndexedURLTitle(int i) { |
679 return StringPrintf(L"URL Title %d", i); | 713 return StringPrintf(L"URL Title %d", i); |
680 } | 714 } |
681 | 715 |
682 std::wstring IndexedFolderName(int i) { | 716 std::wstring IndexedFolderName(int i) { |
683 return StringPrintf(L"Folder Name %d", i); | 717 return StringPrintf(L"Folder Name %d", i); |
684 } | 718 } |
685 | 719 |
686 std::wstring IndexedSubfolderName(int i) { | 720 std::wstring IndexedSubfolderName(int i) { |
687 return StringPrintf(L"Subfolder Name %d", i); | 721 return StringPrintf(L"Subfolder Name %d", i); |
688 } | 722 } |
689 | 723 |
690 std::wstring IndexedSubsubfolderName(int i) { | 724 std::wstring IndexedSubsubfolderName(int i) { |
691 return StringPrintf(L"Subsubfolder Name %d", i); | 725 return StringPrintf(L"Subsubfolder Name %d", i); |
692 } | 726 } |
693 | 727 |
694 } // namespace bookmarks_helper | 728 } // namespace bookmarks_helper |
OLD | NEW |