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 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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(); |
msw
2011/08/23 08:01:01
Remove the extra space after '='.
xji
2011/08/23 23:52:52
Done.
| |
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 Loading... | |
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 // TODO(msw): Bidi implementation, intended to replace the functionality added |
354 // in crrev.com/91881 (discussed in codereview.chromium.org/7324011). | 347 // in crrev.com/91881 (discussed in codereview.chromium.org/7324011). |
348 if (base::i18n::IsRTL()) | |
349 return base::i18n::RIGHT_TO_LEFT; | |
355 return base::i18n::LEFT_TO_RIGHT; | 350 return base::i18n::LEFT_TO_RIGHT; |
356 } | 351 } |
357 | 352 |
358 int RenderText::GetStringWidth() { | 353 int RenderText::GetStringWidth() { |
359 return default_style_.font.GetStringWidth(text()); | 354 return default_style_.font.GetStringWidth(text()); |
360 } | 355 } |
361 | 356 |
362 void RenderText::Draw(Canvas* canvas) { | 357 void RenderText::Draw(Canvas* canvas) { |
363 // Clip the canvas to the text display area. | 358 // Clip the canvas to the text display area. |
364 canvas->ClipRectInt(display_rect_.x(), display_rect_.y(), | 359 canvas->ClipRectInt(display_rect_.x(), display_rect_.y(), |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 // Apply a selection style override to a copy of the style ranges. | 564 // Apply a selection style override to a copy of the style ranges. |
570 if (!EmptySelection()) { | 565 if (!EmptySelection()) { |
571 StyleRange selection_style(default_style_); | 566 StyleRange selection_style(default_style_); |
572 selection_style.foreground = kSelectedTextColor; | 567 selection_style.foreground = kSelectedTextColor; |
573 selection_style.range.set_start(MinOfSelection()); | 568 selection_style.range.set_start(MinOfSelection()); |
574 selection_style.range.set_end(MaxOfSelection()); | 569 selection_style.range.set_end(MaxOfSelection()); |
575 ApplyStyleRangeImpl(style_ranges, selection_style); | 570 ApplyStyleRangeImpl(style_ranges, selection_style); |
576 } | 571 } |
577 } | 572 } |
578 | 573 |
574 Point RenderText::ToTextPoint(const Point& point) { | |
575 Point p(point.Subtract(display_rect_.origin())); | |
576 p = p.Subtract(GetUpdatedDisplayOffset()); | |
577 if (base::i18n::IsRTL()) | |
578 p.Offset(GetStringWidth() - display_rect_.width() + 1, 0); | |
579 return p; | |
580 } | |
581 | |
582 Point RenderText::ToViewPoint(const Point& point) { | |
583 Point p(point.Add(display_rect_.origin())); | |
584 p = p.Add(GetUpdatedDisplayOffset()); | |
585 if (base::i18n::IsRTL()) | |
586 p.Offset(display_rect_.width() - GetStringWidth() - 1, 0); | |
587 return p; | |
588 } | |
589 | |
590 void RenderText::MoveCursorTo(size_t position, bool select) { | |
591 size_t caret_pos = GetIndexOfPreviousGrapheme(position); | |
592 SelectionModel::CaretPlacement placement = (caret_pos == position) ? | |
593 SelectionModel::LEADING : SelectionModel::TRAILING; | |
594 size_t selection_start = select ? GetSelectionStart() : position; | |
595 SelectionModel sel(selection_start, position, caret_pos, placement); | |
596 SetSelectionModel(sel); | |
597 } | |
598 | |
579 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { | 599 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { |
580 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || | 600 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || |
581 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); | 601 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); |
582 } | 602 } |
583 | 603 |
584 void RenderText::UpdateCachedBoundsAndOffset() { | 604 void RenderText::UpdateCachedBoundsAndOffset() { |
585 if (cached_bounds_and_offset_valid_) | 605 if (cached_bounds_and_offset_valid_) |
586 return; | 606 return; |
587 // First, set the valid flag true to calculate the current cursor bounds using | 607 // 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 | 608 // the stale |display_offset_|. Applying |delta_offset| at the end of this |
589 // function will set |cursor_bounds_| and |display_offset_| to correct values. | 609 // function will set |cursor_bounds_| and |display_offset_| to correct values. |
590 cached_bounds_and_offset_valid_ = true; | 610 cached_bounds_and_offset_valid_ = true; |
591 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); | 611 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); |
592 cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1)); | 612 cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1)); |
593 // Update |display_offset_| to ensure the current cursor is visible. | 613 // Update |display_offset_| to ensure the current cursor is visible. |
594 int display_width = display_rect_.width(); | 614 int display_width = display_rect_.width(); |
595 int string_width = GetStringWidth(); | 615 int string_width = GetStringWidth(); |
596 int delta_offset = 0; | 616 int delta_offset = 0; |
597 if (string_width < display_width) { | 617 if (string_width < display_width) { |
598 // Show all text whenever the text fits to the size. | 618 // Show all text whenever the text fits to the size. |
599 delta_offset = -display_offset_.x(); | 619 delta_offset = -display_offset_.x(); |
600 } else if (cursor_bounds_.right() > display_rect_.right()) { | 620 } else if (cursor_bounds_.right() > display_rect_.right()) { |
621 // TODO(xji): when the character overflow is a RTL character, currently, if | |
622 // we pan cursor at the rightmost position, the entered RTL character is not | |
623 // displayed. Should pan cursor to show the last logical characters. | |
624 // BTW, Firefox has the same issue. | |
msw
2011/08/23 08:01:01
No need to call out Firefox here, we can alert the
xji
2011/08/23 23:52:52
Ah, you absolutely right. removed.
| |
625 // | |
601 // Pan to show the cursor when it overflows to the right, | 626 // Pan to show the cursor when it overflows to the right, |
602 delta_offset = display_rect_.right() - cursor_bounds_.right(); | 627 delta_offset = display_rect_.right() - cursor_bounds_.right(); |
603 } else if (cursor_bounds_.x() < display_rect_.x()) { | 628 } else if (cursor_bounds_.x() < display_rect_.x()) { |
629 // TODO(xji): have similar problem as above when overflow character is a | |
630 // LTR character. | |
631 // | |
604 // Pan to show the cursor when it overflows to the left. | 632 // Pan to show the cursor when it overflows to the left. |
605 delta_offset = display_rect_.x() - cursor_bounds_.x(); | 633 delta_offset = display_rect_.x() - cursor_bounds_.x(); |
606 } | 634 } |
607 display_offset_.Offset(delta_offset, 0); | 635 display_offset_.Offset(delta_offset, 0); |
608 cursor_bounds_.Offset(delta_offset, 0); | 636 cursor_bounds_.Offset(delta_offset, 0); |
609 } | 637 } |
610 | 638 |
639 SelectionModel RenderText::GetSelectionModelForSelectionStart() { | |
640 if (GetSelectionStart() < GetCursorPosition()) | |
641 return SelectionModel(GetSelectionStart(), | |
642 GetSelectionStart(), | |
643 SelectionModel::LEADING); | |
644 return SelectionModel(GetSelectionStart(), | |
645 GetIndexOfPreviousGrapheme(GetSelectionStart()), | |
msw
2011/08/23 08:01:01
What if the selection start is 0 and there is not
xji
2011/08/23 23:52:52
this is called when selection is not empty and sel
| |
646 SelectionModel::TRAILING); | |
647 } | |
648 | |
611 } // namespace gfx | 649 } // namespace gfx |
OLD | NEW |