1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/gfx/render_text_win.h"
6
7#include <algorithm>
8
9#include "base/i18n/break_iterator.h"
10#include "base/i18n/rtl.h"
11#include "base/logging.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/win/windows_version.h"
15#include "ui/base/text/utf16_indexing.h"
16#include "ui/gfx/canvas.h"
17#include "ui/gfx/font_fallback_win.h"
18#include "ui/gfx/font_smoothing_win.h"
19#include "ui/gfx/platform_font_win.h"
20
21namespace gfx {
22
23namespace {
24
25// The maximum length of text supported for Uniscribe layout and display.
26// This empirically chosen value should prevent major performance degradations.
27// TODO(msw): Support longer text, partial layout/painting, etc.
28const size_t kMaxUniscribeTextLength = 10000;
29
30// The initial guess and maximum supported number of runs; arbitrary values.
31// TODO(msw): Support more runs, determine a better initial guess, etc.
32const int kGuessRuns = 100;
33const size_t kMaxRuns = 10000;
34
35// The maximum number of glyphs per run; ScriptShape fails on larger values.
36const size_t kMaxGlyphs = 65535;
37
38// Callback to |EnumEnhMetaFile()| to intercept font creation.
39int CALLBACK MetaFileEnumProc(HDC hdc,
40                              HANDLETABLE* table,
41                              CONST ENHMETARECORD* record,
42                              int table_entries,
43                              LPARAM log_font) {
44  if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
45    const EMREXTCREATEFONTINDIRECTW* create_font_record =
46        reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
47    *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
48  }
49  return 1;
50}
51
52// Finds a fallback font to use to render the specified |text| with respect to
53// an initial |font|. Returns the resulting font via out param |result|. Returns
54// |true| if a fallback font was found.
55// Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
56// TODO(asvitkine): This should be moved to font_fallback_win.cc.
57bool ChooseFallbackFont(HDC hdc,
58                        const Font& font,
59                        const wchar_t* text,
60                        int text_length,
61                        Font* result) {
62  // Use a meta file to intercept the fallback font chosen by Uniscribe.
63  HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
64  if (!meta_file_dc)
65    return false;
66
67  SelectObject(meta_file_dc, font.GetNativeFont());
68
69  SCRIPT_STRING_ANALYSIS script_analysis;
70  HRESULT hresult =
71      ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
72                          SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
73                          0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
74
75  if (SUCCEEDED(hresult)) {
76    hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
77    ScriptStringFree(&script_analysis);
78  }
79
80  bool found_fallback = false;
81  HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
82  if (SUCCEEDED(hresult)) {
83    LOGFONT log_font;
84    log_font.lfFaceName[0] = 0;
85    EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
86    if (log_font.lfFaceName[0]) {
87      *result = Font(UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
88      found_fallback = true;
89    }
90  }
91  DeleteEnhMetaFile(meta_file);
92
93  return found_fallback;
94}
95
96// Changes |font| to have the specified |font_size| (or |font_height| on Windows
97// XP) and |font_style| if it is not the case already. Only considers bold and
98// italic styles, since the underlined style has no effect on glyph shaping.
99void DeriveFontIfNecessary(int font_size,
100                           int font_height,
101                           int font_style,
102                           Font* font) {
103  const int kStyleMask = (Font::BOLD | Font::ITALIC);
104  const int target_style = (font_style & kStyleMask);
105
106  // On Windows XP, the font must be resized using |font_height| instead of
107  // |font_size| to match GDI behavior.
108  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
109    PlatformFontWin* platform_font =
110        static_cast<PlatformFontWin*>(font->platform_font());
111    *font = platform_font->DeriveFontWithHeight(font_height, target_style);
112    return;
113  }
114
115  const int current_style = (font->GetStyle() & kStyleMask);
116  const int current_size = font->GetFontSize();
117  if (current_style != target_style || current_size != font_size)
118    *font = font->DeriveFont(font_size - current_size, target_style);
119}
120
121// Returns true if |c| is a Unicode BiDi control character.
122bool IsUnicodeBidiControlCharacter(char16 c) {
123  return c == base::i18n::kRightToLeftMark ||
124         c == base::i18n::kLeftToRightMark ||
125         c == base::i18n::kLeftToRightEmbeddingMark ||
126         c == base::i18n::kRightToLeftEmbeddingMark ||
127         c == base::i18n::kPopDirectionalFormatting ||
128         c == base::i18n::kLeftToRightOverride ||
129         c == base::i18n::kRightToLeftOverride;
130}
131
132// Returns the corresponding glyph range of the given character range.
133// |range| is in text-space (0 corresponds to |GetLayoutText()[0]|).
134// Returned value is in run-space (0 corresponds to the first glyph in the run).
135ui::Range CharRangeToGlyphRange(const internal::TextRun& run,
136                                const ui::Range& range) {
137  DCHECK(run.range.Contains(range));
138  DCHECK(!range.is_reversed());
139  DCHECK(!range.is_empty());
140  const ui::Range run_range = ui::Range(range.start() - run.range.start(),
141                                        range.end() - run.range.start());
142  ui::Range result;
143  if (run.script_analysis.fRTL) {
144    result = ui::Range(run.logical_clusters[run_range.end() - 1],
145        run_range.start() > 0 ? run.logical_clusters[run_range.start() - 1]
146                              : run.glyph_count);
147  } else {
148    result = ui::Range(run.logical_clusters[run_range.start()],
149        run_range.end() < run.range.length() ?
150            run.logical_clusters[run_range.end()] : run.glyph_count);
151  }
152  DCHECK(!result.is_reversed());
153  DCHECK(ui::Range(0, run.glyph_count).Contains(result));
154  return result;
155}
156
157}  // namespace
158
159namespace internal {
160
161TextRun::TextRun()
162  : font_style(0),
163    strike(false),
164    diagonal_strike(false),
165    underline(false),
166    width(0),
167    preceding_run_widths(0),
168    glyph_count(0),
169    script_cache(NULL) {
170  memset(&script_analysis, 0, sizeof(script_analysis));
171  memset(&abc_widths, 0, sizeof(abc_widths));
172}
173
174TextRun::~TextRun() {
175  ScriptFreeCache(&script_cache);
176}
177
178// Returns the X coordinate of the leading or |trailing| edge of the glyph
179// starting at |index|, relative to the left of the text (not the view).
180int GetGlyphXBoundary(const internal::TextRun* run,
181                      size_t index,
182                      bool trailing) {
183  DCHECK_GE(index, run->range.start());
184  DCHECK_LT(index, run->range.end() + (trailing ? 0 : 1));
185  int x = 0;
186  HRESULT hr = ScriptCPtoX(
187      index - run->range.start(),
188      trailing,
189      run->range.length(),
190      run->glyph_count,
191      run->logical_clusters.get(),
192      run->visible_attributes.get(),
193      run->advance_widths.get(),
194      &run->script_analysis,
195      &x);
196  DCHECK(SUCCEEDED(hr));
197  return run->preceding_run_widths + x;
198}
199
200}  // namespace internal
201
202// static
203HDC RenderTextWin::cached_hdc_ = NULL;
204
205// static
206std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
207
208RenderTextWin::RenderTextWin()
209    : RenderText(),
210      common_baseline_(0),
211      needs_layout_(false) {
212  set_truncate_length(kMaxUniscribeTextLength);
213
214  memset(&script_control_, 0, sizeof(script_control_));
215  memset(&script_state_, 0, sizeof(script_state_));
216
217  MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
218}
219
220RenderTextWin::~RenderTextWin() {
221}
222
223Size RenderTextWin::GetStringSize() {
224  EnsureLayout();
225  return string_size_;
226}
227
228int RenderTextWin::GetBaseline() {
229  EnsureLayout();
230  return common_baseline_;
231}
232
233SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
234  if (text().empty())
235    return SelectionModel();
236
237  EnsureLayout();
238  // Find the run that contains the point and adjust the argument location.
239  int x = ToTextPoint(point).x();
240  size_t run_index = GetRunContainingXCoord(x);
241  if (run_index >= runs_.size())
242    return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
243  internal::TextRun* run = runs_[run_index];
244
245  int position = 0, trailing = 0;
246  HRESULT hr = ScriptXtoCP(x - run->preceding_run_widths,
247                           run->range.length(),
248                           run->glyph_count,
249                           run->logical_clusters.get(),
250                           run->visible_attributes.get(),
251                           run->advance_widths.get(),
252                           &(run->script_analysis),
253                           &position,
254                           &trailing);
255  DCHECK(SUCCEEDED(hr));
256  DCHECK_GE(trailing, 0);
257  position += run->range.start();
258  const size_t cursor = LayoutIndexToTextIndex(position + trailing);
259  DCHECK_LE(cursor, text().length());
260  return SelectionModel(cursor, trailing ? CURSOR_BACKWARD : CURSOR_FORWARD);
261}
262
263std::vector<RenderText::FontSpan> RenderTextWin::GetFontSpansForTesting() {
264  EnsureLayout();
265
266  std::vector<RenderText::FontSpan> spans;
267  for (size_t i = 0; i < runs_.size(); ++i) {
268    spans.push_back(RenderText::FontSpan(runs_[i]->font,
269        ui::Range(LayoutIndexToTextIndex(runs_[i]->range.start()),
270                  LayoutIndexToTextIndex(runs_[i]->range.end()))));
271  }
272
273  return spans;
274}
275
276SelectionModel RenderTextWin::AdjacentCharSelectionModel(
277    const SelectionModel& selection,
278    VisualCursorDirection direction) {
279  DCHECK(!needs_layout_);
280  internal::TextRun* run;
281  size_t run_index = GetRunContainingCaret(selection);
282  if (run_index >= runs_.size()) {
283    // The cursor is not in any run: we're at the visual and logical edge.
284    SelectionModel edge = EdgeSelectionModel(direction);
285    if (edge.caret_pos() == selection.caret_pos())
286      return edge;
287    int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1;
288    run = runs_[visual_to_logical_[visual_index]];
289  } else {
290    // If the cursor is moving within the current run, just move it by one
291    // grapheme in the appropriate direction.
292    run = runs_[run_index];
293    size_t caret = selection.caret_pos();
294    bool forward_motion =
295        run->script_analysis.fRTL == (direction == CURSOR_LEFT);
296    if (forward_motion) {
297      if (caret < LayoutIndexToTextIndex(run->range.end())) {
298        caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
299        return SelectionModel(caret, CURSOR_BACKWARD);
300      }
301    } else {
302      if (caret > LayoutIndexToTextIndex(run->range.start())) {
303        caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
304        return SelectionModel(caret, CURSOR_FORWARD);
305      }
306    }
307    // The cursor is at the edge of a run; move to the visually adjacent run.
308    int visual_index = logical_to_visual_[run_index];
309    visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
310    if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size()))
311      return EdgeSelectionModel(direction);
312    run = runs_[visual_to_logical_[visual_index]];
313  }
314  bool forward_motion = run->script_analysis.fRTL == (direction == CURSOR_LEFT);
315  return forward_motion ? FirstSelectionModelInsideRun(run) :
316                          LastSelectionModelInsideRun(run);
317}
318
319// TODO(msw): Implement word breaking for Windows.
320SelectionModel RenderTextWin::AdjacentWordSelectionModel(
321    const SelectionModel& selection,
322    VisualCursorDirection direction) {
323  if (obscured())
324    return EdgeSelectionModel(direction);
325
326  base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
327  bool success = iter.Init();
328  DCHECK(success);
329  if (!success)
330    return selection;
331
332  size_t pos;
333  if (direction == CURSOR_RIGHT) {
334    pos = std::min(selection.caret_pos() + 1, text().length());
335    while (iter.Advance()) {
336      pos = iter.pos();
337      if (iter.IsWord() && pos > selection.caret_pos())
338        break;
339    }
340  } else {  // direction == CURSOR_LEFT
341    // Notes: We always iterate words from the beginning.
342    // This is probably fast enough for our usage, but we may
343    // want to modify WordIterator so that it can start from the
344    // middle of string and advance backwards.
345    pos = std::max<int>(selection.caret_pos() - 1, 0);
346    while (iter.Advance()) {
347      if (iter.IsWord()) {
348        size_t begin = iter.pos() - iter.GetString().length();
349        if (begin == selection.caret_pos()) {
350          // The cursor is at the beginning of a word.
351          // Move to previous word.
352          break;
353        } else if (iter.pos() >= selection.caret_pos()) {
354          // The cursor is in the middle or at the end of a word.
355          // Move to the top of current word.
356          pos = begin;
357          break;
358        } else {
359          pos = iter.pos() - iter.GetString().length();
360        }
361      }
362    }
363  }
364  return SelectionModel(pos, CURSOR_FORWARD);
365}
366
367ui::Range RenderTextWin::GetGlyphBounds(size_t index) {
368  const size_t run_index =
369      GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
370  // Return edge bounds if the index is invalid or beyond the layout text size.
371  if (run_index >= runs_.size())
372    return ui::Range(string_size_.width());
373  internal::TextRun* run = runs_[run_index];
374  const size_t layout_index = TextIndexToLayoutIndex(index);
375  return ui::Range(GetGlyphXBoundary(run, layout_index, false),
376                   GetGlyphXBoundary(run, layout_index, true));
377}
378
379std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) {
380  DCHECK(!needs_layout_);
381  DCHECK(ui::Range(0, text().length()).Contains(range));
382  ui::Range layout_range(TextIndexToLayoutIndex(range.start()),
383                         TextIndexToLayoutIndex(range.end()));
384  DCHECK(ui::Range(0, GetLayoutText().length()).Contains(layout_range));
385
386  std::vector<Rect> bounds;
387  if (layout_range.is_empty())
388    return bounds;
389
390  // Add a Rect for each run/selection intersection.
391  // TODO(msw): The bounds should probably not always be leading the range ends.
392  for (size_t i = 0; i < runs_.size(); ++i) {
393    const internal::TextRun* run = runs_[visual_to_logical_[i]];
394    ui::Range intersection = run->range.Intersect(layout_range);
395    if (intersection.IsValid()) {
396      DCHECK(!intersection.is_reversed());
397      ui::Range range_x(GetGlyphXBoundary(run, intersection.start(), false),
398                        GetGlyphXBoundary(run, intersection.end(), false));
399      Rect rect(range_x.GetMin(), 0, range_x.length(), run->font.GetHeight());
400      rect.set_origin(ToViewPoint(rect.origin()));
401      // Union this with the last rect if they're adjacent.
402      if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) {
403        rect.Union(bounds.back());
404        bounds.pop_back();
405      }
406      bounds.push_back(rect);
407    }
408  }
409  return bounds;
410}
411
412size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
413  DCHECK_LE(index, text().length());
414  ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index;
415  CHECK_GE(i, 0);
416  // Clamp layout indices to the length of the text actually used for layout.
417  return std::min<size_t>(GetLayoutText().length(), i);
418}
419
420size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const {
421  if (!obscured())
422    return index;
423
424  DCHECK_LE(index, GetLayoutText().length());
425  const size_t text_index = ui::UTF16OffsetToIndex(text(), 0, index);
426  DCHECK_LE(text_index, text().length());
427  return text_index;
428}
429
430bool RenderTextWin::IsCursorablePosition(size_t position) {
431  if (position == 0 || position == text().length())
432    return true;
433  EnsureLayout();
434
435  // Check that the index is at a valid code point (not mid-surrgate-pair),
436  // that it is not truncated from layout text (its glyph is shown on screen),
437  // and that its glyph has distinct bounds (not mid-multi-character-grapheme).
438  // An example of a multi-character-grapheme that is not a surrogate-pair is:
439  // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
440  return ui::IsValidCodePointIndex(text(), position) &&
441         position < LayoutIndexToTextIndex(GetLayoutText().length()) &&
442         GetGlyphBounds(position) != GetGlyphBounds(position - 1);
443}
444
445void RenderTextWin::ResetLayout() {
446  // Layout is performed lazily as needed for drawing/metrics.
447  needs_layout_ = true;
448}
449
450void RenderTextWin::EnsureLayout() {
451  if (!needs_layout_)
452    return;
453  // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
454  ItemizeLogicalText();
455  if (!runs_.empty())
456    LayoutVisualText();
457  needs_layout_ = false;
458}
459
460void RenderTextWin::DrawVisualText(Canvas* canvas) {
461  DCHECK(!needs_layout_);
462
463  // Skia will draw glyphs with respect to the baseline.
464  Vector2d offset(GetTextOffset() + Vector2d(0, common_baseline_));
465
466  SkScalar x = SkIntToScalar(offset.x());
467  SkScalar y = SkIntToScalar(offset.y());
468
469  std::vector<SkPoint> pos;
470
471  internal::SkiaTextRenderer renderer(canvas);
472  ApplyFadeEffects(&renderer);
473  ApplyTextShadows(&renderer);
474
475  bool smoothing_enabled;
476  bool cleartype_enabled;
477  GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
478  // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
479  renderer.SetFontSmoothingSettings(
480      smoothing_enabled, cleartype_enabled && !background_is_transparent());
481
482  ApplyCompositionAndSelectionStyles();
483
484  for (size_t i = 0; i < runs_.size(); ++i) {
485    // Get the run specified by the visual-to-logical map.
486    internal::TextRun* run = runs_[visual_to_logical_[i]];
487
488    // Skip painting empty runs and runs outside the display rect area.
489    if ((run->glyph_count == 0) || (x >= display_rect().right()) ||
490        (x + run->width <= display_rect().x())) {
491      x += run->width;
492      continue;
493    }
494
495    // Based on WebCore::skiaDrawText. |pos| contains the positions of glyphs.
496    // An extra terminal |pos| entry is added to simplify width calculations.
497    pos.resize(run->glyph_count + 1);
498    SkScalar glyph_x = x;
499    for (int glyph = 0; glyph < run->glyph_count; glyph++) {
500      pos[glyph].set(glyph_x + run->offsets[glyph].du,
501                     y + run->offsets[glyph].dv);
502      glyph_x += SkIntToScalar(run->advance_widths[glyph]);
503    }
504    pos.back().set(glyph_x, y);
505
506    renderer.SetTextSize(run->font.GetFontSize());
507    renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
508
509    for (BreakList<SkColor>::const_iterator it =
510             colors().GetBreak(run->range.start());
511         it != colors().breaks().end() && it->first < run->range.end();
512         ++it) {
513      const ui::Range glyph_range = CharRangeToGlyphRange(*run,
514          colors().GetRange(it).Intersect(run->range));
515      if (glyph_range.is_empty())
516        continue;
517      renderer.SetForegroundColor(it->second);
518      renderer.DrawPosText(&pos[glyph_range.start()],
519                           &run->glyphs[glyph_range.start()],
520                           glyph_range.length());
521      const SkScalar width = pos[glyph_range.end()].x() -
522          pos[glyph_range.start()].x();
523      renderer.DrawDecorations(pos[glyph_range.start()].x(), y,
524                               SkScalarCeilToInt(width), run->underline,
525                               run->strike, run->diagonal_strike);
526    }
527
528    DCHECK_EQ(glyph_x - x, run->width);
529    x = glyph_x;
530  }
531
532  UndoCompositionAndSelectionStyles();
533}
534
535void RenderTextWin::ItemizeLogicalText() {
536  runs_.clear();
537  // Make |string_size_|'s height and |common_baseline_| tall enough to draw
538  // often-used characters which are rendered with fonts in the font list.
539  string_size_ = Size(0, font_list().GetHeight());
540  common_baseline_ = font_list().GetBaseline();
541
542  // Set Uniscribe's base text direction.
543  script_state_.uBidiLevel =
544      (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0;
545
546  if (text().empty())
547    return;
548
549  HRESULT hr = E_OUTOFMEMORY;
550  int script_items_count = 0;
551  std::vector<SCRIPT_ITEM> script_items;
552  const size_t layout_text_length = GetLayoutText().length();
553  // Ensure that |kMaxRuns| is attempted and the loop terminates afterward.
554  for (size_t runs = kGuessRuns; hr == E_OUTOFMEMORY && runs <= kMaxRuns;
555       runs = std::max(runs + 1, std::min(runs * 2, kMaxRuns))) {
556    // Derive the array of Uniscribe script items from the logical text.
557    // ScriptItemize always adds a terminal array item so that the length of
558    // the last item can be derived from the terminal SCRIPT_ITEM::iCharPos.
559    script_items.resize(runs);
560    hr = ScriptItemize(GetLayoutText().c_str(), layout_text_length,
561                       runs - 1, &script_control_, &script_state_,
562                       &script_items[0], &script_items_count);
563  }
564  DCHECK(SUCCEEDED(hr));
565  if (!SUCCEEDED(hr) || script_items_count <= 0)
566    return;
567
568  // Temporarily apply composition underlines and selection colors.
569  ApplyCompositionAndSelectionStyles();
570
571  // Build the list of runs from the script items and ranged styles. Use an
572  // empty color BreakList to avoid breaking runs at color boundaries.
573  BreakList<SkColor> empty_colors;
574  empty_colors.SetMax(text().length());
575  internal::StyleIterator style(empty_colors, styles());
576  SCRIPT_ITEM* script_item = &script_items[0];
577  const size_t max_run_length = kMaxGlyphs / 2;
578  for (size_t run_break = 0; run_break < layout_text_length;) {
579    internal::TextRun* run = new internal::TextRun();
580    run->range.set_start(run_break);
581    run->font = GetPrimaryFont();
582    run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
583                      (style.style(ITALIC) ? Font::ITALIC : 0);
584    DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(),
585                          run->font_style, &run->font);
586    run->strike = style.style(STRIKE);
587    run->diagonal_strike = style.style(DIAGONAL_STRIKE);
588    run->underline = style.style(UNDERLINE);
589    run->script_analysis = script_item->a;
590
591    // Find the next break and advance the iterators as needed.
592    const size_t script_item_break = (script_item + 1)->iCharPos;
593    run_break = std::min(script_item_break,
594                         TextIndexToLayoutIndex(style.GetRange().end()));
595    // Clamp run lengths to avoid exceeding the maximum supported glyph count.
596    if ((run_break - run->range.start()) > max_run_length)
597      run_break = run->range.start() + max_run_length;
598    style.UpdatePosition(LayoutIndexToTextIndex(run_break));
599    if (script_item_break == run_break)
600      script_item++;
601    run->range.set_end(run_break);
602    runs_.push_back(run);
603  }
604
605  // Undo the temporarily applied composition underlines and selection colors.
606  UndoCompositionAndSelectionStyles();
607}
608
609void RenderTextWin::LayoutVisualText() {
610  DCHECK(!runs_.empty());
611
612  if (!cached_hdc_)
613    cached_hdc_ = CreateCompatibleDC(NULL);
614
615  HRESULT hr = E_FAIL;
616  // Ensure ascent and descent are not smaller than ones of the font list.
617  // Keep them tall enough to draw often-used characters.
618  // For example, if a text field contains a Japanese character, which is
619  // smaller than Latin ones, and then later a Latin one is inserted, this
620  // ensures that the text baseline does not shift.
621  int ascent = font_list().GetBaseline();
622  int descent = font_list().GetHeight() - font_list().GetBaseline();
623  for (size_t i = 0; i < runs_.size(); ++i) {
624    internal::TextRun* run = runs_[i];
625    LayoutTextRun(run);
626
627    ascent = std::max(ascent, run->font.GetBaseline());
628    descent = std::max(descent,
629                       run->font.GetHeight() - run->font.GetBaseline());
630
631    if (run->glyph_count > 0) {
632      run->advance_widths.reset(new int[run->glyph_count]);
633      run->offsets.reset(new GOFFSET[run->glyph_count]);
634      hr = ScriptPlace(cached_hdc_,
635                       &run->script_cache,
636                       run->glyphs.get(),
637                       run->glyph_count,
638                       run->visible_attributes.get(),
639                       &(run->script_analysis),
640                       run->advance_widths.get(),
641                       run->offsets.get(),
642                       &(run->abc_widths));
643      DCHECK(SUCCEEDED(hr));
644    }
645  }
646  string_size_.set_height(ascent + descent);
647  common_baseline_ = ascent;
648
649  // Build the array of bidirectional embedding levels.
650  scoped_ptr<BYTE[]> levels(new BYTE[runs_.size()]);
651  for (size_t i = 0; i < runs_.size(); ++i)
652    levels[i] = runs_[i]->script_analysis.s.uBidiLevel;
653
654  // Get the maps between visual and logical run indices.
655  visual_to_logical_.reset(new int[runs_.size()]);
656  logical_to_visual_.reset(new int[runs_.size()]);
657  hr = ScriptLayout(runs_.size(),
658                    levels.get(),
659                    visual_to_logical_.get(),
660                    logical_to_visual_.get());
661  DCHECK(SUCCEEDED(hr));
662
663  // Precalculate run width information.
664  size_t preceding_run_widths = 0;
665  for (size_t i = 0; i < runs_.size(); ++i) {
666    internal::TextRun* run = runs_[visual_to_logical_[i]];
667    run->preceding_run_widths = preceding_run_widths;
668    const ABC& abc = run->abc_widths;
669    run->width = abc.abcA + abc.abcB + abc.abcC;
670    preceding_run_widths += run->width;
671  }
672  string_size_.set_width(preceding_run_widths);
673}
674
675void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
676  const size_t run_length = run->range.length();
677  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
678  Font original_font = run->font;
679  LinkedFontsIterator fonts(original_font);
680  bool tried_cached_font = false;
681  bool tried_fallback = false;
682  // Keep track of the font that is able to display the greatest number of
683  // characters for which ScriptShape() returned S_OK. This font will be used
684  // in the case where no font is able to display the entire run.
685  int best_partial_font_missing_char_count = INT_MAX;
686  Font best_partial_font = original_font;
687  bool using_best_partial_font = false;
688  Font current_font;
689
690  run->logical_clusters.reset(new WORD[run_length]);
691  while (fonts.NextFont(&current_font)) {
692    HRESULT hr = ShapeTextRunWithFont(run, current_font);
693
694    bool glyphs_missing = false;
695    if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
696      glyphs_missing = true;
697    } else if (hr == S_OK) {
698      // If |hr| is S_OK, there could still be missing glyphs in the output.
699      // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx
700      const int missing_count = CountCharsWithMissingGlyphs(run);
701      // Track the font that produced the least missing glyphs.
702      if (missing_count < best_partial_font_missing_char_count) {
703        best_partial_font_missing_char_count = missing_count;
704        best_partial_font = run->font;
705      }
706      glyphs_missing = (missing_count != 0);
707    } else {
708      NOTREACHED() << hr;
709    }
710
711    // Use the font if it had glyphs for all characters.
712    if (!glyphs_missing) {
713      // Save the successful fallback font that was chosen.
714      if (tried_fallback)
715        successful_substitute_fonts_[original_font.GetFontName()] = run->font;
716      return;
717    }
718
719    // First, try the cached font from previous runs, if any.
720    if (!tried_cached_font) {
721      tried_cached_font = true;
722
723      std::map<std::string, Font>::const_iterator it =
724          successful_substitute_fonts_.find(original_font.GetFontName());
725      if (it != successful_substitute_fonts_.end()) {
726        fonts.SetNextFont(it->second);
727        continue;
728      }
729    }
730
731    // If there are missing glyphs, first try finding a fallback font using a
732    // meta file, if it hasn't yet been attempted for this run.
733    // TODO(msw|asvitkine): Support RenderText's font_list()?
734    if (!tried_fallback) {
735      tried_fallback = true;
736
737      Font fallback_font;
738      if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length,
739                             &fallback_font)) {
740        fonts.SetNextFont(fallback_font);
741        continue;
742      }
743    }
744  }
745
746  // If a font was able to partially display the run, use that now.
747  if (best_partial_font_missing_char_count < static_cast<int>(run_length)) {
748    // Re-shape the run only if |best_partial_font| differs from the last font.
749    if (best_partial_font.GetNativeFont() != run->font.GetNativeFont())
750      ShapeTextRunWithFont(run, best_partial_font);
751    return;
752  }
753
754  // If no font was able to partially display the run, replace all glyphs
755  // with |wgDefault| from the original font to ensure to they don't hold
756  // garbage values.
757  // First, clear the cache and select the original font on the HDC.
758  ScriptFreeCache(&run->script_cache);
759  run->font = original_font;
760  SelectObject(cached_hdc_, run->font.GetNativeFont());
761
762  // Now, get the font's properties.
763  SCRIPT_FONTPROPERTIES properties;
764  memset(&properties, 0, sizeof(properties));
765  properties.cBytes = sizeof(properties);
766  HRESULT hr = ScriptGetFontProperties(cached_hdc_, &run->script_cache,
767                                       &properties);
768
769  // The initial values for the "missing" glyph and the space glyph are taken
770  // from the recommendations section of the OpenType spec:
771  // https://www.microsoft.com/typography/otspec/recom.htm
772  WORD missing_glyph = 0;
773  WORD space_glyph = 3;
774  if (hr == S_OK) {
775    missing_glyph = properties.wgDefault;
776    space_glyph = properties.wgBlank;
777  }
778
779  // Finally, initialize |glyph_count|, |glyphs|, |visible_attributes| and
780  // |logical_clusters| on the run (since they may not have been set yet).
781  run->glyph_count = run_length;
782  memset(run->visible_attributes.get(), 0,
783         run->glyph_count * sizeof(SCRIPT_VISATTR));
784  for (int i = 0; i < run->glyph_count; ++i)
785    run->glyphs[i] = IsWhitespace(run_text[i]) ? space_glyph : missing_glyph;
786  for (size_t i = 0; i < run_length; ++i) {
787    run->logical_clusters[i] = run->script_analysis.fRTL ?
788        run_length - 1 - i : i;
789  }
790
791  // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can
792  //            crash on certain surrogate pairs with SCRIPT_UNDEFINED.
793  //            See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
794  //            And http://maxradi.us/documents/uniscribe/
795  run->script_analysis.eScript = SCRIPT_UNDEFINED;
796}
797
798HRESULT RenderTextWin::ShapeTextRunWithFont(internal::TextRun* run,
799                                            const Font& font) {
800  // Update the run's font only if necessary. If the two fonts wrap the same
801  // PlatformFontWin object, their native fonts will have the same value.
802  if (run->font.GetNativeFont() != font.GetNativeFont()) {
803    const int font_size = run->font.GetFontSize();
804    const int font_height = run->font.GetHeight();
805    run->font = font;
806    DeriveFontIfNecessary(font_size, font_height, run->font_style, &run->font);
807    ScriptFreeCache(&run->script_cache);
808  }
809
810  // Select the font desired for glyph generation.
811  SelectObject(cached_hdc_, run->font.GetNativeFont());
812
813  HRESULT hr = E_OUTOFMEMORY;
814  const size_t run_length = run->range.length();
815  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
816  // Guess the expected number of glyphs from the length of the run.
817  // MSDN suggests this at http://msdn.microsoft.com/en-us/library/dd368564.aspx
818  size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
819  while (hr == E_OUTOFMEMORY && max_glyphs <= kMaxGlyphs) {
820    run->glyph_count = 0;
821    run->glyphs.reset(new WORD[max_glyphs]);
822    run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
823    hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length,
824                     max_glyphs, &run->script_analysis, run->glyphs.get(),
825                     run->logical_clusters.get(), run->visible_attributes.get(),
826                     &run->glyph_count);
827    // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward.
828    max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs));
829  }
830  return hr;
831}
832
833int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run) const {
834  int chars_not_missing_glyphs = 0;
835  SCRIPT_FONTPROPERTIES properties;
836  memset(&properties, 0, sizeof(properties));
837  properties.cBytes = sizeof(properties);
838  ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties);
839
840  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
841  for (size_t char_index = 0; char_index < run->range.length(); ++char_index) {
842    const int glyph_index = run->logical_clusters[char_index];
843    DCHECK_GE(glyph_index, 0);
844    DCHECK_LT(glyph_index, run->glyph_count);
845
846    if (run->glyphs[glyph_index] == properties.wgDefault)
847      continue;
848
849    // Windows Vista sometimes returns glyphs equal to wgBlank (instead of
850    // wgDefault), with fZeroWidth set. Treat such cases as having missing
851    // glyphs if the corresponding character is not whitespace.
852    // See: http://crbug.com/125629
853    if (run->glyphs[glyph_index] == properties.wgBlank &&
854        run->visible_attributes[glyph_index].fZeroWidth &&
855        !IsWhitespace(run_text[char_index]) &&
856        !IsUnicodeBidiControlCharacter(run_text[char_index])) {
857      continue;
858    }
859
860    ++chars_not_missing_glyphs;
861  }
862
863  DCHECK_LE(chars_not_missing_glyphs, static_cast<int>(run->range.length()));
864  return run->range.length() - chars_not_missing_glyphs;
865}
866
867size_t RenderTextWin::GetRunContainingCaret(const SelectionModel& caret) const {
868  DCHECK(!needs_layout_);
869  size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
870  LogicalCursorDirection affinity = caret.caret_affinity();
871  for (size_t run = 0; run < runs_.size(); ++run)
872    if (RangeContainsCaret(runs_[run]->range, layout_position, affinity))
873      return run;
874  return runs_.size();
875}
876
877size_t RenderTextWin::GetRunContainingXCoord(int x) const {
878  DCHECK(!needs_layout_);
879  // Find the text run containing the argument point (assumed already offset).
880  for (size_t run = 0; run < runs_.size(); ++run) {
881    if ((runs_[run]->preceding_run_widths <= x) &&
882        ((runs_[run]->preceding_run_widths + runs_[run]->width) > x))
883      return run;
884  }
885  return runs_.size();
886}
887
888SelectionModel RenderTextWin::FirstSelectionModelInsideRun(
889    const internal::TextRun* run) {
890  size_t position = LayoutIndexToTextIndex(run->range.start());
891  position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD);
892  return SelectionModel(position, CURSOR_BACKWARD);
893}
894
895SelectionModel RenderTextWin::LastSelectionModelInsideRun(
896    const internal::TextRun* run) {
897  size_t position = LayoutIndexToTextIndex(run->range.end());
898  position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
899  return SelectionModel(position, CURSOR_FORWARD);
900}
901
902RenderText* RenderText::CreateInstance() {
903  return new RenderTextWin;
904}
905
906}  // namespace gfx
907