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 |