OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #include <vector> | 5 #include <vector> |
6 | 6 |
7 #include "app/text_elider.h" | 7 #include "app/text_elider.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
| 9 #include "base/i18n/break_iterator.h" |
| 10 #include "base/i18n/char_iterator.h" |
9 #include "base/i18n/rtl.h" | 11 #include "base/i18n/rtl.h" |
10 #include "base/string_split.h" | 12 #include "base/string_split.h" |
11 #include "base/string_util.h" | 13 #include "base/string_util.h" |
12 #include "base/sys_string_conversions.h" | 14 #include "base/sys_string_conversions.h" |
13 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
14 #include "gfx/font.h" | 16 #include "gfx/font.h" |
15 #include "googleurl/src/gurl.h" | 17 #include "googleurl/src/gurl.h" |
16 #include "net/base/escape.h" | 18 #include "net/base/escape.h" |
17 #include "net/base/net_util.h" | 19 #include "net/base/net_util.h" |
18 #include "net/base/registry_controlled_domain.h" | 20 #include "net/base/registry_controlled_domain.h" |
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 output->assign(input.substr(0, lstr_len) + L"..." + | 493 output->assign(input.substr(0, lstr_len) + L"..." + |
492 input.substr(input.length() - rstr_len)); | 494 input.substr(input.length() - rstr_len)); |
493 break; | 495 break; |
494 } | 496 } |
495 } | 497 } |
496 | 498 |
497 return true; | 499 return true; |
498 } | 500 } |
499 | 501 |
500 } // namespace gfx | 502 } // namespace gfx |
| 503 |
| 504 namespace { |
| 505 |
| 506 // Internal class used to track progress of a rectangular string elide |
| 507 // operation. Exists so the top-level ElideRectangleString() function |
| 508 // can be broken into smaller methods sharing this state. |
| 509 class RectangleString { |
| 510 public: |
| 511 RectangleString(size_t max_rows, size_t max_cols, string16 *output) |
| 512 : max_rows_(max_rows), |
| 513 max_cols_(max_cols), |
| 514 current_row_(0), |
| 515 current_col_(0), |
| 516 suppressed_(false), |
| 517 output_(output) {} |
| 518 |
| 519 // Perform deferred initializions following creation. Must be called |
| 520 // before any input can be added via AddString(). |
| 521 void Init() { output_->clear(); } |
| 522 |
| 523 // Add an input string, reformatting to fit the desired dimensions. |
| 524 // AddString() may be called multiple times to concatenate together |
| 525 // multiple strings into the region (the current caller doesn't do |
| 526 // this, however). |
| 527 void AddString(const string16& input); |
| 528 |
| 529 // Perform any deferred output processing. Must be called after the |
| 530 // last AddString() call has occured. |
| 531 bool Finalize(); |
| 532 |
| 533 private: |
| 534 // Add a line to the rectangular region at the current position, |
| 535 // either by itself or by breaking it into words. |
| 536 void AddLine(const string16& line); |
| 537 |
| 538 // Add a word to the rectangluar region at the current position, |
| 539 // either by itelf or by breaking it into characters. |
| 540 void AddWord(const string16& word); |
| 541 |
| 542 // Add text to the output string if the rectangular boundaries |
| 543 // have not been exceeded, advancing the current position. |
| 544 void Append(const string16& string); |
| 545 |
| 546 // Add a newline to the output string if the rectangular boundaries |
| 547 // have not been exceeded, resetting the current position to the |
| 548 // beginning of the next line. |
| 549 void NewLine(); |
| 550 |
| 551 // Maximum number of rows allowed in the output string. |
| 552 size_t max_rows_; |
| 553 |
| 554 // Maximum number of characters allowed in the output string. |
| 555 size_t max_cols_; |
| 556 |
| 557 // Current row position, always incremented and may exceed max_rows_ |
| 558 // when the input can not fit in the region. We stop appending to |
| 559 // the output string, however, when this condition occurs. In the |
| 560 // future, we may want to expose this value to allow the caller to |
| 561 // determine how many rows would actually be required to hold the |
| 562 // formatted string. |
| 563 size_t current_row_; |
| 564 |
| 565 // Current character position, should never exceed max_cols_. |
| 566 size_t current_col_; |
| 567 |
| 568 // True when some of the input has been truncated. |
| 569 bool suppressed_; |
| 570 |
| 571 // String onto which the output is accumulated. |
| 572 string16 *output_; |
| 573 }; |
| 574 |
| 575 void RectangleString::AddString(const string16& input) { |
| 576 base::BreakIterator lines(&input, base::BreakIterator::BREAK_NEWLINE); |
| 577 if (lines.Init()) { |
| 578 while (lines.Advance()) |
| 579 AddLine(lines.GetString()); |
| 580 } else { |
| 581 NOTREACHED() << "BreakIterator (lines) init failed"; |
| 582 } |
| 583 } |
| 584 |
| 585 bool RectangleString::Finalize() { |
| 586 if (suppressed_) { |
| 587 output_->append(ASCIIToUTF16("...")); |
| 588 return true; |
| 589 } |
| 590 return false; |
| 591 } |
| 592 |
| 593 void RectangleString::AddLine(const string16& line) { |
| 594 if (line.length() < max_cols_) { |
| 595 Append(line); |
| 596 } else { |
| 597 base::BreakIterator words(&line, base::BreakIterator::BREAK_SPACE); |
| 598 if (words.Init()) { |
| 599 while (words.Advance()) |
| 600 AddWord(words.GetString()); |
| 601 } else { |
| 602 NOTREACHED() << "BreakIterator (words) init failed"; |
| 603 } |
| 604 } |
| 605 // Account for naturally-occuring newlines. |
| 606 ++current_row_; |
| 607 current_col_ = 0; |
| 608 } |
| 609 |
| 610 void RectangleString::AddWord(const string16& word) { |
| 611 if (word.length() < max_cols_) { |
| 612 // Word can be made to fit, no need to fragment it. |
| 613 if (current_col_ + word.length() >= max_cols_) |
| 614 NewLine(); |
| 615 Append(word); |
| 616 } else { |
| 617 // Word is so big that it must be fragmented. |
| 618 int array_start = 0; |
| 619 int char_start = 0; |
| 620 base::UTF16CharIterator chars(&word); |
| 621 while (!chars.end()) { |
| 622 // When boundary is hit, add as much as will fit on this line. |
| 623 if (current_col_ + (chars.char_pos() - char_start) >= max_cols_) { |
| 624 Append(word.substr(array_start, chars.array_pos() - array_start)); |
| 625 NewLine(); |
| 626 array_start = chars.array_pos(); |
| 627 char_start = chars.char_pos(); |
| 628 } |
| 629 chars.Advance(); |
| 630 } |
| 631 // add last remaining fragment, if any. |
| 632 if (array_start != chars.array_pos()) |
| 633 Append(word.substr(array_start, chars.array_pos() - array_start)); |
| 634 } |
| 635 } |
| 636 |
| 637 void RectangleString::Append(const string16& string) { |
| 638 if (current_row_ < max_rows_) |
| 639 output_->append(string); |
| 640 else |
| 641 suppressed_ = true; |
| 642 current_col_ += string.length(); |
| 643 } |
| 644 |
| 645 void RectangleString::NewLine() { |
| 646 if (current_row_ < max_rows_) |
| 647 output_->append(ASCIIToUTF16("\n")); |
| 648 else |
| 649 suppressed_ = true; |
| 650 ++current_row_; |
| 651 current_col_ = 0; |
| 652 } |
| 653 |
| 654 } // namespace |
| 655 |
| 656 namespace gfx { |
| 657 |
| 658 bool ElideRectangleString(const string16& input, size_t max_rows, |
| 659 size_t max_cols, string16* output) { |
| 660 RectangleString rect(max_rows, max_cols, output); |
| 661 rect.Init(); |
| 662 rect.AddString(input); |
| 663 return rect.Finalize(); |
| 664 } |
| 665 |
| 666 } // namespace gfx |
| 667 |
OLD | NEW |