Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: ui/gfx/render_text_win.cc

Issue 9390022: Simplify handling of BiDi cursor movement (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address comments Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_win.h" 5 #include "ui/gfx/render_text_win.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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 glyph_count(0), 131 glyph_count(0),
132 script_cache(NULL) { 132 script_cache(NULL) {
133 memset(&script_analysis, 0, sizeof(script_analysis)); 133 memset(&script_analysis, 0, sizeof(script_analysis));
134 memset(&abc_widths, 0, sizeof(abc_widths)); 134 memset(&abc_widths, 0, sizeof(abc_widths));
135 } 135 }
136 136
137 TextRun::~TextRun() { 137 TextRun::~TextRun() {
138 ScriptFreeCache(&script_cache); 138 ScriptFreeCache(&script_cache);
139 } 139 }
140 140
141 // Returns the X coordinate of the leading or |trailing| edge of the glyph
142 // starting at |index|, relative to the left of the text (not the view).
143 int GetGlyphXBoundary(internal::TextRun* run, size_t index, bool trailing) {
144 DCHECK_GE(index, run->range.start())
145 DCHECK_LT(index, run->range.end())
146 int x = 0;
147 HRESULT hr = ScriptCPtoX(
148 index - run->range.start(),
149 trailing,
150 run->range.length(),
151 run->glyph_count,
152 run->logical_clusters.get(),
153 run->visible_attributes.get(),
154 run->advance_widths.get(),
155 &run->script_analysis,
156 &x);
157 DCHECK(SUCCEEDED(hr));
158 return run->preceding_run_widths + x;
159 }
160
141 } // namespace internal 161 } // namespace internal
142 162
143 // static 163 // static
144 HDC RenderTextWin::cached_hdc_ = NULL; 164 HDC RenderTextWin::cached_hdc_ = NULL;
145 165
146 // static 166 // static
147 std::map<std::string, std::vector<Font> > RenderTextWin::cached_linked_fonts_; 167 std::map<std::string, std::vector<Font> > RenderTextWin::cached_linked_fonts_;
148 168
149 RenderTextWin::RenderTextWin() 169 RenderTextWin::RenderTextWin()
150 : RenderText(), 170 : RenderText(),
(...skipping 11 matching lines...) Expand all
162 } 182 }
163 183
164 base::i18n::TextDirection RenderTextWin::GetTextDirection() { 184 base::i18n::TextDirection RenderTextWin::GetTextDirection() {
165 // TODO(benrg): Code moved from RenderText::GetTextDirection. Needs to be 185 // TODO(benrg): Code moved from RenderText::GetTextDirection. Needs to be
166 // replaced by a correct Windows implementation. 186 // replaced by a correct Windows implementation.
167 if (base::i18n::IsRTL()) 187 if (base::i18n::IsRTL())
168 return base::i18n::RIGHT_TO_LEFT; 188 return base::i18n::RIGHT_TO_LEFT;
169 return base::i18n::LEFT_TO_RIGHT; 189 return base::i18n::LEFT_TO_RIGHT;
170 } 190 }
171 191
172 int RenderTextWin::GetStringWidth() { 192 Size RenderTextWin::GetStringSize() {
173 EnsureLayout(); 193 EnsureLayout();
174 return string_width_; 194 // TODO(msw): Use the largest font instead of the default font?
195 return Size(string_width_, GetFont().GetHeight());
175 } 196 }
176 197
177 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 198 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
178 if (text().empty()) 199 if (text().empty())
179 return SelectionModel(); 200 return SelectionModel();
180 201
181 EnsureLayout(); 202 EnsureLayout();
182 // Find the run that contains the point and adjust the argument location. 203 // Find the run that contains the point and adjust the argument location.
183 Point p(ToTextPoint(point)); 204 Point p(ToTextPoint(point));
184 size_t run_index = GetRunContainingPoint(p); 205 size_t run_index = GetRunContainingPoint(p);
185 if (run_index == runs_.size()) 206 if (run_index == runs_.size())
186 return EdgeSelectionModel((p.x() < 0) ? CURSOR_LEFT : CURSOR_RIGHT); 207 return EdgeSelectionModel((p.x() < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
187 internal::TextRun* run = runs_[run_index]; 208 internal::TextRun* run = runs_[run_index];
188 209
189 int position = 0, trailing = 0; 210 int position = 0, trailing = 0;
190 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths, 211 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths,
191 run->range.length(), 212 run->range.length(),
192 run->glyph_count, 213 run->glyph_count,
193 run->logical_clusters.get(), 214 run->logical_clusters.get(),
194 run->visible_attributes.get(), 215 run->visible_attributes.get(),
195 run->advance_widths.get(), 216 run->advance_widths.get(),
196 &(run->script_analysis), 217 &(run->script_analysis),
197 &position, 218 &position,
198 &trailing); 219 &trailing);
199 DCHECK(SUCCEEDED(hr)); 220 DCHECK(SUCCEEDED(hr));
221 DCHECK_GE(trailing, 0);
200 position += run->range.start(); 222 position += run->range.start();
201
202 size_t cursor = position + trailing; 223 size_t cursor = position + trailing;
203 DCHECK_GE(cursor, 0U);
204 DCHECK_LE(cursor, text().length()); 224 DCHECK_LE(cursor, text().length());
205 return SelectionModel(cursor, position, 225 return SelectionModel(cursor, trailing ? CURSOR_BACKWARD : CURSOR_FORWARD);
206 (trailing > 0) ? SelectionModel::TRAILING : SelectionModel::LEADING);
207 }
208
209 Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection,
210 bool insert_mode) {
211 EnsureLayout();
212
213 // Highlight the logical cursor (selection end) when not in insert mode.
214 size_t pos = insert_mode ? selection.caret_pos() : selection.selection_end();
215 size_t run_index = GetRunContainingPosition(pos);
216 internal::TextRun* run = run_index == runs_.size() ? NULL : runs_[run_index];
217
218 int start_x = 0, end_x = 0;
219 if (run) {
220 HRESULT hr = 0;
221 hr = ScriptCPtoX(pos - run->range.start(),
222 false,
223 run->range.length(),
224 run->glyph_count,
225 run->logical_clusters.get(),
226 run->visible_attributes.get(),
227 run->advance_widths.get(),
228 &(run->script_analysis),
229 &start_x);
230 DCHECK(SUCCEEDED(hr));
231 hr = ScriptCPtoX(pos - run->range.start(),
232 true,
233 run->range.length(),
234 run->glyph_count,
235 run->logical_clusters.get(),
236 run->visible_attributes.get(),
237 run->advance_widths.get(),
238 &(run->script_analysis),
239 &end_x);
240 DCHECK(SUCCEEDED(hr));
241 }
242 // TODO(msw): Use the last visual run's font instead of the default font?
243 int height = run ? run->font.GetHeight() : GetFont().GetHeight();
244 Rect rect(std::min(start_x, end_x), 0, std::abs(end_x - start_x), height);
245 // Offset to the run start or the right/left end for an out of bounds index.
246 // Also center the rect vertically in the display area.
247 int text_end_offset = base::i18n::IsRTL() ? 0 : GetStringWidth();
248 rect.Offset((run ? run->preceding_run_widths : text_end_offset),
249 (display_rect().height() - rect.height()) / 2);
250 // Adjust for leading/trailing in insert mode.
251 if (insert_mode && run) {
252 bool leading = selection.caret_placement() == SelectionModel::LEADING;
253 // Adjust the x value for right-side placement.
254 if (run->script_analysis.fRTL == leading)
255 rect.set_x(rect.right());
256 rect.set_width(0);
257 }
258 rect.set_origin(ToViewPoint(rect.origin()));
259 return rect;
260 } 226 }
261 227
262 SelectionModel RenderTextWin::AdjacentCharSelectionModel( 228 SelectionModel RenderTextWin::AdjacentCharSelectionModel(
263 const SelectionModel& selection, VisualCursorDirection direction) { 229 const SelectionModel& selection,
230 VisualCursorDirection direction) {
264 DCHECK(!needs_layout_); 231 DCHECK(!needs_layout_);
265 size_t caret = selection.caret_pos(); 232 internal::TextRun* run;
266 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); 233 size_t run_index = GetRunContainingCaret(selection);
267 size_t run_index = GetRunContainingPosition(caret); 234 if (run_index == runs_.size()) {
268 DCHECK(run_index < runs_.size()); 235 // The cursor is not in any run: we're at the visual and logical edge.
269 internal::TextRun* run = runs_[run_index]; 236 SelectionModel edge = EdgeSelectionModel(direction);
270 237 if (edge.caret_pos() == selection.caret_pos())
238 return edge;
239 else
240 run = direction == CURSOR_RIGHT ? runs_.front() : runs_.back();
241 } else {
242 // If the cursor is moving within the current run, just move it by one
243 // grapheme in the appropriate direction.
244 run = runs_[run_index];
245 size_t caret = selection.caret_pos();
246 bool forward_motion =
247 run->script_analysis.fRTL == (direction == CURSOR_LEFT);
248 if (forward_motion) {
249 if (caret < run->range.end()) {
250 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
251 return SelectionModel(caret, CURSOR_BACKWARD);
252 }
253 } else {
254 if (caret > run->range.start()) {
255 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
256 return SelectionModel(caret, CURSOR_FORWARD);
257 }
258 }
259 // The cursor is at the edge of a run; move to the visually adjacent run.
260 int visual_index = logical_to_visual_[run_index];
261 visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
262 if (visual_index < 0 || visual_index >= runs_.size())
263 return EdgeSelectionModel(direction);
264 run = runs_[visual_to_logical_[visual_index]];
265 }
271 bool forward_motion = run->script_analysis.fRTL == (direction == CURSOR_LEFT); 266 bool forward_motion = run->script_analysis.fRTL == (direction == CURSOR_LEFT);
272 if (forward_motion) { 267 return forward_motion ? FirstSelectionModelInsideRun(run) :
273 if (caret_placement == SelectionModel::LEADING) { 268 LastSelectionModelInsideRun(run);
274 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
275 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
276 } else if (selection.selection_end() < run->range.end()) {
277 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
278 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
279 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
280 }
281 } else {
282 if (caret_placement == SelectionModel::TRAILING)
283 return SelectionModel(caret, caret, SelectionModel::LEADING);
284 else if (caret > run->range.start()) {
285 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
286 return SelectionModel(caret, caret, SelectionModel::LEADING);
287 }
288 }
289
290 // The character is at the beginning/end of its run; go to the previous/next
291 // visual run.
292 size_t visual_index = logical_to_visual_[run_index];
293 if (visual_index == (direction == CURSOR_LEFT ? 0 : runs_.size() - 1))
294 return EdgeSelectionModel(direction);
295 internal::TextRun* adjacent = runs_[visual_to_logical_[
296 direction == CURSOR_LEFT ? visual_index - 1 : visual_index + 1]];
297 forward_motion = adjacent->script_analysis.fRTL == (direction == CURSOR_LEFT);
298 return forward_motion ? FirstSelectionModelInsideRun(adjacent) :
299 LastSelectionModelInsideRun(adjacent);
300 } 269 }
301 270
302 // TODO(msw): Implement word breaking for Windows. 271 // TODO(msw): Implement word breaking for Windows.
303 SelectionModel RenderTextWin::AdjacentWordSelectionModel( 272 SelectionModel RenderTextWin::AdjacentWordSelectionModel(
304 const SelectionModel& selection, 273 const SelectionModel& selection,
305 VisualCursorDirection direction) { 274 VisualCursorDirection direction) {
306 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 275 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
307 bool success = iter.Init(); 276 bool success = iter.Init();
308 DCHECK(success); 277 DCHECK(success);
309 if (!success) 278 if (!success)
310 return selection; 279 return selection;
311 280
312 size_t pos; 281 size_t pos;
313 if (direction == CURSOR_RIGHT) { 282 if (direction == CURSOR_RIGHT) {
314 pos = std::min(selection.selection_end() + 1, text().length()); 283 pos = std::min(selection.caret_pos() + 1, text().length());
315 while (iter.Advance()) { 284 while (iter.Advance()) {
316 pos = iter.pos(); 285 pos = iter.pos();
317 if (iter.IsWord() && pos > selection.selection_end()) 286 if (iter.IsWord() && pos > selection.caret_pos())
318 break; 287 break;
319 } 288 }
320 } else { // direction == CURSOR_LEFT 289 } else { // direction == CURSOR_LEFT
321 // Notes: We always iterate words from the beginning. 290 // Notes: We always iterate words from the beginning.
322 // This is probably fast enough for our usage, but we may 291 // This is probably fast enough for our usage, but we may
323 // want to modify WordIterator so that it can start from the 292 // want to modify WordIterator so that it can start from the
324 // middle of string and advance backwards. 293 // middle of string and advance backwards.
325 pos = std::max<int>(selection.selection_end() - 1, 0); 294 pos = std::max<int>(selection.caret_pos() - 1, 0);
326 while (iter.Advance()) { 295 while (iter.Advance()) {
327 if (iter.IsWord()) { 296 if (iter.IsWord()) {
328 size_t begin = iter.pos() - iter.GetString().length(); 297 size_t begin = iter.pos() - iter.GetString().length();
329 if (begin == selection.selection_end()) { 298 if (begin == selection.caret_pos()) {
330 // The cursor is at the beginning of a word. 299 // The cursor is at the beginning of a word.
331 // Move to previous word. 300 // Move to previous word.
332 break; 301 break;
333 } else if (iter.pos() >= selection.selection_end()) { 302 } else if (iter.pos() >= selection.caret_pos()) {
334 // The cursor is in the middle or at the end of a word. 303 // The cursor is in the middle or at the end of a word.
335 // Move to the top of current word. 304 // Move to the top of current word.
336 pos = begin; 305 pos = begin;
337 break; 306 break;
338 } else { 307 } else {
339 pos = iter.pos() - iter.GetString().length(); 308 pos = iter.pos() - iter.GetString().length();
340 } 309 }
341 } 310 }
342 } 311 }
343 } 312 }
344 return SelectionModel(pos, pos, SelectionModel::LEADING); 313 return SelectionModel(pos, CURSOR_FORWARD);
345 } 314 }
346 315
347 SelectionModel RenderTextWin::EdgeSelectionModel( 316 void RenderTextWin::GetGlyphBounds(size_t index,
348 VisualCursorDirection direction) { 317 ui::Range* xspan,
349 if (text().empty()) 318 int* height) {
350 return SelectionModel(0, 0, SelectionModel::LEADING); 319 size_t run_index =
351 320 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
352 EnsureLayout(); 321 DCHECK_LT(run_index, runs_.size());
353 size_t cursor = (direction == GetVisualDirectionOfLogicalEnd()) ? 322 internal::TextRun* run = runs_[run_index];
354 text().length() : 0; 323 xspan->set_start(GetGlyphXBoundary(run, index, false));
355 internal::TextRun* run = runs_[ 324 xspan->set_end(GetGlyphXBoundary(run, index, true));
356 visual_to_logical_[direction == CURSOR_RIGHT ? runs_.size() - 1 : 0]]; 325 *height = run->font.GetHeight();
357 size_t caret;
358 SelectionModel::CaretPlacement placement;
359 if (run->script_analysis.fRTL == (direction == CURSOR_RIGHT)) {
360 caret = run->range.start();
361 placement = SelectionModel::LEADING;
362 } else {
363 caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD);
364 placement = SelectionModel::TRAILING;
365 }
366 return SelectionModel(cursor, caret, placement);
367 } 326 }
368 327
369 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { 328 std::vector<Rect> RenderTextWin::GetSubstringBounds(ui::Range range) {
370 DCHECK(!needs_layout_); 329 DCHECK(!needs_layout_);
371 ui::Range range(from, to);
372 DCHECK(ui::Range(0, text().length()).Contains(range)); 330 DCHECK(ui::Range(0, text().length()).Contains(range));
373 Point display_offset(GetUpdatedDisplayOffset()); 331 Point display_offset(GetUpdatedDisplayOffset());
374 HRESULT hr = 0; 332 HRESULT hr = 0;
375 333
376 std::vector<Rect> bounds; 334 std::vector<Rect> bounds;
377 if (from == to) 335 if (range.is_empty())
378 return bounds; 336 return bounds;
379 337
380 // Add a Rect for each run/selection intersection. 338 // Add a Rect for each run/selection intersection.
381 // TODO(msw): The bounds should probably not always be leading the range ends. 339 // TODO(msw): The bounds should probably not always be leading the range ends.
382 for (size_t i = 0; i < runs_.size(); ++i) { 340 for (size_t i = 0; i < runs_.size(); ++i) {
383 internal::TextRun* run = runs_[visual_to_logical_[i]]; 341 internal::TextRun* run = runs_[visual_to_logical_[i]];
384 ui::Range intersection = run->range.Intersect(range); 342 ui::Range intersection = run->range.Intersect(range);
385 if (intersection.IsValid()) { 343 if (intersection.IsValid()) {
386 DCHECK(!intersection.is_reversed()); 344 DCHECK(!intersection.is_reversed());
387 int start_offset = 0; 345 ui::Range range(GetGlyphXBoundary(run, intersection.start(), false),
388 hr = ScriptCPtoX(intersection.start() - run->range.start(), 346 GetGlyphXBoundary(run, intersection.end(), false));
389 false, 347 Rect rect(range.GetMin(), 0, range.length(), run->font.GetHeight());
390 run->range.length(),
391 run->glyph_count,
392 run->logical_clusters.get(),
393 run->visible_attributes.get(),
394 run->advance_widths.get(),
395 &(run->script_analysis),
396 &start_offset);
397 DCHECK(SUCCEEDED(hr));
398 int end_offset = 0;
399 hr = ScriptCPtoX(intersection.end() - run->range.start(),
400 false,
401 run->range.length(),
402 run->glyph_count,
403 run->logical_clusters.get(),
404 run->visible_attributes.get(),
405 run->advance_widths.get(),
406 &(run->script_analysis),
407 &end_offset);
408 DCHECK(SUCCEEDED(hr));
409 if (start_offset > end_offset)
410 std::swap(start_offset, end_offset);
411 Rect rect(run->preceding_run_widths + start_offset, 0,
412 end_offset - start_offset, run->font.GetHeight());
413 // Center the rect vertically in the display area. 348 // Center the rect vertically in the display area.
414 rect.Offset(0, (display_rect().height() - rect.height()) / 2); 349 rect.Offset(0, (display_rect().height() - rect.height()) / 2);
415 rect.set_origin(ToViewPoint(rect.origin())); 350 rect.set_origin(ToViewPoint(rect.origin()));
416 // Union this with the last rect if they're adjacent. 351 // Union this with the last rect if they're adjacent.
417 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 352 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) {
418 rect = rect.Union(bounds.back()); 353 rect = rect.Union(bounds.back());
419 bounds.pop_back(); 354 bounds.pop_back();
420 } 355 }
421 bounds.push_back(rect); 356 bounds.push_back(rect);
422 } 357 }
423 } 358 }
424 return bounds; 359 return bounds;
425 } 360 }
426 361
427 void RenderTextWin::SetSelectionModel(const SelectionModel& model) { 362 void RenderTextWin::SetSelectionModel(const SelectionModel& model) {
428 RenderText::SetSelectionModel(model); 363 RenderText::SetSelectionModel(model);
429 // TODO(xji): The styles are applied to text inside ItemizeLogicalText(). So, 364 // TODO(xji): The styles are applied to text inside ItemizeLogicalText(). So,
430 // we need to update layout here in order for the styles, such as selection 365 // we need to update layout here in order for the styles, such as selection
431 // foreground, to be picked up. Eventually, we should separate styles from 366 // foreground, to be picked up. Eventually, we should separate styles from
432 // layout by applying foreground, strike, and underline styles during 367 // layout by applying foreground, strike, and underline styles during
433 // DrawVisualText as what RenderTextLinux does. 368 // DrawVisualText as what RenderTextLinux does.
434 UpdateLayout(); 369 UpdateLayout();
435 } 370 }
436 371
437 bool RenderTextWin::IsCursorablePosition(size_t position) { 372 bool RenderTextWin::IsCursorablePosition(size_t position) {
438 if (position == 0 || position == text().length()) 373 if (position == 0 || position == text().length())
439 return true; 374 return true;
440 375
441 EnsureLayout(); 376 EnsureLayout();
442 size_t run_index = GetRunContainingPosition(position); 377 size_t run_index =
378 GetRunContainingCaret(SelectionModel(position, CURSOR_FORWARD));
443 if (run_index >= runs_.size()) 379 if (run_index >= runs_.size())
444 return false; 380 return false;
445 381
446 internal::TextRun* run = runs_[run_index]; 382 internal::TextRun* run = runs_[run_index];
447 size_t start = run->range.start(); 383 size_t start = run->range.start();
448 if (position == start) 384 if (position == start)
449 return true; 385 return true;
450 return run->logical_clusters[position - start] != 386 return run->logical_clusters[position - start] !=
451 run->logical_clusters[position - start - 1]; 387 run->logical_clusters[position - start - 1];
452 } 388 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 return text().length(); 468 return text().length();
533 } else { 469 } else {
534 // The requested |index| is at the end of the text. Use the index of the 470 // The requested |index| is at the end of the text. Use the index of the
535 // last character to find the grapheme. 471 // last character to find the grapheme.
536 index = text().length() - 1; 472 index = text().length() - 1;
537 if (IsCursorablePosition(index)) 473 if (IsCursorablePosition(index))
538 return index; 474 return index;
539 } 475 }
540 } 476 }
541 477
542 size_t run_index = GetRunContainingPosition(index); 478 size_t run_index =
479 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
543 DCHECK(run_index < runs_.size()); 480 DCHECK(run_index < runs_.size());
544 internal::TextRun* run = runs_[run_index]; 481 internal::TextRun* run = runs_[run_index];
545 size_t start = run->range.start(); 482 size_t start = run->range.start();
546 size_t ch = index - start; 483 size_t ch = index - start;
547 484
548 if (direction == CURSOR_BACKWARD) { 485 if (direction == CURSOR_BACKWARD) {
549 // If |ch| is the start of the run, use the preceding run, if any. 486 // If |ch| is the start of the run, use the preceding run, if any.
550 if (ch == 0) { 487 if (ch == 0) {
551 if (run_index == 0) 488 if (run_index == 0)
552 return 0; 489 return 0;
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 cached_linked_fonts_.find(font_name); 718 cached_linked_fonts_.find(font_name);
782 if (it != cached_linked_fonts_.end()) 719 if (it != cached_linked_fonts_.end())
783 return &it->second; 720 return &it->second;
784 721
785 cached_linked_fonts_[font_name] = std::vector<Font>(); 722 cached_linked_fonts_[font_name] = std::vector<Font>();
786 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; 723 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
787 QueryLinkedFontsFromRegistry(font, linked_fonts); 724 QueryLinkedFontsFromRegistry(font, linked_fonts);
788 return linked_fonts; 725 return linked_fonts;
789 } 726 }
790 727
791 size_t RenderTextWin::GetRunContainingPosition(size_t position) const { 728 size_t RenderTextWin::GetRunContainingCaret(const SelectionModel& caret) const {
792 DCHECK(!needs_layout_); 729 DCHECK(!needs_layout_);
793 // Find the text run containing the argument position. 730 size_t position = caret.caret_pos();
731 LogicalCursorDirection affinity = caret.caret_affinity();
794 size_t run = 0; 732 size_t run = 0;
795 for (; run < runs_.size(); ++run) 733 for (; run < runs_.size(); ++run)
796 if (runs_[run]->range.start() <= position && 734 if (RangeContainsCaret(runs_[run]->range, position, affinity))
797 runs_[run]->range.end() > position)
798 break; 735 break;
799 return run; 736 return run;
800 } 737 }
801 738
802 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const { 739 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const {
803 DCHECK(!needs_layout_); 740 DCHECK(!needs_layout_);
804 // Find the text run containing the argument point (assumed already offset). 741 // Find the text run containing the argument point (assumed already offset).
805 size_t run = 0; 742 size_t run = 0;
806 for (; run < runs_.size(); ++run) 743 for (; run < runs_.size(); ++run)
807 if (runs_[run]->preceding_run_widths <= point.x() && 744 if (runs_[run]->preceding_run_widths <= point.x() &&
808 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) 745 runs_[run]->preceding_run_widths + runs_[run]->width > point.x())
809 break; 746 break;
810 return run; 747 return run;
811 } 748 }
812 749
813 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( 750 SelectionModel RenderTextWin::FirstSelectionModelInsideRun(
814 internal::TextRun* run) { 751 internal::TextRun* run) {
815 size_t caret = run->range.start(); 752 size_t cursor = IndexOfAdjacentGrapheme(run->range.start(), CURSOR_FORWARD);
816 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); 753 return SelectionModel(cursor, CURSOR_BACKWARD);
817 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
818 } 754 }
819 755
820 SelectionModel RenderTextWin::LastSelectionModelInsideRun( 756 SelectionModel RenderTextWin::LastSelectionModelInsideRun(
821 internal::TextRun* run) { 757 internal::TextRun* run) {
822 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); 758 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD);
823 return SelectionModel(caret, caret, SelectionModel::LEADING); 759 return SelectionModel(caret, CURSOR_FORWARD);
824 } 760 }
825 761
826 RenderText* RenderText::CreateRenderText() { 762 RenderText* RenderText::CreateRenderText() {
827 return new RenderTextWin; 763 return new RenderTextWin;
828 } 764 }
829 765
830 } // namespace gfx 766 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698