| Index: app/text_elider.cc
|
| ===================================================================
|
| --- app/text_elider.cc (revision 69878)
|
| +++ app/text_elider.cc (working copy)
|
| @@ -6,6 +6,8 @@
|
|
|
| #include "app/text_elider.h"
|
| #include "base/file_path.h"
|
| +#include "base/i18n/break_iterator.h"
|
| +#include "base/i18n/char_iterator.h"
|
| #include "base/i18n/rtl.h"
|
| #include "base/string_split.h"
|
| #include "base/string_util.h"
|
| @@ -498,3 +500,168 @@
|
| }
|
|
|
| } // namespace gfx
|
| +
|
| +namespace {
|
| +
|
| +// Internal class used to track progress of a rectangular string elide
|
| +// operation. Exists so the top-level ElideRectangleString() function
|
| +// can be broken into smaller methods sharing this state.
|
| +class RectangleString {
|
| + public:
|
| + RectangleString(size_t max_rows, size_t max_cols, string16 *output)
|
| + : max_rows_(max_rows),
|
| + max_cols_(max_cols),
|
| + current_row_(0),
|
| + current_col_(0),
|
| + suppressed_(false),
|
| + output_(output) {}
|
| +
|
| + // Perform deferred initializions following creation. Must be called
|
| + // before any input can be added via AddString().
|
| + void Init() { output_->clear(); }
|
| +
|
| + // Add an input string, reformatting to fit the desired dimensions.
|
| + // AddString() may be called multiple times to concatenate together
|
| + // multiple strings into the region (the current caller doesn't do
|
| + // this, however).
|
| + void AddString(const string16& input);
|
| +
|
| + // Perform any deferred output processing. Must be called after the
|
| + // last AddString() call has occured.
|
| + bool Finalize();
|
| +
|
| + private:
|
| + // Add a line to the rectangular region at the current position,
|
| + // either by itself or by breaking it into words.
|
| + void AddLine(const string16& line);
|
| +
|
| + // Add a word to the rectangluar region at the current position,
|
| + // either by itelf or by breaking it into characters.
|
| + void AddWord(const string16& word);
|
| +
|
| + // Add text to the output string if the rectangular boundaries
|
| + // have not been exceeded, advancing the current position.
|
| + void Append(const string16& string);
|
| +
|
| + // Add a newline to the output string if the rectangular boundaries
|
| + // have not been exceeded, resetting the current position to the
|
| + // beginning of the next line.
|
| + void NewLine();
|
| +
|
| + // Maximum number of rows allowed in the output string.
|
| + size_t max_rows_;
|
| +
|
| + // Maximum number of characters allowed in the output string.
|
| + size_t max_cols_;
|
| +
|
| + // Current row position, always incremented and may exceed max_rows_
|
| + // when the input can not fit in the region. We stop appending to
|
| + // the output string, however, when this condition occurs. In the
|
| + // future, we may want to expose this value to allow the caller to
|
| + // determine how many rows would actually be required to hold the
|
| + // formatted string.
|
| + size_t current_row_;
|
| +
|
| + // Current character position, should never exceed max_cols_.
|
| + size_t current_col_;
|
| +
|
| + // True when some of the input has been truncated.
|
| + bool suppressed_;
|
| +
|
| + // String onto which the output is accumulated.
|
| + string16 *output_;
|
| +};
|
| +
|
| +void RectangleString::AddString(const string16& input) {
|
| + base::BreakIterator lines(&input, base::BreakIterator::BREAK_NEWLINE);
|
| + if (lines.Init()) {
|
| + while (lines.Advance())
|
| + AddLine(lines.GetString());
|
| + } else {
|
| + NOTREACHED() << "BreakIterator (lines) init failed";
|
| + }
|
| +}
|
| +
|
| +bool RectangleString::Finalize() {
|
| + if (suppressed_) {
|
| + output_->append(ASCIIToUTF16("..."));
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void RectangleString::AddLine(const string16& line) {
|
| + if (line.length() < max_cols_) {
|
| + Append(line);
|
| + } else {
|
| + base::BreakIterator words(&line, base::BreakIterator::BREAK_SPACE);
|
| + if (words.Init()) {
|
| + while (words.Advance())
|
| + AddWord(words.GetString());
|
| + } else {
|
| + NOTREACHED() << "BreakIterator (words) init failed";
|
| + }
|
| + }
|
| + // Account for naturally-occuring newlines.
|
| + ++current_row_;
|
| + current_col_ = 0;
|
| +}
|
| +
|
| +void RectangleString::AddWord(const string16& word) {
|
| + if (word.length() < max_cols_) {
|
| + // Word can be made to fit, no need to fragment it.
|
| + if (current_col_ + word.length() >= max_cols_)
|
| + NewLine();
|
| + Append(word);
|
| + } else {
|
| + // Word is so big that it must be fragmented.
|
| + int array_start = 0;
|
| + int char_start = 0;
|
| + base::UTF16CharIterator chars(&word);
|
| + while (!chars.end()) {
|
| + // When boundary is hit, add as much as will fit on this line.
|
| + if (current_col_ + (chars.char_pos() - char_start) >= max_cols_) {
|
| + Append(word.substr(array_start, chars.array_pos() - array_start));
|
| + NewLine();
|
| + array_start = chars.array_pos();
|
| + char_start = chars.char_pos();
|
| + }
|
| + chars.Advance();
|
| + }
|
| + // add last remaining fragment, if any.
|
| + if (array_start != chars.array_pos())
|
| + Append(word.substr(array_start, chars.array_pos() - array_start));
|
| + }
|
| +}
|
| +
|
| +void RectangleString::Append(const string16& string) {
|
| + if (current_row_ < max_rows_)
|
| + output_->append(string);
|
| + else
|
| + suppressed_ = true;
|
| + current_col_ += string.length();
|
| +}
|
| +
|
| +void RectangleString::NewLine() {
|
| + if (current_row_ < max_rows_)
|
| + output_->append(ASCIIToUTF16("\n"));
|
| + else
|
| + suppressed_ = true;
|
| + ++current_row_;
|
| + current_col_ = 0;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace gfx {
|
| +
|
| +bool ElideRectangleString(const string16& input, size_t max_rows,
|
| + size_t max_cols, string16* output) {
|
| + RectangleString rect(max_rows, max_cols, output);
|
| + rect.Init();
|
| + rect.AddString(input);
|
| + return rect.Finalize();
|
| +}
|
| +
|
| +} // namespace gfx
|
| +
|
|
|