diff options
author | Daniel Connelly <dconnelly@chromium.org> | 2014-09-02 10:44:21 +0200 |
---|---|---|
committer | Daniel Connelly <dconnelly@chromium.org> | 2014-09-02 08:47:26 +0000 |
commit | f2476198a16985790529c35ddb5fa7446677bd8b (patch) | |
tree | 61aa72f8650c337551fea85068a479a833aedb69 | |
parent | c23fbaff892ecd995d1141c13c47000e9fe10c99 (diff) | |
download | chromium_src-f2476198a16985790529c35ddb5fa7446677bd8b.zip chromium_src-f2476198a16985790529c35ddb5fa7446677bd8b.tar.gz chromium_src-f2476198a16985790529c35ddb5fa7446677bd8b.tar.bz2 |
Update Mac password generation autofill popup to match latest mocks.
Screenshots available on the bug.
BUG=394303
Review URL: https://codereview.chromium.org/487193003
Cr-Commit-Position: refs/heads/master@{#291389}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291389 0039d316-1c4b-4281-b951-d872f2087c98
(cherry picked from commit 73902b67c97fda182d22991a9e7faa110f926531)
Review URL: https://codereview.chromium.org/529903002
Cr-Commit-Position: refs/branch-heads/2125@{#165}
Cr-Branched-From: b68026d94bda36dd106a3d91a098719f952a9477-refs/heads/master@{#290040}
5 files changed, 231 insertions, 80 deletions
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller.h b/chrome/browser/ui/autofill/password_generation_popup_controller.h index cd912ec..bcd0c9a 100644 --- a/chrome/browser/ui/autofill/password_generation_popup_controller.h +++ b/chrome/browser/ui/autofill/password_generation_popup_controller.h @@ -22,6 +22,9 @@ class PasswordGenerationPopupController : public AutofillPopupViewDelegate { // Spacing between the border of the popup and any text. static const int kHorizontalPadding = 10; + // Desired height of the password section. + static const int kPopupPasswordSectionHeight = 62; + // Called by the view when the saved passwords link is clicked. virtual void OnSavedPasswordsLinkClicked() = 0; diff --git a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_bridge.mm index 6c22cb8..9f4cd9a 100644 --- a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_bridge.mm +++ b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_bridge.mm @@ -9,8 +9,7 @@ #include "base/logging.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" #import "chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h" -#include "ui/base/cocoa/window_size_constants.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" namespace autofill { @@ -36,8 +35,7 @@ void PasswordGenerationPopupViewBridge::Show() { } gfx::Size PasswordGenerationPopupViewBridge::GetPreferredSizeOfPasswordView() { - // TODO(gcasto): Implement this function. - return gfx::Size(); + return gfx::Size(NSSizeToCGSize([view_ preferredSize])); } void PasswordGenerationPopupViewBridge::UpdateBoundsAndRedrawPopup() { @@ -50,8 +48,7 @@ void PasswordGenerationPopupViewBridge::PasswordSelectionUpdated() { bool PasswordGenerationPopupViewBridge::IsPointInPasswordBounds( const gfx::Point& point) { - // TODO(gcasto): Implement this function. - return true; + return [view_ isPointInPasswordBounds:NSPointFromCGPoint(point.ToCGPoint())]; } PasswordGenerationPopupView* PasswordGenerationPopupView::Create( diff --git a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h index e475161..35dd04f 100644 --- a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h +++ b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h @@ -7,6 +7,7 @@ #import <Cocoa/Cocoa.h> +#include "base/mac/scoped_nsobject.h" #include "chrome/browser/ui/autofill/password_generation_popup_controller.h" #import "chrome/browser/ui/cocoa/autofill/autofill_popup_base_view_cocoa.h" @@ -23,9 +24,12 @@ class AutofillPopupController; // The cross-platform controller for this view. __weak autofill::PasswordGenerationPopupController* controller_; - __weak NSTextField* passwordField_; - __weak NSTextField* passwordSubtextField_; - __weak HyperlinkTextView* helpTextView_; + base::scoped_nsobject<NSView> passwordSection_; + base::scoped_nsobject<NSTextField> passwordField_; + base::scoped_nsobject<NSTextField> passwordTitleField_; + base::scoped_nsobject<NSImageView> keyIcon_; + base::scoped_nsobject<NSBox> divider_; + base::scoped_nsobject<HyperlinkTextView> helpTextView_; } // Designated initializer. @@ -33,10 +37,17 @@ class AutofillPopupController; (autofill::PasswordGenerationPopupController*)controller frame:(NSRect)frame; +// Determines whether |point| falls inside the password section of the popup. +// |point| needs to be in the popup's coordinate system. +- (BOOL)isPointInPasswordBounds:(NSPoint)point; + // Informs the view that its controller has been (or will imminently be) // destroyed. - (void)controllerDestroyed; +// The preferred size for the popup. +- (NSSize)preferredSize; + @end #endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_PASSWORD_GENERATION_POPUP_VIEW_COCOA_H_ 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 a8a85fd..5eec744 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 diff --git a/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc b/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc index 2979d42..3c836b2 100644 --- a/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc @@ -25,7 +25,6 @@ namespace { // The amount of whitespace that is present when there is no padding. Used // to get the proper spacing in the help section. const int kHelpVerticalOffset = 5; -const int kPasswordSectionHeight = 62; // Wrapper around just the text portions of the generation UI (password and // prompting text). @@ -173,7 +172,8 @@ gfx::Size PasswordGenerationPopupViewViews::GetPreferredSizeOfPasswordView() { int height = kPopupBorderThickness; if (controller_->display_password()) { // Add divider height as well. - height += kPasswordSectionHeight + 1; + height += + PasswordGenerationPopupController::kPopupPasswordSectionHeight + 1; } int width = controller_->GetMinimumWidth(); int popup_width = width - 2 * kPopupBorderThickness; @@ -217,7 +217,10 @@ void PasswordGenerationPopupViewViews::Layout() { // it), but it can't change the other way around. CreatePasswordView(); password_view_->SetBounds( - kPopupBorderThickness, y, popup_width, kPasswordSectionHeight); + kPopupBorderThickness, + y, + popup_width, + PasswordGenerationPopupController::kPopupPasswordSectionHeight); divider_bounds_ = gfx::Rect(kPopupBorderThickness, password_view_->bounds().bottom(), popup_width, 1); |