Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3548)

Unified Diff: chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm

Issue 1099403005: [AiS] changing mac omnibox suggestions form NSMatrix to NSTableView (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merge form master Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
index 67d7c2239e23dd8aa5759ec2147f5047702d38e6..4b706e64fe7bc2c621b6a5379c13fff9e1cbff01 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -24,6 +24,13 @@
namespace {
+// How much to adjust the cell sizing up from the default determined
+// by the font.
+const CGFloat kCellHeightAdjust = 6.0;
+
+// How large the icon should be when displayed.
+const CGFloat kImageSize = 19.0;
+
// How far to offset image column from the left.
const CGFloat kImageXOffset = 5.0;
@@ -279,73 +286,149 @@ NSAttributedString* CreateClassifiedAttributedString(
} // namespace
-@implementation OmniboxPopupCell
-
-- (id)init {
- self = [super init];
- if (self) {
- [self setImagePosition:NSImageLeft];
- [self setBordered:NO];
- [self setButtonType:NSRadioButton];
+@interface OmniboxPopupCell ()
+- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString
+ withFrame:(NSRect)cellFrame
+ atOffset:(CGFloat)offset
+ withMaxWidth:(int)maxWidth
+ inView:(NSView*)controlView;
+@end
- // Without this highlighting messes up white areas of images.
- [self setHighlightsBy:NSNoCellMask];
+@interface OmniboxPopupCellData ()
+- (NSAttributedString*)contents;
+- (NSAttributedString*)description;
+- (NSAttributedString*)prefix;
+- (NSImage*)image;
+- (NSImage*)answerImage;
+- (CGFloat)maxMatchContentsWidth;
+- (CGFloat)contentsOffset;
+- (bool)isContentsRTL;
+- (AutocompleteMatch::Type)matchType;
+@end
- const base::string16& raw_separator =
- l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
- separator_.reset(
- [CreateAttributedString(raw_separator, DimTextColor()) retain]);
+@implementation OmniboxPopupCellData
+
+- (instancetype)initWithMatch:(const AutocompleteMatch&)match
+ image:(NSImage*)image {
+ if ((self = [super init])) {
+ image_.reset([image retain]);
+
+ isContentsRTL_ =
+ (base::i18n::RIGHT_TO_LEFT ==
+ base::i18n::GetFirstStrongCharacterDirection(match.contents));
+ matchType_ = match.type;
+
+ // Prefix may not have any characters with strong directionality, and may
+ // take the UI directionality. But prefix needs to appear in continuation
+ // of the contents so we force the directionality.
+ NSTextAlignment textAlignment =
+ isContentsRTL_ ? NSRightTextAlignment : NSLeftTextAlignment;
+ prefix_.reset(
+ [CreateAttributedString(base::UTF8ToUTF16(match.GetAdditionalInfo(
+ kACMatchPropertyContentsPrefix)),
+ ContentTextColor(), textAlignment) retain]);
+
+ contents_.reset([CreateClassifiedAttributedString(
+ match.contents, ContentTextColor(), match.contents_class) retain]);
+
+ if (match.answer) {
+ base::scoped_nsobject<NSMutableAttributedString> answerString(
+ [[NSMutableAttributedString alloc] init]);
+ DCHECK(!match.answer->second_line().text_fields().empty());
+ for (const SuggestionAnswer::TextField& textField :
+ match.answer->second_line().text_fields()) {
+ [answerString
+ appendAttributedString:CreateAnswerString(textField.text(),
+ textField.type())];
+ }
+ const base::string16 space(base::ASCIIToUTF16(" "));
+ // const base::char16 space(' ');
+ const SuggestionAnswer::TextField* textField =
+ match.answer->second_line().additional_text();
+ if (textField) {
+ [answerString
+ appendAttributedString:CreateAnswerString(space + textField->text(),
+ textField->type())];
+ }
+ textField = match.answer->second_line().status_text();
+ if (textField) {
+ [answerString
+ appendAttributedString:CreateAnswerString(space + textField->text(),
+ textField->type())];
+ }
+ description_.reset(answerString.release());
+ } else if (match.description.empty()) {
+ description_.reset();
+ } else {
+ description_.reset([CreateClassifiedAttributedString(
+ match.description, DimTextColor(), match.description_class) retain]);
+ }
}
return self;
}
+- (instancetype)copyWithZone:(NSZone*)zone {
+ OmniboxPopupCellData* copy = [[OmniboxPopupCellData alloc] init];
groby-ooo-7-16 2015/06/11 01:22:17 Since we seem to retain all the members - iow, thi
Scott Hess - ex-Googler 2015/06/11 21:52:02 Yeah, as long as it's returning a shallow copy, sh
dschuyler 2015/06/11 22:34:22 That seems to work nicely. Done.
dschuyler 2015/06/11 22:34:22 Done.
+ copy->contents_.reset([contents_ retain]);
+ copy->description_.reset([description_ retain]);
+ copy->prefix_.reset([prefix_ retain]);
+ copy->image_.reset([image_ retain]);
+ copy->answerImage_.reset([answerImage_ retain]);
+ copy->maxMatchContentsWidth_ = maxMatchContentsWidth_;
+ copy->contentsOffset_ = contentsOffset_;
+ copy->isContentsRTL_ = isContentsRTL_;
+ copy->matchType_ = matchType_;
+ return copy;
+}
+
+- (void)setContents:(NSAttributedString*)contents {
+ contents_.reset([contents retain]);
+}
+
+- (void)setImage:(NSImage*)image {
+ image_.reset([image retain]);
+}
+
- (void)setAnswerImage:(NSImage*)image {
answerImage_.reset([image retain]);
}
-- (void)setMatch:(const AutocompleteMatch&)match {
- match_ = match;
- NSAttributedString *contents = CreateClassifiedAttributedString(
- match_.contents, ContentTextColor(), match_.contents_class);
- [self setAttributedTitle:contents];
- [self setAnswerImage:nil];
- if (match_.answer) {
- base::scoped_nsobject<NSMutableAttributedString> answerString(
- [[NSMutableAttributedString alloc] init]);
- DCHECK(!match_.answer->second_line().text_fields().empty());
- for (const SuggestionAnswer::TextField& textField :
- match_.answer->second_line().text_fields()) {
- NSAttributedString* as =
- CreateAnswerString(textField.text(), textField.type());
- [answerString appendAttributedString:as];
- }
- const base::char16 space(' ');
- const SuggestionAnswer::TextField* textField =
- match_.answer->second_line().additional_text();
- if (textField) {
- [answerString
- appendAttributedString:CreateAnswerString(space + textField->text(),
- textField->type())];
- }
- textField = match_.answer->second_line().status_text();
- if (textField) {
- [answerString
- appendAttributedString:CreateAnswerString(space + textField->text(),
- textField->type())];
- }
- description_.reset(answerString.release());
- } else if (match_.description.empty()) {
- description_.reset();
- } else {
- description_.reset([CreateClassifiedAttributedString(
- match_.description, DimTextColor(), match_.description_class) retain]);
- }
+- (NSAttributedString*)contents {
+ return contents_;
}
- (NSAttributedString*)description {
return description_;
}
+- (NSAttributedString*)prefix {
+ return prefix_;
+}
+
+- (NSImage*)image {
+ return image_;
+}
+
+- (NSImage*)answerImage {
+ return answerImage_;
+}
+
+- (CGFloat)maxMatchContentsWidth {
+ return maxMatchContentsWidth_;
+}
+
+- (CGFloat)contentsOffset {
+ return contentsOffset_;
+}
+
+- (bool)isContentsRTL {
+ return isContentsRTL_;
+}
+
+- (AutocompleteMatch::Type)matchType {
+ return matchType_;
+}
+
- (void)setMaxMatchContentsWidth:(CGFloat)maxMatchContentsWidth {
maxMatchContentsWidth_ = maxMatchContentsWidth;
}
@@ -354,10 +437,29 @@ NSAttributedString* CreateClassifiedAttributedString(
contentsOffset_ = contentsOffset;
}
-// The default NSButtonCell drawing leaves the image flush left and
-// the title next to the image. This spaces things out to line up
-// with the star button and autocomplete field.
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
+- (CGFloat)getMatchContentsWidth {
+ return [contents_ size].width;
+}
+
+- (CGFloat)rowHeight {
+ return kImageSize + kCellHeightAdjust;
+}
+
+@end
+
+@implementation OmniboxPopupCell
+
+- (instancetype)init {
+ if ((self = [super init])) {
+ base::string16 raw_separator =
+ l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
+ separator_.reset(
+ [CreateAttributedString(raw_separator, DimTextColor()) retain]);
+ }
+ return self;
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
if ([self state] == NSOnState || [self isHighlighted]) {
if ([self state] == NSOnState)
[SelectedBackgroundColor() set];
@@ -370,51 +472,51 @@ NSAttributedString* CreateClassifiedAttributedString(
[path fill];
}
- // Put the image centered vertically but in a fixed column.
- NSImage* image = [self image];
- if (image) {
- NSRect imageRect = cellFrame;
- imageRect.size = [image size];
- imageRect.origin.y +=
- std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
- imageRect.origin.x += kImageXOffset;
- [image drawInRect:FlipIfRTL(imageRect, cellFrame)
- fromRect:NSZeroRect // Entire image
- operation:NSCompositeSourceOver
- fraction:1.0
- respectFlipped:YES
- hints:nil];
- }
-
- [self drawMatchWithFrame:cellFrame inView:controlView];
+ [self drawMatchWithFrame:cellFrame
+ withCellData:[self objectValue]
+ inView:controlView];
}
-- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- NSAttributedString* contents = [self attributedTitle];
-
+- (void)drawMatchWithFrame:(NSRect)cellFrame
+ withCellData:(OmniboxPopupCellData*)cellData
+ inView:(NSView*)controlView {
CGFloat remainingWidth = GetContentAreaWidth(cellFrame);
- CGFloat contentsWidth = [self getMatchContentsWidth];
+ CGFloat contentsWidth = [cellData getMatchContentsWidth];
CGFloat separatorWidth = [separator_ size].width;
- CGFloat descriptionWidth = description_.get() ? [description_ size].width : 0;
+ CGFloat descriptionWidth =
+ [cellData description] ? [[cellData description] size].width : 0;
int contentsMaxWidth, descriptionMaxWidth;
OmniboxPopupModel::ComputeMatchMaxWidths(
- ceilf(contentsWidth),
- ceilf(separatorWidth),
- ceilf(descriptionWidth),
+ ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth),
ceilf(remainingWidth),
- !AutocompleteMatch::IsSearchType(match_.type),
- &contentsMaxWidth,
+ !AutocompleteMatch::IsSearchType([cellData matchType]), &contentsMaxWidth,
&descriptionMaxWidth);
+ // Put the image centered vertically but in a fixed column.
+ if ([cellData image]) {
+ NSRect imageRect = cellFrame;
+ imageRect.size = [[cellData image] size];
+ imageRect.origin.y +=
+ std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
+ imageRect.origin.x += kImageXOffset;
+ [[cellData image] drawInRect:FlipIfRTL(imageRect, cellFrame)
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ respectFlipped:YES
+ hints:nil];
+ }
+
CGFloat offset = kTextStartOffset;
- if (match_.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) {
+ if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) {
// Infinite suggestions are rendered with a prefix (usually ellipsis), which
// appear vertically stacked.
offset += [self drawMatchPrefixWithFrame:cellFrame
+ withCellData:cellData
inView:controlView
withContentsMaxWidth:&contentsMaxWidth];
}
- offset += [self drawMatchPart:contents
+ offset += [self drawMatchPart:[cellData contents]
withFrame:cellFrame
atOffset:offset
withMaxWidth:contentsMaxWidth
@@ -426,18 +528,18 @@ NSAttributedString* CreateClassifiedAttributedString(
atOffset:offset
withMaxWidth:separatorWidth
inView:controlView];
- if (answerImage_) {
+ if ([cellData answerImage]) {
NSRect imageRect = NSMakeRect(offset, NSMinY(cellFrame),
NSHeight(cellFrame), NSHeight(cellFrame));
- [answerImage_ drawInRect:FlipIfRTL(imageRect, cellFrame)
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0
- respectFlipped:YES
- hints:nil];
+ [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame)
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ respectFlipped:YES
+ hints:nil];
offset += NSWidth(imageRect);
}
- offset += [self drawMatchPart:description_
+ offset += [self drawMatchPart:[cellData description]
withFrame:cellFrame
atOffset:offset
withMaxWidth:descriptionMaxWidth
@@ -446,48 +548,39 @@ NSAttributedString* CreateClassifiedAttributedString(
}
- (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame
+ withCellData:(OmniboxPopupCellData*)cellData
inView:(NSView*)controlView
withContentsMaxWidth:(int*)contentsMaxWidth {
CGFloat offset = 0.0f;
CGFloat remainingWidth = GetContentAreaWidth(cellFrame);
- bool isRTL = base::i18n::IsRTL();
- bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT ==
- base::i18n::GetFirstStrongCharacterDirection(match_.contents));
- // Prefix may not have any characters with strong directionality, and may take
- // the UI directionality. But prefix needs to appear in continuation of the
- // contents so we force the directionality.
- NSTextAlignment textAlignment = isContentsRTL ?
- NSRightTextAlignment : NSLeftTextAlignment;
- prefix_.reset([CreateAttributedString(base::UTF8ToUTF16(
- match_.GetAdditionalInfo(kACMatchPropertyContentsPrefix)),
- ContentTextColor(), textAlignment) retain]);
- CGFloat prefixWidth = [prefix_ size].width;
+ CGFloat prefixWidth = [[cellData prefix] size].width;
CGFloat prefixOffset = 0.0f;
- if (isRTL != isContentsRTL) {
+ if (base::i18n::IsRTL() != [cellData isContentsRTL]) {
// The contents is rendered between the contents offset extending towards
// the start edge, while prefix is rendered in opposite direction. Ideally
// the prefix should be rendered at |contentsOffset_|. If that is not
// sufficient to render the widest suggestion, we increase it to
- // |maxMatchContentsWidth_|. If |remainingWidth| is not sufficient to
+ // |maxMatchContentsWidth|. If |remainingWidth| is not sufficient to
// accommodate that, we reduce the offset so that the prefix gets rendered.
prefixOffset = std::min(
- remainingWidth - prefixWidth, std::max(contentsOffset_,
- maxMatchContentsWidth_));
+ remainingWidth - prefixWidth,
+ std::max([cellData contentsOffset], [cellData maxMatchContentsWidth]));
offset = std::max<CGFloat>(0.0, prefixOffset - *contentsMaxWidth);
} else { // The direction of contents is same as UI direction.
// Ideally the offset should be |contentsOffset_|. If the max total width
- // (|prefixWidth| + |maxMatchContentsWidth_|) from offset will exceed the
+ // (|prefixWidth| + |maxMatchContentsWidth|) from offset will exceed the
// |remainingWidth|, then we shift the offset to the left , so that all
// postfix suggestions are visible.
// We have to render the prefix, so offset has to be at least |prefixWidth|.
- offset = std::max(prefixWidth,
- std::min(remainingWidth - maxMatchContentsWidth_, contentsOffset_));
+ offset = std::max(
+ prefixWidth, std::min(remainingWidth - [cellData maxMatchContentsWidth],
+ [cellData contentsOffset]));
prefixOffset = offset - prefixWidth;
}
*contentsMaxWidth = std::min((int)ceilf(remainingWidth - prefixWidth),
*contentsMaxWidth);
- [self drawMatchPart:prefix_
+ [self drawMatchPart:[cellData prefix]
withFrame:cellFrame
atOffset:prefixOffset + kTextStartOffset
withMaxWidth:prefixWidth
@@ -495,7 +588,7 @@ NSAttributedString* CreateClassifiedAttributedString(
return offset;
}
-- (CGFloat)drawMatchPart:(NSAttributedString*)as
+- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString
withFrame:(NSRect)cellFrame
atOffset:(CGFloat)offset
withMaxWidth:(int)maxWidth
@@ -505,20 +598,15 @@ NSAttributedString* CreateClassifiedAttributedString(
NSRect renderRect = ShiftRect(cellFrame, offset);
renderRect.size.width =
std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth));
- if (renderRect.size.width != 0) {
- [self drawTitle:as
- withFrame:FlipIfRTL(renderRect, cellFrame)
- inView:controlView];
- }
+ NSRect textRect =
+ [attributedString boundingRectWithSize:renderRect.size options:nil];
+ renderRect.origin.y +=
+ std::floor((NSHeight(cellFrame) - NSHeight(textRect)) / 2.0);
+ if (NSWidth(renderRect) > 0.0)
+ [attributedString drawInRect:FlipIfRTL(renderRect, cellFrame)];
return NSWidth(renderRect);
}
-- (CGFloat)getMatchContentsWidth {
- NSAttributedString* contents = [self attributedTitle];
- return contents ? [contents size].width : 0;
-}
-
-
+ (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match {
const base::string16& inputText = base::UTF8ToUTF16(
match.GetAdditionalInfo(kACMatchPropertyInputText));
@@ -537,9 +625,10 @@ NSAttributedString* CreateClassifiedAttributedString(
base::i18n::GetFirstStrongCharacterDirection(match.contents));
// Color does not matter.
- NSAttributedString* as = CreateAttributedString(inputText, DimTextColor());
- base::scoped_nsobject<NSTextStorage> textStorage([[NSTextStorage alloc]
- initWithAttributedString:as]);
+ NSAttributedString* attributedString =
+ CreateAttributedString(inputText, DimTextColor());
+ base::scoped_nsobject<NSTextStorage> textStorage(
+ [[NSTextStorage alloc] initWithAttributedString:attributedString]);
base::scoped_nsobject<NSLayoutManager> layoutManager(
[[NSLayoutManager alloc] init]);
base::scoped_nsobject<NSTextContainer> textContainer(
@@ -555,7 +644,7 @@ NSAttributedString* CreateClassifiedAttributedString(
// left edge of the string, irrespective of the directionality of UI or text.
CGFloat glyphOffset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;
- CGFloat inputWidth = [as size].width;
+ CGFloat inputWidth = [attributedString size].width;
// The offset obtained above may need to be corrected because the left-most
// glyph may not have 0 offset. So we find the offset of left-most glyph, and
@@ -569,7 +658,7 @@ NSAttributedString* CreateClassifiedAttributedString(
// we are looking for.
CGFloat glyphWidth = inputWidth;
- for (NSUInteger i = 0; i < [as length]; i++) {
+ for (NSUInteger i = 0; i < [attributedString length]; i++) {
if (i == charIndex) continue;
glyphIndex = [layoutManager glyphIndexForCharacterAtIndex:i];
CGFloat offset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;

Powered by Google App Engine
This is Rietveld 408576698