Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(421)

Side by Side Diff: ui/gfx/render_text.cc

Issue 7511029: Implement Pango RenderText for Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "ui/gfx/render_text.h" 5 #include "ui/gfx/render_text.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/i18n/break_iterator.h" 9 #include "base/i18n/break_iterator.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 selection_start_ = start; 128 selection_start_ = start;
129 selection_end_ = end; 129 selection_end_ = end;
130 caret_pos_ = pos; 130 caret_pos_ = pos;
131 caret_placement_ = placement; 131 caret_placement_ = placement;
132 } 132 }
133 133
134 RenderText::~RenderText() { 134 RenderText::~RenderText() {
135 } 135 }
136 136
137 void RenderText::SetText(const string16& text) { 137 void RenderText::SetText(const string16& text) {
138 DCHECK(!composition_range_.IsValid());
138 size_t old_text_length = text_.length(); 139 size_t old_text_length = text_.length();
139 text_ = text; 140 text_ = text;
140 141
141 // Update the style ranges as needed. 142 // Update the style ranges as needed.
142 if (text_.empty()) { 143 if (text_.empty()) {
143 style_ranges_.clear(); 144 style_ranges_.clear();
144 } else if (style_ranges_.empty()) { 145 } else if (style_ranges_.empty()) {
145 ApplyDefaultStyle(); 146 ApplyDefaultStyle();
146 } else if (text_.length() > old_text_length) { 147 } else if (text_.length() > old_text_length) {
147 style_ranges_.back().range.set_end(text_.length()); 148 style_ranges_.back().range.set_end(text_.length());
148 } else if (text_.length() < old_text_length) { 149 } else if (text_.length() < old_text_length) {
149 StyleRanges::iterator i; 150 StyleRanges::iterator i;
150 for (i = style_ranges_.begin(); i != style_ranges_.end(); i++) { 151 for (i = style_ranges_.begin(); i != style_ranges_.end(); i++) {
151 if (i->range.start() >= text_.length()) { 152 if (i->range.start() >= text_.length()) {
152 i = style_ranges_.erase(i); 153 i = style_ranges_.erase(i);
153 if (i == style_ranges_.end()) 154 if (i == style_ranges_.end())
154 break; 155 break;
155 } else if (i->range.end() > text_.length()) { 156 } else if (i->range.end() > text_.length()) {
156 i->range.set_end(text_.length()); 157 i->range.set_end(text_.length());
157 } 158 }
158 } 159 }
159 style_ranges_.back().range.set_end(text_.length()); 160 style_ranges_.back().range.set_end(text_.length());
160 } 161 }
161 #ifndef NDEBUG 162 #ifndef NDEBUG
162 CheckStyleRanges(style_ranges_, text_.length()); 163 CheckStyleRanges(style_ranges_, text_.length());
163 #endif 164 #endif
164 cached_bounds_and_offset_valid_ = false; 165 cached_bounds_and_offset_valid_ = false;
166
167 // Reset selection model. SetText should always followed by SetSelectionModel
168 // or SetCursorPosition in upper layer.
169 SetSelectionModel(SelectionModel(0, 0, SelectionModel::LEADING));
165 } 170 }
166 171
167 void RenderText::ToggleInsertMode() { 172 void RenderText::ToggleInsertMode() {
168 insert_mode_ = !insert_mode_; 173 insert_mode_ = !insert_mode_;
169 cached_bounds_and_offset_valid_ = false; 174 cached_bounds_and_offset_valid_ = false;
170 } 175 }
171 176
172 void RenderText::SetDisplayRect(const Rect& r) { 177 void RenderText::SetDisplayRect(const Rect& r) {
173 display_rect_ = r; 178 display_rect_ = r;
174 cached_bounds_and_offset_valid_ = false; 179 cached_bounds_and_offset_valid_ = false;
175 } 180 }
176 181
177 size_t RenderText::GetCursorPosition() const { 182 size_t RenderText::GetCursorPosition() const {
178 return selection_model_.selection_end(); 183 return selection_model_.selection_end();
179 } 184 }
180 185
181 void RenderText::SetCursorPosition(size_t position) { 186 void RenderText::SetCursorPosition(size_t position) {
182 MoveCursorTo(position, false); 187 MoveCursorTo(position, false);
183 } 188 }
184 189
185 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { 190 void RenderText::MoveCursorLeft(BreakType break_type, bool select) {
186 SelectionModel position(selection_model()); 191 SelectionModel position(selection_model());
187 position.set_selection_start(GetCursorPosition()); 192 position.set_selection_start(GetCursorPosition());
188 // Cancelling a selection moves to the edge of the selection. 193 // Cancelling a selection moves to the edge of the selection.
189 if (break_type != LINE_BREAK && !EmptySelection() && !select) { 194 if (break_type != LINE_BREAK && !EmptySelection() && !select) {
190 // Use the selection start if it is left of the selection end. 195 // Use the selection start if it is left of the selection end.
191 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 196 SelectionModel selection_start = GetSelectionModelForSelectionStart();
192 SelectionModel::LEADING); 197 if (GetCursorBounds(selection_start, true).x() <
193 if (GetCursorBounds(selection_start, false).x() < 198 GetCursorBounds(position, true).x())
194 GetCursorBounds(position, false).x())
195 position = selection_start; 199 position = selection_start;
196 // For word breaks, use the nearest word boundary left of the selection. 200 // For word breaks, use the nearest word boundary left of the selection.
197 if (break_type == WORD_BREAK) 201 if (break_type == WORD_BREAK)
198 position = GetLeftSelectionModel(position, break_type); 202 position = GetLeftSelectionModel(position, break_type);
199 } else { 203 } else {
200 position = GetLeftSelectionModel(position, break_type); 204 position = GetLeftSelectionModel(position, break_type);
201 } 205 }
202 if (select) 206 if (select)
203 position.set_selection_start(GetSelectionStart()); 207 position.set_selection_start(GetSelectionStart());
204 MoveCursorTo(position); 208 MoveCursorTo(position);
205 } 209 }
206 210
207 void RenderText::MoveCursorRight(BreakType break_type, bool select) { 211 void RenderText::MoveCursorRight(BreakType break_type, bool select) {
208 SelectionModel position(selection_model()); 212 SelectionModel position(selection_model());
209 position.set_selection_start(GetCursorPosition()); 213 position.set_selection_start(GetCursorPosition());
210 // Cancelling a selection moves to the edge of the selection. 214 // Cancelling a selection moves to the edge of the selection.
211 if (break_type != LINE_BREAK && !EmptySelection() && !select) { 215 if (break_type != LINE_BREAK && !EmptySelection() && !select) {
212 // Use the selection start if it is right of the selection end. 216 // Use the selection start if it is right of the selection end.
213 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 217 SelectionModel selection_start = GetSelectionModelForSelectionStart();
214 SelectionModel::LEADING); 218 if (GetCursorBounds(selection_start, true).x() >
215 if (GetCursorBounds(selection_start, false).x() > 219 GetCursorBounds(position, true).x())
216 GetCursorBounds(position, false).x())
217 position = selection_start; 220 position = selection_start;
218 // For word breaks, use the nearest word boundary right of the selection. 221 // For word breaks, use the nearest word boundary right of the selection.
219 if (break_type == WORD_BREAK) 222 if (break_type == WORD_BREAK)
220 position = GetRightSelectionModel(position, break_type); 223 position = GetRightSelectionModel(position, break_type);
221 } else { 224 } else {
222 position = GetRightSelectionModel(position, break_type); 225 position = GetRightSelectionModel(position, break_type);
223 } 226 }
224 if (select) 227 if (select)
225 position.set_selection_start(GetSelectionStart()); 228 position.set_selection_start(GetSelectionStart());
226 MoveCursorTo(position); 229 MoveCursorTo(position);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 } 349 }
347 350
348 void RenderText::ApplyDefaultStyle() { 351 void RenderText::ApplyDefaultStyle() {
349 style_ranges_.clear(); 352 style_ranges_.clear();
350 StyleRange style = StyleRange(default_style_); 353 StyleRange style = StyleRange(default_style_);
351 style.range.set_end(text_.length()); 354 style.range.set_end(text_.length());
352 style_ranges_.push_back(style); 355 style_ranges_.push_back(style);
353 cached_bounds_and_offset_valid_ = false; 356 cached_bounds_and_offset_valid_ = false;
354 } 357 }
355 358
356 base::i18n::TextDirection RenderText::GetTextDirection() const { 359 base::i18n::TextDirection RenderText::GetTextDirection() {
357 if (base::i18n::IsRTL()) 360 if (base::i18n::IsRTL())
358 return base::i18n::RIGHT_TO_LEFT; 361 return base::i18n::RIGHT_TO_LEFT;
359 return base::i18n::LEFT_TO_RIGHT; 362 return base::i18n::LEFT_TO_RIGHT;
360 } 363 }
361 364
362 int RenderText::GetStringWidth() { 365 int RenderText::GetStringWidth() {
363 return default_style_.font.GetStringWidth(text()); 366 return default_style_.font.GetStringWidth(text());
364 } 367 }
365 368
366 void RenderText::Draw(Canvas* canvas) { 369 void RenderText::Draw(Canvas* canvas) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 int left = 0; 426 int left = 0;
424 int left_pos = 0; 427 int left_pos = 0;
425 int right = font.GetStringWidth(text()); 428 int right = font.GetStringWidth(text());
426 int right_pos = text().length(); 429 int right_pos = text().length();
427 430
428 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); 431 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x());
429 if (x <= left) return SelectionModel(left_pos); 432 if (x <= left) return SelectionModel(left_pos);
430 if (x >= right) return SelectionModel(right_pos); 433 if (x >= right) return SelectionModel(right_pos);
431 // binary searching the cursor position. 434 // binary searching the cursor position.
432 // TODO(oshima): use the center of character instead of edge. 435 // TODO(oshima): use the center of character instead of edge.
433 // Binary search may not work for language like arabic. 436 // Binary search may not work for language like Arabic.
434 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) { 437 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) {
435 int pivot_pos = left_pos + (right_pos - left_pos) / 2; 438 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
436 int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); 439 int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
437 if (pivot < x) { 440 if (pivot < x) {
438 left = pivot; 441 left = pivot;
439 left_pos = pivot_pos; 442 left_pos = pivot_pos;
440 } else if (pivot == x) { 443 } else if (pivot == x) {
441 return SelectionModel(pivot_pos); 444 return SelectionModel(pivot_pos);
442 } else { 445 } else {
443 right = pivot; 446 right = pivot;
(...skipping 14 matching lines...) Expand all
458 UpdateCachedBoundsAndOffset(); 461 UpdateCachedBoundsAndOffset();
459 return cursor_bounds_; 462 return cursor_bounds_;
460 } 463 }
461 464
462 RenderText::RenderText() 465 RenderText::RenderText()
463 : text_(), 466 : text_(),
464 selection_model_(), 467 selection_model_(),
465 cursor_bounds_(), 468 cursor_bounds_(),
466 cursor_visible_(false), 469 cursor_visible_(false),
467 insert_mode_(true), 470 insert_mode_(true),
468 composition_range_(), 471 composition_range_(ui::Range::InvalidRange()),
469 style_ranges_(), 472 style_ranges_(),
470 default_style_(), 473 default_style_(),
471 display_rect_(), 474 display_rect_(),
472 display_offset_(), 475 display_offset_(),
473 cached_bounds_and_offset_valid_(false) { 476 cached_bounds_and_offset_valid_(false) {
474 } 477 }
475 478
476 const Point& RenderText::GetUpdatedDisplayOffset() { 479 const Point& RenderText::GetUpdatedDisplayOffset() {
477 UpdateCachedBoundsAndOffset(); 480 UpdateCachedBoundsAndOffset();
478 return display_offset_; 481 return display_offset_;
479 } 482 }
480 483
481 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, 484 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
482 BreakType break_type) { 485 BreakType break_type) {
483 if (break_type == LINE_BREAK) 486 if (break_type == LINE_BREAK)
484 return SelectionModel(0, 0, SelectionModel::LEADING); 487 return SelectionModel(0, 0, SelectionModel::LEADING);
485 size_t pos = std::max(static_cast<long>(current.selection_end() - 1), 488 size_t pos = std::max(static_cast<long>(current.selection_end() - 1),
486 static_cast<long>(0)); 489 static_cast<long>(0));
487 if (break_type == CHARACTER_BREAK) 490 if (break_type == CHARACTER_BREAK)
488 return SelectionModel(pos, pos, SelectionModel::LEADING); 491 return SelectionModel(pos, pos, SelectionModel::LEADING);
489 492
490 // Notes: We always iterate words from the begining. 493 // Notes: We always iterate words from the beginning.
491 // This is probably fast enough for our usage, but we may 494 // This is probably fast enough for our usage, but we may
492 // want to modify WordIterator so that it can start from the 495 // want to modify WordIterator so that it can start from the
493 // middle of string and advance backwards. 496 // middle of string and advance backwards.
494 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 497 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
495 bool success = iter.Init(); 498 bool success = iter.Init();
496 DCHECK(success); 499 DCHECK(success);
497 if (!success) 500 if (!success)
498 return current; 501 return current;
499 while (iter.Advance()) { 502 while (iter.Advance()) {
500 if (iter.IsWord()) { 503 if (iter.IsWord()) {
(...skipping 11 matching lines...) Expand all
512 pos = iter.pos() - iter.GetString().length(); 515 pos = iter.pos() - iter.GetString().length();
513 } 516 }
514 } 517 }
515 } 518 }
516 519
517 return SelectionModel(pos, pos, SelectionModel::LEADING); 520 return SelectionModel(pos, pos, SelectionModel::LEADING);
518 } 521 }
519 522
520 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, 523 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
521 BreakType break_type) { 524 BreakType break_type) {
525 if (text_.empty())
526 return SelectionModel(0, 0, SelectionModel::LEADING);
522 if (break_type == LINE_BREAK) 527 if (break_type == LINE_BREAK)
523 return SelectionModel(text().length(), 528 return SelectionModel(text().length(),
524 GetIndexOfPreviousGrapheme(text().length()), SelectionModel::TRAILING); 529 GetIndexOfPreviousGrapheme(text().length()), SelectionModel::TRAILING);
525 size_t pos = std::min(current.selection_end() + 1, text().length()); 530 size_t pos = std::min(current.selection_end() + 1, text().length());
526 if (break_type == CHARACTER_BREAK) 531 if (break_type == CHARACTER_BREAK)
527 return SelectionModel(pos, pos, SelectionModel::LEADING); 532 return SelectionModel(pos, pos, SelectionModel::LEADING);
528 533
529 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 534 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
530 bool success = iter.Init(); 535 bool success = iter.Init();
531 DCHECK(success); 536 DCHECK(success);
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 cached_bounds_and_offset_valid_ = true; 650 cached_bounds_and_offset_valid_ = true;
646 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 651 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
647 // Update |display_offset_| to ensure the current cursor is visible. 652 // Update |display_offset_| to ensure the current cursor is visible.
648 int display_width = display_rect_.width(); 653 int display_width = display_rect_.width();
649 int string_width = GetStringWidth(); 654 int string_width = GetStringWidth();
650 int delta_offset = 0; 655 int delta_offset = 0;
651 if (string_width < display_width) { 656 if (string_width < display_width) {
652 // Show all text whenever the text fits to the size. 657 // Show all text whenever the text fits to the size.
653 delta_offset = -display_offset_.x(); 658 delta_offset = -display_offset_.x();
654 } else if (cursor_bounds_.right() > display_rect_.right()) { 659 } else if (cursor_bounds_.right() > display_rect_.right()) {
660 // TODO(xji): when the character overflow is a RTL character, currently, if
661 // we pan cursor at the rightmost position, the entered RTL character is not
662 // displayed. Should pan cursor to show the last logical characters.
663 //
655 // Pan to show the cursor when it overflows to the right, 664 // Pan to show the cursor when it overflows to the right,
656 delta_offset = display_rect_.right() - cursor_bounds_.right(); 665 delta_offset = display_rect_.right() - cursor_bounds_.right();
657 } else if (cursor_bounds_.x() < display_rect_.x()) { 666 } else if (cursor_bounds_.x() < display_rect_.x()) {
667 // TODO(xji): have similar problem as above when overflow character is a
668 // LTR character.
669 //
658 // Pan to show the cursor when it overflows to the left. 670 // Pan to show the cursor when it overflows to the left.
659 delta_offset = display_rect_.x() - cursor_bounds_.x(); 671 delta_offset = display_rect_.x() - cursor_bounds_.x();
660 } 672 }
661 display_offset_.Offset(delta_offset, 0); 673 display_offset_.Offset(delta_offset, 0);
662 cursor_bounds_.Offset(delta_offset, 0); 674 cursor_bounds_.Offset(delta_offset, 0);
663 } 675 }
664 676
677 SelectionModel RenderText::GetSelectionModelForSelectionStart() {
678 size_t selection_start = GetSelectionStart();
679 size_t selection_end = GetCursorPosition();
680 if (selection_start < selection_end)
681 return SelectionModel(selection_start,
682 selection_start,
683 SelectionModel::LEADING);
684 else if (selection_start > selection_end)
685 return SelectionModel(selection_start,
686 GetIndexOfPreviousGrapheme(selection_start),
687 SelectionModel::TRAILING);
688 return selection_model_;
689 }
690
665 } // namespace gfx 691 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_linux.h » ('j') | ui/gfx/render_text_linux.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698