1 // Copyright (c) 2010 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 <cmath> 6 7 #import "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h" 8 9 #include "base/logging.h" 10 11 namespace { 12 13 // This is used to increase the right margin of this decoration. 14 const CGFloat kRightSideMargin = 1.0; 15 16 // Padding between the icon/label and bubble edges. 17 const CGFloat kBubblePadding = 3.0; 18 19 // Padding between the icon and label. 20 const CGFloat kIconLabelPadding = 4.0; 21 22 // Inset for the background. 23 const CGFloat kBackgroundYInset = 4.0; 24 25 } // namespace 26 27 BubbleDecoration::BubbleDecoration() { 28 attributes_.reset([[NSMutableDictionary alloc] init]); 29 [attributes_ setObject:GetFont() forKey:NSFontAttributeName]; 30 } 31 32 BubbleDecoration::~BubbleDecoration() { 33 } 34 35 CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image, 36 NSString* label) { 37 if (!image && !label) 38 return kOmittedWidth; 39 40 const CGFloat image_width = image ? [image size].width : 0.0; 41 if (!label) 42 return kBubblePadding + image_width; 43 44 // The bubble needs to take up an integral number of pixels. 45 // Generally -sizeWithAttributes: seems to overestimate rather than 46 // underestimate, so floor() seems to work better. 47 const CGFloat label_width = 48 std::floor([label sizeWithAttributes:attributes_].width); 49 return kBubblePadding + image_width + kIconLabelPadding + label_width; 50 } 51 52 NSRect BubbleDecoration::GetImageRectInFrame(NSRect frame) { 53 NSRect imageRect = NSInsetRect(frame, 0.0, kBackgroundYInset); 54 if (image_) { 55 // Center the image vertically. 56 const NSSize imageSize = [image_ size]; 57 imageRect.origin.y += 58 std::floor((NSHeight(frame) - imageSize.height) / 2.0); 59 imageRect.size = imageSize; 60 } 61 return imageRect; 62 } 63 64 CGFloat BubbleDecoration::GetWidthForSpace(CGFloat width) { 65 const CGFloat all_width = GetWidthForImageAndLabel(image_, label_); 66 if (all_width <= width) 67 return all_width; 68 69 const CGFloat image_width = GetWidthForImageAndLabel(image_, nil); 70 if (image_width <= width) 71 return image_width; 72 73 return kOmittedWidth; 74 } 75 76 void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) { 77 const NSRect decoration_frame = NSInsetRect(frame, 0.0, kBackgroundYInset); 78 CGFloat textOffset = NSMinX(decoration_frame); 79 if (image_) { 80 // Center the image vertically. 81 const NSSize imageSize = [image_ size]; 82 NSRect imageRect = decoration_frame; 83 imageRect.origin.y += 84 std::floor((NSHeight(decoration_frame) - imageSize.height) / 2.0); 85 imageRect.size = imageSize; 86 [image_ drawInRect:imageRect 87 fromRect:NSZeroRect // Entire image 88 operation:NSCompositeSourceOver 89 fraction:1.0 90 respectFlipped:YES 91 hints:nil]; 92 textOffset = NSMaxX(imageRect) + kIconLabelPadding; 93 } 94 95 if (label_) { 96 NSRect textRect = frame; 97 textRect.origin.x = textOffset; 98 textRect.size.width = NSMaxX(decoration_frame) - NSMinX(textRect); 99 DrawLabel(label_, attributes_, textRect); 100 } 101 } 102 103 void BubbleDecoration::DrawWithBackgroundInFrame(NSRect background_frame, 104 NSRect frame, 105 NSView* control_view) { 106 NSRect rect = NSInsetRect(background_frame, 0, 1); 107 rect.size.width -= kRightSideMargin; 108 ui::DrawNinePartImage( 109 rect, GetBubbleImageIds(), NSCompositeSourceOver, 1.0, true); 110 111 DrawInFrame(frame, control_view); 112 } 113 114 NSImage* BubbleDecoration::GetImage() { 115 return image_; 116 } 117 118 void BubbleDecoration::SetImage(NSImage* image) { 119 image_.reset([image retain]); 120 } 121 122 void BubbleDecoration::SetLabel(NSString* label) { 123 // If the initializer was called with |nil|, then the code cannot 124 // process a label. 125 DCHECK(attributes_); 126 if (attributes_) 127 label_.reset([label copy]); 128 } 129 130 void BubbleDecoration::SetTextColor(NSColor* text_color) { 131 [attributes_ setObject:text_color forKey:NSForegroundColorAttributeName]; 132 } 133