diff options
Diffstat (limited to 'ui/gfx/render_text_win.cc')
-rw-r--r-- | ui/gfx/render_text_win.cc | 94 |
1 files changed, 71 insertions, 23 deletions
diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 93aba52..4ff03ff 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -254,10 +254,15 @@ SelectionModel RenderTextWin::LeftEndSelectionModel() { EnsureLayout(); size_t cursor = base::i18n::IsRTL() ? text().length() : 0; internal::TextRun* run = runs_[visual_to_logical_[0]]; - bool rtl = run->script_analysis.fRTL; - size_t caret = rtl ? run->range.end() - 1 : run->range.start(); - SelectionModel::CaretPlacement placement = - rtl ? SelectionModel::TRAILING : SelectionModel::LEADING; + size_t caret; + SelectionModel::CaretPlacement placement; + if (run->script_analysis.fRTL) { + caret = IndexOfAdjacentGrapheme(run->range.end(), false); + placement = SelectionModel::TRAILING; + } else { + caret = run->range.start(); + placement = SelectionModel::LEADING; + } return SelectionModel(cursor, caret, placement); } @@ -268,10 +273,15 @@ SelectionModel RenderTextWin::RightEndSelectionModel() { EnsureLayout(); size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; - bool rtl = run->script_analysis.fRTL; - size_t caret = rtl ? run->range.start() : run->range.end() - 1; - SelectionModel::CaretPlacement placement = - rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; + size_t caret; + SelectionModel::CaretPlacement placement; + if (run->script_analysis.fRTL) { + caret = run->range.start(); + placement = SelectionModel::LEADING; + } else { + caret = IndexOfAdjacentGrapheme(run->range.end(), false); + placement = SelectionModel::TRAILING; + } return SelectionModel(cursor, caret, placement); } @@ -402,22 +412,50 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) { size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { EnsureLayout(); + + if (text().empty()) + return 0; + + if (index >= text().length()) { + if (next || index > text().length()) { + return text().length(); + } else { + // The requested |index| is at the end of the text. Use the index of the + // last character to find the grapheme. + index = text().length() - 1; + if (IsCursorablePosition(index)) + return index; + } + } + size_t run_index = GetRunContainingPosition(index); - internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; - int start = run ? run->range.start() : 0; - int length = run ? run->range.length() : text().length(); - int ch = index - start; - WORD cluster = run ? run->logical_clusters[ch] : 0; + DCHECK(run_index < runs_.size()); + internal::TextRun* run = runs_[run_index]; + size_t start = run->range.start(); + size_t ch = index - start; if (!next) { + // If |ch| is the start of the run, use the preceding run, if any. + if (ch == 0) { + if (run_index == 0) + return 0; + run = runs_[run_index - 1]; + start = run->range.start(); + ch = run->range.length(); + } + + // Loop to find the start of the grapheme. + WORD cluster = run->logical_clusters[ch - 1]; do { ch--; - } while (ch >= 0 && run && run->logical_clusters[ch] == cluster); + } while (ch > 0 && run->logical_clusters[ch - 1] == cluster); } else { - while (ch < length && run && run->logical_clusters[ch] == cluster) + WORD cluster = run->logical_clusters[ch]; + while (ch < run->range.length() && run->logical_clusters[ch] == cluster) ch++; } - return std::max(std::min(ch, length) + start, 0); + + return start + ch; } void RenderTextWin::ItemizeLogicalText() { @@ -487,6 +525,7 @@ void RenderTextWin::LayoutVisualText() { internal::TextRun* run = *run_iter; size_t run_length = run->range.length(); const wchar_t* run_text = &(text()[run->range.start()]); + bool tried_fallback = false; // Select the font desired for glyph generation. SelectObject(hdc, run->font.GetNativeFont()); @@ -511,12 +550,21 @@ void RenderTextWin::LayoutVisualText() { if (hr == E_OUTOFMEMORY) { max_glyphs *= 2; } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { - // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can crash - // on certain surrogate pairs with SCRIPT_UNDEFINED. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 - // And http://maxradi.us/documents/uniscribe/ - if (run->script_analysis.eScript == SCRIPT_UNDEFINED) - break; + // Only try font fallback if it hasn't yet been attempted for this run. + if (tried_fallback) { + // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can + // crash on certain surrogate pairs with SCRIPT_UNDEFINED. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 + // And http://maxradi.us/documents/uniscribe/ + run->script_analysis.eScript = SCRIPT_UNDEFINED; + // Reset |hr| to 0 to not trigger the DCHECK() below when a font is + // not found that can display the text. This is expected behavior + // under Windows XP without additional language packs installed and + // may also happen on newer versions when trying to display text in + // an obscure script that the system doesn't have the right font for. + hr = 0; + break; + } // The run's font doesn't contain the required glyphs, use an alternate. if (ChooseFallbackFont(hdc, run->font, run_text, run_length, @@ -525,7 +573,7 @@ void RenderTextWin::LayoutVisualText() { SelectObject(hdc, run->font.GetNativeFont()); } - run->script_analysis.eScript = SCRIPT_UNDEFINED; + tried_fallback = true; } else { break; } |