| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // This file implements utility functions for eliding and formatting UI text. | 5 // This file implements utility functions for eliding and formatting UI text. |
| 6 // | 6 // |
| 7 // Note that several of the functions declared in text_elider.h are implemented | 7 // Note that several of the functions declared in text_elider.h are implemented |
| 8 // in this file using helper classes in an unnamed namespace. | 8 // in this file using helper classes in an unnamed namespace. |
| 9 | 9 |
| 10 #include "ui/gfx/text_elider.h" | 10 #include "ui/gfx/text_elider.h" |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 RectangleText(const FontList& font_list, | 470 RectangleText(const FontList& font_list, |
| 471 float available_pixel_width, | 471 float available_pixel_width, |
| 472 int available_pixel_height, | 472 int available_pixel_height, |
| 473 WordWrapBehavior wrap_behavior, | 473 WordWrapBehavior wrap_behavior, |
| 474 std::vector<base::string16>* lines) | 474 std::vector<base::string16>* lines) |
| 475 : font_list_(font_list), | 475 : font_list_(font_list), |
| 476 line_height_(font_list.GetHeight()), | 476 line_height_(font_list.GetHeight()), |
| 477 available_pixel_width_(available_pixel_width), | 477 available_pixel_width_(available_pixel_width), |
| 478 available_pixel_height_(available_pixel_height), | 478 available_pixel_height_(available_pixel_height), |
| 479 wrap_behavior_(wrap_behavior), | 479 wrap_behavior_(wrap_behavior), |
| 480 current_width_(0), | |
| 481 current_height_(0), | 480 current_height_(0), |
| 482 last_line_ended_in_lf_(false), | 481 last_line_ended_in_lf_(false), |
| 483 lines_(lines), | 482 lines_(lines), |
| 484 insufficient_width_(false), | 483 insufficient_width_(false), |
| 485 insufficient_height_(false) {} | 484 insufficient_height_(false) {} |
| 486 | 485 |
| 487 // Perform deferred initializions following creation. Must be called | 486 // Perform deferred initializions following creation. Must be called |
| 488 // before any input can be added via AddString(). | 487 // before any input can be added via AddString(). |
| 489 void Init() { lines_->clear(); } | 488 void Init() { lines_->clear(); } |
| 490 | 489 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 507 | 506 |
| 508 // Wrap the specified word across multiple lines. | 507 // Wrap the specified word across multiple lines. |
| 509 int WrapWord(const base::string16& word); | 508 int WrapWord(const base::string16& word); |
| 510 | 509 |
| 511 // Add a long word - wrapping, eliding or truncating per the wrap behavior. | 510 // Add a long word - wrapping, eliding or truncating per the wrap behavior. |
| 512 int AddWordOverflow(const base::string16& word); | 511 int AddWordOverflow(const base::string16& word); |
| 513 | 512 |
| 514 // Add a word to the rectangluar region at the current position. | 513 // Add a word to the rectangluar region at the current position. |
| 515 int AddWord(const base::string16& word); | 514 int AddWord(const base::string16& word); |
| 516 | 515 |
| 517 // Append the specified |text| to the current output line, incrementing the | |
| 518 // running width by the specified amount. This is an optimization over | |
| 519 // |AddToCurrentLine()| when |text_width| is already known. | |
| 520 void AddToCurrentLineWithWidth(const base::string16& text, float text_width); | |
| 521 | |
| 522 // Append the specified |text| to the current output line. | 516 // Append the specified |text| to the current output line. |
| 523 void AddToCurrentLine(const base::string16& text); | 517 void AddToCurrentLine(const base::string16& text); |
| 524 | 518 |
| 525 // Set the current position to the beginning of the next line. | 519 // Set the current position to the beginning of the next line. |
| 526 bool NewLine(); | 520 bool NewLine(); |
| 527 | 521 |
| 528 // The font list used for measuring text width. | 522 // The font list used for measuring text width. |
| 529 const FontList& font_list_; | 523 const FontList& font_list_; |
| 530 | 524 |
| 531 // The height of each line of text. | 525 // The height of each line of text. |
| 532 const int line_height_; | 526 const int line_height_; |
| 533 | 527 |
| 534 // The number of pixels of available width in the rectangle. | 528 // The number of pixels of available width in the rectangle. |
| 535 const float available_pixel_width_; | 529 const float available_pixel_width_; |
| 536 | 530 |
| 537 // The number of pixels of available height in the rectangle. | 531 // The number of pixels of available height in the rectangle. |
| 538 const int available_pixel_height_; | 532 const int available_pixel_height_; |
| 539 | 533 |
| 540 // The wrap behavior for words that are too long to fit on a single line. | 534 // The wrap behavior for words that are too long to fit on a single line. |
| 541 const WordWrapBehavior wrap_behavior_; | 535 const WordWrapBehavior wrap_behavior_; |
| 542 | 536 |
| 543 // The current running width. | |
| 544 float current_width_; | |
| 545 | |
| 546 // The current running height. | 537 // The current running height. |
| 547 int current_height_; | 538 int current_height_; |
| 548 | 539 |
| 549 // The current line of text. | 540 // The current line of text. |
| 550 base::string16 current_line_; | 541 base::string16 current_line_; |
| 551 | 542 |
| 552 // Indicates whether the last line ended with \n. | 543 // Indicates whether the last line ended with \n. |
| 553 bool last_line_ended_in_lf_; | 544 bool last_line_ended_in_lf_; |
| 554 | 545 |
| 555 // The output vector of lines. | 546 // The output vector of lines. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 } | 585 } |
| 595 if (last_line_ended_in_lf_) | 586 if (last_line_ended_in_lf_) |
| 596 lines_->push_back(base::string16()); | 587 lines_->push_back(base::string16()); |
| 597 return (insufficient_width_ ? INSUFFICIENT_SPACE_HORIZONTAL : 0) | | 588 return (insufficient_width_ ? INSUFFICIENT_SPACE_HORIZONTAL : 0) | |
| 598 (insufficient_height_ ? INSUFFICIENT_SPACE_VERTICAL : 0); | 589 (insufficient_height_ ? INSUFFICIENT_SPACE_VERTICAL : 0); |
| 599 } | 590 } |
| 600 | 591 |
| 601 void RectangleText::AddLine(const base::string16& line) { | 592 void RectangleText::AddLine(const base::string16& line) { |
| 602 const float line_width = GetStringWidthF(line, font_list_); | 593 const float line_width = GetStringWidthF(line, font_list_); |
| 603 if (line_width <= available_pixel_width_) { | 594 if (line_width <= available_pixel_width_) { |
| 604 AddToCurrentLineWithWidth(line, line_width); | 595 AddToCurrentLine(line); |
| 605 } else { | 596 } else { |
| 606 // Iterate over positions that are valid to break the line at. In general, | 597 // Iterate over positions that are valid to break the line at. In general, |
| 607 // these are word boundaries but after any punctuation following the word. | 598 // these are word boundaries but after any punctuation following the word. |
| 608 base::i18n::BreakIterator words(line, | 599 base::i18n::BreakIterator words(line, |
| 609 base::i18n::BreakIterator::BREAK_LINE); | 600 base::i18n::BreakIterator::BREAK_LINE); |
| 610 if (words.Init()) { | 601 if (words.Init()) { |
| 611 while (words.Advance()) { | 602 while (words.Advance()) { |
| 612 const bool truncate = !current_line_.empty(); | 603 const bool truncate = !current_line_.empty(); |
| 613 const base::string16& word = words.GetString(); | 604 const base::string16& word = words.GetString(); |
| 614 const int lines_added = AddWord(word); | 605 const int lines_added = AddWord(word); |
| 615 if (lines_added) { | 606 if (lines_added) { |
| 616 if (truncate) { | 607 if (truncate) { |
| 617 // Trim trailing whitespace from the line that was added. | 608 // Trim trailing whitespace from the line that was added. |
| 618 const int line = lines_->size() - lines_added; | 609 const int line = lines_->size() - lines_added; |
| 619 base::TrimWhitespace(lines_->at(line), base::TRIM_TRAILING, | 610 base::TrimWhitespace(lines_->at(line), base::TRIM_TRAILING, |
| 620 &lines_->at(line)); | 611 &lines_->at(line)); |
| 621 } | 612 } |
| 622 if (base::ContainsOnlyChars(word, base::kWhitespaceUTF16)) { | 613 if (base::ContainsOnlyChars(word, base::kWhitespaceUTF16)) { |
| 623 // Skip the first space if the previous line was carried over. | 614 // Skip the first space if the previous line was carried over. |
| 624 current_width_ = 0; | |
| 625 current_line_.clear(); | 615 current_line_.clear(); |
| 626 } | 616 } |
| 627 } | 617 } |
| 628 } | 618 } |
| 629 } else { | 619 } else { |
| 630 NOTREACHED() << "BreakIterator (words) init failed"; | 620 NOTREACHED() << "BreakIterator (words) init failed"; |
| 631 } | 621 } |
| 632 } | 622 } |
| 633 // Account for naturally-occuring newlines. | 623 // Account for naturally-occuring newlines. |
| 634 NewLine(); | 624 NewLine(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 660 | 650 |
| 661 // Unless this is the very first word, put it on a new line. | 651 // Unless this is the very first word, put it on a new line. |
| 662 if (!current_line_.empty()) { | 652 if (!current_line_.empty()) { |
| 663 if (!NewLine()) | 653 if (!NewLine()) |
| 664 return 0; | 654 return 0; |
| 665 lines_added++; | 655 lines_added++; |
| 666 } | 656 } |
| 667 | 657 |
| 668 if (wrap_behavior_ == IGNORE_LONG_WORDS) { | 658 if (wrap_behavior_ == IGNORE_LONG_WORDS) { |
| 669 current_line_ = word; | 659 current_line_ = word; |
| 670 current_width_ = available_pixel_width_; | |
| 671 } else if (wrap_behavior_ == WRAP_LONG_WORDS) { | 660 } else if (wrap_behavior_ == WRAP_LONG_WORDS) { |
| 672 lines_added += WrapWord(word); | 661 lines_added += WrapWord(word); |
| 673 } else { | 662 } else { |
| 674 const ElideBehavior elide_behavior = | 663 const ElideBehavior elide_behavior = |
| 675 (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE); | 664 (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE); |
| 676 const base::string16 elided_word = | 665 const base::string16 elided_word = |
| 677 ElideText(word, font_list_, available_pixel_width_, elide_behavior); | 666 ElideText(word, font_list_, available_pixel_width_, elide_behavior); |
| 678 AddToCurrentLine(elided_word); | 667 AddToCurrentLine(elided_word); |
| 679 insufficient_width_ = true; | 668 insufficient_width_ = true; |
| 680 } | 669 } |
| 681 | 670 |
| 682 return lines_added; | 671 return lines_added; |
| 683 } | 672 } |
| 684 | 673 |
| 685 int RectangleText::AddWord(const base::string16& word) { | 674 int RectangleText::AddWord(const base::string16& word) { |
| 686 int lines_added = 0; | 675 int lines_added = 0; |
| 687 base::string16 trimmed; | 676 base::string16 trimmed; |
| 688 base::TrimWhitespace(word, base::TRIM_TRAILING, &trimmed); | 677 base::TrimWhitespace(word, base::TRIM_TRAILING, &trimmed); |
| 689 const float trimmed_width = GetStringWidthF(trimmed, font_list_); | 678 const float trimmed_width = GetStringWidthF(trimmed, font_list_); |
| 690 if (trimmed_width <= available_pixel_width_) { | 679 if (trimmed_width <= available_pixel_width_) { |
| 691 // Word can be made to fit, no need to fragment it. | 680 // Word can be made to fit, no need to fragment it. |
| 692 if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine()) | 681 base::string16 line_with_new_word(current_line_); |
| 682 line_with_new_word.append(trimmed); |
| 683 float new_width = GetStringWidthF(line_with_new_word, font_list_); |
| 684 // We can't just add trimmed_width to current_width and compare it to |
| 685 // available_pixel_width. Sometimes sum of widths of two strings is not |
| 686 // equal to width of concatenation of these strings (see crbug.com/415213). |
| 687 if ((new_width > available_pixel_width_) && NewLine()) |
| 693 lines_added++; | 688 lines_added++; |
| 694 // Append the non-trimmed word, in case more words are added after. | 689 // Append the non-trimmed word, in case more words are added after. |
| 695 AddToCurrentLine(word); | 690 AddToCurrentLine(word); |
| 696 } else { | 691 } else { |
| 697 lines_added = AddWordOverflow(wrap_behavior_ == IGNORE_LONG_WORDS ? | 692 lines_added = AddWordOverflow(wrap_behavior_ == IGNORE_LONG_WORDS ? |
| 698 trimmed : word); | 693 trimmed : word); |
| 699 } | 694 } |
| 700 return lines_added; | 695 return lines_added; |
| 701 } | 696 } |
| 702 | 697 |
| 703 void RectangleText::AddToCurrentLine(const base::string16& text) { | 698 void RectangleText::AddToCurrentLine(const base::string16& text) { |
| 704 AddToCurrentLineWithWidth(text, GetStringWidthF(text, font_list_)); | |
| 705 } | |
| 706 | |
| 707 void RectangleText::AddToCurrentLineWithWidth(const base::string16& text, | |
| 708 float text_width) { | |
| 709 if (current_height_ >= available_pixel_height_) { | 699 if (current_height_ >= available_pixel_height_) { |
| 710 insufficient_height_ = true; | 700 insufficient_height_ = true; |
| 711 return; | 701 return; |
| 712 } | 702 } |
| 713 current_line_.append(text); | 703 current_line_.append(text); |
| 714 current_width_ += text_width; | |
| 715 } | 704 } |
| 716 | 705 |
| 717 bool RectangleText::NewLine() { | 706 bool RectangleText::NewLine() { |
| 718 bool line_added = false; | 707 bool line_added = false; |
| 719 if (current_height_ < available_pixel_height_) { | 708 if (current_height_ < available_pixel_height_) { |
| 720 lines_->push_back(current_line_); | 709 lines_->push_back(current_line_); |
| 721 current_line_.clear(); | 710 current_line_.clear(); |
| 722 line_added = true; | 711 line_added = true; |
| 723 } else { | 712 } else { |
| 724 insufficient_height_ = true; | 713 insufficient_height_ = true; |
| 725 } | 714 } |
| 726 current_height_ += line_height_; | 715 current_height_ += line_height_; |
| 727 current_width_ = 0; | |
| 728 return line_added; | 716 return line_added; |
| 729 } | 717 } |
| 730 | 718 |
| 731 } // namespace | 719 } // namespace |
| 732 | 720 |
| 733 bool ElideRectangleString(const base::string16& input, size_t max_rows, | 721 bool ElideRectangleString(const base::string16& input, size_t max_rows, |
| 734 size_t max_cols, bool strict, | 722 size_t max_cols, bool strict, |
| 735 base::string16* output) { | 723 base::string16* output) { |
| 736 RectangleString rect(max_rows, max_cols, strict, output); | 724 RectangleString rect(max_rows, max_cols, strict, output); |
| 737 rect.Init(); | 725 rect.Init(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 815 index = char_iterator.getIndex(); | 803 index = char_iterator.getIndex(); |
| 816 } else { | 804 } else { |
| 817 // String has leading whitespace, return the elide string. | 805 // String has leading whitespace, return the elide string. |
| 818 return kElideString; | 806 return kElideString; |
| 819 } | 807 } |
| 820 | 808 |
| 821 return string.substr(0, index) + kElideString; | 809 return string.substr(0, index) + kElideString; |
| 822 } | 810 } |
| 823 | 811 |
| 824 } // namespace gfx | 812 } // namespace gfx |
| OLD | NEW |