| Index: ui/gfx/render_text_win.cc
|
| ===================================================================
|
| --- ui/gfx/render_text_win.cc (revision 113627)
|
| +++ ui/gfx/render_text_win.cc (working copy)
|
| @@ -291,10 +291,15 @@
|
| 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);
|
| }
|
|
|
| @@ -305,10 +310,15 @@
|
| 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);
|
| }
|
|
|
| @@ -461,22 +471,50 @@
|
|
|
| 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() {
|
| @@ -545,6 +583,7 @@
|
| 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());
|
| @@ -569,12 +608,21 @@
|
| 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,
|
| @@ -583,7 +631,7 @@
|
| SelectObject(hdc, run->font.GetNativeFont());
|
| }
|
|
|
| - run->script_analysis.eScript = SCRIPT_UNDEFINED;
|
| + tried_fallback = true;
|
| } else {
|
| break;
|
| }
|
|
|