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 >= 0 && 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, bool next) const { |
msw
2011/09/16 17:39:08
|next| belongs on the following line, our style gu
xji
2011/09/16 20:29:24
Done.
| |
269 RelativeLogicalPosition pos) const { | |
270 const char* ch = layout_text_ + utf8_index_of_current_grapheme; | 277 const char* ch = layout_text_ + utf8_index_of_current_grapheme; |
271 int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, | 278 int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, |
272 ch)); | 279 ch)); |
273 int start_char_offset = char_offset; | 280 int start_char_offset = char_offset; |
274 if (pos == PREVIOUS) { | 281 if (!next) { |
275 if (char_offset > 0) { | 282 if (char_offset > 0) { |
276 do { | 283 do { |
277 --char_offset; | 284 --char_offset; |
278 } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position); | 285 } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position); |
279 } | 286 } |
280 } else { | 287 } else { |
281 if (char_offset < num_log_attrs_ - 1) { | 288 if (char_offset < num_log_attrs_ - 1) { |
282 do { | 289 do { |
283 ++char_offset; | 290 ++char_offset; |
284 } while (char_offset < num_log_attrs_ - 1 && | 291 } while (char_offset < num_log_attrs_ - 1 && |
285 !log_attrs_[char_offset].is_cursor_position); | 292 !log_attrs_[char_offset].is_cursor_position); |
286 } | 293 } |
287 } | 294 } |
288 | 295 |
289 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); | 296 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); |
290 return static_cast<size_t>(ch - layout_text_); | 297 return static_cast<size_t>(ch - layout_text_); |
291 } | 298 } |
292 | 299 |
293 size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme( | 300 size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme( |
294 size_t utf8_index_of_current_grapheme, | 301 size_t utf8_index_of_current_grapheme, bool next) const { |
msw
2011/09/16 17:39:08
|next| on next line.
xji
2011/09/16 20:29:24
Done.
| |
295 RelativeLogicalPosition pos) const { | |
296 size_t utf8_index = Utf8IndexOfAdjacentGrapheme( | 302 size_t utf8_index = Utf8IndexOfAdjacentGrapheme( |
297 utf8_index_of_current_grapheme, pos); | 303 utf8_index_of_current_grapheme, next); |
298 return Utf8IndexToUtf16Index(utf8_index); | 304 return Utf8IndexToUtf16Index(utf8_index); |
299 } | 305 } |
300 | 306 |
301 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( | 307 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
302 const PangoItem* item) const { | 308 const PangoItem* item) const { |
303 size_t caret = Utf8IndexToUtf16Index(item->offset); | 309 size_t caret = Utf8IndexToUtf16Index(item->offset); |
304 size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, NEXT); | 310 size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, true); |
305 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 311 return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
306 } | 312 } |
307 | 313 |
308 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( | 314 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
309 const PangoItem* item) const { | 315 const PangoItem* item) const { |
310 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, | 316 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, |
311 PREVIOUS); | 317 false); |
312 return SelectionModel(caret, caret, SelectionModel::LEADING); | 318 return SelectionModel(caret, caret, SelectionModel::LEADING); |
313 } | 319 } |
314 | 320 |
315 // Assume caret_pos in |current| is n, 'l' represents leading in | 321 // Assume caret_pos in |current| is n, 'l' represents leading in |
316 // caret_placement and 't' represents trailing in caret_placement. Following | 322 // caret_placement and 't' represents trailing in caret_placement. Following |
317 // is the calculation from (caret_pos, caret_placement) in |current| to | 323 // is the calculation from (caret_pos, caret_placement) in |current| to |
318 // (selection_end, caret_pos, caret_placement) when moving cursor left by | 324 // (selection_end, caret_pos, caret_placement) when moving cursor left by |
319 // one grapheme (for simplicity, assume each grapheme is one character). | 325 // one grapheme (for simplicity, assume each grapheme is one character). |
320 // If n is in LTR run, | 326 // If n is in LTR run, |
321 // (n, t) ---> (n, n, l). | 327 // (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 { | 587 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { |
582 int32_t utf16_index = 0; | 588 int32_t utf16_index = 0; |
583 UErrorCode ec = U_ZERO_ERROR; | 589 UErrorCode ec = U_ZERO_ERROR; |
584 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); | 590 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); |
585 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || | 591 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
586 ec == U_STRING_NOT_TERMINATED_WARNING); | 592 ec == U_STRING_NOT_TERMINATED_WARNING); |
587 return utf16_index; | 593 return utf16_index; |
588 } | 594 } |
589 | 595 |
590 } // namespace gfx | 596 } // namespace gfx |
OLD | NEW |