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 <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
11 #include "base/mac/foundation_util.h" | |
11 #include "base/mac/scoped_nsobject.h" | 12 #include "base/mac/scoped_nsobject.h" |
12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
14 #include "base/strings/sys_string_conversions.h" | 15 #include "base/strings/sys_string_conversions.h" |
15 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
16 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" | 17 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" |
17 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" | 18 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" |
18 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" | 19 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" |
19 #include "chrome/grit/generated_resources.h" | 20 #include "chrome/grit/generated_resources.h" |
20 #include "components/omnibox/suggestion_answer.h" | 21 #include "components/omnibox/suggestion_answer.h" |
21 #include "skia/ext/skia_utils_mac.h" | 22 #include "skia/ext/skia_utils_mac.h" |
22 #include "ui/base/l10n/l10n_util.h" | 23 #include "ui/base/l10n/l10n_util.h" |
23 #include "ui/gfx/font.h" | 24 #include "ui/gfx/font.h" |
24 | 25 |
25 namespace { | 26 namespace { |
26 | 27 |
28 // How much to adjust the cell sizing up from the default determined | |
29 // by the font. | |
30 const CGFloat kCellHeightAdjust = 6.0; | |
31 | |
32 // How large the icon should be when displayed. | |
33 const CGFloat kImageSize = 19.0; | |
34 | |
27 // How far to offset image column from the left. | 35 // How far to offset image column from the left. |
28 const CGFloat kImageXOffset = 5.0; | 36 const CGFloat kImageXOffset = 5.0; |
29 | 37 |
30 // How far to offset the text column from the left. | 38 // How far to offset the text column from the left. |
31 const CGFloat kTextStartOffset = 28.0; | 39 const CGFloat kTextStartOffset = 28.0; |
32 | 40 |
33 // Rounding radius of selection and hover background on popup items. | 41 // Rounding radius of selection and hover background on popup items. |
34 const CGFloat kCellRoundingRadius = 2.0; | 42 const CGFloat kCellRoundingRadius = 2.0; |
35 | 43 |
36 // Flips the given |rect| in context of the given |frame|. | 44 // Flips the given |rect| in context of the given |frame|. |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
272 value:DimTextColor() | 280 value:DimTextColor() |
273 range:range]; | 281 range:range]; |
274 } | 282 } |
275 } | 283 } |
276 | 284 |
277 return attributedString; | 285 return attributedString; |
278 } | 286 } |
279 | 287 |
280 } // namespace | 288 } // namespace |
281 | 289 |
282 @implementation OmniboxPopupCell | 290 @interface OmniboxPopupCell () |
291 - (CGFloat)drawMatchPart:(NSAttributedString*)attributedString | |
292 withFrame:(NSRect)cellFrame | |
293 atOffset:(CGFloat)offset | |
294 withMaxWidth:(int)maxWidth; | |
295 @end | |
283 | 296 |
284 - (instancetype)init { | 297 @implementation OmniboxPopupCellData |
285 self = [super init]; | |
286 if (self) { | |
287 [self setImagePosition:NSImageLeft]; | |
288 [self setBordered:NO]; | |
289 [self setButtonType:NSRadioButton]; | |
290 | 298 |
291 // Without this highlighting messes up white areas of images. | 299 @synthesize contents = contents_; |
groby-ooo-7-16
2015/06/12 18:51:07
This is the "default" mode for @synthesize. Since
dschuyler
2015/06/12 21:39:14
It seems that there is a warning that requires it.
| |
292 [self setHighlightsBy:NSNoCellMask]; | 300 @synthesize description = description_; |
301 @synthesize prefix = prefix_; | |
302 @synthesize image = image_; | |
303 @synthesize answerImage = answerImage_; | |
304 @synthesize contentsOffset = contentsOffset_; | |
305 @synthesize isContentsRTL = isContentsRTL_; | |
306 @synthesize matchType = matchType_; | |
293 | 307 |
294 const base::string16& raw_separator = | 308 - (instancetype)initWithMatch:(const AutocompleteMatch&)match |
295 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); | 309 image:(NSImage*)image |
296 separator_.reset( | 310 answerImage:(NSImage*)answerImage { |
297 [CreateAttributedString(raw_separator, DimTextColor()) retain]); | 311 if ((self = [super init])) { |
312 image_ = [image retain]; | |
313 answerImage_ = [answerImage retain]; | |
314 | |
315 isContentsRTL_ = | |
316 (base::i18n::RIGHT_TO_LEFT == | |
317 base::i18n::GetFirstStrongCharacterDirection(match.contents)); | |
318 matchType_ = match.type; | |
319 | |
320 // Prefix may not have any characters with strong directionality, and may | |
321 // take the UI directionality. But prefix needs to appear in continuation | |
322 // of the contents so we force the directionality. | |
323 NSTextAlignment textAlignment = | |
324 isContentsRTL_ ? NSRightTextAlignment : NSLeftTextAlignment; | |
325 prefix_ = | |
326 [CreateAttributedString(base::UTF8ToUTF16(match.GetAdditionalInfo( | |
327 kACMatchPropertyContentsPrefix)), | |
328 ContentTextColor(), textAlignment) retain]; | |
329 | |
330 contents_ = [CreateClassifiedAttributedString( | |
331 match.contents, ContentTextColor(), match.contents_class) retain]; | |
332 | |
333 if (match.answer) { | |
334 base::scoped_nsobject<NSMutableAttributedString> answerString( | |
335 [[NSMutableAttributedString alloc] init]); | |
336 DCHECK(!match.answer->second_line().text_fields().empty()); | |
337 for (const SuggestionAnswer::TextField& textField : | |
338 match.answer->second_line().text_fields()) { | |
339 [answerString | |
340 appendAttributedString:CreateAnswerString(textField.text(), | |
341 textField.type())]; | |
342 } | |
343 const base::string16 space(base::ASCIIToUTF16(" ")); | |
344 // const base::char16 space(' '); | |
groby-ooo-7-16
2015/06/12 18:51:07
Kill comment
dschuyler
2015/06/12 21:39:14
Done.
| |
345 const SuggestionAnswer::TextField* textField = | |
346 match.answer->second_line().additional_text(); | |
347 if (textField) { | |
348 [answerString | |
349 appendAttributedString:CreateAnswerString(space + textField->text(), | |
350 textField->type())]; | |
351 } | |
352 textField = match.answer->second_line().status_text(); | |
353 if (textField) { | |
354 [answerString | |
355 appendAttributedString:CreateAnswerString(space + textField->text(), | |
356 textField->type())]; | |
357 } | |
358 description_ = [answerString.release() retain]; | |
groby-ooo-7-16
2015/06/12 18:51:06
scoped_nsobject's release is not ObjC's release -
Scott Hess - ex-Googler
2015/06/12 20:21:32
IMHO this would be pretty clear to a C++ programme
groby-ooo-7-16
2015/06/12 21:01:54
swap won't work, since description_ isn't scoped_n
dschuyler
2015/06/12 21:39:14
Done.
| |
359 } else if (match.description.empty()) { | |
360 description_ = nil; | |
groby-ooo-7-16
2015/06/12 18:51:07
Not necessary - all ivars are initialized to nil i
dschuyler
2015/06/12 21:39:14
Done.
| |
361 } else { | |
362 description_ = [CreateClassifiedAttributedString( | |
363 match.description, DimTextColor(), match.description_class) retain]; | |
364 } | |
298 } | 365 } |
299 return self; | 366 return self; |
300 } | 367 } |
301 | 368 |
302 - (void)setAnswerImage:(NSImage*)image { | 369 - (instancetype)copyWithZone:(NSZone*)zone { |
303 answerImage_.reset([image retain]); | 370 return [self retain]; |
304 } | 371 } |
305 | 372 |
306 - (void)setMatch:(const AutocompleteMatch&)match { | 373 - (CGFloat)getMatchContentsWidth { |
307 match_ = match; | 374 return [contents_ size].width; |
308 NSAttributedString *contents = CreateClassifiedAttributedString( | |
309 match_.contents, ContentTextColor(), match_.contents_class); | |
310 [self setAttributedTitle:contents]; | |
311 [self setAnswerImage:nil]; | |
312 if (match_.answer) { | |
313 base::scoped_nsobject<NSMutableAttributedString> answerString( | |
314 [[NSMutableAttributedString alloc] init]); | |
315 DCHECK(!match_.answer->second_line().text_fields().empty()); | |
316 for (const SuggestionAnswer::TextField& textField : | |
317 match_.answer->second_line().text_fields()) { | |
318 NSAttributedString* attributedString = | |
319 CreateAnswerString(textField.text(), textField.type()); | |
320 [answerString appendAttributedString:attributedString]; | |
321 } | |
322 const base::char16 space(' '); | |
323 const SuggestionAnswer::TextField* textField = | |
324 match_.answer->second_line().additional_text(); | |
325 if (textField) { | |
326 [answerString | |
327 appendAttributedString:CreateAnswerString(space + textField->text(), | |
328 textField->type())]; | |
329 } | |
330 textField = match_.answer->second_line().status_text(); | |
331 if (textField) { | |
332 [answerString | |
333 appendAttributedString:CreateAnswerString(space + textField->text(), | |
334 textField->type())]; | |
335 } | |
336 description_.reset(answerString.release()); | |
337 } else if (match_.description.empty()) { | |
338 description_.reset(); | |
339 } else { | |
340 description_.reset([CreateClassifiedAttributedString( | |
341 match_.description, DimTextColor(), match_.description_class) retain]); | |
342 } | |
343 } | 375 } |
344 | 376 |
345 - (NSAttributedString*)description { | 377 - (CGFloat)rowHeight { |
346 return description_; | 378 return kImageSize + kCellHeightAdjust; |
347 } | 379 } |
348 | 380 |
349 - (void)setMaxMatchContentsWidth:(CGFloat)maxMatchContentsWidth { | 381 @end |
350 maxMatchContentsWidth_ = maxMatchContentsWidth; | |
351 } | |
352 | 382 |
353 - (void)setContentsOffset:(CGFloat)contentsOffset { | 383 @implementation OmniboxPopupCell |
354 contentsOffset_ = contentsOffset; | |
355 } | |
356 | 384 |
357 // The default NSButtonCell drawing leaves the image flush left and | 385 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { |
358 // the title next to the image. This spaces things out to line up | |
359 // with the star button and autocomplete field. | |
360 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { | |
361 if ([self state] == NSOnState || [self isHighlighted]) { | 386 if ([self state] == NSOnState || [self isHighlighted]) { |
362 if ([self state] == NSOnState) | 387 if ([self state] == NSOnState) |
363 [SelectedBackgroundColor() set]; | 388 [SelectedBackgroundColor() set]; |
364 else | 389 else |
365 [HoveredBackgroundColor() set]; | 390 [HoveredBackgroundColor() set]; |
366 NSBezierPath* path = | 391 NSBezierPath* path = |
367 [NSBezierPath bezierPathWithRoundedRect:cellFrame | 392 [NSBezierPath bezierPathWithRoundedRect:cellFrame |
368 xRadius:kCellRoundingRadius | 393 xRadius:kCellRoundingRadius |
369 yRadius:kCellRoundingRadius]; | 394 yRadius:kCellRoundingRadius]; |
370 [path fill]; | 395 [path fill]; |
371 } | 396 } |
372 | 397 |
398 [self drawMatchWithFrame:cellFrame | |
399 withCellData:[self objectValue] | |
400 inView:controlView]; | |
401 } | |
402 | |
403 - (void)drawMatchWithFrame:(NSRect)cellFrame | |
404 withCellData:(OmniboxPopupCellData*)cellData | |
405 inView:(NSView*)controlView { | |
406 OmniboxPopupMatrix* tableView = | |
407 base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); | |
408 CGFloat remainingWidth = GetContentAreaWidth(cellFrame); | |
409 CGFloat contentsWidth = [cellData getMatchContentsWidth]; | |
410 CGFloat separatorWidth = [[tableView separator] size].width; | |
411 CGFloat descriptionWidth = | |
412 [cellData description] ? [[cellData description] size].width : 0; | |
413 int contentsMaxWidth, descriptionMaxWidth; | |
414 OmniboxPopupModel::ComputeMatchMaxWidths( | |
415 ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth), | |
416 ceilf(remainingWidth), | |
417 !AutocompleteMatch::IsSearchType([cellData matchType]), &contentsMaxWidth, | |
418 &descriptionMaxWidth); | |
419 | |
373 // Put the image centered vertically but in a fixed column. | 420 // Put the image centered vertically but in a fixed column. |
374 NSImage* image = [self image]; | 421 if ([cellData image]) { |
groby-ooo-7-16
2015/06/12 18:51:07
This check is not necessary. (A nil image would ju
dschuyler
2015/06/12 21:39:14
Done.
| |
375 if (image) { | |
376 NSRect imageRect = cellFrame; | 422 NSRect imageRect = cellFrame; |
377 imageRect.size = [image size]; | 423 imageRect.size = [[cellData image] size]; |
378 imageRect.origin.y += | 424 imageRect.origin.y += |
379 std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0); | 425 std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0); |
380 imageRect.origin.x += kImageXOffset; | 426 imageRect.origin.x += kImageXOffset; |
381 [image drawInRect:FlipIfRTL(imageRect, cellFrame) | 427 [[cellData image] drawInRect:FlipIfRTL(imageRect, cellFrame) |
382 fromRect:NSZeroRect // Entire image | 428 fromRect:NSZeroRect |
383 operation:NSCompositeSourceOver | 429 operation:NSCompositeSourceOver |
384 fraction:1.0 | 430 fraction:1.0 |
385 respectFlipped:YES | 431 respectFlipped:YES |
386 hints:nil]; | 432 hints:nil]; |
387 } | 433 } |
388 | 434 |
389 [self drawMatchWithFrame:cellFrame inView:controlView]; | |
390 } | |
391 | |
392 - (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { | |
393 NSAttributedString* contents = [self attributedTitle]; | |
394 | |
395 CGFloat remainingWidth = GetContentAreaWidth(cellFrame); | |
396 CGFloat contentsWidth = [self getMatchContentsWidth]; | |
397 CGFloat separatorWidth = [separator_ size].width; | |
398 CGFloat descriptionWidth = description_.get() ? [description_ size].width : 0; | |
399 int contentsMaxWidth, descriptionMaxWidth; | |
400 OmniboxPopupModel::ComputeMatchMaxWidths( | |
401 ceilf(contentsWidth), | |
402 ceilf(separatorWidth), | |
403 ceilf(descriptionWidth), | |
404 ceilf(remainingWidth), | |
405 !AutocompleteMatch::IsSearchType(match_.type), | |
406 &contentsMaxWidth, | |
407 &descriptionMaxWidth); | |
408 | |
409 CGFloat offset = kTextStartOffset; | 435 CGFloat offset = kTextStartOffset; |
410 if (match_.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { | 436 if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { |
411 // Infinite suggestions are rendered with a prefix (usually ellipsis), which | 437 // Infinite suggestions are rendered with a prefix (usually ellipsis), which |
412 // appear vertically stacked. | 438 // appear vertically stacked. |
413 offset += [self drawMatchPrefixWithFrame:cellFrame | 439 offset += [self drawMatchPrefixWithFrame:cellFrame |
440 withCellData:cellData | |
414 inView:controlView | 441 inView:controlView |
415 withContentsMaxWidth:&contentsMaxWidth]; | 442 withContentsMaxWidth:&contentsMaxWidth]; |
416 } | 443 } |
417 offset += [self drawMatchPart:contents | 444 offset += [self drawMatchPart:[cellData contents] |
418 withFrame:cellFrame | 445 withFrame:cellFrame |
419 atOffset:offset | 446 atOffset:offset |
420 withMaxWidth:contentsMaxWidth | 447 withMaxWidth:contentsMaxWidth]; |
421 inView:controlView]; | |
422 | 448 |
423 if (descriptionMaxWidth != 0) { | 449 if (descriptionMaxWidth != 0) { |
424 offset += [self drawMatchPart:separator_ | 450 offset += [self drawMatchPart:[tableView separator] |
425 withFrame:cellFrame | 451 withFrame:cellFrame |
426 atOffset:offset | 452 atOffset:offset |
427 withMaxWidth:separatorWidth | 453 withMaxWidth:separatorWidth]; |
428 inView:controlView]; | 454 if ([cellData answerImage]) { |
groby-ooo-7-16
2015/06/12 18:51:07
Unnecessary check
dschuyler
2015/06/12 21:39:14
Done.
| |
429 if (answerImage_) { | |
430 NSRect imageRect = NSMakeRect(offset, NSMinY(cellFrame), | 455 NSRect imageRect = NSMakeRect(offset, NSMinY(cellFrame), |
431 NSHeight(cellFrame), NSHeight(cellFrame)); | 456 NSHeight(cellFrame), NSHeight(cellFrame)); |
432 [answerImage_ drawInRect:FlipIfRTL(imageRect, cellFrame) | 457 [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame) |
433 fromRect:NSZeroRect | 458 fromRect:NSZeroRect |
434 operation:NSCompositeSourceOver | 459 operation:NSCompositeSourceOver |
435 fraction:1.0 | 460 fraction:1.0 |
436 respectFlipped:YES | 461 respectFlipped:YES |
437 hints:nil]; | 462 hints:nil]; |
438 offset += NSWidth(imageRect); | 463 offset += NSWidth(imageRect); |
439 } | 464 } |
440 offset += [self drawMatchPart:description_ | 465 offset += [self drawMatchPart:[cellData description] |
441 withFrame:cellFrame | 466 withFrame:cellFrame |
442 atOffset:offset | 467 atOffset:offset |
443 withMaxWidth:descriptionMaxWidth | 468 withMaxWidth:descriptionMaxWidth]; |
444 inView:controlView]; | |
445 } | 469 } |
446 } | 470 } |
447 | 471 |
448 - (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame | 472 - (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame |
groby-ooo-7-16
2015/06/12 18:51:06
Didn't see a prototype for this?
dschuyler
2015/06/12 21:39:14
Done.
| |
473 withCellData:(OmniboxPopupCellData*)cellData | |
449 inView:(NSView*)controlView | 474 inView:(NSView*)controlView |
450 withContentsMaxWidth:(int*)contentsMaxWidth { | 475 withContentsMaxWidth:(int*)contentsMaxWidth { |
451 CGFloat offset = 0.0f; | 476 CGFloat offset = 0.0f; |
452 CGFloat remainingWidth = GetContentAreaWidth(cellFrame); | 477 CGFloat remainingWidth = GetContentAreaWidth(cellFrame); |
453 bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT == | 478 CGFloat prefixWidth = [[cellData prefix] size].width; |
454 base::i18n::GetFirstStrongCharacterDirection(match_.contents)); | 479 |
455 // Prefix may not have any characters with strong directionality, and may take | 480 OmniboxPopupMatrix* tableView = |
456 // the UI directionality. But prefix needs to appear in continuation of the | 481 base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); |
groby-ooo-7-16
2015/06/12 18:51:06
You could just pass in the OmniboxPopupMatrix dire
dschuyler
2015/06/12 21:39:14
Done.
| |
457 // contents so we force the directionality. | |
458 NSTextAlignment textAlignment = isContentsRTL ? | |
459 NSRightTextAlignment : NSLeftTextAlignment; | |
460 prefix_.reset([CreateAttributedString(base::UTF8ToUTF16( | |
461 match_.GetAdditionalInfo(kACMatchPropertyContentsPrefix)), | |
462 ContentTextColor(), textAlignment) retain]); | |
463 CGFloat prefixWidth = [prefix_ size].width; | |
464 | 482 |
465 CGFloat prefixOffset = 0.0f; | 483 CGFloat prefixOffset = 0.0f; |
466 if (base::i18n::IsRTL() != isContentsRTL) { | 484 if (base::i18n::IsRTL() != [cellData isContentsRTL]) { |
467 // The contents is rendered between the contents offset extending towards | 485 // The contents is rendered between the contents offset extending towards |
468 // the start edge, while prefix is rendered in opposite direction. Ideally | 486 // the start edge, while prefix is rendered in opposite direction. Ideally |
469 // the prefix should be rendered at |contentsOffset_|. If that is not | 487 // the prefix should be rendered at |contentsOffset_|. If that is not |
470 // sufficient to render the widest suggestion, we increase it to | 488 // sufficient to render the widest suggestion, we increase it to |
471 // |maxMatchContentsWidth_|. If |remainingWidth| is not sufficient to | 489 // |maxMatchContentsWidth|. If |remainingWidth| is not sufficient to |
472 // accommodate that, we reduce the offset so that the prefix gets rendered. | 490 // accommodate that, we reduce the offset so that the prefix gets rendered. |
473 prefixOffset = std::min( | 491 prefixOffset = std::min( |
474 remainingWidth - prefixWidth, std::max(contentsOffset_, | 492 remainingWidth - prefixWidth, |
475 maxMatchContentsWidth_)); | 493 std::max([cellData contentsOffset], [tableView maxMatchContentsWidth])); |
476 offset = std::max<CGFloat>(0.0, prefixOffset - *contentsMaxWidth); | 494 offset = std::max<CGFloat>(0.0, prefixOffset - *contentsMaxWidth); |
477 } else { // The direction of contents is same as UI direction. | 495 } else { // The direction of contents is same as UI direction. |
478 // Ideally the offset should be |contentsOffset_|. If the max total width | 496 // Ideally the offset should be |contentsOffset_|. If the max total width |
479 // (|prefixWidth| + |maxMatchContentsWidth_|) from offset will exceed the | 497 // (|prefixWidth| + |maxMatchContentsWidth|) from offset will exceed the |
480 // |remainingWidth|, then we shift the offset to the left , so that all | 498 // |remainingWidth|, then we shift the offset to the left , so that all |
481 // postfix suggestions are visible. | 499 // postfix suggestions are visible. |
482 // We have to render the prefix, so offset has to be at least |prefixWidth|. | 500 // We have to render the prefix, so offset has to be at least |prefixWidth|. |
483 offset = std::max(prefixWidth, | 501 offset = |
484 std::min(remainingWidth - maxMatchContentsWidth_, contentsOffset_)); | 502 std::max(prefixWidth, |
503 std::min(remainingWidth - [tableView maxMatchContentsWidth], | |
504 [cellData contentsOffset])); | |
485 prefixOffset = offset - prefixWidth; | 505 prefixOffset = offset - prefixWidth; |
486 } | 506 } |
487 *contentsMaxWidth = std::min((int)ceilf(remainingWidth - prefixWidth), | 507 *contentsMaxWidth = std::min((int)ceilf(remainingWidth - prefixWidth), |
488 *contentsMaxWidth); | 508 *contentsMaxWidth); |
489 [self drawMatchPart:prefix_ | 509 [self drawMatchPart:[cellData prefix] |
490 withFrame:cellFrame | 510 withFrame:cellFrame |
491 atOffset:prefixOffset + kTextStartOffset | 511 atOffset:prefixOffset + kTextStartOffset |
492 withMaxWidth:prefixWidth | 512 withMaxWidth:prefixWidth]; |
493 inView:controlView]; | |
494 return offset; | 513 return offset; |
495 } | 514 } |
496 | 515 |
497 - (CGFloat)drawMatchPart:(NSAttributedString*)attributedString | 516 - (CGFloat)drawMatchPart:(NSAttributedString*)attributedString |
498 withFrame:(NSRect)cellFrame | 517 withFrame:(NSRect)cellFrame |
499 atOffset:(CGFloat)offset | 518 atOffset:(CGFloat)offset |
500 withMaxWidth:(int)maxWidth | 519 withMaxWidth:(int)maxWidth { |
501 inView:(NSView*)controlView { | |
502 if (offset > NSWidth(cellFrame)) | 520 if (offset > NSWidth(cellFrame)) |
503 return 0.0f; | 521 return 0.0f; |
504 NSRect renderRect = ShiftRect(cellFrame, offset); | 522 NSRect renderRect = ShiftRect(cellFrame, offset); |
505 renderRect.size.width = | 523 renderRect.size.width = |
506 std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth)); | 524 std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth)); |
507 if (renderRect.size.width != 0) { | 525 NSRect textRect = |
508 [self drawTitle:attributedString | 526 [attributedString boundingRectWithSize:renderRect.size options:nil]; |
509 withFrame:FlipIfRTL(renderRect, cellFrame) | 527 renderRect.origin.y += |
510 inView:controlView]; | 528 std::floor((NSHeight(cellFrame) - NSHeight(textRect)) / 2.0); |
groby-ooo-7-16
2015/06/12 18:51:06
Since this is only part of the match, are you sure
dschuyler
2015/06/12 21:39:14
I'm not 100% sure. I do have a bug to look into t
| |
511 } | 529 if (NSWidth(renderRect) > 0.0) |
530 [attributedString drawInRect:FlipIfRTL(renderRect, cellFrame)]; | |
512 return NSWidth(renderRect); | 531 return NSWidth(renderRect); |
513 } | 532 } |
514 | 533 |
515 - (CGFloat)getMatchContentsWidth { | |
516 NSAttributedString* contents = [self attributedTitle]; | |
517 return contents ? [contents size].width : 0; | |
518 } | |
519 | |
520 | |
521 + (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match { | 534 + (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match { |
522 const base::string16& inputText = base::UTF8ToUTF16( | 535 const base::string16& inputText = base::UTF8ToUTF16( |
523 match.GetAdditionalInfo(kACMatchPropertyInputText)); | 536 match.GetAdditionalInfo(kACMatchPropertyInputText)); |
524 int contentsStartIndex = 0; | 537 int contentsStartIndex = 0; |
525 base::StringToInt( | 538 base::StringToInt( |
526 match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex), | 539 match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex), |
527 &contentsStartIndex); | 540 &contentsStartIndex); |
528 // Ignore invalid state. | 541 // Ignore invalid state. |
529 if (!StartsWith(match.fill_into_edit, inputText, true) | 542 if (!StartsWith(match.fill_into_edit, inputText, true) |
530 || !EndsWith(match.fill_into_edit, match.contents, true) | 543 || !EndsWith(match.fill_into_edit, match.contents, true) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
577 glyphWidth = std::min(glyphWidth, offset - glyphOffset); | 590 glyphWidth = std::min(glyphWidth, offset - glyphOffset); |
578 } | 591 } |
579 glyphOffset -= minOffset; | 592 glyphOffset -= minOffset; |
580 if (glyphWidth == 0) | 593 if (glyphWidth == 0) |
581 glyphWidth = inputWidth - glyphOffset; | 594 glyphWidth = inputWidth - glyphOffset; |
582 if (isContentsRTL) | 595 if (isContentsRTL) |
583 glyphOffset += glyphWidth; | 596 glyphOffset += glyphWidth; |
584 return base::i18n::IsRTL() ? (inputWidth - glyphOffset) : glyphOffset; | 597 return base::i18n::IsRTL() ? (inputWidth - glyphOffset) : glyphOffset; |
585 } | 598 } |
586 | 599 |
600 + (NSAttributedString*)createSeparatorString { | |
601 base::string16 raw_separator = | |
602 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); | |
603 return CreateAttributedString(raw_separator, DimTextColor()); | |
604 } | |
605 | |
587 @end | 606 @end |
OLD | NEW |