| OLD | NEW |
| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 split_style.range.set_end(new_range.start()); | 60 split_style.range.set_end(new_range.start()); |
| 61 i = style_ranges->insert(i, split_style) + 1; | 61 i = style_ranges->insert(i, split_style) + 1; |
| 62 i->range.set_start(new_range.end()); | 62 i->range.set_start(new_range.end()); |
| 63 break; | 63 break; |
| 64 } else if (i->range.start() < new_range.start()) { | 64 } else if (i->range.start() < new_range.start()) { |
| 65 i->range.set_end(new_range.start()); | 65 i->range.set_end(new_range.start()); |
| 66 i++; | 66 i++; |
| 67 } else if (i->range.end() > new_range.end()) { | 67 } else if (i->range.end() > new_range.end()) { |
| 68 i->range.set_start(new_range.end()); | 68 i->range.set_start(new_range.end()); |
| 69 break; | 69 break; |
| 70 } else | 70 } else { |
| 71 NOTREACHED(); | 71 NOTREACHED(); |
| 72 } |
| 72 } | 73 } |
| 73 // Add the new range in its sorted location. | 74 // Add the new range in its sorted location. |
| 74 style_ranges->insert(i, style_range); | 75 style_ranges->insert(i, style_range); |
| 75 } | 76 } |
| 76 | 77 |
| 77 } // namespace | 78 } // namespace |
| 78 | 79 |
| 79 namespace gfx { | 80 namespace gfx { |
| 80 | 81 |
| 81 StyleRange::StyleRange() | 82 StyleRange::StyleRange() |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 if (break_type == WORD_BREAK) | 182 if (break_type == WORD_BREAK) |
| 182 position = GetRightSelectionModel(position, break_type); | 183 position = GetRightSelectionModel(position, break_type); |
| 183 } else { | 184 } else { |
| 184 position = GetRightSelectionModel(position, break_type); | 185 position = GetRightSelectionModel(position, break_type); |
| 185 } | 186 } |
| 186 if (select) | 187 if (select) |
| 187 position.set_selection_start(GetSelectionStart()); | 188 position.set_selection_start(GetSelectionStart()); |
| 188 MoveCursorTo(position); | 189 MoveCursorTo(position); |
| 189 } | 190 } |
| 190 | 191 |
| 191 bool RenderText::MoveCursorTo(const SelectionModel& selection_model) { | 192 bool RenderText::MoveCursorTo(const SelectionModel& model) { |
| 192 SelectionModel sel(selection_model); | 193 SelectionModel sel(model); |
| 193 size_t text_length = text().length(); | 194 size_t text_length = text().length(); |
| 194 // Enforce valid selection model components. | 195 // Enforce valid selection model components. |
| 195 if (sel.selection_start() > text_length) | 196 if (sel.selection_start() > text_length) |
| 196 sel.set_selection_start(text_length); | 197 sel.set_selection_start(text_length); |
| 197 if (sel.selection_end() > text_length) | 198 if (sel.selection_end() > text_length) |
| 198 sel.set_selection_end(text_length); | 199 sel.set_selection_end(text_length); |
| 199 // The current model only supports caret positions at valid character indices. | 200 // The current model only supports caret positions at valid character indices. |
| 200 if (text_length == 0) { | 201 if (text_length == 0) { |
| 201 sel.set_caret_pos(0); | 202 sel.set_caret_pos(0); |
| 202 sel.set_caret_placement(SelectionModel::LEADING); | 203 sel.set_caret_placement(SelectionModel::LEADING); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 int left_pos = 0; | 362 int left_pos = 0; |
| 362 int right = font.GetStringWidth(text()); | 363 int right = font.GetStringWidth(text()); |
| 363 int right_pos = text().length(); | 364 int right_pos = text().length(); |
| 364 | 365 |
| 365 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); | 366 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); |
| 366 if (x <= left) return SelectionModel(left_pos); | 367 if (x <= left) return SelectionModel(left_pos); |
| 367 if (x >= right) return SelectionModel(right_pos); | 368 if (x >= right) return SelectionModel(right_pos); |
| 368 // binary searching the cursor position. | 369 // binary searching the cursor position. |
| 369 // TODO(oshima): use the center of character instead of edge. | 370 // TODO(oshima): use the center of character instead of edge. |
| 370 // Binary search may not work for language like Arabic. | 371 // Binary search may not work for language like Arabic. |
| 371 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) { | 372 while (std::abs(right_pos - left_pos) > 1) { |
| 372 int pivot_pos = left_pos + (right_pos - left_pos) / 2; | 373 int pivot_pos = left_pos + (right_pos - left_pos) / 2; |
| 373 int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); | 374 int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); |
| 374 if (pivot < x) { | 375 if (pivot < x) { |
| 375 left = pivot; | 376 left = pivot; |
| 376 left_pos = pivot_pos; | 377 left_pos = pivot_pos; |
| 377 } else if (pivot == x) { | 378 } else if (pivot == x) { |
| 378 return SelectionModel(pivot_pos); | 379 return SelectionModel(pivot_pos); |
| 379 } else { | 380 } else { |
| 380 right = pivot; | 381 right = pivot; |
| 381 right_pos = pivot_pos; | 382 right_pos = pivot_pos; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 | 424 |
| 424 const Point& RenderText::GetUpdatedDisplayOffset() { | 425 const Point& RenderText::GetUpdatedDisplayOffset() { |
| 425 UpdateCachedBoundsAndOffset(); | 426 UpdateCachedBoundsAndOffset(); |
| 426 return display_offset_; | 427 return display_offset_; |
| 427 } | 428 } |
| 428 | 429 |
| 429 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, | 430 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, |
| 430 BreakType break_type) { | 431 BreakType break_type) { |
| 431 if (break_type == LINE_BREAK) | 432 if (break_type == LINE_BREAK) |
| 432 return LeftEndSelectionModel(); | 433 return LeftEndSelectionModel(); |
| 433 size_t pos = std::max(static_cast<long>(current.selection_end() - 1), | 434 size_t pos = std::max<int>(current.selection_end() - 1, 0); |
| 434 static_cast<long>(0)); | |
| 435 if (break_type == CHARACTER_BREAK) | 435 if (break_type == CHARACTER_BREAK) |
| 436 return SelectionModel(pos, pos, SelectionModel::LEADING); | 436 return SelectionModel(pos, pos, SelectionModel::LEADING); |
| 437 | 437 |
| 438 // Notes: We always iterate words from the beginning. | 438 // Notes: We always iterate words from the beginning. |
| 439 // This is probably fast enough for our usage, but we may | 439 // This is probably fast enough for our usage, but we may |
| 440 // want to modify WordIterator so that it can start from the | 440 // want to modify WordIterator so that it can start from the |
| 441 // middle of string and advance backwards. | 441 // middle of string and advance backwards. |
| 442 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 442 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 443 bool success = iter.Init(); | 443 bool success = iter.Init(); |
| 444 DCHECK(success); | 444 DCHECK(success); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? | 498 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? |
| 499 SelectionModel::LEADING : SelectionModel::TRAILING; | 499 SelectionModel::LEADING : SelectionModel::TRAILING; |
| 500 return SelectionModel(cursor, caret_pos, placement); | 500 return SelectionModel(cursor, caret_pos, placement); |
| 501 } | 501 } |
| 502 | 502 |
| 503 void RenderText::SetSelectionModel(const SelectionModel& model) { | 503 void RenderText::SetSelectionModel(const SelectionModel& model) { |
| 504 DCHECK_LE(model.selection_start(), text().length()); | 504 DCHECK_LE(model.selection_start(), text().length()); |
| 505 selection_model_.set_selection_start(model.selection_start()); | 505 selection_model_.set_selection_start(model.selection_start()); |
| 506 DCHECK_LE(model.selection_end(), text().length()); | 506 DCHECK_LE(model.selection_end(), text().length()); |
| 507 selection_model_.set_selection_end(model.selection_end()); | 507 selection_model_.set_selection_end(model.selection_end()); |
| 508 DCHECK_LT(model.caret_pos(), | 508 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1)); |
| 509 std::max(text().length(), static_cast<size_t>(1))); | |
| 510 selection_model_.set_caret_pos(model.caret_pos()); | 509 selection_model_.set_caret_pos(model.caret_pos()); |
| 511 selection_model_.set_caret_placement(model.caret_placement()); | 510 selection_model_.set_caret_placement(model.caret_placement()); |
| 512 | 511 |
| 513 cached_bounds_and_offset_valid_ = false; | 512 cached_bounds_and_offset_valid_ = false; |
| 514 UpdateLayout(); | 513 UpdateLayout(); |
| 515 } | 514 } |
| 516 | 515 |
| 517 size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) { | 516 size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) { |
| 518 return IndexOfAdjacentGrapheme(position, false); | 517 return IndexOfAdjacentGrapheme(position, false); |
| 519 } | 518 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 void RenderText::DrawCursor(Canvas* canvas) { | 611 void RenderText::DrawCursor(Canvas* canvas) { |
| 613 // Paint cursor. Replace cursor is drawn as rectangle for now. | 612 // Paint cursor. Replace cursor is drawn as rectangle for now. |
| 614 // TODO(msw): Draw a better cursor with a better indication of association. | 613 // TODO(msw): Draw a better cursor with a better indication of association. |
| 615 if (cursor_visible() && focused()) { | 614 if (cursor_visible() && focused()) { |
| 616 Rect r(GetUpdatedCursorBounds()); | 615 Rect r(GetUpdatedCursorBounds()); |
| 617 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); | 616 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); |
| 618 } | 617 } |
| 619 } | 618 } |
| 620 | 619 |
| 621 } // namespace gfx | 620 } // namespace gfx |
| OLD | NEW |