| 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 |