| 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_linux.h" | 5 #include "ui/gfx/render_text_linux.h" |
| 6 | 6 |
| 7 #include <pango/pangocairo.h> | 7 #include <pango/pangocairo.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 bounds = GetUpdatedCursorBounds(); | 116 bounds = GetUpdatedCursorBounds(); |
| 117 if (cursor_visible() && focused()) | 117 if (cursor_visible() && focused()) |
| 118 canvas->DrawRectInt(kCursorColor, | 118 canvas->DrawRectInt(kCursorColor, |
| 119 bounds.x(), | 119 bounds.x(), |
| 120 bounds.y(), | 120 bounds.y(), |
| 121 bounds.width(), | 121 bounds.width(), |
| 122 bounds.height()); | 122 bounds.height()); |
| 123 } | 123 } |
| 124 | 124 |
| 125 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { | 125 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { |
| 126 // TODO(xji): when points outside of text, return HOME/END position. | |
| 127 PangoLayout* layout = EnsureLayout(); | 126 PangoLayout* layout = EnsureLayout(); |
| 128 | 127 |
| 129 if (text().empty()) | 128 if (text().empty()) |
| 130 return SelectionModel(0, 0, SelectionModel::LEADING); | 129 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 131 | 130 |
| 132 Point p(ToTextPoint(point)); | 131 Point p(ToTextPoint(point)); |
| 132 |
| 133 // When the point is outside of text, return HOME/END position. |
| 134 if (p.x() < 0) |
| 135 return LeftEndSelectionModel(); |
| 136 else if (p.x() > GetStringWidth()) |
| 137 return RightEndSelectionModel(); |
| 138 |
| 133 int caret_pos, trailing; | 139 int caret_pos, trailing; |
| 134 pango_layout_xy_to_index(layout, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, | 140 pango_layout_xy_to_index(layout, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, |
| 135 &caret_pos, &trailing); | 141 &caret_pos, &trailing); |
| 136 | 142 |
| 137 size_t selection_end = caret_pos; | 143 size_t selection_end = caret_pos; |
| 138 if (trailing > 0) { | 144 if (trailing > 0) { |
| 139 const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, | 145 const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
| 140 trailing); | 146 trailing); |
| 141 DCHECK_GE(ch, layout_text_); | 147 DCHECK_GE(ch, layout_text_); |
| 142 DCHECK_LE(ch, layout_text_ + layout_text_len_); | 148 DCHECK_LE(ch, layout_text_ + layout_text_len_); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 if (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) { | 211 if (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) { |
| 206 if (current_line_->runs) { | 212 if (current_line_->runs) { |
| 207 PangoLayoutRun* first_visual_run = | 213 PangoLayoutRun* first_visual_run = |
| 208 reinterpret_cast<PangoLayoutRun*>(current_line_->runs->data); | 214 reinterpret_cast<PangoLayoutRun*>(current_line_->runs->data); |
| 209 PangoItem* item = first_visual_run->item; | 215 PangoItem* item = first_visual_run->item; |
| 210 if (item->analysis.level % 2 == 0) { // LTR. | 216 if (item->analysis.level % 2 == 0) { // LTR. |
| 211 size_t caret = Utf8IndexToUtf16Index(item->offset); | 217 size_t caret = Utf8IndexToUtf16Index(item->offset); |
| 212 return SelectionModel(text().length(), caret, SelectionModel::LEADING); | 218 return SelectionModel(text().length(), caret, SelectionModel::LEADING); |
| 213 } else { // RTL. | 219 } else { // RTL. |
| 214 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, | 220 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, |
| 215 PREVIOUS); | 221 false); |
| 216 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); | 222 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); |
| 217 } | 223 } |
| 218 } | 224 } |
| 219 } | 225 } |
| 220 return SelectionModel(0, 0, SelectionModel::LEADING); | 226 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 221 } | 227 } |
| 222 | 228 |
| 223 SelectionModel RenderTextLinux::RightEndSelectionModel() { | 229 SelectionModel RenderTextLinux::RightEndSelectionModel() { |
| 224 if (GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { | 230 if (GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { |
| 225 PangoLayoutRun* last_visual_run = GetLastRun(); | 231 PangoLayoutRun* last_visual_run = GetLastRun(); |
| 226 if (last_visual_run) { | 232 if (last_visual_run) { |
| 227 PangoItem* item = last_visual_run->item; | 233 PangoItem* item = last_visual_run->item; |
| 228 if (item->analysis.level % 2 == 0) { // LTR. | 234 if (item->analysis.level % 2 == 0) { // LTR. |
| 229 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, | 235 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, |
| 230 PREVIOUS); | 236 false); |
| 231 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); | 237 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); |
| 232 } else { // RTL. | 238 } else { // RTL. |
| 233 size_t caret = Utf8IndexToUtf16Index(item->offset); | 239 size_t caret = Utf8IndexToUtf16Index(item->offset); |
| 234 return SelectionModel(text().length(), caret, SelectionModel::LEADING); | 240 return SelectionModel(text().length(), caret, SelectionModel::LEADING); |
| 235 } | 241 } |
| 236 } | 242 } |
| 237 } | 243 } |
| 238 return SelectionModel(0, 0, SelectionModel::LEADING); | 244 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 239 } | 245 } |
| 240 | 246 |
| 241 size_t RenderTextLinux::GetIndexOfPreviousGrapheme(size_t position) { | 247 bool RenderTextLinux::IsCursorablePosition(size_t position) { |
| 248 if (position == 0 && text().empty()) |
| 249 return true; |
| 250 |
| 242 EnsureLayout(); | 251 EnsureLayout(); |
| 243 size_t index = Utf16IndexToUtf8Index(position); | 252 return (position < static_cast<size_t>(num_log_attrs_) && |
| 244 return Utf16IndexOfAdjacentGrapheme(index, PREVIOUS); | 253 log_attrs_[position].is_cursor_position); |
| 245 } | 254 } |
| 246 | 255 |
| 247 size_t RenderTextLinux::GetIndexOfNextGrapheme(size_t position) { | 256 size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) { |
| 248 EnsureLayout(); | 257 EnsureLayout(); |
| 249 size_t index = Utf16IndexToUtf8Index(position); | 258 return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next); |
| 250 return Utf16IndexOfAdjacentGrapheme(index, NEXT); | |
| 251 } | 259 } |
| 252 | 260 |
| 253 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { | 261 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { |
| 254 GSList* run = current_line_->runs; | 262 GSList* run = current_line_->runs; |
| 255 while (run) { | 263 while (run) { |
| 256 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 264 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
| 257 size_t run_start = Utf8IndexToUtf16Index(item->offset); | 265 size_t run_start = Utf8IndexToUtf16Index(item->offset); |
| 258 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | 266 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); |
| 259 | 267 |
| 260 if (position >= run_start && position < run_end) | 268 if (position >= run_start && position < run_end) |
| 261 return run; | 269 return run; |
| 262 run = run->next; | 270 run = run->next; |
| 263 } | 271 } |
| 264 return NULL; | 272 return NULL; |
| 265 } | 273 } |
| 266 | 274 |
| 267 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( | 275 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( |
| 268 size_t utf8_index_of_current_grapheme, | 276 size_t utf8_index_of_current_grapheme, |
| 269 RelativeLogicalPosition pos) const { | 277 bool next) const { |
| 270 const char* ch = layout_text_ + utf8_index_of_current_grapheme; | 278 const char* ch = layout_text_ + utf8_index_of_current_grapheme; |
| 271 int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, | 279 int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, |
| 272 ch)); | 280 ch)); |
| 273 int start_char_offset = char_offset; | 281 int start_char_offset = char_offset; |
| 274 if (pos == PREVIOUS) { | 282 if (!next) { |
| 275 if (char_offset > 0) { | 283 if (char_offset > 0) { |
| 276 do { | 284 do { |
| 277 --char_offset; | 285 --char_offset; |
| 278 } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position); | 286 } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position); |
| 279 } | 287 } |
| 280 } else { | 288 } else { |
| 281 if (char_offset < num_log_attrs_ - 1) { | 289 if (char_offset < num_log_attrs_ - 1) { |
| 282 do { | 290 do { |
| 283 ++char_offset; | 291 ++char_offset; |
| 284 } while (char_offset < num_log_attrs_ - 1 && | 292 } while (char_offset < num_log_attrs_ - 1 && |
| 285 !log_attrs_[char_offset].is_cursor_position); | 293 !log_attrs_[char_offset].is_cursor_position); |
| 286 } | 294 } |
| 287 } | 295 } |
| 288 | 296 |
| 289 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); | 297 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); |
| 290 return static_cast<size_t>(ch - layout_text_); | 298 return static_cast<size_t>(ch - layout_text_); |
| 291 } | 299 } |
| 292 | 300 |
| 293 size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme( | 301 size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme( |
| 294 size_t utf8_index_of_current_grapheme, | 302 size_t utf8_index_of_current_grapheme, |
| 295 RelativeLogicalPosition pos) const { | 303 bool next) const { |
| 296 size_t utf8_index = Utf8IndexOfAdjacentGrapheme( | 304 size_t utf8_index = Utf8IndexOfAdjacentGrapheme( |
| 297 utf8_index_of_current_grapheme, pos); | 305 utf8_index_of_current_grapheme, next); |
| 298 return Utf8IndexToUtf16Index(utf8_index); | 306 return Utf8IndexToUtf16Index(utf8_index); |
| 299 } | 307 } |
| 300 | 308 |
| 301 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( | 309 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
| 302 const PangoItem* item) const { | 310 const PangoItem* item) const { |
| 303 size_t caret = Utf8IndexToUtf16Index(item->offset); | 311 size_t caret = Utf8IndexToUtf16Index(item->offset); |
| 304 size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, NEXT); | 312 size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, true); |
| 305 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 313 return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
| 306 } | 314 } |
| 307 | 315 |
| 308 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( | 316 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
| 309 const PangoItem* item) const { | 317 const PangoItem* item) const { |
| 310 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, | 318 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, |
| 311 PREVIOUS); | 319 false); |
| 312 return SelectionModel(caret, caret, SelectionModel::LEADING); | 320 return SelectionModel(caret, caret, SelectionModel::LEADING); |
| 313 } | 321 } |
| 314 | 322 |
| 315 // Assume caret_pos in |current| is n, 'l' represents leading in | 323 // Assume caret_pos in |current| is n, 'l' represents leading in |
| 316 // caret_placement and 't' represents trailing in caret_placement. Following | 324 // caret_placement and 't' represents trailing in caret_placement. Following |
| 317 // is the calculation from (caret_pos, caret_placement) in |current| to | 325 // is the calculation from (caret_pos, caret_placement) in |current| to |
| 318 // (selection_end, caret_pos, caret_placement) when moving cursor left by | 326 // (selection_end, caret_pos, caret_placement) when moving cursor left by |
| 319 // one grapheme (for simplicity, assume each grapheme is one character). | 327 // one grapheme (for simplicity, assume each grapheme is one character). |
| 320 // If n is in LTR run, | 328 // If n is in LTR run, |
| 321 // (n, t) ---> (n, n, l). | 329 // (n, t) ---> (n, n, l). |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { | 589 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { |
| 582 int32_t utf16_index = 0; | 590 int32_t utf16_index = 0; |
| 583 UErrorCode ec = U_ZERO_ERROR; | 591 UErrorCode ec = U_ZERO_ERROR; |
| 584 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); | 592 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); |
| 585 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || | 593 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
| 586 ec == U_STRING_NOT_TERMINATED_WARNING); | 594 ec == U_STRING_NOT_TERMINATED_WARNING); |
| 587 return utf16_index; | 595 return utf16_index; |
| 588 } | 596 } |
| 589 | 597 |
| 590 } // namespace gfx | 598 } // namespace gfx |
| OLD | NEW |