| 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_win.h" | 5 #include "ui/gfx/render_text_win.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 TextRun::~TextRun() { | 138 TextRun::~TextRun() { |
| 139 ScriptFreeCache(&script_cache); | 139 ScriptFreeCache(&script_cache); |
| 140 } | 140 } |
| 141 | 141 |
| 142 } // namespace internal | 142 } // namespace internal |
| 143 | 143 |
| 144 RenderTextWin::RenderTextWin() | 144 RenderTextWin::RenderTextWin() |
| 145 : RenderText(), | 145 : RenderText(), |
| 146 script_control_(), | 146 script_control_(), |
| 147 script_state_(), | 147 script_state_(), |
| 148 string_width_(0) { | 148 string_width_(0), |
| 149 needs_layout_(false) { |
| 149 // Omitting default constructors for script_* would leave POD uninitialized. | 150 // Omitting default constructors for script_* would leave POD uninitialized. |
| 150 HRESULT hr = 0; | 151 HRESULT hr = 0; |
| 151 | 152 |
| 152 // TODO(msw): Call ScriptRecordDigitSubstitution on WM_SETTINGCHANGE message. | 153 // TODO(msw): Call ScriptRecordDigitSubstitution on WM_SETTINGCHANGE message. |
| 153 // TODO(msw): Use Chrome/profile locale/language settings? | 154 // TODO(msw): Use Chrome/profile locale/language settings? |
| 154 hr = ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &digit_substitute_); | 155 hr = ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &digit_substitute_); |
| 155 DCHECK(SUCCEEDED(hr)); | 156 DCHECK(SUCCEEDED(hr)); |
| 156 | 157 |
| 157 hr = ScriptApplyDigitSubstitution(&digit_substitute_, | 158 hr = ScriptApplyDigitSubstitution(&digit_substitute_, |
| 158 &script_control_, | 159 &script_control_, |
| 159 &script_state_); | 160 &script_state_); |
| 160 DCHECK(SUCCEEDED(hr)); | 161 DCHECK(SUCCEEDED(hr)); |
| 161 script_control_.fMergeNeutralItems = true; | 162 script_control_.fMergeNeutralItems = true; |
| 162 | 163 |
| 163 MoveCursorTo(LeftEndSelectionModel()); | 164 MoveCursorTo(LeftEndSelectionModel()); |
| 164 } | 165 } |
| 165 | 166 |
| 166 RenderTextWin::~RenderTextWin() { | 167 RenderTextWin::~RenderTextWin() { |
| 167 STLDeleteContainerPointers(runs_.begin(), runs_.end()); | 168 STLDeleteContainerPointers(runs_.begin(), runs_.end()); |
| 168 } | 169 } |
| 169 | 170 |
| 170 int RenderTextWin::GetStringWidth() { | 171 int RenderTextWin::GetStringWidth() { |
| 172 EnsureLayout(); |
| 171 return string_width_; | 173 return string_width_; |
| 172 } | 174 } |
| 173 | 175 |
| 174 void RenderTextWin::Draw(Canvas* canvas) { | 176 void RenderTextWin::Draw(Canvas* canvas) { |
| 177 EnsureLayout(); |
| 175 DrawSelection(canvas); | 178 DrawSelection(canvas); |
| 176 DrawVisualText(canvas); | 179 DrawVisualText(canvas); |
| 177 DrawCursor(canvas); | 180 DrawCursor(canvas); |
| 178 } | 181 } |
| 179 | 182 |
| 180 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { | 183 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { |
| 181 if (text().empty()) | 184 if (text().empty()) |
| 182 return SelectionModel(); | 185 return SelectionModel(); |
| 183 | 186 |
| 187 EnsureLayout(); |
| 184 // Find the run that contains the point and adjust the argument location. | 188 // Find the run that contains the point and adjust the argument location. |
| 185 Point p(ToTextPoint(point)); | 189 Point p(ToTextPoint(point)); |
| 186 size_t run_index = GetRunContainingPoint(p); | 190 size_t run_index = GetRunContainingPoint(p); |
| 187 if (run_index == runs_.size()) | 191 if (run_index == runs_.size()) |
| 188 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); | 192 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); |
| 189 internal::TextRun* run = runs_[run_index]; | 193 internal::TextRun* run = runs_[run_index]; |
| 190 | 194 |
| 191 int position = 0, trailing = 0; | 195 int position = 0, trailing = 0; |
| 192 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths, | 196 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths, |
| 193 run->range.length(), | 197 run->range.length(), |
| 194 run->glyph_count, | 198 run->glyph_count, |
| 195 run->logical_clusters.get(), | 199 run->logical_clusters.get(), |
| 196 run->visible_attributes.get(), | 200 run->visible_attributes.get(), |
| 197 run->advance_widths.get(), | 201 run->advance_widths.get(), |
| 198 &(run->script_analysis), | 202 &(run->script_analysis), |
| 199 &position, | 203 &position, |
| 200 &trailing); | 204 &trailing); |
| 201 DCHECK(SUCCEEDED(hr)); | 205 DCHECK(SUCCEEDED(hr)); |
| 202 position += run->range.start(); | 206 position += run->range.start(); |
| 203 | 207 |
| 204 size_t cursor = position + trailing; | 208 size_t cursor = position + trailing; |
| 205 DCHECK_GE(cursor, 0U); | 209 DCHECK_GE(cursor, 0U); |
| 206 DCHECK_LE(cursor, text().length()); | 210 DCHECK_LE(cursor, text().length()); |
| 207 return SelectionModel(cursor, position, | 211 return SelectionModel(cursor, position, |
| 208 (trailing > 0) ? SelectionModel::TRAILING : SelectionModel::LEADING); | 212 (trailing > 0) ? SelectionModel::TRAILING : SelectionModel::LEADING); |
| 209 } | 213 } |
| 210 | 214 |
| 211 Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection, | 215 Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection, |
| 212 bool insert_mode) { | 216 bool insert_mode) { |
| 217 EnsureLayout(); |
| 218 |
| 213 // Highlight the logical cursor (selection end) when not in insert mode. | 219 // Highlight the logical cursor (selection end) when not in insert mode. |
| 214 size_t pos = insert_mode ? selection.caret_pos() : selection.selection_end(); | 220 size_t pos = insert_mode ? selection.caret_pos() : selection.selection_end(); |
| 215 size_t run_index = GetRunContainingPosition(pos); | 221 size_t run_index = GetRunContainingPosition(pos); |
| 216 internal::TextRun* run = run_index == runs_.size() ? NULL : runs_[run_index]; | 222 internal::TextRun* run = run_index == runs_.size() ? NULL : runs_[run_index]; |
| 217 | 223 |
| 218 int start_x = 0, end_x = 0; | 224 int start_x = 0, end_x = 0; |
| 219 if (run) { | 225 if (run) { |
| 220 HRESULT hr = 0; | 226 HRESULT hr = 0; |
| 221 hr = ScriptCPtoX(pos - run->range.start(), | 227 hr = ScriptCPtoX(pos - run->range.start(), |
| 222 false, | 228 false, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 rect.set_x(rect.right()); | 261 rect.set_x(rect.right()); |
| 256 rect.set_width(0); | 262 rect.set_width(0); |
| 257 } | 263 } |
| 258 rect.set_origin(ToViewPoint(rect.origin())); | 264 rect.set_origin(ToViewPoint(rect.origin())); |
| 259 return rect; | 265 return rect; |
| 260 } | 266 } |
| 261 | 267 |
| 262 SelectionModel RenderTextWin::GetLeftSelectionModel( | 268 SelectionModel RenderTextWin::GetLeftSelectionModel( |
| 263 const SelectionModel& selection, | 269 const SelectionModel& selection, |
| 264 BreakType break_type) { | 270 BreakType break_type) { |
| 271 EnsureLayout(); |
| 272 |
| 265 if (break_type == LINE_BREAK || text().empty()) | 273 if (break_type == LINE_BREAK || text().empty()) |
| 266 return LeftEndSelectionModel(); | 274 return LeftEndSelectionModel(); |
| 267 if (break_type == CHARACTER_BREAK) | 275 if (break_type == CHARACTER_BREAK) |
| 268 return LeftSelectionModel(selection); | 276 return LeftSelectionModel(selection); |
| 269 // TODO(msw): Implement word breaking. | 277 // TODO(msw): Implement word breaking. |
| 270 return RenderText::GetLeftSelectionModel(selection, break_type); | 278 return RenderText::GetLeftSelectionModel(selection, break_type); |
| 271 } | 279 } |
| 272 | 280 |
| 273 SelectionModel RenderTextWin::GetRightSelectionModel( | 281 SelectionModel RenderTextWin::GetRightSelectionModel( |
| 274 const SelectionModel& selection, | 282 const SelectionModel& selection, |
| 275 BreakType break_type) { | 283 BreakType break_type) { |
| 284 EnsureLayout(); |
| 285 |
| 276 if (break_type == LINE_BREAK || text().empty()) | 286 if (break_type == LINE_BREAK || text().empty()) |
| 277 return RightEndSelectionModel(); | 287 return RightEndSelectionModel(); |
| 278 if (break_type == CHARACTER_BREAK) | 288 if (break_type == CHARACTER_BREAK) |
| 279 return RightSelectionModel(selection); | 289 return RightSelectionModel(selection); |
| 280 // TODO(msw): Implement word breaking. | 290 // TODO(msw): Implement word breaking. |
| 281 return RenderText::GetRightSelectionModel(selection, break_type); | 291 return RenderText::GetRightSelectionModel(selection, break_type); |
| 282 } | 292 } |
| 283 | 293 |
| 284 SelectionModel RenderTextWin::LeftEndSelectionModel() { | 294 SelectionModel RenderTextWin::LeftEndSelectionModel() { |
| 285 if (text().empty()) | 295 if (text().empty()) |
| 286 return SelectionModel(0, 0, SelectionModel::LEADING); | 296 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 297 |
| 298 EnsureLayout(); |
| 287 size_t cursor = base::i18n::IsRTL() ? text().length() : 0; | 299 size_t cursor = base::i18n::IsRTL() ? text().length() : 0; |
| 288 internal::TextRun* run = runs_[visual_to_logical_[0]]; | 300 internal::TextRun* run = runs_[visual_to_logical_[0]]; |
| 289 bool rtl = run->script_analysis.fRTL; | 301 bool rtl = run->script_analysis.fRTL; |
| 290 size_t caret = rtl ? run->range.end() - 1 : run->range.start(); | 302 size_t caret = rtl ? run->range.end() - 1 : run->range.start(); |
| 291 SelectionModel::CaretPlacement placement = | 303 SelectionModel::CaretPlacement placement = |
| 292 rtl ? SelectionModel::TRAILING : SelectionModel::LEADING; | 304 rtl ? SelectionModel::TRAILING : SelectionModel::LEADING; |
| 293 return SelectionModel(cursor, caret, placement); | 305 return SelectionModel(cursor, caret, placement); |
| 294 } | 306 } |
| 295 | 307 |
| 296 SelectionModel RenderTextWin::RightEndSelectionModel() { | 308 SelectionModel RenderTextWin::RightEndSelectionModel() { |
| 297 if (text().empty()) | 309 if (text().empty()) |
| 298 return SelectionModel(0, 0, SelectionModel::LEADING); | 310 return SelectionModel(0, 0, SelectionModel::LEADING); |
| 311 |
| 312 EnsureLayout(); |
| 299 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); | 313 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); |
| 300 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; | 314 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; |
| 301 bool rtl = run->script_analysis.fRTL; | 315 bool rtl = run->script_analysis.fRTL; |
| 302 size_t caret = rtl ? run->range.start() : run->range.end() - 1; | 316 size_t caret = rtl ? run->range.start() : run->range.end() - 1; |
| 303 SelectionModel::CaretPlacement placement = | 317 SelectionModel::CaretPlacement placement = |
| 304 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; | 318 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; |
| 305 return SelectionModel(cursor, caret, placement); | 319 return SelectionModel(cursor, caret, placement); |
| 306 } | 320 } |
| 307 | 321 |
| 308 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { | 322 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { |
| 323 DCHECK(!needs_layout_); |
| 309 ui::Range range(from, to); | 324 ui::Range range(from, to); |
| 310 DCHECK(ui::Range(0, text().length()).Contains(range)); | 325 DCHECK(ui::Range(0, text().length()).Contains(range)); |
| 311 Point display_offset(GetUpdatedDisplayOffset()); | 326 Point display_offset(GetUpdatedDisplayOffset()); |
| 312 std::vector<Rect> bounds; | 327 std::vector<Rect> bounds; |
| 313 HRESULT hr = 0; | 328 HRESULT hr = 0; |
| 314 | 329 |
| 315 // Add a Rect for each run/selection intersection. | 330 // Add a Rect for each run/selection intersection. |
| 316 // TODO(msw): The bounds should probably not always be leading the range ends. | 331 // TODO(msw): The bounds should probably not always be leading the range ends. |
| 317 for (size_t i = 0; i < runs_.size(); ++i) { | 332 for (size_t i = 0; i < runs_.size(); ++i) { |
| 318 internal::TextRun* run = runs_[visual_to_logical_[i]]; | 333 internal::TextRun* run = runs_[visual_to_logical_[i]]; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 bounds.push_back(rect); | 371 bounds.push_back(rect); |
| 357 } | 372 } |
| 358 } | 373 } |
| 359 return bounds; | 374 return bounds; |
| 360 } | 375 } |
| 361 | 376 |
| 362 bool RenderTextWin::IsCursorablePosition(size_t position) { | 377 bool RenderTextWin::IsCursorablePosition(size_t position) { |
| 363 if (position == 0 || position == text().length()) | 378 if (position == 0 || position == text().length()) |
| 364 return true; | 379 return true; |
| 365 | 380 |
| 381 EnsureLayout(); |
| 366 size_t run_index = GetRunContainingPosition(position); | 382 size_t run_index = GetRunContainingPosition(position); |
| 367 if (run_index >= runs_.size()) | 383 if (run_index >= runs_.size()) |
| 368 return false; | 384 return false; |
| 369 | 385 |
| 370 internal::TextRun* run = runs_[run_index]; | 386 internal::TextRun* run = runs_[run_index]; |
| 371 size_t start = run->range.start(); | 387 size_t start = run->range.start(); |
| 372 if (position == start) | 388 if (position == start) |
| 373 return true; | 389 return true; |
| 374 return run->logical_clusters[position - start] != | 390 return run->logical_clusters[position - start] != |
| 375 run->logical_clusters[position - start - 1]; | 391 run->logical_clusters[position - start - 1]; |
| 376 } | 392 } |
| 377 | 393 |
| 378 void RenderTextWin::UpdateLayout() { | 394 void RenderTextWin::UpdateLayout() { |
| 379 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. | 395 // Layout is performed lazily as needed for drawing/metrics. |
| 380 ItemizeLogicalText(); | 396 needs_layout_ = true; |
| 381 if (!runs_.empty()) | |
| 382 LayoutVisualText(); | |
| 383 } | 397 } |
| 384 | 398 |
| 385 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { | 399 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { |
| 400 EnsureLayout(); |
| 386 size_t run_index = GetRunContainingPosition(index); | 401 size_t run_index = GetRunContainingPosition(index); |
| 387 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; | 402 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; |
| 388 int start = run ? run->range.start() : 0; | 403 int start = run ? run->range.start() : 0; |
| 389 int length = run ? run->range.length() : text().length(); | 404 int length = run ? run->range.length() : text().length(); |
| 390 int ch = index - start; | 405 int ch = index - start; |
| 391 WORD cluster = run ? run->logical_clusters[ch] : 0; | 406 WORD cluster = run ? run->logical_clusters[ch] : 0; |
| 392 | 407 |
| 393 if (!next) { | 408 if (!next) { |
| 394 do { | 409 do { |
| 395 ch--; | 410 ch--; |
| 396 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster); | 411 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster); |
| 397 } else { | 412 } else { |
| 398 while (ch < length && run && run->logical_clusters[ch] == cluster) | 413 while (ch < length && run && run->logical_clusters[ch] == cluster) |
| 399 ch++; | 414 ch++; |
| 400 } | 415 } |
| 401 return std::max(std::min(ch, length) + start, 0); | 416 return std::max(std::min(ch, length) + start, 0); |
| 402 } | 417 } |
| 403 | 418 |
| 419 void RenderTextWin::EnsureLayout() { |
| 420 if (!needs_layout_) |
| 421 return; |
| 422 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. |
| 423 ItemizeLogicalText(); |
| 424 if (!runs_.empty()) |
| 425 LayoutVisualText(); |
| 426 needs_layout_ = false; |
| 427 } |
| 428 |
| 404 void RenderTextWin::ItemizeLogicalText() { | 429 void RenderTextWin::ItemizeLogicalText() { |
| 405 STLDeleteContainerPointers(runs_.begin(), runs_.end()); | 430 STLDeleteContainerPointers(runs_.begin(), runs_.end()); |
| 406 runs_.clear(); | 431 runs_.clear(); |
| 432 string_width_ = 0; |
| 407 if (text().empty()) | 433 if (text().empty()) |
| 408 return; | 434 return; |
| 409 | 435 |
| 410 const wchar_t* raw_text = text().c_str(); | 436 const wchar_t* raw_text = text().c_str(); |
| 411 const int text_length = text().length(); | 437 const int text_length = text().length(); |
| 412 | 438 |
| 413 HRESULT hr = E_OUTOFMEMORY; | 439 HRESULT hr = E_OUTOFMEMORY; |
| 414 int script_items_count = 0; | 440 int script_items_count = 0; |
| 415 std::vector<SCRIPT_ITEM> script_items; | 441 std::vector<SCRIPT_ITEM> script_items; |
| 416 for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) { | 442 for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 internal::TextRun* run = runs_[visual_to_logical_[i]]; | 575 internal::TextRun* run = runs_[visual_to_logical_[i]]; |
| 550 run->preceding_run_widths = preceding_run_widths; | 576 run->preceding_run_widths = preceding_run_widths; |
| 551 const ABC& abc = run->abc_widths; | 577 const ABC& abc = run->abc_widths; |
| 552 run->width = abc.abcA + abc.abcB + abc.abcC; | 578 run->width = abc.abcA + abc.abcB + abc.abcC; |
| 553 preceding_run_widths += run->width; | 579 preceding_run_widths += run->width; |
| 554 } | 580 } |
| 555 string_width_ = preceding_run_widths; | 581 string_width_ = preceding_run_widths; |
| 556 } | 582 } |
| 557 | 583 |
| 558 size_t RenderTextWin::GetRunContainingPosition(size_t position) const { | 584 size_t RenderTextWin::GetRunContainingPosition(size_t position) const { |
| 585 DCHECK(!needs_layout_); |
| 559 // Find the text run containing the argument position. | 586 // Find the text run containing the argument position. |
| 560 size_t run = 0; | 587 size_t run = 0; |
| 561 for (; run < runs_.size(); ++run) | 588 for (; run < runs_.size(); ++run) |
| 562 if (runs_[run]->range.start() <= position && | 589 if (runs_[run]->range.start() <= position && |
| 563 runs_[run]->range.end() > position) | 590 runs_[run]->range.end() > position) |
| 564 break; | 591 break; |
| 565 return run; | 592 return run; |
| 566 } | 593 } |
| 567 | 594 |
| 568 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const { | 595 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const { |
| 596 DCHECK(!needs_layout_); |
| 569 // Find the text run containing the argument point (assumed already offset). | 597 // Find the text run containing the argument point (assumed already offset). |
| 570 size_t run = 0; | 598 size_t run = 0; |
| 571 for (; run < runs_.size(); ++run) | 599 for (; run < runs_.size(); ++run) |
| 572 if (runs_[run]->preceding_run_widths <= point.x() && | 600 if (runs_[run]->preceding_run_widths <= point.x() && |
| 573 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) | 601 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) |
| 574 break; | 602 break; |
| 575 return run; | 603 return run; |
| 576 } | 604 } |
| 577 | 605 |
| 578 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( | 606 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( |
| 579 internal::TextRun* run) { | 607 internal::TextRun* run) { |
| 580 size_t caret = run->range.start(); | 608 size_t caret = run->range.start(); |
| 581 size_t cursor = IndexOfAdjacentGrapheme(caret, true); | 609 size_t cursor = IndexOfAdjacentGrapheme(caret, true); |
| 582 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 610 return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
| 583 } | 611 } |
| 584 | 612 |
| 585 SelectionModel RenderTextWin::LastSelectionModelInsideRun( | 613 SelectionModel RenderTextWin::LastSelectionModelInsideRun( |
| 586 internal::TextRun* run) { | 614 internal::TextRun* run) { |
| 587 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), false); | 615 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), false); |
| 588 return SelectionModel(caret, caret, SelectionModel::LEADING); | 616 return SelectionModel(caret, caret, SelectionModel::LEADING); |
| 589 } | 617 } |
| 590 | 618 |
| 591 SelectionModel RenderTextWin::LeftSelectionModel( | 619 SelectionModel RenderTextWin::LeftSelectionModel( |
| 592 const SelectionModel& selection) { | 620 const SelectionModel& selection) { |
| 621 DCHECK(!needs_layout_); |
| 593 size_t caret = selection.caret_pos(); | 622 size_t caret = selection.caret_pos(); |
| 594 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); | 623 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); |
| 595 size_t run_index = GetRunContainingPosition(caret); | 624 size_t run_index = GetRunContainingPosition(caret); |
| 596 DCHECK(run_index < runs_.size()); | 625 DCHECK(run_index < runs_.size()); |
| 597 internal::TextRun* run = runs_[run_index]; | 626 internal::TextRun* run = runs_[run_index]; |
| 598 | 627 |
| 599 // If the caret's associated character is in a LTR run. | 628 // If the caret's associated character is in a LTR run. |
| 600 if (!run->script_analysis.fRTL) { | 629 if (!run->script_analysis.fRTL) { |
| 601 if (caret_placement == SelectionModel::TRAILING) | 630 if (caret_placement == SelectionModel::TRAILING) |
| 602 return SelectionModel(caret, caret, SelectionModel::LEADING); | 631 return SelectionModel(caret, caret, SelectionModel::LEADING); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 619 size_t visual_index = logical_to_visual_[run_index]; | 648 size_t visual_index = logical_to_visual_[run_index]; |
| 620 if (visual_index == 0) | 649 if (visual_index == 0) |
| 621 return LeftEndSelectionModel(); | 650 return LeftEndSelectionModel(); |
| 622 internal::TextRun* prev = runs_[visual_to_logical_[visual_index - 1]]; | 651 internal::TextRun* prev = runs_[visual_to_logical_[visual_index - 1]]; |
| 623 return prev->script_analysis.fRTL ? FirstSelectionModelInsideRun(prev) : | 652 return prev->script_analysis.fRTL ? FirstSelectionModelInsideRun(prev) : |
| 624 LastSelectionModelInsideRun(prev); | 653 LastSelectionModelInsideRun(prev); |
| 625 } | 654 } |
| 626 | 655 |
| 627 SelectionModel RenderTextWin::RightSelectionModel( | 656 SelectionModel RenderTextWin::RightSelectionModel( |
| 628 const SelectionModel& selection) { | 657 const SelectionModel& selection) { |
| 658 DCHECK(!needs_layout_); |
| 629 size_t caret = selection.caret_pos(); | 659 size_t caret = selection.caret_pos(); |
| 630 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); | 660 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); |
| 631 size_t run_index = GetRunContainingPosition(caret); | 661 size_t run_index = GetRunContainingPosition(caret); |
| 632 DCHECK(run_index < runs_.size()); | 662 DCHECK(run_index < runs_.size()); |
| 633 internal::TextRun* run = runs_[run_index]; | 663 internal::TextRun* run = runs_[run_index]; |
| 634 | 664 |
| 635 // If the caret's associated character is in a LTR run. | 665 // If the caret's associated character is in a LTR run. |
| 636 if (!run->script_analysis.fRTL) { | 666 if (!run->script_analysis.fRTL) { |
| 637 if (caret_placement == SelectionModel::LEADING) { | 667 if (caret_placement == SelectionModel::LEADING) { |
| 638 size_t cursor = IndexOfAdjacentGrapheme(caret, true); | 668 size_t cursor = IndexOfAdjacentGrapheme(caret, true); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 Rect r(GetUpdatedCursorBounds()); | 764 Rect r(GetUpdatedCursorBounds()); |
| 735 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); | 765 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); |
| 736 } | 766 } |
| 737 } | 767 } |
| 738 | 768 |
| 739 RenderText* RenderText::CreateRenderText() { | 769 RenderText* RenderText::CreateRenderText() { |
| 740 return new RenderTextWin; | 770 return new RenderTextWin; |
| 741 } | 771 } |
| 742 | 772 |
| 743 } // namespace gfx | 773 } // namespace gfx |
| OLD | NEW |