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

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

Issue 8819001: Revert 113075 (requested by asvitkine) (requested by asvitkine) (requested by asvitkine) (request... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years 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) 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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 return RenderText::GetRightSelectionModel(selection, break_type); 284 return RenderText::GetRightSelectionModel(selection, break_type);
285 } 285 }
286 286
287 SelectionModel RenderTextWin::LeftEndSelectionModel() { 287 SelectionModel RenderTextWin::LeftEndSelectionModel() {
288 if (text().empty()) 288 if (text().empty())
289 return SelectionModel(0, 0, SelectionModel::LEADING); 289 return SelectionModel(0, 0, SelectionModel::LEADING);
290 290
291 EnsureLayout(); 291 EnsureLayout();
292 size_t cursor = base::i18n::IsRTL() ? text().length() : 0; 292 size_t cursor = base::i18n::IsRTL() ? text().length() : 0;
293 internal::TextRun* run = runs_[visual_to_logical_[0]]; 293 internal::TextRun* run = runs_[visual_to_logical_[0]];
294 size_t caret; 294 bool rtl = run->script_analysis.fRTL;
295 SelectionModel::CaretPlacement placement; 295 size_t caret = rtl ? run->range.end() - 1 : run->range.start();
296 if (run->script_analysis.fRTL) { 296 SelectionModel::CaretPlacement placement =
297 caret = IndexOfAdjacentGrapheme(run->range.end(), false); 297 rtl ? SelectionModel::TRAILING : SelectionModel::LEADING;
298 placement = SelectionModel::TRAILING;
299 } else {
300 caret = run->range.start();
301 placement = SelectionModel::LEADING;
302 }
303 return SelectionModel(cursor, caret, placement); 298 return SelectionModel(cursor, caret, placement);
304 } 299 }
305 300
306 SelectionModel RenderTextWin::RightEndSelectionModel() { 301 SelectionModel RenderTextWin::RightEndSelectionModel() {
307 if (text().empty()) 302 if (text().empty())
308 return SelectionModel(0, 0, SelectionModel::LEADING); 303 return SelectionModel(0, 0, SelectionModel::LEADING);
309 304
310 EnsureLayout(); 305 EnsureLayout();
311 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); 306 size_t cursor = base::i18n::IsRTL() ? 0 : text().length();
312 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; 307 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]];
313 size_t caret; 308 bool rtl = run->script_analysis.fRTL;
314 SelectionModel::CaretPlacement placement; 309 size_t caret = rtl ? run->range.start() : run->range.end() - 1;
315 if (run->script_analysis.fRTL) { 310 SelectionModel::CaretPlacement placement =
316 caret = run->range.start(); 311 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING;
317 placement = SelectionModel::LEADING;
318 } else {
319 caret = IndexOfAdjacentGrapheme(run->range.end(), false);
320 placement = SelectionModel::TRAILING;
321 }
322 return SelectionModel(cursor, caret, placement); 312 return SelectionModel(cursor, caret, placement);
323 } 313 }
324 314
325 void RenderTextWin::GetSubstringBounds(size_t from, 315 void RenderTextWin::GetSubstringBounds(size_t from,
326 size_t to, 316 size_t to,
327 std::vector<Rect>* bounds) { 317 std::vector<Rect>* bounds) {
328 DCHECK(!needs_layout_); 318 DCHECK(!needs_layout_);
329 ui::Range range(from, to); 319 ui::Range range(from, to);
330 DCHECK(ui::Range(0, text().length()).Contains(range)); 320 DCHECK(ui::Range(0, text().length()).Contains(range));
331 Point display_offset(GetUpdatedDisplayOffset()); 321 Point display_offset(GetUpdatedDisplayOffset());
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 size_t byte_length = run->glyph_count * sizeof(WORD); 454 size_t byte_length = run->glyph_count * sizeof(WORD);
465 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint); 455 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
466 456
467 if (run->strike || run->underline) 457 if (run->strike || run->underline)
468 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y); 458 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
469 } 459 }
470 } 460 }
471 461
472 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 462 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
473 EnsureLayout(); 463 EnsureLayout();
474
475 if (text().empty())
476 return 0;
477
478 if (index >= text().length()) {
479 if (next || index > text().length()) {
480 return text().length();
481 } else {
482 // The requested |index| is at the end of the text. Use the index of the
483 // last character to find the grapheme.
484 index = text().length() - 1;
485 if (IsCursorablePosition(index))
486 return index;
487 }
488 }
489
490 size_t run_index = GetRunContainingPosition(index); 464 size_t run_index = GetRunContainingPosition(index);
491 DCHECK(run_index < runs_.size()); 465 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL;
492 internal::TextRun* run = runs_[run_index]; 466 int start = run ? run->range.start() : 0;
493 size_t start = run->range.start(); 467 int length = run ? run->range.length() : text().length();
494 size_t ch = index - start; 468 int ch = index - start;
469 WORD cluster = run ? run->logical_clusters[ch] : 0;
495 470
496 if (!next) { 471 if (!next) {
497 // If |ch| is the start of the run, use the preceding run, if any.
498 if (ch == 0) {
499 if (run_index == 0)
500 return 0;
501 run = runs_[run_index - 1];
502 start = run->range.start();
503 ch = run->range.length();
504 }
505
506 // Loop to find the start of the grapheme.
507 WORD cluster = run->logical_clusters[ch - 1];
508 do { 472 do {
509 ch--; 473 ch--;
510 } while (ch > 0 && run->logical_clusters[ch - 1] == cluster); 474 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster);
511 } else { 475 } else {
512 WORD cluster = run->logical_clusters[ch]; 476 while (ch < length && run && run->logical_clusters[ch] == cluster)
513 while (ch < run->range.length() && run->logical_clusters[ch] == cluster)
514 ch++; 477 ch++;
515 } 478 }
516 479 return std::max(std::min(ch, length) + start, 0);
517 return start + ch;
518 } 480 }
519 481
520 void RenderTextWin::ItemizeLogicalText() { 482 void RenderTextWin::ItemizeLogicalText() {
521 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 483 STLDeleteContainerPointers(runs_.begin(), runs_.end());
522 runs_.clear(); 484 runs_.clear();
523 string_width_ = 0; 485 string_width_ = 0;
524 if (text().empty()) 486 if (text().empty())
525 return; 487 return;
526 488
527 const wchar_t* raw_text = text().c_str(); 489 const wchar_t* raw_text = text().c_str();
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 } 538 }
577 539
578 void RenderTextWin::LayoutVisualText() { 540 void RenderTextWin::LayoutVisualText() {
579 HRESULT hr = E_FAIL; 541 HRESULT hr = E_FAIL;
580 base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL)); 542 base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL));
581 std::vector<internal::TextRun*>::const_iterator run_iter; 543 std::vector<internal::TextRun*>::const_iterator run_iter;
582 for (run_iter = runs_.begin(); run_iter < runs_.end(); ++run_iter) { 544 for (run_iter = runs_.begin(); run_iter < runs_.end(); ++run_iter) {
583 internal::TextRun* run = *run_iter; 545 internal::TextRun* run = *run_iter;
584 size_t run_length = run->range.length(); 546 size_t run_length = run->range.length();
585 const wchar_t* run_text = &(text()[run->range.start()]); 547 const wchar_t* run_text = &(text()[run->range.start()]);
586 bool tried_fallback = false;
587 548
588 // Select the font desired for glyph generation. 549 // Select the font desired for glyph generation.
589 SelectObject(hdc, run->font.GetNativeFont()); 550 SelectObject(hdc, run->font.GetNativeFont());
590 551
591 run->logical_clusters.reset(new WORD[run_length]); 552 run->logical_clusters.reset(new WORD[run_length]);
592 run->glyph_count = 0; 553 run->glyph_count = 0;
593 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx 554 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx
594 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); 555 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
595 while (max_glyphs < kMaxGlyphs) { 556 while (max_glyphs < kMaxGlyphs) {
596 run->glyphs.reset(new WORD[max_glyphs]); 557 run->glyphs.reset(new WORD[max_glyphs]);
597 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); 558 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
598 hr = ScriptShape(hdc, 559 hr = ScriptShape(hdc,
599 &run->script_cache, 560 &run->script_cache,
600 run_text, 561 run_text,
601 run_length, 562 run_length,
602 max_glyphs, 563 max_glyphs,
603 &(run->script_analysis), 564 &(run->script_analysis),
604 run->glyphs.get(), 565 run->glyphs.get(),
605 run->logical_clusters.get(), 566 run->logical_clusters.get(),
606 run->visible_attributes.get(), 567 run->visible_attributes.get(),
607 &(run->glyph_count)); 568 &(run->glyph_count));
608 if (hr == E_OUTOFMEMORY) { 569 if (hr == E_OUTOFMEMORY) {
609 max_glyphs *= 2; 570 max_glyphs *= 2;
610 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { 571 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
611 // Only try font fallback if it hasn't yet been attempted for this run. 572 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can crash
612 if (tried_fallback) { 573 // on certain surrogate pairs with SCRIPT_UNDEFINED.
613 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can 574 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
614 // crash on certain surrogate pairs with SCRIPT_UNDEFINED. 575 // And http://maxradi.us/documents/uniscribe/
615 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 576 if (run->script_analysis.eScript == SCRIPT_UNDEFINED)
616 // And http://maxradi.us/documents/uniscribe/ 577 break;
617 run->script_analysis.eScript = SCRIPT_UNDEFINED;
618 // Reset |hr| to 0 to not trigger the DCHECK() below when a font is
619 // not found that can display the text. This is expected behavior
620 // under Windows XP without additional language packs installed and
621 // may also happen on newer versions when trying to display text in
622 // an obscure script that the system doesn't have the right font for.
623 hr = 0;
624 break;
625 }
626 578
627 // The run's font doesn't contain the required glyphs, use an alternate. 579 // The run's font doesn't contain the required glyphs, use an alternate.
628 if (ChooseFallbackFont(hdc, run->font, run_text, run_length, 580 if (ChooseFallbackFont(hdc, run->font, run_text, run_length,
629 &run->font)) { 581 &run->font)) {
630 ScriptFreeCache(&run->script_cache); 582 ScriptFreeCache(&run->script_cache);
631 SelectObject(hdc, run->font.GetNativeFont()); 583 SelectObject(hdc, run->font.GetNativeFont());
632 } 584 }
633 585
634 tried_fallback = true; 586 run->script_analysis.eScript = SCRIPT_UNDEFINED;
635 } else { 587 } else {
636 break; 588 break;
637 } 589 }
638 } 590 }
639 DCHECK(SUCCEEDED(hr)); 591 DCHECK(SUCCEEDED(hr));
640 592
641 if (run->glyph_count > 0) { 593 if (run->glyph_count > 0) {
642 run->advance_widths.reset(new int[run->glyph_count]); 594 run->advance_widths.reset(new int[run->glyph_count]);
643 run->offsets.reset(new GOFFSET[run->glyph_count]); 595 run->offsets.reset(new GOFFSET[run->glyph_count]);
644 hr = ScriptPlace(hdc, 596 hr = ScriptPlace(hdc,
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; 741 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]];
790 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : 742 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) :
791 FirstSelectionModelInsideRun(next); 743 FirstSelectionModelInsideRun(next);
792 } 744 }
793 745
794 RenderText* RenderText::CreateRenderText() { 746 RenderText* RenderText::CreateRenderText() {
795 return new RenderTextWin; 747 return new RenderTextWin;
796 } 748 }
797 749
798 } // namespace gfx 750 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_unittest.cc ('k') | ui/views/controls/textfield/textfield_views_model_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698