diff options
author | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-13 00:53:18 +0000 |
---|---|---|
committer | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-13 00:53:18 +0000 |
commit | 89ed01c883dabd07d5e4cf760a290ce682cbf34d (patch) | |
tree | dec1237ef5fbcfc99f889dd09ae41c1125014a38 | |
parent | 16adb28574253284c920079a6800a7cc192c8dc4 (diff) | |
download | chromium_src-89ed01c883dabd07d5e4cf760a290ce682cbf34d.zip chromium_src-89ed01c883dabd07d5e4cf760a290ce682cbf34d.tar.gz chromium_src-89ed01c883dabd07d5e4cf760a290ce682cbf34d.tar.bz2 |
Add favicons to Mac bookmark bar.
BUG=8381
TEST=Open bookmark bar (Cmd-B). Add some bookmarks with sites that
have favicons (cnn.com). See icons in bookmark buttons. Make sure
color is correct.
Review URL: http://codereview.chromium.org/125061
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18340 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.mm | 37 | ||||
-rw-r--r-- | chrome/browser/cocoa/cocoa_utils.h | 19 | ||||
-rw-r--r-- | chrome/browser/cocoa/cocoa_utils.mm | 99 | ||||
-rw-r--r-- | chrome/browser/cocoa/cocoa_utils_unittest.mm | 83 | ||||
-rw-r--r-- | chrome/chrome.gyp | 3 | ||||
-rw-r--r-- | skia/skia.gyp | 10 |
6 files changed, 244 insertions, 7 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index 0b3d8e7..e30a1a2 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -10,10 +10,13 @@ #import "chrome/browser/cocoa/bookmark_bar_controller.h" #import "chrome/browser/cocoa/bookmark_bar_view.h" #import "chrome/browser/cocoa/bookmark_button_cell.h" +#import "chrome/browser/cocoa/cocoa_utils.h" #include "chrome/browser/profile.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" +using namespace CocoaUtils; + @interface BookmarkBarController(Private) - (void)applyContentAreaOffset:(BOOL)apply; - (void)positionBar; @@ -149,7 +152,7 @@ const CGFloat kBookmarkHorizontalPadding = 8.0; [delegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; } -// Return an NSCell suitable for a bookmark button. +// Return an autoreleased NSCell suitable for a bookmark button. - (NSCell *)cellForBookmarkNode:(BookmarkNode*)node frame:(NSRect)frame { NSString* title = base::SysWideToNSString(node->GetTitle()); NSButtonCell *cell = [[[BookmarkButtonCell alloc] initTextCell:nil] @@ -160,10 +163,16 @@ const CGFloat kBookmarkHorizontalPadding = 8.0; [cell setBezelStyle:NSShadowlessSquareBezelStyle]; [cell setShowsBorderOnlyWhileMouseInside:YES]; - // TODO(jrg): add the real image. Find or write an SkBitmap-to-NSImage helper. - // For now I'm using the nav icon just to have something. - [cell setImage:[NSImage imageNamed:@"nav"]]; - [cell setImagePosition:NSImageLeft]; + // The favicon may be NULL if we haven't loaded it yet. Bookmarks + // (and their icons) are loaded on the IO thread to speed launch. + const SkBitmap& favicon = bookmarkModel_->GetFavIcon(node); + if (!favicon.isNull()) { + NSImage* image = SkBitmapToNSImage(favicon); + if (image) { + [cell setImage:image]; + [cell setImagePosition:NSImageLeft]; + } + } [cell setTitle:title]; [cell setControlSize:NSSmallControlSize]; @@ -243,6 +252,7 @@ const CGFloat kBookmarkHorizontalPadding = 8.0; // TODO(jrg): for now this is brute force. - (void)loaded:(BookmarkModel*)model { + DCHECK(model == bookmarkModel_); // Do nothing if not visible or too early if ((barIsVisible_ == NO) || !model->IsLoaded()) return; @@ -275,9 +285,24 @@ const CGFloat kBookmarkHorizontalPadding = 8.0; [self loaded:model]; } +// TODO(jrg): linear searching is bad. +// Need a BookmarkNode-->NSCell mapping. - (void)nodeFavIconLoaded:(BookmarkModel*)model node:(BookmarkNode*)node { - // TODO(jrg): no icons yet + NSArray* views = [bookmarkBarView_ subviews]; + for (NSButton* button in views) { + NSButtonCell* cell = [button cell]; + void* pointer = [[cell representedObject] pointerValue]; + BookmarkNode* cellnode = static_cast<BookmarkNode*>(pointer); + if (cellnode == node) { + NSImage* image = SkBitmapToNSImage(bookmarkModel_->GetFavIcon(node)); + if (image) { + [cell setImage:image]; + [cell setImagePosition:NSImageLeft]; + } + return; + } + } } // TODO(jrg): for now this is brute force. diff --git a/chrome/browser/cocoa/cocoa_utils.h b/chrome/browser/cocoa/cocoa_utils.h new file mode 100644 index 0000000..9f721d1 --- /dev/null +++ b/chrome/browser/cocoa/cocoa_utils.h @@ -0,0 +1,19 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <Cocoa/Cocoa.h> +#include "third_party/skia/include/core/SkBitmap.h" + +// Generic Cocoa utilities which fit nowhere else. + +namespace CocoaUtils { + +// Given an SkBitmap, return an autoreleased NSImage. This function +// was not placed in +// third_party/skia/src/utils/mac/SkCreateCGImageRef.cpp since that +// would make Skia dependent on Cocoa. +NSImage* SkBitmapToNSImage(const SkBitmap& icon); + + +}; // namespace CocoaUtils diff --git a/chrome/browser/cocoa/cocoa_utils.mm b/chrome/browser/cocoa/cocoa_utils.mm new file mode 100644 index 0000000..e9bd9be --- /dev/null +++ b/chrome/browser/cocoa/cocoa_utils.mm @@ -0,0 +1,99 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <base/logging.h> +#include "chrome/browser/cocoa/cocoa_utils.h" +#import <QuartzCore/CIImage.h> +#include "third_party/skia/include/utils/mac/SkCGUtils.h" +#include "third_party/skia/include/core/SkColorPriv.h" + +namespace { + +// Callback passed to CGDataProviderCreateWithData() +void ReleaseData(void* info, const void* pixelData, size_t size) { + // info is a non-const pixelData + if (info) + free(info); +} + +} + +namespace CocoaUtils { + +NSImage* SkBitmapToNSImage(const SkBitmap& icon) { + // First convert SkBitmap to CGImageRef. + CGImageRef cgimage; + if (icon.config() != SkBitmap::kARGB_8888_Config) { + cgimage = SkCreateCGImageRef(icon); + } else { + // The above code returns a valid NSImage even in the + // kARGB_8888_Config case. As an example, the unit test which + // draws a blue SkBitmap can lockPixels, NSReadPixel, and pull out + // a single pixel from the NSImage and see it blue. However, the + // NSImage returned will be in ABGR format. Although Cocoa is + // otherwise happy with that format (as seen in simple tests + // outside Chromium), Chromium is NOT happy. In Chromium, B and R + // are swapped. + // + // As a hint, CIImage supports a few formats, such as ARGB. + // Interestingly, it does NOT support ABGR. I speculate there is + // some way we set up our drawing context which has the format + // specified wrong (in skia/ext/bitmap_platform_device_mac.cc), + // but I have not been able to solve this yet. + // + // TODO(jrg): track down the disconnect. + // TODO(jrg): Remove byte conversion. + // TODO(jrg): Fix unit tests to NOT swap bytes. + // http://crbug.com/14020 + CGBitmapInfo info = (kCGImageAlphaPremultipliedFirst | + kCGBitmapByteOrder32Host); + int width = icon.width(); + int height = icon.height(); + int rowbytes = icon.rowBytes(); + int rowwords = rowbytes/4; + unsigned length = rowbytes * height; + DCHECK(length > 0); + uint32_t* rawptr = static_cast<uint32_t*>(malloc(length)); + DCHECK(rawptr); + if (!rawptr || !length) + return nil; + + // Convert ABGR to ARGB + icon.lockPixels(); + uint32_t* rawbitmap = static_cast<uint32_t*>(icon.getPixels()); + uint32_t rawbit; + int offset; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + offset = x + y*rowwords; + rawbit = rawbitmap[offset]; + rawptr[offset] = SkPackARGB32(SkGetPackedA32(rawbit), + SkGetPackedR32(rawbit), + SkGetPackedG32(rawbit), + SkGetPackedB32(rawbit)); + } + } + icon.unlockPixels(); + + CGDataProviderRef dataRef = + CGDataProviderCreateWithData(rawptr, rawptr, length, ReleaseData); + CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + cgimage = CGImageCreate(width, height, 8, + icon.bytesPerPixel() * 8, + rowbytes, space, info, dataRef, + NULL, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(space); + CGDataProviderRelease(dataRef); + } + + // Now convert to NSImage. + NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] + initWithCGImage:cgimage] autorelease]; + NSImage* image = [[[NSImage alloc] init] autorelease]; + [image addRepresentation:bitmap]; + return image; +} + +} // namespace CocoaUtils + diff --git a/chrome/browser/cocoa/cocoa_utils_unittest.mm b/chrome/browser/cocoa/cocoa_utils_unittest.mm new file mode 100644 index 0000000..7812f2c --- /dev/null +++ b/chrome/browser/cocoa/cocoa_utils_unittest.mm @@ -0,0 +1,83 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/cocoa_utils.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class CocoaUtilsTest : public testing::Test { + public: + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... + + // If not red, is blue. + // If not tfbit (twenty-four-bit), is 444. + // If swap, swap R and B before testing (see TODOs in cocoa_utils.mm) + void ShapeHelper(int width, int height, bool isred, bool tfbit, bool swap); +}; + +void CocoaUtilsTest::ShapeHelper(int width, int height, + bool isred, bool tfbit, bool swap) { + SkBitmap thing; + + if (tfbit) + thing.setConfig(SkBitmap::kARGB_8888_Config, width, height); + else + thing.setConfig(SkBitmap::kARGB_4444_Config, width, height); + thing.allocPixels(); + + if (isred) + thing.eraseRGB(0xff, 0, 0); + else + thing.eraseRGB(0, 0, 0xff); + + // Confirm size + NSImage* image = CocoaUtils::SkBitmapToNSImage(thing); + EXPECT_DOUBLE_EQ([image size].width, (double)width); + EXPECT_DOUBLE_EQ([image size].height, (double)height); + + // Get the color of a pixel and make sure it looks fine + [image lockFocus]; + + int x = width > 17 ? 17 : 0; + int y = height > 17 ? 17 : 0; + NSColor* color = NSReadPixel(NSMakePoint(x, y)); + CGFloat red = 0, green = 0, blue = 0, alpha = 0; + [image unlockFocus]; + [color getRed:&red green:&green blue:&blue alpha:&alpha]; + + if (swap) { + CGFloat tmp = red; + red = blue; + blue = tmp; + } + + // Be tolerant of floating point rounding, gamma, etc. + if (isred) { + EXPECT_GT(red, 0.8); + EXPECT_LT(blue, 0.2); + } else { + EXPECT_LT(red, 0.2); + EXPECT_GT(blue, 0.8); + } + EXPECT_LT(green, 0.2); + EXPECT_GT(alpha, 0.9); +} + + +TEST_F(CocoaUtilsTest, BitmapToNSImage_RedSquare64x64) { + ShapeHelper(64, 64, true, true, true); +} + +TEST_F(CocoaUtilsTest, BitmapToNSImage_BlueRectangle199x19) { + ShapeHelper(199, 19, false, true, true); +} + +TEST_F(CocoaUtilsTest, BitmapToNSImage_BlueRectangle444) { + ShapeHelper(200, 200, false, false, false); +} + + +} // namespace diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 4ac0cb7..a2a8162 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -708,6 +708,8 @@ 'browser/cocoa/clear_browsing_data_controller.h', 'browser/cocoa/clear_browsing_data_controller.mm', 'browser/cocoa/cocoa_test_helper.h', + 'browser/cocoa/cocoa_utils.h', + 'browser/cocoa/cocoa_utils.mm', 'browser/cocoa/command_observer_bridge.h', 'browser/cocoa/command_observer_bridge.mm', 'browser/cocoa/custom_home_pages_model.h', @@ -3262,6 +3264,7 @@ 'browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm', 'browser/cocoa/browser_window_cocoa_unittest.mm', 'browser/cocoa/browser_window_controller_unittest.mm', + 'browser/cocoa/cocoa_utils_unittest.mm', 'browser/cocoa/command_observer_bridge_unittest.mm', 'browser/cocoa/custom_home_pages_model_unittest.mm', 'browser/cocoa/find_bar_bridge_unittest.mm', diff --git a/skia/skia.gyp b/skia/skia.gyp index 9c3ad85..b9b0714 100644 --- a/skia/skia.gyp +++ b/skia/skia.gyp @@ -384,6 +384,9 @@ #'../third_party/skia/src/ports/SkXMLPullParser_expat.cpp', '../third_party/skia/src/ports/sk_predefined_gamma.h', + '../third_party/skia/src/include/utils/mac/SkCGUtils.h', + '../third_party/skia/src/utils/mac/SkCreateCGImageRef.cpp', + '../third_party/skia/include/core/Sk64.h', '../third_party/skia/include/core/SkAutoKern.h', '../third_party/skia/include/core/SkBitmap.h', @@ -555,7 +558,9 @@ ], 'conditions': [ [ 'OS != "mac"', { - 'sources/': [ ['exclude', '_mac\\.(cc|cpp)$'] ], + 'sources/': [ + ['exclude', '_mac\\.(cc|cpp)$'], + ['exclude', '/mac/'] ], }], [ 'OS != "linux"', { 'sources/': [ ['exclude', '_linux\\.(cc|cpp)$'] ], @@ -601,6 +606,9 @@ 'defines': [ 'SK_BUILD_FOR_MAC', ], + 'include_dirs': [ + '../third_party/skia/include/utils/mac', + ], }], [ 'OS == "win"', { 'sources!': [ |