| 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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 } | 175 } |
| 176 | 176 |
| 177 size_t RenderText::GetCursorPosition() const { | 177 size_t RenderText::GetCursorPosition() const { |
| 178 return selection_model_.selection_end(); | 178 return selection_model_.selection_end(); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void RenderText::SetCursorPosition(const size_t position) { | 181 void RenderText::SetCursorPosition(const size_t position) { |
| 182 SelectionModel sel(selection_model()); | 182 SelectionModel sel(selection_model()); |
| 183 sel.set_selection_start(position); | 183 sel.set_selection_start(position); |
| 184 sel.set_selection_end(position); | 184 sel.set_selection_end(position); |
| 185 sel.set_caret_pos(GetIndexOfPreviousGrapheme(position)); |
| 186 sel.set_caret_placement(SelectionModel::TRAILING); |
| 185 SetSelectionModel(sel); | 187 SetSelectionModel(sel); |
| 186 } | 188 } |
| 187 | 189 |
| 188 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { | 190 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { |
| 189 if (break_type == LINE_BREAK) { | 191 SelectionModel position(selection_model()); |
| 190 SelectionModel selection(GetSelectionStart(), 0, | 192 position.set_selection_start(GetCursorPosition()); |
| 191 0, SelectionModel::LEADING); | |
| 192 if (!select) | |
| 193 selection.set_selection_start(selection.selection_end()); | |
| 194 MoveCursorTo(selection); | |
| 195 return; | |
| 196 } | |
| 197 SelectionModel position = selection_model_; | |
| 198 // Cancelling a selection moves to the edge of the selection. | 193 // Cancelling a selection moves to the edge of the selection. |
| 199 if (!EmptySelection() && !select) { | 194 if (break_type != LINE_BREAK && !EmptySelection() && !select) { |
| 200 // 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. |
| 201 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), | 196 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), |
| 202 GetSelectionStart(), SelectionModel::LEADING); | 197 SelectionModel::LEADING); |
| 203 if (GetCursorBounds(selection_start, false).x() < | 198 if (GetCursorBounds(selection_start, false).x() < |
| 204 GetCursorBounds(position, false).x()) | 199 GetCursorBounds(position, false).x()) |
| 205 position = selection_start; | 200 position = selection_start; |
| 206 // If |move_by_word|, use the nearest word boundary left of the selection. | 201 // For word breaks, use the nearest word boundary left of the selection. |
| 207 if (break_type == WORD_BREAK) | 202 if (break_type == WORD_BREAK) |
| 208 position = GetLeftCursorPosition(position, true); | 203 position = GetLeftSelectionModel(position, break_type); |
| 209 } else { | 204 } else { |
| 210 position = GetLeftCursorPosition(position, break_type == WORD_BREAK); | 205 position = GetLeftSelectionModel(position, break_type); |
| 211 } | 206 } |
| 212 if (!select) | 207 if (select) |
| 213 position.set_selection_start(position.selection_end()); | 208 position.set_selection_start(GetSelectionStart()); |
| 214 MoveCursorTo(position); | 209 MoveCursorTo(position); |
| 215 } | 210 } |
| 216 | 211 |
| 217 void RenderText::MoveCursorRight(BreakType break_type, bool select) { | 212 void RenderText::MoveCursorRight(BreakType break_type, bool select) { |
| 218 if (break_type == LINE_BREAK) { | 213 SelectionModel position(selection_model()); |
| 219 SelectionModel selection(GetSelectionStart(), text().length(), | 214 position.set_selection_start(GetCursorPosition()); |
| 220 text().length(), SelectionModel::PREVIOUS_GRAPHEME_TRAILING); | |
| 221 if (!select) | |
| 222 selection.set_selection_start(selection.selection_end()); | |
| 223 MoveCursorTo(selection); | |
| 224 return; | |
| 225 } | |
| 226 SelectionModel position = selection_model_; | |
| 227 // Cancelling a selection moves to the edge of the selection. | 215 // Cancelling a selection moves to the edge of the selection. |
| 228 if (!EmptySelection() && !select) { | 216 if (break_type != LINE_BREAK && !EmptySelection() && !select) { |
| 229 // 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. |
| 230 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), | 218 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), |
| 231 GetSelectionStart(), SelectionModel::LEADING); | 219 SelectionModel::LEADING); |
| 232 if (GetCursorBounds(selection_start, false).x() > | 220 if (GetCursorBounds(selection_start, false).x() > |
| 233 GetCursorBounds(position, false).x()) | 221 GetCursorBounds(position, false).x()) |
| 234 position = selection_start; | 222 position = selection_start; |
| 235 // If |move_by_word|, use the nearest word boundary right of the selection. | 223 // For word breaks, use the nearest word boundary right of the selection. |
| 236 if (break_type == WORD_BREAK) | 224 if (break_type == WORD_BREAK) |
| 237 position = GetRightCursorPosition(position, true); | 225 position = GetRightSelectionModel(position, break_type); |
| 238 } else { | 226 } else { |
| 239 position = GetRightCursorPosition(position, break_type == WORD_BREAK); | 227 position = GetRightSelectionModel(position, break_type); |
| 240 } | 228 } |
| 241 if (!select) | 229 if (select) |
| 242 position.set_selection_start(position.selection_end()); | 230 position.set_selection_start(GetSelectionStart()); |
| 243 MoveCursorTo(position); | 231 MoveCursorTo(position); |
| 244 } | 232 } |
| 245 | 233 |
| 246 bool RenderText::MoveCursorTo(const SelectionModel& selection) { | 234 bool RenderText::MoveCursorTo(const SelectionModel& selection) { |
| 247 bool changed = !selection.Equals(selection_model_); | 235 bool changed = !selection.Equals(selection_model_); |
| 248 SetSelectionModel(selection); | 236 SetSelectionModel(selection); |
| 249 return changed; | 237 return changed; |
| 250 } | 238 } |
| 251 | 239 |
| 252 bool RenderText::MoveCursorTo(const Point& point, bool select) { | 240 bool RenderText::MoveCursorTo(const Point& point, bool select) { |
| 253 SelectionModel selection = FindCursorPosition(point); | 241 SelectionModel selection = FindCursorPosition(point); |
| 254 if (select) | 242 if (select) |
| 255 selection.set_selection_start(GetSelectionStart()); | 243 selection.set_selection_start(GetSelectionStart()); |
| 256 else | |
| 257 selection.set_selection_start(selection.selection_end()); | |
| 258 return MoveCursorTo(selection); | 244 return MoveCursorTo(selection); |
| 259 } | 245 } |
| 260 | 246 |
| 261 bool RenderText::IsPointInSelection(const Point& point) { | 247 bool RenderText::IsPointInSelection(const Point& point) { |
| 262 // TODO(xji): should this check whether the point is inside the visual | 248 // TODO(xji): should this check whether the point is inside the visual |
| 263 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points | 249 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points |
| 264 // to the right half of 'c', is the point in selection? | 250 // to the right half of 'c', is the point in selection? |
| 265 size_t pos = FindCursorPosition(point).selection_end(); | 251 size_t pos = FindCursorPosition(point).selection_end(); |
| 266 return (pos >= MinOfSelection() && pos < MaxOfSelection()); | 252 return (pos >= MinOfSelection() && pos < MaxOfSelection()); |
| 267 } | 253 } |
| 268 | 254 |
| 269 void RenderText::ClearSelection() { | 255 void RenderText::ClearSelection() { |
| 270 SetCursorPosition(GetCursorPosition()); | 256 SelectionModel sel(selection_model()); |
| 257 sel.set_selection_start(GetCursorPosition()); |
| 258 SetSelectionModel(sel); |
| 271 } | 259 } |
| 272 | 260 |
| 273 void RenderText::SelectAll() { | 261 void RenderText::SelectAll() { |
| 274 SelectionModel sel(0, text().length(), | 262 SelectionModel sel(0, text().length(), |
| 275 text().length(), SelectionModel::LEADING); | 263 text().length(), SelectionModel::LEADING); |
| 276 SetSelectionModel(sel); | 264 SetSelectionModel(sel); |
| 277 } | 265 } |
| 278 | 266 |
| 279 void RenderText::SelectWord() { | 267 void RenderText::SelectWord() { |
| 280 size_t selection_start = GetSelectionStart(); | 268 size_t selection_start = GetSelectionStart(); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 cursor_bounds_valid_(false), | 484 cursor_bounds_valid_(false), |
| 497 cursor_visible_(false), | 485 cursor_visible_(false), |
| 498 insert_mode_(true), | 486 insert_mode_(true), |
| 499 composition_range_(), | 487 composition_range_(), |
| 500 style_ranges_(), | 488 style_ranges_(), |
| 501 default_style_(), | 489 default_style_(), |
| 502 display_rect_(), | 490 display_rect_(), |
| 503 display_offset_() { | 491 display_offset_() { |
| 504 } | 492 } |
| 505 | 493 |
| 506 SelectionModel RenderText::GetLeftCursorPosition(const SelectionModel& current, | 494 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, |
| 507 bool move_by_word) { | 495 BreakType break_type) { |
| 508 size_t position = current.selection_end(); | 496 if (break_type == LINE_BREAK) |
| 509 SelectionModel left = current; | 497 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 510 if (!move_by_word) { | 498 size_t pos = std::max(static_cast<long>(current.selection_end() - 1), |
| 511 left.set_selection_end(std::max(static_cast<long>(position - 1), | 499 static_cast<long>(0)); |
| 512 static_cast<long>(0))); | 500 if (break_type == CHARACTER_BREAK) |
| 513 return left; | 501 return SelectionModel(pos, pos, SelectionModel::LEADING); |
| 514 } | 502 |
| 515 // Notes: We always iterate words from the begining. | 503 // Notes: We always iterate words from the begining. |
| 516 // This is probably fast enough for our usage, but we may | 504 // This is probably fast enough for our usage, but we may |
| 517 // want to modify WordIterator so that it can start from the | 505 // want to modify WordIterator so that it can start from the |
| 518 // middle of string and advance backwards. | 506 // middle of string and advance backwards. |
| 519 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 507 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 520 bool success = iter.Init(); | 508 bool success = iter.Init(); |
| 521 DCHECK(success); | 509 DCHECK(success); |
| 522 if (!success) { | 510 if (!success) |
| 523 left.set_selection_end(position); | 511 return current; |
| 524 return left; | |
| 525 } | |
| 526 int last = 0; | |
| 527 while (iter.Advance()) { | 512 while (iter.Advance()) { |
| 528 if (iter.IsWord()) { | 513 if (iter.IsWord()) { |
| 529 size_t begin = iter.pos() - iter.GetString().length(); | 514 size_t begin = iter.pos() - iter.GetString().length(); |
| 530 if (begin == position) { | 515 if (begin == current.selection_end()) { |
| 531 // The cursor is at the beginning of a word. | 516 // The cursor is at the beginning of a word. |
| 532 // Move to previous word. | 517 // Move to previous word. |
| 533 break; | 518 break; |
| 534 } else if (iter.pos() >= position) { | 519 } else if (iter.pos() >= current.selection_end()) { |
| 535 // The cursor is in the middle or at the end of a word. | 520 // The cursor is in the middle or at the end of a word. |
| 536 // Move to the top of current word. | 521 // Move to the top of current word. |
| 537 last = begin; | 522 pos = begin; |
| 538 break; | 523 break; |
| 539 } else { | 524 } else { |
| 540 last = iter.pos() - iter.GetString().length(); | 525 pos = iter.pos() - iter.GetString().length(); |
| 541 } | 526 } |
| 542 } | 527 } |
| 543 } | 528 } |
| 544 | 529 |
| 545 left.set_selection_end(last); | 530 return SelectionModel(pos, pos, SelectionModel::LEADING); |
| 546 return left; | |
| 547 } | 531 } |
| 548 | 532 |
| 549 SelectionModel RenderText::GetRightCursorPosition(const SelectionModel& current, | 533 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, |
| 550 bool move_by_word) { | 534 BreakType break_type) { |
| 551 size_t position = current.selection_end(); | 535 if (break_type == LINE_BREAK) |
| 552 SelectionModel right = current; | 536 return SelectionModel(text().length(), |
| 553 | 537 GetIndexOfPreviousGrapheme(text().length()), SelectionModel::TRAILING); |
| 554 if (!move_by_word) { | 538 size_t pos = std::min(current.selection_end() + 1, text().length()); |
| 555 right.set_selection_end(std::min(position + 1, text().length())); | 539 if (break_type == CHARACTER_BREAK) |
| 556 return right; | 540 return SelectionModel(pos, pos, SelectionModel::LEADING); |
| 557 } | |
| 558 | 541 |
| 559 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 542 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 560 bool success = iter.Init(); | 543 bool success = iter.Init(); |
| 561 DCHECK(success); | 544 DCHECK(success); |
| 562 if (!success) { | 545 if (!success) |
| 563 right.set_selection_end(position); | 546 return current; |
| 564 return right; | |
| 565 } | |
| 566 size_t pos = 0; | |
| 567 while (iter.Advance()) { | 547 while (iter.Advance()) { |
| 568 pos = iter.pos(); | 548 pos = iter.pos(); |
| 569 if (iter.IsWord() && pos > position) { | 549 if (iter.IsWord() && pos > current.selection_end()) |
| 570 break; | 550 break; |
| 571 } | |
| 572 } | 551 } |
| 573 right.set_selection_end(pos); | 552 return SelectionModel(pos, pos, SelectionModel::LEADING); |
| 574 return right; | 553 } |
| 554 |
| 555 size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) const { |
| 556 // TODO(msw): Handle complex script. |
| 557 return std::max(static_cast<int>(position - 1), static_cast<int>(0)); |
| 575 } | 558 } |
| 576 | 559 |
| 577 void RenderText::ApplyCompositionAndSelectionStyles( | 560 void RenderText::ApplyCompositionAndSelectionStyles( |
| 578 StyleRanges* style_ranges) const { | 561 StyleRanges* style_ranges) const { |
| 579 // TODO(msw): This pattern ought to be reconsidered; what about composition | 562 // TODO(msw): This pattern ought to be reconsidered; what about composition |
| 580 // and selection overlaps, retain existing local style features? | 563 // and selection overlaps, retain existing local style features? |
| 581 // Apply a composition style override to a copy of the style ranges. | 564 // Apply a composition style override to a copy of the style ranges. |
| 582 if (composition_range_.IsValid() && !composition_range_.is_empty()) { | 565 if (composition_range_.IsValid() && !composition_range_.is_empty()) { |
| 583 StyleRange composition_style(default_style_); | 566 StyleRange composition_style(default_style_); |
| 584 composition_style.underline = true; | 567 composition_style.underline = true; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 612 } else if ((display_offset_.x() + cursor_bounds_.right()) > display_width) { | 595 } else if ((display_offset_.x() + cursor_bounds_.right()) > display_width) { |
| 613 // Pan to show the cursor when it overflows to the right, | 596 // Pan to show the cursor when it overflows to the right, |
| 614 display_offset_.set_x(display_width - cursor_bounds_.right()); | 597 display_offset_.set_x(display_width - cursor_bounds_.right()); |
| 615 } else if ((display_offset_.x() + cursor_bounds_.x()) < 0) { | 598 } else if ((display_offset_.x() + cursor_bounds_.x()) < 0) { |
| 616 // Pan to show the cursor when it overflows to the left. | 599 // Pan to show the cursor when it overflows to the left. |
| 617 display_offset_.set_x(-cursor_bounds_.x()); | 600 display_offset_.set_x(-cursor_bounds_.x()); |
| 618 } | 601 } |
| 619 } | 602 } |
| 620 | 603 |
| 621 } // namespace gfx | 604 } // namespace gfx |
| OLD | NEW |