summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordschuyler <dschuyler@chromium.org>2015-05-28 14:41:57 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-28 21:42:25 +0000
commit330027c8db08545748e034bced2a3962d08759a3 (patch)
treebbcba781ea5d4beb5e5f70d2d8eaa0c61dbf208f
parentdb4d433ae7ce4cd1a0770798328db86f933bcc03 (diff)
downloadchromium_src-330027c8db08545748e034bced2a3962d08759a3.zip
chromium_src-330027c8db08545748e034bced2a3962d08759a3.tar.gz
chromium_src-330027c8db08545748e034bced2a3962d08759a3.tar.bz2
[AiS] answer font styling
Answers in Suggest calls for mixed font styling. This CL allows for font size, color, and baseline to be controlled via the downloaded answer test style types. BUG=449593 Review URL: https://codereview.chromium.org/1125513002 Cr-Commit-Position: refs/heads/master@{#331858}
-rw-r--r--chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h2
-rw-r--r--chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm193
-rw-r--r--chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm39
-rw-r--r--chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h2
-rw-r--r--chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm16
-rw-r--r--components/omnibox/suggestion_answer.h18
6 files changed, 242 insertions, 28 deletions
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
index d2f3736..7e60da9 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -46,6 +46,8 @@ class OmniboxPopupViewMac;
- (void)setMatch:(const AutocompleteMatch&)match;
+- (NSAttributedString*)description;
+
- (void)setMaxMatchContentsWidth:(CGFloat)maxMatchContentsWidth;
- (void)setContentsOffset:(CGFloat)contentsOffset;
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
index 5100d12..67d7c22 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -18,6 +18,7 @@
#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
#include "chrome/grit/generated_resources.h"
#include "components/omnibox/suggestion_answer.h"
+#include "skia/ext/skia_utils_mac.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/font.h"
@@ -66,6 +67,12 @@ NSColor* ContentTextColor() {
NSColor* DimTextColor() {
return [NSColor darkGrayColor];
}
+NSColor* PositiveTextColor() {
+ return gfx::SkColorToCalibratedNSColor(SkColorSetRGB(0x0b, 0x80, 0x43));
+}
+NSColor* NegativeTextColor() {
+ return gfx::SkColorToCalibratedNSColor(SkColorSetRGB(0xc5, 0x39, 0x29));
+}
NSColor* URLTextColor() {
return [NSColor colorWithCalibratedRed:0.0 green:0.55 blue:0.0 alpha:1.0];
}
@@ -76,11 +83,126 @@ NSFont* FieldFont() {
NSFont* BoldFieldFont() {
return OmniboxViewMac::GetFieldFont(gfx::Font::BOLD);
}
+NSFont* LargeFont() {
+ return OmniboxViewMac::GetLargeFont(gfx::Font::NORMAL);
+}
+NSFont* LargeSuperscriptFont() {
+ NSFont* font = OmniboxViewMac::GetLargeFont(gfx::Font::NORMAL);
+ // Calculate a slightly smaller font. The ratio here is somewhat arbitrary.
+ // Proportions from 5/9 to 5/7 all look pretty good.
+ CGFloat size = [font pointSize] * 5.0 / 9.0;
+ NSFontDescriptor* descriptor = [font fontDescriptor];
+ return [NSFont fontWithDescriptor:descriptor size:size];
+}
+NSFont* SmallFont() {
+ return OmniboxViewMac::GetSmallFont(gfx::Font::NORMAL);
+}
CGFloat GetContentAreaWidth(NSRect cellFrame) {
return NSWidth(cellFrame) - kTextStartOffset;
}
+NSAttributedString* CreateAnswerString(const base::string16& text,
+ NSInteger style_type) {
+ NSDictionary* answer_style = nil;
+ switch (style_type) {
+ case SuggestionAnswer::ANSWER:
+ answer_style = @{
+ NSForegroundColorAttributeName : ContentTextColor(),
+ NSFontAttributeName : LargeFont()
+ };
+ break;
+ case SuggestionAnswer::HEADLINE:
+ answer_style = @{
+ NSForegroundColorAttributeName : DimTextColor(),
+ NSFontAttributeName : LargeFont()
+ };
+ break;
+ case SuggestionAnswer::TOP_ALIGNED:
+ answer_style = @{
+ NSForegroundColorAttributeName : DimTextColor(),
+ NSFontAttributeName : LargeSuperscriptFont(),
+ NSSuperscriptAttributeName : @1
+ };
+ break;
+ case SuggestionAnswer::DESCRIPTION:
+ answer_style = @{
+ NSForegroundColorAttributeName : DimTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ case SuggestionAnswer::DESCRIPTION_NEGATIVE:
+ answer_style = @{
+ NSForegroundColorAttributeName : NegativeTextColor(),
+ NSFontAttributeName : LargeSuperscriptFont()
+ };
+ break;
+ case SuggestionAnswer::DESCRIPTION_POSITIVE:
+ answer_style = @{
+ NSForegroundColorAttributeName : PositiveTextColor(),
+ NSFontAttributeName : LargeSuperscriptFont()
+ };
+ break;
+ case SuggestionAnswer::MORE_INFO:
+ answer_style = @{
+ NSForegroundColorAttributeName : DimTextColor(),
+ NSFontAttributeName : SmallFont()
+ };
+ break;
+ case SuggestionAnswer::SUGGESTION:
+ answer_style = @{
+ NSForegroundColorAttributeName : ContentTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ case SuggestionAnswer::SUGGESTION_POSITIVE:
+ answer_style = @{
+ NSForegroundColorAttributeName : PositiveTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ case SuggestionAnswer::SUGGESTION_NEGATIVE:
+ answer_style = @{
+ NSForegroundColorAttributeName : NegativeTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ case SuggestionAnswer::SUGGESTION_LINK:
+ answer_style = @{
+ NSForegroundColorAttributeName : URLTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ case SuggestionAnswer::STATUS:
+ answer_style = @{
+ NSForegroundColorAttributeName : DimTextColor(),
+ NSFontAttributeName : LargeSuperscriptFont()
+ };
+ break;
+ case SuggestionAnswer::PERSONALIZED_SUGGESTION:
+ answer_style = @{
+ NSForegroundColorAttributeName : ContentTextColor(),
+ NSFontAttributeName : FieldFont()
+ };
+ break;
+ }
+
+ // Start out with a string using the default style info.
+ base::scoped_nsobject<NSMutableAttributedString> attributed_string(
+ [[NSMutableAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(text)
+ attributes:answer_style]);
+
+ base::scoped_nsobject<NSMutableParagraphStyle> style(
+ [[NSMutableParagraphStyle alloc] init]);
+ [style setLineBreakMode:NSLineBreakByTruncatingTail];
+ [style setTighteningFactorForTruncation:0.0];
+ [attributed_string addAttribute:NSParagraphStyleAttributeName
+ value:style
+ range:NSMakeRange(0, [attributed_string length])];
+ return attributed_string.autorelease();
+}
+
NSMutableAttributedString* CreateAttributedString(
const base::string16& text,
NSColor* text_color,
@@ -91,21 +213,20 @@ NSMutableAttributedString* CreateAttributedString(
NSFontAttributeName : FieldFont(),
NSForegroundColorAttributeName : text_color
};
- NSMutableAttributedString* as =
- [[[NSMutableAttributedString alloc] initWithString:s
- attributes:attributes]
- autorelease];
+ NSMutableAttributedString* attributedString = [[
+ [NSMutableAttributedString alloc] initWithString:s
+ attributes:attributes] autorelease];
NSMutableParagraphStyle* style =
[[[NSMutableParagraphStyle alloc] init] autorelease];
[style setLineBreakMode:NSLineBreakByTruncatingTail];
[style setTighteningFactorForTruncation:0.0];
[style setAlignment:textAlignment];
- [as addAttribute:NSParagraphStyleAttributeName
- value:style
- range:NSMakeRange(0, [as length])];
+ [attributedString addAttribute:NSParagraphStyleAttributeName
+ value:style
+ range:NSMakeRange(0, [attributedString length])];
- return as;
+ return attributedString;
}
NSMutableAttributedString* CreateAttributedString(
@@ -118,8 +239,9 @@ NSAttributedString* CreateClassifiedAttributedString(
const base::string16& text,
NSColor* text_color,
const ACMatchClassifications& classifications) {
- NSMutableAttributedString* as = CreateAttributedString(text, text_color);
- NSUInteger match_length = [as length];
+ NSMutableAttributedString* attributedString =
+ CreateAttributedString(text, text_color);
+ NSUInteger match_length = [attributedString length];
// Mark up the runs which differ from the default.
for (ACMatchClassifications::const_iterator i = classifications.begin();
@@ -136,21 +258,23 @@ NSAttributedString* CreateClassifiedAttributedString(
NSMakeRange(location, std::min(length, match_length - location));
if (0 != (i->style & ACMatchClassification::MATCH)) {
- [as addAttribute:NSFontAttributeName value:BoldFieldFont() range:range];
+ [attributedString addAttribute:NSFontAttributeName
+ value:BoldFieldFont()
+ range:range];
}
if (0 != (i->style & ACMatchClassification::URL)) {
- [as addAttribute:NSForegroundColorAttributeName
- value:URLTextColor()
- range:range];
+ [attributedString addAttribute:NSForegroundColorAttributeName
+ value:URLTextColor()
+ range:range];
} else if (0 != (i->style & ACMatchClassification::DIM)) {
- [as addAttribute:NSForegroundColorAttributeName
- value:DimTextColor()
- range:range];
+ [attributedString addAttribute:NSForegroundColorAttributeName
+ value:DimTextColor()
+ range:range];
}
}
- return as;
+ return attributedString;
}
} // namespace
@@ -184,23 +308,32 @@ NSAttributedString* CreateClassifiedAttributedString(
NSAttributedString *contents = CreateClassifiedAttributedString(
match_.contents, ContentTextColor(), match_.contents_class);
[self setAttributedTitle:contents];
-
[self setAnswerImage:nil];
if (match_.answer) {
- base::string16 answerString;
+ 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 += textField.text();
+ 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 += space + textField->text();
+ if (textField) {
+ [answerString
+ appendAttributedString:CreateAnswerString(space + textField->text(),
+ textField->type())];
+ }
textField = match_.answer->second_line().status_text();
- if (textField)
- answerString += space + textField->text();
- description_.reset([CreateClassifiedAttributedString(
- answerString, DimTextColor(), match_.description_class) retain]);
+ if (textField) {
+ [answerString
+ appendAttributedString:CreateAnswerString(space + textField->text(),
+ textField->type())];
+ }
+ description_.reset(answerString.release());
} else if (match_.description.empty()) {
description_.reset();
} else {
@@ -209,6 +342,10 @@ NSAttributedString* CreateClassifiedAttributedString(
}
}
+- (NSAttributedString*)description {
+ return description_;
+}
+
- (void)setMaxMatchContentsWidth:(CGFloat)maxMatchContentsWidth {
maxMatchContentsWidth_ = maxMatchContentsWidth;
}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
index e4bb64b..0367a84 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
@@ -4,8 +4,12 @@
#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
+#include "base/json/json_reader.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/values.h"
#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "components/omnibox/suggestion_answer.h"
+#import "testing/gtest_mac.h"
namespace {
@@ -44,4 +48,39 @@ TEST_F(OmniboxPopupCellTest, Title) {
[button_ display];
}
+TEST_F(OmniboxPopupCellTest, AnswerStyle) {
+ const char* weatherJson =
+ "{\"l\": [ {\"il\": {\"t\": [ {"
+ "\"t\": \"weather in pari&lt;b&gt;s&lt;/b&gt;\", \"tt\": 8} ]}}, {"
+ "\"il\": {\"at\": {\"t\": \"Thu\",\"tt\": 12}, "
+ "\"i\": {\"d\": \"//ssl.gstatic.com/onebox/weather/64/cloudy.png\","
+ "\"t\": 3}, \"t\": [ {\"t\": \"46\",\"tt\": 1}, {"
+ "\"t\": \"°F\",\"tt\": 3} ]}} ]}";
+ NSString* finalString = @"46°F Thu";
+
+ scoped_ptr<base::Value> root(base::JSONReader::Read(weatherJson));
+ ASSERT_NE(root, nullptr);
+ base::DictionaryValue* dictionary;
+ root->GetAsDictionary(&dictionary);
+ ASSERT_NE(dictionary, nullptr);
+ AutocompleteMatch match;
+ match.answer = SuggestionAnswer::ParseAnswer(dictionary);
+ EXPECT_TRUE(match.answer);
+ [cell_ setMatch:match];
+ EXPECT_NSEQ([[cell_ description] string], finalString);
+ size_t length = [[cell_ description] length];
+ const NSRange checkValues[] = {{0, 2}, {2, 2}, {4, 4}};
+ EXPECT_EQ(length, 8UL);
+ NSDictionary* lastAttributes = nil;
+ for (const NSRange& value : checkValues) {
+ NSRange range;
+ NSDictionary* currentAttributes =
+ [[cell_ description] attributesAtIndex:value.location
+ effectiveRange:&range];
+ EXPECT_TRUE(NSEqualRanges(value, range));
+ EXPECT_FALSE([currentAttributes isEqualToDictionary:lastAttributes]);
+ lastAttributes = currentAttributes;
+ }
+}
+
} // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
index ec0d2c13..385b79ed 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
@@ -102,6 +102,8 @@ class OmniboxViewMac : public OmniboxView,
// The style parameter specifies the new style for the font, and is a
// bitmask of the values: BOLD, ITALIC and UNDERLINE (see ui/gfx/font.h).
static NSFont* GetFieldFont(int style);
+ static NSFont* GetLargeFont(int style);
+ static NSFont* GetSmallFont(int style);
// If |resource_id| has a PDF image which can be used, return it.
// Otherwise return the PNG image from the resource bundle.
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index efa97fe..0e8f701 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -1021,6 +1021,22 @@ NSFont* OmniboxViewMac::GetFieldFont(int style) {
.GetPrimaryFont().GetNativeFont();
}
+NSFont* OmniboxViewMac::GetLargeFont(int style) {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ return rb.GetFontList(ui::ResourceBundle::LargeFont)
+ .Derive(1, style)
+ .GetPrimaryFont()
+ .GetNativeFont();
+}
+
+NSFont* OmniboxViewMac::GetSmallFont(int style) {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ return rb.GetFontList(ui::ResourceBundle::SmallFont)
+ .Derive(1, style)
+ .GetPrimaryFont()
+ .GetNativeFont();
+}
+
int OmniboxViewMac::GetOmniboxTextLength() const {
return static_cast<int>(GetTextLength());
}
diff --git a/components/omnibox/suggestion_answer.h b/components/omnibox/suggestion_answer.h
index a2df1bc..98e3969 100644
--- a/components/omnibox/suggestion_answer.h
+++ b/components/omnibox/suggestion_answer.h
@@ -35,6 +35,24 @@ class SuggestionAnswer {
typedef std::vector<TextField> TextFields;
typedef std::vector<GURL> URLs;
+ // These values are named and numbered to match a specification at go/ais_api.
+ // The values are only used for answer results.
+ enum TextType {
+ ANSWER = 1,
+ HEADLINE = 2,
+ TOP_ALIGNED = 3,
+ DESCRIPTION = 4,
+ DESCRIPTION_NEGATIVE = 5,
+ DESCRIPTION_POSITIVE = 6,
+ MORE_INFO = 7,
+ SUGGESTION = 8,
+ SUGGESTION_POSITIVE = 9,
+ SUGGESTION_NEGATIVE = 10,
+ SUGGESTION_LINK = 11,
+ STATUS = 12,
+ PERSONALIZED_SUGGESTION = 13,
+ };
+
class TextField {
public:
TextField();