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

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: address comments on patch 20, move SetupPango to pango_util 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 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 177
178 void RenderText::SetDisplayRect(const Rect& r) { 178 void RenderText::SetDisplayRect(const Rect& r) {
179 display_rect_ = r; 179 display_rect_ = r;
180 cached_bounds_and_offset_valid_ = false; 180 cached_bounds_and_offset_valid_ = false;
181 } 181 }
182 182
183 size_t RenderText::GetCursorPosition() const { 183 size_t RenderText::GetCursorPosition() const {
184 return selection_model_.selection_end(); 184 return selection_model_.selection_end();
185 } 185 }
186 186
187 void RenderText::SetCursorPosition(const size_t position) { 187 void RenderText::SetCursorPosition(size_t position) {
188 SelectionModel sel(selection_model()); 188 MoveCursorTo(position, false);
189 sel.set_selection_start(position);
190 sel.set_selection_end(position);
191 sel.set_caret_pos(GetIndexOfPreviousGrapheme(position));
192 sel.set_caret_placement(SelectionModel::TRAILING);
193 SetSelectionModel(sel);
194 } 189 }
195 190
196 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { 191 void RenderText::MoveCursorLeft(BreakType break_type, bool select) {
197 SelectionModel position(selection_model()); 192 SelectionModel position(selection_model());
198 position.set_selection_start(GetCursorPosition()); 193 position.set_selection_start(GetCursorPosition());
199 // Cancelling a selection moves to the edge of the selection. 194 // Cancelling a selection moves to the edge of the selection.
200 if (break_type != LINE_BREAK && !EmptySelection() && !select) { 195 if (break_type != LINE_BREAK && !EmptySelection() && !select) {
201 // Use the selection start if it is left of the selection end. 196 // Use the selection start if it is left of the selection end.
202 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 197 SelectionModel selection_start = GetSelectionModelForSelectionStart();
203 SelectionModel::LEADING);
204 if (GetCursorBounds(selection_start, false).x() < 198 if (GetCursorBounds(selection_start, false).x() <
205 GetCursorBounds(position, false).x()) 199 GetCursorBounds(position, false).x())
206 position = selection_start; 200 position = selection_start;
207 // For word breaks, use the nearest word boundary left of the selection. 201 // For word breaks, use the nearest word boundary left of the selection.
208 if (break_type == WORD_BREAK) 202 if (break_type == WORD_BREAK)
209 position = GetLeftSelectionModel(position, break_type); 203 position = GetLeftSelectionModel(position, break_type);
210 } else { 204 } else {
211 position = GetLeftSelectionModel(position, break_type); 205 position = GetLeftSelectionModel(position, break_type);
212 } 206 }
213 if (select) 207 if (select)
214 position.set_selection_start(GetSelectionStart()); 208 position.set_selection_start(GetSelectionStart());
215 MoveCursorTo(position); 209 MoveCursorTo(position);
216 } 210 }
217 211
218 void RenderText::MoveCursorRight(BreakType break_type, bool select) { 212 void RenderText::MoveCursorRight(BreakType break_type, bool select) {
219 SelectionModel position(selection_model()); 213 SelectionModel position(selection_model());
220 position.set_selection_start(GetCursorPosition()); 214 position.set_selection_start(GetCursorPosition());
221 // Cancelling a selection moves to the edge of the selection. 215 // Cancelling a selection moves to the edge of the selection.
222 if (break_type != LINE_BREAK && !EmptySelection() && !select) { 216 if (break_type != LINE_BREAK && !EmptySelection() && !select) {
223 // Use the selection start if it is right of the selection end. 217 // Use the selection start if it is right of the selection end.
224 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 218 SelectionModel selection_start = GetSelectionModelForSelectionStart();
225 SelectionModel::LEADING);
226 if (GetCursorBounds(selection_start, false).x() > 219 if (GetCursorBounds(selection_start, false).x() >
227 GetCursorBounds(position, false).x()) 220 GetCursorBounds(position, false).x())
228 position = selection_start; 221 position = selection_start;
229 // For word breaks, use the nearest word boundary right of the selection. 222 // For word breaks, use the nearest word boundary right of the selection.
230 if (break_type == WORD_BREAK) 223 if (break_type == WORD_BREAK)
231 position = GetRightSelectionModel(position, break_type); 224 position = GetRightSelectionModel(position, break_type);
232 } else { 225 } else {
233 position = GetRightSelectionModel(position, break_type); 226 position = GetRightSelectionModel(position, break_type);
234 } 227 }
235 if (select) 228 if (select)
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 } 335 }
343 336
344 void RenderText::ApplyDefaultStyle() { 337 void RenderText::ApplyDefaultStyle() {
345 style_ranges_.clear(); 338 style_ranges_.clear();
346 StyleRange style = StyleRange(default_style_); 339 StyleRange style = StyleRange(default_style_);
347 style.range.set_end(text_.length()); 340 style.range.set_end(text_.length());
348 style_ranges_.push_back(style); 341 style_ranges_.push_back(style);
349 cached_bounds_and_offset_valid_ = false; 342 cached_bounds_and_offset_valid_ = false;
350 } 343 }
351 344
352 base::i18n::TextDirection RenderText::GetTextDirection() const { 345 base::i18n::TextDirection RenderText::GetTextDirection() {
353 // TODO(msw): Bidi implementation, intended to replace the functionality added 346 if (base::i18n::IsRTL())
354 // in crrev.com/91881 (discussed in codereview.chromium.org/7324011). 347 return base::i18n::RIGHT_TO_LEFT;
355 return base::i18n::LEFT_TO_RIGHT; 348 return base::i18n::LEFT_TO_RIGHT;
356 } 349 }
357 350
358 int RenderText::GetStringWidth() { 351 int RenderText::GetStringWidth() {
359 return default_style_.font.GetStringWidth(text()); 352 return default_style_.font.GetStringWidth(text());
360 } 353 }
361 354
362 void RenderText::Draw(Canvas* canvas) { 355 void RenderText::Draw(Canvas* canvas) {
363 // Clip the canvas to the text display area. 356 // Clip the canvas to the text display area.
364 canvas->ClipRectInt(display_rect_.x(), display_rect_.y(), 357 canvas->ClipRectInt(display_rect_.x(), display_rect_.y(),
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 int left = 0; 412 int left = 0;
420 int left_pos = 0; 413 int left_pos = 0;
421 int right = font.GetStringWidth(text()); 414 int right = font.GetStringWidth(text());
422 int right_pos = text().length(); 415 int right_pos = text().length();
423 416
424 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); 417 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x());
425 if (x <= left) return SelectionModel(left_pos); 418 if (x <= left) return SelectionModel(left_pos);
426 if (x >= right) return SelectionModel(right_pos); 419 if (x >= right) return SelectionModel(right_pos);
427 // binary searching the cursor position. 420 // binary searching the cursor position.
428 // TODO(oshima): use the center of character instead of edge. 421 // TODO(oshima): use the center of character instead of edge.
429 // Binary search may not work for language like arabic. 422 // Binary search may not work for language like Arabic.
430 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) { 423 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) {
431 int pivot_pos = left_pos + (right_pos - left_pos) / 2; 424 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
432 int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); 425 int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
433 if (pivot < x) { 426 if (pivot < x) {
434 left = pivot; 427 left = pivot;
435 left_pos = pivot_pos; 428 left_pos = pivot_pos;
436 } else if (pivot == x) { 429 } else if (pivot == x) {
437 return SelectionModel(pivot_pos); 430 return SelectionModel(pivot_pos);
438 } else { 431 } else {
439 right = pivot; 432 right = pivot;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 483
491 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, 484 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
492 BreakType break_type) { 485 BreakType break_type) {
493 if (break_type == LINE_BREAK) 486 if (break_type == LINE_BREAK)
494 return SelectionModel(0, 0, SelectionModel::LEADING); 487 return SelectionModel(0, 0, SelectionModel::LEADING);
495 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),
496 static_cast<long>(0)); 489 static_cast<long>(0));
497 if (break_type == CHARACTER_BREAK) 490 if (break_type == CHARACTER_BREAK)
498 return SelectionModel(pos, pos, SelectionModel::LEADING); 491 return SelectionModel(pos, pos, SelectionModel::LEADING);
499 492
500 // Notes: We always iterate words from the begining. 493 // Notes: We always iterate words from the beginning.
501 // This is probably fast enough for our usage, but we may 494 // This is probably fast enough for our usage, but we may
502 // want to modify WordIterator so that it can start from the 495 // want to modify WordIterator so that it can start from the
503 // middle of string and advance backwards. 496 // middle of string and advance backwards.
504 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 497 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
505 bool success = iter.Init(); 498 bool success = iter.Init();
506 DCHECK(success); 499 DCHECK(success);
507 if (!success) 500 if (!success)
508 return current; 501 return current;
509 while (iter.Advance()) { 502 while (iter.Advance()) {
510 if (iter.IsWord()) { 503 if (iter.IsWord()) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 // Apply a selection style override to a copy of the style ranges. 562 // Apply a selection style override to a copy of the style ranges.
570 if (!EmptySelection()) { 563 if (!EmptySelection()) {
571 StyleRange selection_style(default_style_); 564 StyleRange selection_style(default_style_);
572 selection_style.foreground = kSelectedTextColor; 565 selection_style.foreground = kSelectedTextColor;
573 selection_style.range.set_start(MinOfSelection()); 566 selection_style.range.set_start(MinOfSelection());
574 selection_style.range.set_end(MaxOfSelection()); 567 selection_style.range.set_end(MaxOfSelection());
575 ApplyStyleRangeImpl(style_ranges, selection_style); 568 ApplyStyleRangeImpl(style_ranges, selection_style);
576 } 569 }
577 } 570 }
578 571
572 Point RenderText::ToTextPoint(const Point& point) {
573 Point p(point.Subtract(display_rect_.origin()));
574 p = p.Subtract(GetUpdatedDisplayOffset());
575 if (base::i18n::IsRTL())
576 p.Offset(GetStringWidth() - display_rect_.width() + 1, 0);
577 return p;
578 }
579
580 Point RenderText::ToViewPoint(const Point& point) {
581 Point p(point.Add(display_rect_.origin()));
582 p = p.Add(GetUpdatedDisplayOffset());
583 if (base::i18n::IsRTL())
584 p.Offset(display_rect_.width() - GetStringWidth() - 1, 0);
585 return p;
586 }
587
588 void RenderText::MoveCursorTo(size_t position, bool select) {
589 size_t caret_pos = GetIndexOfPreviousGrapheme(position);
590 SelectionModel::CaretPlacement placement = (caret_pos == position) ?
591 SelectionModel::LEADING : SelectionModel::TRAILING;
592 size_t selection_start = select ? GetSelectionStart() : position;
593 SelectionModel sel(selection_start, position, caret_pos, placement);
594 SetSelectionModel(sel);
595 }
596
579 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { 597 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) {
580 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || 598 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) ||
581 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); 599 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos]));
582 } 600 }
583 601
584 void RenderText::UpdateCachedBoundsAndOffset() { 602 void RenderText::UpdateCachedBoundsAndOffset() {
585 if (cached_bounds_and_offset_valid_) 603 if (cached_bounds_and_offset_valid_)
586 return; 604 return;
587 // First, set the valid flag true to calculate the current cursor bounds using 605 // First, set the valid flag true to calculate the current cursor bounds using
588 // the stale |display_offset_|. Applying |delta_offset| at the end of this 606 // the stale |display_offset_|. Applying |delta_offset| at the end of this
589 // function will set |cursor_bounds_| and |display_offset_| to correct values. 607 // function will set |cursor_bounds_| and |display_offset_| to correct values.
590 cached_bounds_and_offset_valid_ = true; 608 cached_bounds_and_offset_valid_ = true;
591 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 609 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
592 cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1)); 610 cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1));
593 // Update |display_offset_| to ensure the current cursor is visible. 611 // Update |display_offset_| to ensure the current cursor is visible.
594 int display_width = display_rect_.width(); 612 int display_width = display_rect_.width();
595 int string_width = GetStringWidth(); 613 int string_width = GetStringWidth();
596 int delta_offset = 0; 614 int delta_offset = 0;
597 if (string_width < display_width) { 615 if (string_width < display_width) {
598 // Show all text whenever the text fits to the size. 616 // Show all text whenever the text fits to the size.
599 delta_offset = -display_offset_.x(); 617 delta_offset = -display_offset_.x();
600 } else if (cursor_bounds_.right() > display_rect_.right()) { 618 } else if (cursor_bounds_.right() > display_rect_.right()) {
619 // TODO(xji): when the character overflow is a RTL character, currently, if
620 // we pan cursor at the rightmost position, the entered RTL character is not
621 // displayed. Should pan cursor to show the last logical characters.
622 //
601 // Pan to show the cursor when it overflows to the right, 623 // Pan to show the cursor when it overflows to the right,
602 delta_offset = display_rect_.right() - cursor_bounds_.right(); 624 delta_offset = display_rect_.right() - cursor_bounds_.right();
603 } else if (cursor_bounds_.x() < display_rect_.x()) { 625 } else if (cursor_bounds_.x() < display_rect_.x()) {
626 // TODO(xji): have similar problem as above when overflow character is a
627 // LTR character.
628 //
604 // Pan to show the cursor when it overflows to the left. 629 // Pan to show the cursor when it overflows to the left.
605 delta_offset = display_rect_.x() - cursor_bounds_.x(); 630 delta_offset = display_rect_.x() - cursor_bounds_.x();
606 } 631 }
607 display_offset_.Offset(delta_offset, 0); 632 display_offset_.Offset(delta_offset, 0);
608 cursor_bounds_.Offset(delta_offset, 0); 633 cursor_bounds_.Offset(delta_offset, 0);
609 } 634 }
610 635
636 SelectionModel RenderText::GetSelectionModelForSelectionStart() {
637 if (GetSelectionStart() < GetCursorPosition())
638 return SelectionModel(GetSelectionStart(),
639 GetSelectionStart(),
640 SelectionModel::LEADING);
641 return SelectionModel(GetSelectionStart(),
642 GetIndexOfPreviousGrapheme(GetSelectionStart()),
643 SelectionModel::TRAILING);
644 }
645
611 } // namespace gfx 646 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698