Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" | 5 #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cmath> | 10 #include <cmath> |
| 11 | 11 |
| 12 #include "base/feature_list.h" | |
| 12 #include "base/i18n/rtl.h" | 13 #include "base/i18n/rtl.h" |
| 13 #include "base/mac/foundation_util.h" | 14 #include "base/mac/foundation_util.h" |
| 14 #include "base/mac/objc_property_releaser.h" | 15 #include "base/mac/objc_property_releaser.h" |
| 15 #include "base/mac/scoped_nsobject.h" | 16 #include "base/mac/scoped_nsobject.h" |
| 16 #include "base/metrics/field_trial_params.h" | 17 #include "base/metrics/field_trial_params.h" |
| 17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 19 #include "base/strings/sys_string_conversions.h" | 20 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 21 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" | 22 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 33 | 34 |
| 34 namespace { | 35 namespace { |
| 35 | 36 |
| 36 // Extra padding beyond the vertical text padding. | 37 // Extra padding beyond the vertical text padding. |
| 37 constexpr CGFloat kMaterialExtraVerticalImagePadding = 2.0; | 38 constexpr CGFloat kMaterialExtraVerticalImagePadding = 2.0; |
| 38 | 39 |
| 39 constexpr CGFloat kMaterialTextStartOffset = 27.0; | 40 constexpr CGFloat kMaterialTextStartOffset = 27.0; |
| 40 | 41 |
| 41 constexpr CGFloat kMaterialImageXOffset = 6.0; | 42 constexpr CGFloat kMaterialImageXOffset = 6.0; |
| 42 | 43 |
| 44 constexpr CGFloat kDefaultVerticalMargin = 3.0; | |
| 45 | |
| 46 constexpr CGFloat kDefaultTextHeight = 19; | |
| 47 | |
| 43 // Returns the margin that should appear at the top and bottom of the result. | 48 // Returns the margin that should appear at the top and bottom of the result. |
| 44 CGFloat GetVerticalMargin() { | 49 CGFloat GetVerticalMargin() { |
| 45 constexpr CGFloat kDefaultVerticalMargin = 3.0; | |
| 46 | |
| 47 return base::GetFieldTrialParamByFeatureAsInt( | 50 return base::GetFieldTrialParamByFeatureAsInt( |
| 48 omnibox::kUIExperimentVerticalMargin, | 51 omnibox::kUIExperimentVerticalMargin, |
| 49 OmniboxFieldTrial::kUIVerticalMarginParam, kDefaultVerticalMargin); | 52 OmniboxFieldTrial::kUIVerticalMarginParam, kDefaultVerticalMargin); |
| 50 } | 53 } |
| 51 | 54 |
| 52 // Flips the given |rect| in context of the given |frame|. | 55 // Flips the given |rect| in context of the given |frame|. |
| 53 NSRect FlipIfRTL(NSRect rect, NSRect frame) { | 56 NSRect FlipIfRTL(NSRect rect, NSRect frame) { |
| 54 DCHECK_LE(NSMinX(frame), NSMinX(rect)); | 57 DCHECK_LE(NSMinX(frame), NSMinX(rect)); |
| 55 DCHECK_GE(NSMaxX(frame), NSMaxX(rect)); | 58 DCHECK_GE(NSMaxX(frame), NSMaxX(rect)); |
| 56 if (base::i18n::IsRTL()) { | 59 if (base::i18n::IsRTL()) { |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 [CreateAnswerLine(match.answer->second_line(), isDarkTheme) retain]; | 420 [CreateAnswerLine(match.answer->second_line(), isDarkTheme) retain]; |
| 418 maxLines_ = match.answer->second_line().num_text_lines(); | 421 maxLines_ = match.answer->second_line().num_text_lines(); |
| 419 } else { | 422 } else { |
| 420 contents_ = [CreateClassifiedAttributedString( | 423 contents_ = [CreateClassifiedAttributedString( |
| 421 match.contents, ContentTextColor(isDarkTheme), match.contents_class, | 424 match.contents, ContentTextColor(isDarkTheme), match.contents_class, |
| 422 isDarkTheme) retain]; | 425 isDarkTheme) retain]; |
| 423 if (!match.description.empty()) { | 426 if (!match.description.empty()) { |
| 424 description_ = [CreateClassifiedAttributedString( | 427 description_ = [CreateClassifiedAttributedString( |
| 425 match.description, DimTextColor(isDarkTheme), | 428 match.description, DimTextColor(isDarkTheme), |
| 426 match.description_class, isDarkTheme) retain]; | 429 match.description_class, isDarkTheme) retain]; |
| 430 | |
| 431 if (base::FeatureList::IsEnabled( | |
| 432 omnibox::kUIExperimentVerticalLayout) && | |
| 433 !AutocompleteMatch::IsSearchType(match.type)) { | |
| 434 // Somtimes swap the contents and description in vertical layouts. | |
| 435 // TODO(tommycli): If vertical layouts become permanent, swap these | |
| 436 // in the underlying match instead of the UI code. | |
| 437 NSAttributedString* temp = contents_; | |
| 438 contents_ = description_; | |
| 439 description_ = temp; | |
| 440 } | |
| 427 } | 441 } |
| 428 maxLines_ = 1; | |
|
tommycli
2017/05/26 22:28:14
Unused for non-answers. Probably good to followup
| |
| 429 } | 442 } |
| 430 propertyReleaser_OmniboxPopupCellData_.Init(self, | 443 propertyReleaser_OmniboxPopupCellData_.Init(self, |
| 431 [OmniboxPopupCellData class]); | 444 [OmniboxPopupCellData class]); |
| 432 } | 445 } |
| 433 return self; | 446 return self; |
| 434 } | 447 } |
| 435 | 448 |
| 436 - (instancetype)copyWithZone:(NSZone*)zone { | 449 - (instancetype)copyWithZone:(NSZone*)zone { |
| 437 return [self retain]; | 450 return [self retain]; |
| 438 } | 451 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 456 } else { | 469 } else { |
| 457 [HoveredBackgroundColor(isDarkTheme) set]; | 470 [HoveredBackgroundColor(isDarkTheme) set]; |
| 458 } | 471 } |
| 459 NSRectFillUsingOperation(cellFrame, NSCompositeSourceOver); | 472 NSRectFillUsingOperation(cellFrame, NSCompositeSourceOver); |
| 460 } | 473 } |
| 461 | 474 |
| 462 [self drawMatchWithFrame:cellFrame inView:controlView]; | 475 [self drawMatchWithFrame:cellFrame inView:controlView]; |
| 463 } | 476 } |
| 464 | 477 |
| 465 - (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { | 478 - (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { |
| 479 bool is_vertical_layout = | |
| 480 base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout); | |
| 481 | |
| 466 OmniboxPopupCellData* cellData = | 482 OmniboxPopupCellData* cellData = |
| 467 base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); | 483 base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); |
| 468 OmniboxPopupMatrix* tableView = | 484 OmniboxPopupMatrix* tableView = |
| 469 base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); | 485 base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); |
| 470 CGFloat remainingWidth = [OmniboxPopupCell getContentAreaWidth:cellFrame] - | 486 CGFloat remainingWidth = [OmniboxPopupCell getContentAreaWidth:cellFrame] - |
| 471 [tableView contentLeftPadding]; | 487 [tableView contentLeftPadding]; |
| 472 CGFloat contentsWidth = [cellData getMatchContentsWidth]; | 488 CGFloat contentsWidth = [cellData getMatchContentsWidth]; |
| 473 CGFloat separatorWidth = [[tableView separator] size].width; | 489 CGFloat separatorWidth = [[tableView separator] size].width; |
| 474 CGFloat descriptionWidth = | 490 CGFloat descriptionWidth = |
| 475 [cellData description] ? [[cellData description] size].width : 0; | 491 [cellData description] ? [[cellData description] size].width : 0; |
| 476 int contentsMaxWidth, descriptionMaxWidth; | 492 int contentsMaxWidth, descriptionMaxWidth; |
| 477 OmniboxPopupModel::ComputeMatchMaxWidths( | 493 OmniboxPopupModel::ComputeMatchMaxWidths( |
| 478 ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth), | 494 ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth), |
| 479 ceilf(remainingWidth), | 495 ceilf(remainingWidth), [cellData isAnswer] || is_vertical_layout, |
| 480 [cellData isAnswer], | 496 !AutocompleteMatch::IsSearchType([cellData matchType]), &contentsMaxWidth, |
| 481 !AutocompleteMatch::IsSearchType([cellData matchType]), | |
| 482 &contentsMaxWidth, | |
| 483 &descriptionMaxWidth); | 497 &descriptionMaxWidth); |
| 484 | 498 |
| 499 CGFloat half_line_height = (kDefaultTextHeight + kDefaultVerticalMargin) / 2; | |
| 500 | |
| 485 NSWindow* parentWindow = [[controlView window] parentWindow]; | 501 NSWindow* parentWindow = [[controlView window] parentWindow]; |
| 486 BOOL isDarkTheme = [parentWindow hasDarkTheme]; | 502 BOOL isDarkTheme = [parentWindow hasDarkTheme]; |
| 487 NSRect imageRect = cellFrame; | 503 NSRect imageRect = cellFrame; |
| 488 NSImage* theImage = | 504 NSImage* theImage = |
| 489 isDarkTheme ? [cellData incognitoImage] : [cellData image]; | 505 isDarkTheme ? [cellData incognitoImage] : [cellData image]; |
| 490 imageRect.size = [theImage size]; | 506 imageRect.size = [theImage size]; |
| 491 imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding]; | 507 imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding]; |
| 492 imageRect.origin.y += | 508 imageRect.origin.y += |
| 493 GetVerticalMargin() + kMaterialExtraVerticalImagePadding; | 509 GetVerticalMargin() + kMaterialExtraVerticalImagePadding; |
| 510 if (is_vertical_layout) | |
| 511 imageRect.origin.y += half_line_height; | |
| 494 [theImage drawInRect:FlipIfRTL(imageRect, cellFrame) | 512 [theImage drawInRect:FlipIfRTL(imageRect, cellFrame) |
| 495 fromRect:NSZeroRect | 513 fromRect:NSZeroRect |
| 496 operation:NSCompositeSourceOver | 514 operation:NSCompositeSourceOver |
| 497 fraction:1.0 | 515 fraction:1.0 |
| 498 respectFlipped:YES | 516 respectFlipped:YES |
| 499 hints:nil]; | 517 hints:nil]; |
| 500 | 518 |
| 501 NSPoint origin = | 519 CGFloat left = kMaterialTextStartOffset + [tableView contentLeftPadding]; |
| 502 NSMakePoint(kMaterialTextStartOffset + [tableView contentLeftPadding], | 520 NSPoint origin = NSMakePoint(left, GetVerticalMargin()); |
| 503 GetVerticalMargin()); | 521 |
| 522 // For matches lacking description in vertical layout, center vertically. | |
| 523 if (is_vertical_layout && descriptionMaxWidth == 0) | |
| 524 origin.y += half_line_height; | |
| 525 | |
| 504 if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { | 526 if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { |
| 505 // Tail suggestions are rendered with a prefix (usually ellipsis), which | 527 // Tail suggestions are rendered with a prefix (usually ellipsis), which |
| 506 // appear vertically stacked. | 528 // appear vertically stacked. |
| 507 origin.x += [self drawMatchPrefixWithFrame:cellFrame | 529 origin.x += [self drawMatchPrefixWithFrame:cellFrame |
| 508 tableView:tableView | 530 tableView:tableView |
| 509 withContentsMaxWidth:&contentsMaxWidth | 531 withContentsMaxWidth:&contentsMaxWidth |
| 510 forDarkTheme:isDarkTheme]; | 532 forDarkTheme:isDarkTheme]; |
| 511 } | 533 } |
| 512 origin.x += [self drawMatchPart:[cellData contents] | 534 origin.x += [self drawMatchPart:[cellData contents] |
| 513 withFrame:cellFrame | 535 withFrame:cellFrame |
| 514 origin:origin | 536 origin:origin |
| 515 withMaxWidth:contentsMaxWidth | 537 withMaxWidth:contentsMaxWidth |
| 516 forDarkTheme:isDarkTheme]; | 538 forDarkTheme:isDarkTheme]; |
| 517 | 539 |
| 518 if (descriptionMaxWidth > 0) { | 540 if (descriptionMaxWidth > 0) { |
| 519 if ([cellData isAnswer]) { | 541 if ([cellData isAnswer]) { |
| 520 origin = NSMakePoint( | 542 origin = NSMakePoint(left, [OmniboxPopupCell getContentTextHeight:false] - |
| 521 kMaterialTextStartOffset + [tableView contentLeftPadding], | 543 GetVerticalMargin()); |
| 522 [OmniboxPopupCell getContentTextHeight] - GetVerticalMargin()); | |
| 523 CGFloat imageSize = [tableView answerLineHeight]; | 544 CGFloat imageSize = [tableView answerLineHeight]; |
| 524 NSRect imageRect = | 545 NSRect imageRect = |
| 525 NSMakeRect(NSMinX(cellFrame) + origin.x, NSMinY(cellFrame) + origin.y, | 546 NSMakeRect(NSMinX(cellFrame) + origin.x, NSMinY(cellFrame) + origin.y, |
| 526 imageSize, imageSize); | 547 imageSize, imageSize); |
| 527 [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame) | 548 [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame) |
| 528 fromRect:NSZeroRect | 549 fromRect:NSZeroRect |
| 529 operation:NSCompositeSourceOver | 550 operation:NSCompositeSourceOver |
| 530 fraction:1.0 | 551 fraction:1.0 |
| 531 respectFlipped:YES | 552 respectFlipped:YES |
| 532 hints:nil]; | 553 hints:nil]; |
| 533 if ([cellData answerImage]) { | 554 if ([cellData answerImage]) { |
| 534 origin.x += imageSize + kMaterialImageXOffset; | 555 origin.x += imageSize + kMaterialImageXOffset; |
| 535 | 556 |
| 536 // Have to nudge the baseline down 1pt in Material Design for the text | 557 // Have to nudge the baseline down 1pt in Material Design for the text |
| 537 // that follows, so that it's the same as the bottom of the image. | 558 // that follows, so that it's the same as the bottom of the image. |
| 538 origin.y += 1; | 559 origin.y += 1; |
| 539 } | 560 } |
| 540 } else { | 561 } else { |
| 541 origin.x += [self drawMatchPart:[tableView separator] | 562 if (is_vertical_layout) { |
| 542 withFrame:cellFrame | 563 origin.x = left; |
| 543 origin:origin | 564 origin.y += half_line_height * 2; |
| 544 withMaxWidth:separatorWidth | 565 } else { |
| 545 forDarkTheme:isDarkTheme]; | 566 origin.x += [self drawMatchPart:[tableView separator] |
| 567 withFrame:cellFrame | |
| 568 origin:origin | |
| 569 withMaxWidth:separatorWidth | |
| 570 forDarkTheme:isDarkTheme]; | |
| 571 } | |
| 546 } | 572 } |
| 547 origin.x += [self drawMatchPart:[cellData description] | 573 [self drawMatchPart:[cellData description] |
| 548 withFrame:cellFrame | 574 withFrame:cellFrame |
| 549 origin:origin | 575 origin:origin |
| 550 withMaxWidth:descriptionMaxWidth | 576 withMaxWidth:descriptionMaxWidth |
| 551 forDarkTheme:isDarkTheme]; | 577 forDarkTheme:isDarkTheme]; |
| 552 } | 578 } |
| 553 } | 579 } |
| 554 | 580 |
| 555 - (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame | 581 - (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame |
| 556 tableView:(OmniboxPopupMatrix*)tableView | 582 tableView:(OmniboxPopupMatrix*)tableView |
| 557 withContentsMaxWidth:(int*)contentsMaxWidth | 583 withContentsMaxWidth:(int*)contentsMaxWidth |
| 558 forDarkTheme:(BOOL)isDarkTheme { | 584 forDarkTheme:(BOOL)isDarkTheme { |
| 559 OmniboxPopupCellData* cellData = | 585 OmniboxPopupCellData* cellData = |
| 560 base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); | 586 base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); |
| 561 CGFloat offset = 0.0f; | 587 CGFloat offset = 0.0f; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 688 + (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme { | 714 + (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme { |
| 689 base::string16 raw_separator = | 715 base::string16 raw_separator = |
| 690 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); | 716 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); |
| 691 return CreateAttributedString(raw_separator, DimTextColor(isDarkTheme)); | 717 return CreateAttributedString(raw_separator, DimTextColor(isDarkTheme)); |
| 692 } | 718 } |
| 693 | 719 |
| 694 + (CGFloat)getContentAreaWidth:(NSRect)cellFrame { | 720 + (CGFloat)getContentAreaWidth:(NSRect)cellFrame { |
| 695 return NSWidth(cellFrame) - kMaterialTextStartOffset; | 721 return NSWidth(cellFrame) - kMaterialTextStartOffset; |
| 696 } | 722 } |
| 697 | 723 |
| 698 + (CGFloat)getContentTextHeight { | 724 + (CGFloat)getContentTextHeight:(BOOL)isTwoLine { |
| 699 constexpr CGFloat kDefaultTextHeight = 19; | 725 CGFloat height = kDefaultTextHeight + 2 * GetVerticalMargin(); |
| 700 return kDefaultTextHeight + 2 * GetVerticalMargin(); | 726 if (isTwoLine) |
| 727 height += kDefaultTextHeight + kDefaultVerticalMargin; | |
| 728 return height; | |
| 701 } | 729 } |
| 702 | 730 |
| 703 @end | 731 @end |
| OLD | NEW |