| Index: chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
|
| diff --git a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
|
| index a8a85fdc74e95a18c14aa2f3dad1cb9f3c4f0ab9..5eec7443d37e46d8c4b567e5f25b09493fa982c9 100644
|
| --- a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
|
| +++ b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
|
| @@ -4,6 +4,8 @@
|
|
|
| #import "chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h"
|
|
|
| +#include <cmath>
|
| +
|
| #include "base/logging.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
|
| @@ -14,6 +16,7 @@
|
| #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
|
| #import "chrome/browser/ui/cocoa/l10n_util.h"
|
| #include "components/autofill/core/browser/popup_item_ids.h"
|
| +#include "grit/theme_resources.h"
|
| #include "skia/ext/skia_utils_mac.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| #include "ui/gfx/font_list.h"
|
| @@ -24,11 +27,19 @@
|
| #include "ui/gfx/text_constants.h"
|
|
|
| using autofill::AutofillPopupView;
|
| +using autofill::PasswordGenerationPopupController;
|
| using autofill::PasswordGenerationPopupView;
|
| using base::scoped_nsobject;
|
|
|
| namespace {
|
|
|
| +// The height of the divider between the password and help sections, in pixels.
|
| +const CGFloat kDividerHeight = 1;
|
| +
|
| +// The amount of whitespace, in pixels, between lines of text in the password
|
| +// section.
|
| +const CGFloat kPasswordSectionVerticalSeparation = 5;
|
| +
|
| NSColor* DividerColor() {
|
| return gfx::SkColorToCalibratedNSColor(
|
| PasswordGenerationPopupView::kDividerColor);
|
| @@ -65,30 +76,52 @@ NSColor* HelpLinkColor() {
|
| if (self = [super initWithDelegate:controller frame:frame]) {
|
| controller_ = controller;
|
|
|
| - passwordField_ = [self textFieldWithText:controller_->password()
|
| - color:[self nameColor]
|
| - alignment:NSLeftTextAlignment];
|
| - [self addSubview:passwordField_];
|
| -
|
| - passwordSubtextField_ = [self textFieldWithText:controller_->SuggestedText()
|
| - color:[self subtextColor]
|
| - alignment:NSRightTextAlignment];
|
| - [self addSubview:passwordSubtextField_];
|
| -
|
| - scoped_nsobject<HyperlinkTextView> helpTextView(
|
| - [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
|
| - [helpTextView setMessage:base::SysUTF16ToNSString(controller_->HelpText())
|
| - withFont:[self textFont]
|
| - messageColor:HelpTextColor()];
|
| - [helpTextView addLinkRange:controller_->HelpTextLinkRange().ToNSRange()
|
| - withName:@""
|
| - linkColor:HelpLinkColor()];
|
| - [helpTextView setDelegate:self];
|
| - [[helpTextView textContainer] setLineFragmentPadding:0.0f];
|
| - [helpTextView setVerticallyResizable:YES];
|
| - [self addSubview:helpTextView];
|
| - helpTextView_ = helpTextView.get();
|
| - }
|
| + passwordSection_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
|
| + [self addSubview:passwordSection_];
|
| +
|
| + passwordField_.reset(
|
| + [[self textFieldWithText:controller_->password()
|
| + attributes:[self passwordAttributes]] retain]);
|
| + [passwordSection_ addSubview:passwordField_];
|
| +
|
| + passwordTitleField_.reset(
|
| + [[self textFieldWithText:controller_->SuggestedText()
|
| + attributes:[self passwordTitleAttributes]] retain]);
|
| + [passwordSection_ addSubview:passwordTitleField_];
|
| +
|
| + keyIcon_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
|
| + NSImage* keyImage = ResourceBundle::GetSharedInstance()
|
| + .GetImageNamed(IDR_GENERATE_PASSWORD_KEY)
|
| + .ToNSImage();
|
| + [keyIcon_ setImage:keyImage];
|
| + [passwordSection_ addSubview:keyIcon_];
|
| +
|
| + divider_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
|
| + [divider_ setBoxType:NSBoxCustom];
|
| + [divider_ setBorderType:NSLineBorder];
|
| + [divider_ setBorderColor:DividerColor()];
|
| + [self addSubview:divider_];
|
| +
|
| + helpTextView_.reset([[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
|
| + [helpTextView_ setMessage:base::SysUTF16ToNSString(controller_->HelpText())
|
| + withFont:[self textFont]
|
| + messageColor:HelpTextColor()];
|
| + [helpTextView_ addLinkRange:controller_->HelpTextLinkRange().ToNSRange()
|
| + withName:@""
|
| + linkColor:HelpLinkColor()];
|
| + [helpTextView_ setDelegate:self];
|
| + [helpTextView_ setDrawsBackground:YES];
|
| + [helpTextView_ setBackgroundColor:HelpTextBackgroundColor()];
|
| + [helpTextView_
|
| + setTextContainerInset:NSMakeSize(controller_->kHorizontalPadding,
|
| + controller_->kHelpVerticalPadding)];
|
| + // Remove the underlining.
|
| + NSTextStorage* text = [helpTextView_ textStorage];
|
| + [text addAttribute:NSUnderlineStyleAttributeName
|
| + value:@(NSUnderlineStyleNone)
|
| + range:controller_->HelpTextLinkRange().ToNSRange()];
|
| + [self addSubview:helpTextView_];
|
| +}
|
|
|
| return self;
|
| }
|
| @@ -96,6 +129,8 @@ NSColor* HelpLinkColor() {
|
| #pragma mark NSView implementation:
|
|
|
| - (void)drawRect:(NSRect)dirtyRect {
|
| + [super drawRect:dirtyRect];
|
| +
|
| // If the view is in the process of being destroyed, don't bother drawing.
|
| if (!controller_)
|
| return;
|
| @@ -104,30 +139,120 @@ NSColor* HelpLinkColor() {
|
|
|
| if (controller_->password_selected()) {
|
| // Draw a highlight under the suggested password.
|
| - NSRect highlightBounds = [self passwordBounds];
|
| + NSRect highlightBounds = [passwordSection_ frame];
|
| [[self highlightColor] set];
|
| [NSBezierPath fillRect:highlightBounds];
|
| }
|
| -
|
| - // Render the background of the help text.
|
| - [HelpTextBackgroundColor() set];
|
| - [NSBezierPath fillRect:[self helpBounds]];
|
| -
|
| - // Render the divider.
|
| - [DividerColor() set];
|
| - [NSBezierPath fillRect:[self dividerBounds]];
|
| }
|
|
|
| #pragma mark Public API:
|
|
|
| +- (NSSize)preferredSize {
|
| + const NSSize passwordTitleSize =
|
| + [base::SysUTF16ToNSString(controller_->SuggestedText())
|
| + sizeWithAttributes:@{ NSFontAttributeName : [self boldFont] }];
|
| + const NSSize passwordSize = [base::SysUTF16ToNSString(controller_->password())
|
| + sizeWithAttributes:@{ NSFontAttributeName : [self textFont] }];
|
| +
|
| + CGFloat width =
|
| + autofill::kPopupBorderThickness +
|
| + controller_->kHorizontalPadding +
|
| + [[keyIcon_ image] size].width +
|
| + controller_->kHorizontalPadding +
|
| + std::max(passwordSize.width, passwordTitleSize.width) +
|
| + controller_->kHorizontalPadding +
|
| + autofill::kPopupBorderThickness;
|
| +
|
| + width = std::max(width, (CGFloat)controller_->GetMinimumWidth());
|
| +
|
| + CGFloat height =
|
| + autofill::kPopupBorderThickness +
|
| + controller_->kHelpVerticalPadding +
|
| + [self helpSizeForPopupWidth:width].height +
|
| + controller_->kHelpVerticalPadding +
|
| + autofill::kPopupBorderThickness;
|
| +
|
| + if (controller_->display_password())
|
| + height += controller_->kPopupPasswordSectionHeight;
|
| +
|
| + return NSMakeSize(width, height);
|
| +}
|
| +
|
| - (void)updateBoundsAndRedrawPopup {
|
| - [self positionView:passwordField_ inRect:[self passwordBounds]];
|
| - [self positionView:passwordSubtextField_ inRect:[self passwordBounds]];
|
| - [self positionView:helpTextView_ inRect:[self helpBounds]];
|
| + const CGFloat popupWidth = controller_->popup_bounds().width();
|
| + const CGFloat contentWidth =
|
| + popupWidth - (2 * autofill::kPopupBorderThickness);
|
| + const CGFloat contentHeight = controller_->popup_bounds().height() -
|
| + (2 * autofill::kPopupBorderThickness);
|
| +
|
| + if (controller_->display_password()) {
|
| + // The password can change while the bubble is shown: If the user has
|
| + // accepted the password and then selects the form again and starts deleting
|
| + // the password, the field will be initially invisible and then become
|
| + // visible.
|
| + [self updatePassword];
|
| +
|
| + // Lay out the password section, which includes the key icon, the title, and
|
| + // the suggested password.
|
| + [passwordSection_
|
| + setFrame:NSMakeRect(autofill::kPopupBorderThickness,
|
| + autofill::kPopupBorderThickness,
|
| + contentWidth,
|
| + controller_->kPopupPasswordSectionHeight)];
|
| +
|
| + // The key icon falls to the left of the title and password.
|
| + const NSSize imageSize = [[keyIcon_ image] size];
|
| + const CGFloat keyX = controller_->kHorizontalPadding;
|
| + const CGFloat keyY =
|
| + std::ceil((controller_->kPopupPasswordSectionHeight / 2.0) -
|
| + (imageSize.height / 2.0));
|
| + [keyIcon_ setFrameOrigin:NSMakePoint(keyX, keyY)];
|
| + [keyIcon_ sizeToFit];
|
| +
|
| + // The title and password fall to the right of the key icon and are centered
|
| + // vertically as a group with some padding in between.
|
| + [passwordTitleField_ sizeToFit];
|
| + [passwordField_ sizeToFit];
|
| + const CGFloat groupHeight = NSHeight([passwordField_ frame]) +
|
| + kPasswordSectionVerticalSeparation +
|
| + NSHeight([passwordTitleField_ frame]);
|
| + const CGFloat groupX =
|
| + NSMaxX([keyIcon_ frame]) + controller_->kHorizontalPadding;
|
| + const CGFloat groupY =
|
| + std::ceil((controller_->kPopupPasswordSectionHeight / 2.0) -
|
| + (groupHeight / 2.0));
|
| + [passwordField_ setFrameOrigin:NSMakePoint(groupX, groupY)];
|
| + const CGFloat titleY = groupY +
|
| + NSHeight([passwordField_ frame]) +
|
| + kPasswordSectionVerticalSeparation;
|
| + [passwordTitleField_ setFrameOrigin:NSMakePoint(groupX, titleY)];
|
| +
|
| + // Layout the divider, which falls immediately below the password section.
|
| + const CGFloat dividerX = autofill::kPopupBorderThickness;
|
| + const CGFloat dividerY = NSMaxY([passwordSection_ frame]);
|
| + NSRect dividerFrame =
|
| + NSMakeRect(dividerX, dividerY, contentWidth, kDividerHeight);
|
| + [divider_ setFrame:dividerFrame];
|
| + }
|
| +
|
| + // Layout the help section beneath the divider (if applicable, otherwise
|
| + // beneath the border).
|
| + const CGFloat helpX = autofill::kPopupBorderThickness;
|
| + const CGFloat helpY = controller_->display_password()
|
| + ? NSMaxY([divider_ frame])
|
| + : autofill::kPopupBorderThickness;
|
| + const CGFloat helpHeight = contentHeight -
|
| + NSHeight([passwordSection_ frame]) -
|
| + NSHeight([divider_ frame]);
|
| + [helpTextView_ setFrame:NSMakeRect(helpX, helpY, contentWidth, helpHeight)];
|
|
|
| [super updateBoundsAndRedrawPopup];
|
| }
|
|
|
| +- (BOOL)isPointInPasswordBounds:(NSPoint)point {
|
| + return NSPointInRect(point, [passwordSection_ frame]);
|
| +}
|
| +
|
| - (void)controllerDestroyed {
|
| controller_ = NULL;
|
| [super delegateDestroyed];
|
| @@ -144,27 +269,45 @@ NSColor* HelpLinkColor() {
|
|
|
| #pragma mark Private helpers:
|
|
|
| -- (NSTextField*)textFieldWithText:(const base::string16&)text
|
| - color:(NSColor*)color
|
| - alignment:(NSTextAlignment)alignment {
|
| +- (void)updatePassword {
|
| + base::scoped_nsobject<NSMutableAttributedString> updatedPassword(
|
| + [[NSMutableAttributedString alloc]
|
| + initWithString:base::SysUTF16ToNSString(controller_->password())
|
| + attributes:[self passwordAttributes]]);
|
| + [passwordField_ setAttributedStringValue:updatedPassword];
|
| +}
|
| +
|
| +- (NSDictionary*)passwordTitleAttributes {
|
| scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
|
| [[NSMutableParagraphStyle alloc] init]);
|
| - [paragraphStyle setAlignment:alignment];
|
| + [paragraphStyle setAlignment:NSLeftTextAlignment];
|
| + return @{
|
| + NSFontAttributeName : [self boldFont],
|
| + NSForegroundColorAttributeName : [self nameColor],
|
| + NSParagraphStyleAttributeName : paragraphStyle.autorelease()
|
| + };
|
| +}
|
|
|
| - NSDictionary* textAttributes = @{
|
| +- (NSDictionary*)passwordAttributes {
|
| + scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
|
| + [[NSMutableParagraphStyle alloc] init]);
|
| + [paragraphStyle setAlignment:NSLeftTextAlignment];
|
| + return @{
|
| NSFontAttributeName : [self textFont],
|
| - NSForegroundColorAttributeName : color,
|
| - NSParagraphStyleAttributeName : paragraphStyle
|
| + NSForegroundColorAttributeName : [self nameColor],
|
| + NSParagraphStyleAttributeName : paragraphStyle.autorelease()
|
| };
|
| +}
|
|
|
| +- (NSTextField*)textFieldWithText:(const base::string16&)text
|
| + attributes:(NSDictionary*)attributes {
|
| + NSTextField* textField =
|
| + [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease];
|
| scoped_nsobject<NSAttributedString> attributedString(
|
| [[NSAttributedString alloc]
|
| initWithString:base::SysUTF16ToNSString(text)
|
| - attributes:textAttributes]);
|
| -
|
| - NSTextField* textField =
|
| - [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease];
|
| - [textField setAttributedStringValue:attributedString];
|
| + attributes:attributes]);
|
| + [textField setAttributedStringValue:attributedString.autorelease()];
|
| [textField setEditable:NO];
|
| [textField setSelectable:NO];
|
| [textField setDrawsBackground:NO];
|
| @@ -172,31 +315,25 @@ NSColor* HelpLinkColor() {
|
| return textField;
|
| }
|
|
|
| -- (void)positionView:(NSView*)view inRect:(NSRect)bounds {
|
| - NSRect frame = NSInsetRect(bounds, controller_->kHorizontalPadding, 0);
|
| - [view setFrame:frame];
|
| -
|
| - // Center the text vertically within the bounds.
|
| - NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
|
| - [view setFrameOrigin:
|
| - NSInsetRect(frame, 0, floor(-delta.height/2)).origin];
|
| -}
|
| -
|
| -- (NSRect)passwordBounds {
|
| - return NSZeroRect;
|
| -}
|
| -
|
| -- (NSRect)helpBounds {
|
| - return NSZeroRect;
|
| +- (NSSize)helpSizeForPopupWidth:(CGFloat)width {
|
| + const CGFloat helpWidth = width -
|
| + 2 * controller_->kHorizontalPadding -
|
| + 2 * autofill::kPopupBorderThickness;
|
| + const NSSize size = NSMakeSize(helpWidth, MAXFLOAT);
|
| + NSRect textFrame = [base::SysUTF16ToNSString(controller_->HelpText())
|
| + boundingRectWithSize:size
|
| + options:NSLineBreakByWordWrapping |
|
| + NSStringDrawingUsesLineFragmentOrigin
|
| + attributes:@{ NSFontAttributeName : [self textFont] }];
|
| + return textFrame.size;
|
| }
|
|
|
| -- (NSRect)dividerBounds {
|
| - return NSZeroRect;
|
| +- (NSFont*)boldFont {
|
| + return [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
|
| }
|
|
|
| - (NSFont*)textFont {
|
| - return ResourceBundle::GetSharedInstance().GetFontList(
|
| - ResourceBundle::SmallFont).GetPrimaryFont().GetNativeFont();
|
| + return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
|
| }
|
|
|
| @end
|
|
|