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

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

Issue 8575020: Improve RenderTextWin font fallback. (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 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 return SelectionModel(cursor, caret, placement); 298 return SelectionModel(cursor, caret, placement);
299 } 299 }
300 300
301 SelectionModel RenderTextWin::RightEndSelectionModel() { 301 SelectionModel RenderTextWin::RightEndSelectionModel() {
302 if (text().empty()) 302 if (text().empty())
303 return SelectionModel(0, 0, SelectionModel::LEADING); 303 return SelectionModel(0, 0, SelectionModel::LEADING);
304 304
305 EnsureLayout(); 305 EnsureLayout();
306 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); 306 size_t cursor = base::i18n::IsRTL() ? 0 : text().length();
307 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; 307 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]];
308 bool rtl = run->script_analysis.fRTL; 308 size_t caret;
309 size_t caret = rtl ? run->range.start() : run->range.end() - 1; 309 SelectionModel::CaretPlacement placement;
310 SelectionModel::CaretPlacement placement = 310 if (run->script_analysis.fRTL) {
311 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; 311 caret = run->range.start();
312 placement = SelectionModel::LEADING;
313 } else {
314 caret = IndexOfAdjacentGrapheme(run->range.end(), false);
315 placement = SelectionModel::TRAILING;
316 }
312 return SelectionModel(cursor, caret, placement); 317 return SelectionModel(cursor, caret, placement);
313 } 318 }
314 319
315 void RenderTextWin::GetSubstringBounds(size_t from, 320 void RenderTextWin::GetSubstringBounds(size_t from,
316 size_t to, 321 size_t to,
317 std::vector<Rect>* bounds) { 322 std::vector<Rect>* bounds) {
318 DCHECK(!needs_layout_); 323 DCHECK(!needs_layout_);
319 ui::Range range(from, to); 324 ui::Range range(from, to);
320 DCHECK(ui::Range(0, text().length()).Contains(range)); 325 DCHECK(ui::Range(0, text().length()).Contains(range));
321 Point display_offset(GetUpdatedDisplayOffset()); 326 Point display_offset(GetUpdatedDisplayOffset());
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 size_t byte_length = run->glyph_count * sizeof(WORD); 459 size_t byte_length = run->glyph_count * sizeof(WORD);
455 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint); 460 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
456 461
457 if (run->strike || run->underline) 462 if (run->strike || run->underline)
458 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y); 463 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
459 } 464 }
460 } 465 }
461 466
462 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 467 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
463 EnsureLayout(); 468 EnsureLayout();
469
470 if (text().empty())
471 return 0;
472
473 if (index >= text().length()) {
474 if (next) {
475 return text().length();
476 } else {
477 size_t last = text().length() - 1;
478 index = IndexOfAdjacentGrapheme(last, false);
xji 2011/12/01 08:31:58 is the reason of this special handling that: run_i
Alexei Svitkine (slow) 2011/12/01 18:17:24 Correct. The previous logic was incorrect in this
479 if (index == last)
480 return index;
481 next = true;
482 }
483 }
484
464 size_t run_index = GetRunContainingPosition(index); 485 size_t run_index = GetRunContainingPosition(index);
465 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; 486 DCHECK(run_index < runs_.size());
466 int start = run ? run->range.start() : 0; 487 internal::TextRun* run = runs_[run_index];
467 int length = run ? run->range.length() : text().length(); 488 int start = run->range.start();
489 int length = run->range.length();
468 int ch = index - start; 490 int ch = index - start;
469 WORD cluster = run ? run->logical_clusters[ch] : 0; 491 WORD cluster = run->logical_clusters[ch];
470 492
471 if (!next) { 493 if (!next) {
472 do { 494 do {
473 ch--; 495 ch--;
474 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster); 496 } while (ch >= 0 && run->logical_clusters[ch] == cluster);
497
498 // Now, |ch| is at the end of the previous grapheme. Find the start.
499 while (ch > 0 && run->logical_clusters[ch - 1] == run->logical_clusters[ch])
500 ch--;
xji 2011/12/01 08:31:58 this does not seem right. for example: ABCDE, assu
Alexei Svitkine (slow) 2011/12/01 18:17:24 I see - this wasn't clear to me before. I've adjus
475 } else { 501 } else {
476 while (ch < length && run && run->logical_clusters[ch] == cluster) 502 while (ch < length && run->logical_clusters[ch] == cluster)
477 ch++; 503 ch++;
478 } 504 }
505
479 return std::max(std::min(ch, length) + start, 0); 506 return std::max(std::min(ch, length) + start, 0);
480 } 507 }
481 508
482 void RenderTextWin::ItemizeLogicalText() { 509 void RenderTextWin::ItemizeLogicalText() {
483 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 510 STLDeleteContainerPointers(runs_.begin(), runs_.end());
484 runs_.clear(); 511 runs_.clear();
485 string_width_ = 0; 512 string_width_ = 0;
486 if (text().empty()) 513 if (text().empty())
487 return; 514 return;
488 515
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 } 565 }
539 566
540 void RenderTextWin::LayoutVisualText() { 567 void RenderTextWin::LayoutVisualText() {
541 HRESULT hr = E_FAIL; 568 HRESULT hr = E_FAIL;
542 base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL)); 569 base::win::ScopedCreateDC hdc(CreateCompatibleDC(NULL));
543 std::vector<internal::TextRun*>::const_iterator run_iter; 570 std::vector<internal::TextRun*>::const_iterator run_iter;
544 for (run_iter = runs_.begin(); run_iter < runs_.end(); ++run_iter) { 571 for (run_iter = runs_.begin(); run_iter < runs_.end(); ++run_iter) {
545 internal::TextRun* run = *run_iter; 572 internal::TextRun* run = *run_iter;
546 size_t run_length = run->range.length(); 573 size_t run_length = run->range.length();
547 const wchar_t* run_text = &(text()[run->range.start()]); 574 const wchar_t* run_text = &(text()[run->range.start()]);
575 bool tried_fallback = false;
548 576
549 // Select the font desired for glyph generation. 577 // Select the font desired for glyph generation.
550 SelectObject(hdc, run->font.GetNativeFont()); 578 SelectObject(hdc, run->font.GetNativeFont());
551 579
552 run->logical_clusters.reset(new WORD[run_length]); 580 run->logical_clusters.reset(new WORD[run_length]);
553 run->glyph_count = 0; 581 run->glyph_count = 0;
554 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx 582 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx
555 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); 583 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
556 while (max_glyphs < kMaxGlyphs) { 584 while (max_glyphs < kMaxGlyphs) {
557 run->glyphs.reset(new WORD[max_glyphs]); 585 run->glyphs.reset(new WORD[max_glyphs]);
558 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); 586 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
559 hr = ScriptShape(hdc, 587 hr = ScriptShape(hdc,
560 &run->script_cache, 588 &run->script_cache,
561 run_text, 589 run_text,
562 run_length, 590 run_length,
563 max_glyphs, 591 max_glyphs,
564 &(run->script_analysis), 592 &(run->script_analysis),
565 run->glyphs.get(), 593 run->glyphs.get(),
566 run->logical_clusters.get(), 594 run->logical_clusters.get(),
567 run->visible_attributes.get(), 595 run->visible_attributes.get(),
568 &(run->glyph_count)); 596 &(run->glyph_count));
569 if (hr == E_OUTOFMEMORY) { 597 if (hr == E_OUTOFMEMORY) {
570 max_glyphs *= 2; 598 max_glyphs *= 2;
571 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { 599 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
572 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can crash 600 // Only try font fallback if it hasn't yet been attempted for this run.
573 // on certain surrogate pairs with SCRIPT_UNDEFINED. 601 if (tried_fallback) {
574 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 602 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can
575 // And http://maxradi.us/documents/uniscribe/ 603 // crash on certain surrogate pairs with SCRIPT_UNDEFINED.
576 if (run->script_analysis.eScript == SCRIPT_UNDEFINED) 604 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
577 break; 605 // And http://maxradi.us/documents/uniscribe/
606 run->script_analysis.eScript = SCRIPT_UNDEFINED;
607 break;
608 }
578 609
579 // The run's font doesn't contain the required glyphs, use an alternate. 610 // The run's font doesn't contain the required glyphs, use an alternate.
580 if (ChooseFallbackFont(hdc, run->font, run_text, run_length, 611 if (ChooseFallbackFont(hdc, run->font, run_text, run_length,
581 &run->font)) { 612 &run->font)) {
582 ScriptFreeCache(&run->script_cache); 613 ScriptFreeCache(&run->script_cache);
583 SelectObject(hdc, run->font.GetNativeFont()); 614 SelectObject(hdc, run->font.GetNativeFont());
584 } 615 }
585 616
586 run->script_analysis.eScript = SCRIPT_UNDEFINED; 617 tried_fallback = true;
587 } else { 618 } else {
588 break; 619 break;
589 } 620 }
590 } 621 }
591 DCHECK(SUCCEEDED(hr)); 622 DCHECK(SUCCEEDED(hr));
592 623
593 if (run->glyph_count > 0) { 624 if (run->glyph_count > 0) {
594 run->advance_widths.reset(new int[run->glyph_count]); 625 run->advance_widths.reset(new int[run->glyph_count]);
595 run->offsets.reset(new GOFFSET[run->glyph_count]); 626 run->offsets.reset(new GOFFSET[run->glyph_count]);
596 hr = ScriptPlace(hdc, 627 hr = ScriptPlace(hdc,
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
741 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; 772 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]];
742 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : 773 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) :
743 FirstSelectionModelInsideRun(next); 774 FirstSelectionModelInsideRun(next);
744 } 775 }
745 776
746 RenderText* RenderText::CreateRenderText() { 777 RenderText* RenderText::CreateRenderText() {
747 return new RenderTextWin; 778 return new RenderTextWin;
748 } 779 }
749 780
750 } // namespace gfx 781 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698