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/char_iterator.h"
11#include "base/i18n/rtl.h"
12#include "base/logging.h"
13#include "base/strings/string_util.h"
14#include "base/strings/utf_string_conversions.h"
15#include "base/win/windows_version.h"
16#include "third_party/icu/source/common/unicode/uchar.h"
17#include "ui/gfx/canvas.h"
18#include "ui/gfx/font_fallback_win.h"
19#include "ui/gfx/font_render_params.h"
20#include "ui/gfx/geometry/size_conversions.h"
21#include "ui/gfx/platform_font_win.h"
22#include "ui/gfx/utf16_indexing.h"
23
24namespace gfx {
25
26namespace {
27
28// The maximum length of text supported for Uniscribe layout and display.
29// This empirically chosen value should prevent major performance degradations.
30// TODO(msw): Support longer text, partial layout/painting, etc.
31const size_t kMaxUniscribeTextLength = 10000;
32
33// The initial guess and maximum supported number of runs; arbitrary values.
34// TODO(msw): Support more runs, determine a better initial guess, etc.
35const int kGuessRuns = 100;
36const size_t kMaxRuns = 10000;
37
38// The maximum number of glyphs per run; ScriptShape fails on larger values.
39const size_t kMaxGlyphs = 65535;
40
41// Changes |font| to have the specified |font_size| (or |font_height| on Windows
42// XP) and |font_style| if it is not the case already. Only considers bold and
43// italic styles, since the underlined style has no effect on glyph shaping.
44void DeriveFontIfNecessary(int font_size,
45                           int font_height,
46                           int font_style,
47                           Font* font) {
48  const int kStyleMask = (Font::BOLD | Font::ITALIC);
49  const int target_style = (font_style & kStyleMask);
50
51  // On Windows XP, the font must be resized using |font_height| instead of
52  // |font_size| to match GDI behavior.
53  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
54    PlatformFontWin* platform_font =
55        static_cast<PlatformFontWin*>(font->platform_font());
56    *font = platform_font->DeriveFontWithHeight(font_height, target_style);
57    return;
58  }
59
60  const int current_style = (font->GetStyle() & kStyleMask);
61  const int current_size = font->GetFontSize();
62  if (current_style != target_style || current_size != font_size)
63    *font = font->Derive(font_size - current_size, target_style);
64}
65
66// Returns true if |c| is a Unicode BiDi control character.
67bool IsUnicodeBidiControlCharacter(base::char16 c) {
68  return c == base::i18n::kRightToLeftMark ||
69         c == base::i18n::kLeftToRightMark ||
70         c == base::i18n::kLeftToRightEmbeddingMark ||
71         c == base::i18n::kRightToLeftEmbeddingMark ||
72         c == base::i18n::kPopDirectionalFormatting ||
73         c == base::i18n::kLeftToRightOverride ||
74         c == base::i18n::kRightToLeftOverride;
75}
76
77// Returns the corresponding glyph range of the given character range.
78// |range| is in text-space (0 corresponds to |GetLayoutText()[0]|).
79// Returned value is in run-space (0 corresponds to the first glyph in the run).
80Range CharRangeToGlyphRange(const internal::TextRun& run,
81                            const Range& range) {
82  DCHECK(run.range.Contains(range));
83  DCHECK(!range.is_reversed());
84  DCHECK(!range.is_empty());
85  const Range run_range(range.start() - run.range.start(),
86                        range.end() - run.range.start());
87  Range result;
88  if (run.script_analysis.fRTL) {
89    result = Range(run.logical_clusters[run_range.end() - 1],
90        run_range.start() > 0 ? run.logical_clusters[run_range.start() - 1]
91                              : run.glyph_count);
92  } else {
93    result = Range(run.logical_clusters[run_range.start()],
94        run_range.end() < run.range.length() ?
95            run.logical_clusters[run_range.end()] : run.glyph_count);
96  }
97  DCHECK(!result.is_reversed());
98  DCHECK(Range(0, run.glyph_count).Contains(result));
99  return result;
100}
101
102// Starting from |start_char|, finds a suitable line break position at or before
103// |available_width| using word break info from |breaks|. If |empty_line| is
104// true, this function will not roll back to |start_char| and |*next_char| will
105// be greater than |start_char| (to avoid constructing empty lines). Returns
106// whether to skip the line before |*next_char|.
107// TODO(ckocagil): Do not break ligatures and diacritics.
108//                 TextRun::logical_clusters might help.
109// TODO(ckocagil): We might have to reshape after breaking at ligatures.
110//                 See whether resolving the TODO above resolves this too.
111// TODO(ckocagil): Do not reserve width for whitespace at the end of lines.
112bool BreakRunAtWidth(const wchar_t* text,
113                     const internal::TextRun& run,
114                     const BreakList<size_t>& breaks,
115                     size_t start_char,
116                     int available_width,
117                     bool empty_line,
118                     int* width,
119                     size_t* next_char) {
120  DCHECK(run.range.Contains(Range(start_char, start_char + 1)));
121  BreakList<size_t>::const_iterator word = breaks.GetBreak(start_char);
122  BreakList<size_t>::const_iterator next_word = word + 1;
123  // Width from |std::max(word->first, start_char)| to the current character.
124  int word_width = 0;
125  *width = 0;
126
127  for (size_t i = start_char; i < run.range.end(); ++i) {
128    if (U16_IS_SINGLE(text[i]) && text[i] == L'\n') {
129      *next_char = i + 1;
130      return true;
131    }
132
133    // |word| holds the word boundary at or before |i|, and |next_word| holds
134    // the word boundary right after |i|. Advance both |word| and |next_word|
135    // when |i| reaches |next_word|.
136    if (next_word != breaks.breaks().end() && i >= next_word->first) {
137      word = next_word++;
138      word_width = 0;
139    }
140
141    Range glyph_range = CharRangeToGlyphRange(run, Range(i, i + 1));
142    int char_width = 0;
143    for (size_t j = glyph_range.start(); j < glyph_range.end(); ++j)
144      char_width += run.advance_widths[j];
145
146    *width += char_width;
147    word_width += char_width;
148
149    if (*width > available_width) {
150      if (!empty_line || word_width < *width) {
151        // Roll back one word.
152        *width -= word_width;
153        *next_char = std::max(word->first, start_char);
154      } else if (char_width < *width) {
155        // Roll back one character.
156        *width -= char_width;
157        *next_char = i;
158      } else {
159        // Continue from the next character.
160        *next_char = i + 1;
161      }
162
163      return true;
164    }
165  }
166
167  *next_char = run.range.end();
168  return false;
169}
170
171// For segments in the same run, checks the continuity and order of |x_range|
172// and |char_range| fields.
173void CheckLineIntegrity(const std::vector<internal::Line>& lines,
174                        const ScopedVector<internal::TextRun>& runs) {
175  size_t previous_segment_line = 0;
176  const internal::LineSegment* previous_segment = NULL;
177
178  for (size_t i = 0; i < lines.size(); ++i) {
179    for (size_t j = 0; j < lines[i].segments.size(); ++j) {
180      const internal::LineSegment* segment = &lines[i].segments[j];
181      internal::TextRun* run = runs[segment->run];
182
183      if (!previous_segment) {
184        previous_segment = segment;
185      } else if (runs[previous_segment->run] != run) {
186        previous_segment = NULL;
187      } else {
188        DCHECK_EQ(previous_segment->char_range.end(),
189                  segment->char_range.start());
190        if (!run->script_analysis.fRTL) {
191          DCHECK_EQ(previous_segment->x_range.end(), segment->x_range.start());
192        } else {
193          DCHECK_EQ(segment->x_range.end(), previous_segment->x_range.start());
194        }
195
196        previous_segment = segment;
197        previous_segment_line = i;
198      }
199    }
200  }
201}
202
203// Returns true if characters of |block_code| may trigger font fallback.
204bool IsUnusualBlockCode(const UBlockCode block_code) {
205  return block_code == UBLOCK_GEOMETRIC_SHAPES ||
206         block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
207}
208
209// Returns the index of the first unusual character after a usual character or
210// vice versa. Unusual characters are defined by |IsUnusualBlockCode|.
211size_t FindUnusualCharacter(const base::string16& text,
212                            size_t run_start,
213                            size_t run_break) {
214  const int32 run_length = static_cast<int32>(run_break - run_start);
215  base::i18n::UTF16CharIterator iter(text.c_str() + run_start,
216                                     run_length);
217  const UBlockCode first_block_code = ublock_getCode(iter.get());
218  const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
219  while (iter.Advance() && iter.array_pos() < run_length) {
220    const UBlockCode current_block_code = ublock_getCode(iter.get());
221    if (current_block_code != first_block_code &&
222        (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
223      return run_start + iter.array_pos();
224    }
225  }
226  return run_break;
227}
228
229// Callback to |EnumEnhMetaFile()| to intercept font creation.
230int CALLBACK MetaFileEnumProc(HDC hdc,
231                              HANDLETABLE* table,
232                              CONST ENHMETARECORD* record,
233                              int table_entries,
234                              LPARAM log_font) {
235  if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
236    const EMREXTCREATEFONTINDIRECTW* create_font_record =
237        reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
238    *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
239  }
240  return 1;
241}
242
243// Finds a fallback font to use to render the specified |text| with respect to
244// an initial |font|. Returns the resulting font via out param |result|. Returns
245// |true| if a fallback font was found.
246// Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
247// TODO(asvitkine): This should be moved to font_fallback_win.cc.
248bool ChooseFallbackFont(HDC hdc,
249                        const Font& font,
250                        const wchar_t* text,
251                        int text_length,
252                        Font* result) {
253  // Use a meta file to intercept the fallback font chosen by Uniscribe.
254  HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
255  if (!meta_file_dc)
256    return false;
257
258  SelectObject(meta_file_dc, font.GetNativeFont());
259
260  SCRIPT_STRING_ANALYSIS script_analysis;
261  HRESULT hresult =
262      ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
263                          SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
264                          0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
265
266  if (SUCCEEDED(hresult)) {
267    hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
268    ScriptStringFree(&script_analysis);
269  }
270
271  bool found_fallback = false;
272  HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
273  if (SUCCEEDED(hresult)) {
274    LOGFONT log_font;
275    log_font.lfFaceName[0] = 0;
276    EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
277    if (log_font.lfFaceName[0]) {
278      *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
279                     font.GetFontSize());
280      found_fallback = true;
281    }
282  }
283  DeleteEnhMetaFile(meta_file);
284
285  return found_fallback;
286}
287
288}  // namespace
289
290namespace internal {
291
292TextRun::TextRun()
293  : font_style(0),
294    strike(false),
295    diagonal_strike(false),
296    underline(false),
297    width(0),
298    preceding_run_widths(0),
299    glyph_count(0),
300    script_cache(NULL) {
301  memset(&script_analysis, 0, sizeof(script_analysis));
302  memset(&abc_widths, 0, sizeof(abc_widths));
303}
304
305TextRun::~TextRun() {
306  ScriptFreeCache(&script_cache);
307}
308
309// Returns the X coordinate of the leading or |trailing| edge of the glyph
310// starting at |index|, relative to the left of the text (not the view).
311int GetGlyphXBoundary(const internal::TextRun* run,
312                      size_t index,
313                      bool trailing) {
314  DCHECK_GE(index, run->range.start());
315  DCHECK_LT(index, run->range.end() + (trailing ? 0 : 1));
316  int x = 0;
317  HRESULT hr = ScriptCPtoX(
318      index - run->range.start(),
319      trailing,
320      run->range.length(),
321      run->glyph_count,
322      run->logical_clusters.get(),
323      run->visible_attributes.get(),
324      run->advance_widths.get(),
325      &run->script_analysis,
326      &x);
327  DCHECK(SUCCEEDED(hr));
328  return run->preceding_run_widths + x;
329}
330
331// Internal class to generate Line structures. If |multiline| is true, the text
332// is broken into lines at |words| boundaries such that each line is no longer
333// than |max_width|. If |multiline| is false, only outputs a single Line from
334// the given runs. |min_baseline| and |min_height| are the minimum baseline and
335// height for each line.
336// TODO(ckocagil): Expose the interface of this class in the header and test
337//                 this class directly.
338class LineBreaker {
339 public:
340  LineBreaker(int max_width,
341              int min_baseline,
342              int min_height,
343              bool multiline,
344              const wchar_t* text,
345              const BreakList<size_t>* words,
346              const ScopedVector<TextRun>& runs)
347      : max_width_(max_width),
348        min_baseline_(min_baseline),
349        min_height_(min_height),
350        multiline_(multiline),
351        text_(text),
352        words_(words),
353        runs_(runs),
354        text_x_(0),
355        line_x_(0),
356        line_ascent_(0),
357        line_descent_(0) {
358    AdvanceLine();
359  }
360
361  // Breaks the run at given |run_index| into Line structs.
362  void AddRun(int run_index) {
363    const TextRun* run = runs_[run_index];
364    bool run_fits = !multiline_;
365    if (multiline_ && line_x_ + run->width <= max_width_) {
366      DCHECK(!run->range.is_empty());
367      const wchar_t first_char = text_[run->range.start()];
368      // Uniscribe always puts newline characters in their own runs.
369      if (!U16_IS_SINGLE(first_char) || first_char != L'\n')
370        run_fits = true;
371    }
372
373    if (!run_fits)
374      BreakRun(run_index);
375    else
376      AddSegment(run_index, run->range, run->width);
377  }
378
379  // Finishes line breaking and outputs the results. Can be called at most once.
380  void Finalize(std::vector<Line>* lines, Size* size) {
381    DCHECK(!lines_.empty());
382    // Add an empty line to finish the line size calculation and remove it.
383    AdvanceLine();
384    lines_.pop_back();
385    *size = total_size_;
386    lines->swap(lines_);
387  }
388
389 private:
390  // A (line index, segment index) pair that specifies a segment in |lines_|.
391  typedef std::pair<size_t, size_t> SegmentHandle;
392
393  LineSegment* SegmentFromHandle(const SegmentHandle& handle) {
394    return &lines_[handle.first].segments[handle.second];
395  }
396
397  // Breaks a run into segments that fit in the last line in |lines_| and adds
398  // them. Adds a new Line to the back of |lines_| whenever a new segment can't
399  // be added without the Line's width exceeding |max_width_|.
400  void BreakRun(int run_index) {
401    DCHECK(words_);
402    const TextRun* const run = runs_[run_index];
403    int width = 0;
404    size_t next_char = run->range.start();
405
406    // Break the run until it fits the current line.
407    while (next_char < run->range.end()) {
408      const size_t current_char = next_char;
409      const bool skip_line = BreakRunAtWidth(text_, *run, *words_, current_char,
410          max_width_ - line_x_, line_x_ == 0, &width, &next_char);
411      AddSegment(run_index, Range(current_char, next_char), width);
412      if (skip_line)
413        AdvanceLine();
414    }
415  }
416
417  // RTL runs are broken in logical order but displayed in visual order. To find
418  // the text-space coordinate (where it would fall in a single-line text)
419  // |x_range| of RTL segments, segment widths are applied in reverse order.
420  // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}.
421  void UpdateRTLSegmentRanges() {
422    if (rtl_segments_.empty())
423      return;
424    int x = SegmentFromHandle(rtl_segments_[0])->x_range.start();
425    for (size_t i = rtl_segments_.size(); i > 0; --i) {
426      LineSegment* segment = SegmentFromHandle(rtl_segments_[i - 1]);
427      const size_t segment_width = segment->x_range.length();
428      segment->x_range = Range(x, x + segment_width);
429      x += segment_width;
430    }
431    rtl_segments_.clear();
432  }
433
434  // Finishes the size calculations of the last Line in |lines_|. Adds a new
435  // Line to the back of |lines_|.
436  void AdvanceLine() {
437    if (!lines_.empty()) {
438      Line* line = &lines_.back();
439      // TODO(ckocagil): Determine optimal multiline height behavior.
440      if (line_ascent_ + line_descent_ == 0) {
441        line_ascent_ = min_baseline_;
442        line_descent_ = min_height_ - min_baseline_;
443      }
444      // Set the single-line mode Line's metrics to be at least
445      // |RenderText::font_list()| to not break the current single-line code.
446      line_ascent_ = std::max(line_ascent_, min_baseline_);
447      line_descent_ = std::max(line_descent_, min_height_ - min_baseline_);
448
449      line->baseline = line_ascent_;
450      line->size.set_height(line_ascent_ + line_descent_);
451      line->preceding_heights = total_size_.height();
452      const Size line_size(ToCeiledSize(line->size));
453      total_size_.set_height(total_size_.height() + line_size.height());
454      total_size_.set_width(std::max(total_size_.width(), line_size.width()));
455    }
456    line_x_ = 0;
457    line_ascent_ = 0;
458    line_descent_ = 0;
459    lines_.push_back(Line());
460  }
461
462  // Adds a new segment with the given properties to |lines_.back()|.
463  void AddSegment(int run_index, Range char_range, int width) {
464    if (char_range.is_empty()) {
465      DCHECK_EQ(width, 0);
466      return;
467    }
468    const TextRun* run = runs_[run_index];
469    line_ascent_ = std::max(line_ascent_, run->font.GetBaseline());
470    line_descent_ = std::max(line_descent_,
471                             run->font.GetHeight() - run->font.GetBaseline());
472
473    LineSegment segment;
474    segment.run = run_index;
475    segment.char_range = char_range;
476    segment.x_range = Range(text_x_, text_x_ + width);
477
478    Line* line = &lines_.back();
479    line->segments.push_back(segment);
480    line->size.set_width(line->size.width() + segment.x_range.length());
481    if (run->script_analysis.fRTL) {
482      rtl_segments_.push_back(SegmentHandle(lines_.size() - 1,
483                                            line->segments.size() - 1));
484      // If this is the last segment of an RTL run, reprocess the text-space x
485      // ranges of all segments from the run.
486      if (char_range.end() == run->range.end())
487        UpdateRTLSegmentRanges();
488    }
489    text_x_ += width;
490    line_x_ += width;
491  }
492
493  const int max_width_;
494  const int min_baseline_;
495  const int min_height_;
496  const bool multiline_;
497  const wchar_t* text_;
498  const BreakList<size_t>* const words_;
499  const ScopedVector<TextRun>& runs_;
500
501  // Stores the resulting lines.
502  std::vector<Line> lines_;
503
504  // Text space and line space x coordinates of the next segment to be added.
505  int text_x_;
506  int line_x_;
507
508  // Size of the multiline text, not including the currently processed line.
509  Size total_size_;
510
511  // Ascent and descent values of the current line, |lines_.back()|.
512  int line_ascent_;
513  int line_descent_;
514
515  // The current RTL run segments, to be applied by |UpdateRTLSegmentRanges()|.
516  std::vector<SegmentHandle> rtl_segments_;
517
518  DISALLOW_COPY_AND_ASSIGN(LineBreaker);
519};
520
521}  // namespace internal
522
523// static
524HDC RenderTextWin::cached_hdc_ = NULL;
525
526// static
527std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
528
529RenderTextWin::RenderTextWin() : RenderText(), needs_layout_(false) {
530  set_truncate_length(kMaxUniscribeTextLength);
531  memset(&script_control_, 0, sizeof(script_control_));
532  memset(&script_state_, 0, sizeof(script_state_));
533  MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
534}
535
536RenderTextWin::~RenderTextWin() {}
537
538Size RenderTextWin::GetStringSize() {
539  EnsureLayout();
540  return multiline_string_size_;
541}
542
543SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
544  if (text().empty())
545    return SelectionModel();
546
547  EnsureLayout();
548  // Find the run that contains the point and adjust the argument location.
549  int x = ToTextPoint(point).x();
550  size_t run_index = GetRunContainingXCoord(x);
551  if (run_index >= runs_.size())
552    return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
553  internal::TextRun* run = runs_[run_index];
554
555  int position = 0, trailing = 0;
556  HRESULT hr = ScriptXtoCP(x - run->preceding_run_widths,
557                           run->range.length(),
558                           run->glyph_count,
559                           run->logical_clusters.get(),
560                           run->visible_attributes.get(),
561                           run->advance_widths.get(),
562                           &(run->script_analysis),
563                           &position,
564                           &trailing);
565  DCHECK(SUCCEEDED(hr));
566  DCHECK_GE(trailing, 0);
567  position += run->range.start();
568  const size_t cursor = LayoutIndexToTextIndex(position + trailing);
569  DCHECK_LE(cursor, text().length());
570  return SelectionModel(cursor, trailing ? CURSOR_BACKWARD : CURSOR_FORWARD);
571}
572
573std::vector<RenderText::FontSpan> RenderTextWin::GetFontSpansForTesting() {
574  EnsureLayout();
575
576  std::vector<RenderText::FontSpan> spans;
577  for (size_t i = 0; i < runs_.size(); ++i) {
578    spans.push_back(RenderText::FontSpan(runs_[i]->font,
579        Range(LayoutIndexToTextIndex(runs_[i]->range.start()),
580              LayoutIndexToTextIndex(runs_[i]->range.end()))));
581  }
582
583  return spans;
584}
585
586int RenderTextWin::GetLayoutTextBaseline() {
587  EnsureLayout();
588  return lines()[0].baseline;
589}
590
591SelectionModel RenderTextWin::AdjacentCharSelectionModel(
592    const SelectionModel& selection,
593    VisualCursorDirection direction) {
594  DCHECK(!needs_layout_);
595  internal::TextRun* run;
596  size_t run_index = GetRunContainingCaret(selection);
597  if (run_index >= runs_.size()) {
598    // The cursor is not in any run: we're at the visual and logical edge.
599    SelectionModel edge = EdgeSelectionModel(direction);
600    if (edge.caret_pos() == selection.caret_pos())
601      return edge;
602    int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1;
603    run = runs_[visual_to_logical_[visual_index]];
604  } else {
605    // If the cursor is moving within the current run, just move it by one
606    // grapheme in the appropriate direction.
607    run = runs_[run_index];
608    size_t caret = selection.caret_pos();
609    bool forward_motion =
610        run->script_analysis.fRTL == (direction == CURSOR_LEFT);
611    if (forward_motion) {
612      if (caret < LayoutIndexToTextIndex(run->range.end())) {
613        caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
614        return SelectionModel(caret, CURSOR_BACKWARD);
615      }
616    } else {
617      if (caret > LayoutIndexToTextIndex(run->range.start())) {
618        caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
619        return SelectionModel(caret, CURSOR_FORWARD);
620      }
621    }
622    // The cursor is at the edge of a run; move to the visually adjacent run.
623    int visual_index = logical_to_visual_[run_index];
624    visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
625    if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size()))
626      return EdgeSelectionModel(direction);
627    run = runs_[visual_to_logical_[visual_index]];
628  }
629  bool forward_motion = run->script_analysis.fRTL == (direction == CURSOR_LEFT);
630  return forward_motion ? FirstSelectionModelInsideRun(run) :
631                          LastSelectionModelInsideRun(run);
632}
633
634// TODO(msw): Implement word breaking for Windows.
635SelectionModel RenderTextWin::AdjacentWordSelectionModel(
636    const SelectionModel& selection,
637    VisualCursorDirection direction) {
638  if (obscured())
639    return EdgeSelectionModel(direction);
640
641  base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
642  bool success = iter.Init();
643  DCHECK(success);
644  if (!success)
645    return selection;
646
647  size_t pos;
648  if (direction == CURSOR_RIGHT) {
649    pos = std::min(selection.caret_pos() + 1, text().length());
650    while (iter.Advance()) {
651      pos = iter.pos();
652      if (iter.IsWord() && pos > selection.caret_pos())
653        break;
654    }
655  } else {  // direction == CURSOR_LEFT
656    // Notes: We always iterate words from the beginning.
657    // This is probably fast enough for our usage, but we may
658    // want to modify WordIterator so that it can start from the
659    // middle of string and advance backwards.
660    pos = std::max<int>(selection.caret_pos() - 1, 0);
661    while (iter.Advance()) {
662      if (iter.IsWord()) {
663        size_t begin = iter.pos() - iter.GetString().length();
664        if (begin == selection.caret_pos()) {
665          // The cursor is at the beginning of a word.
666          // Move to previous word.
667          break;
668        } else if (iter.pos() >= selection.caret_pos()) {
669          // The cursor is in the middle or at the end of a word.
670          // Move to the top of current word.
671          pos = begin;
672          break;
673        } else {
674          pos = iter.pos() - iter.GetString().length();
675        }
676      }
677    }
678  }
679  return SelectionModel(pos, CURSOR_FORWARD);
680}
681
682Range RenderTextWin::GetGlyphBounds(size_t index) {
683  EnsureLayout();
684  const size_t run_index =
685      GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
686  // Return edge bounds if the index is invalid or beyond the layout text size.
687  if (run_index >= runs_.size())
688    return Range(string_width_);
689  internal::TextRun* run = runs_[run_index];
690  const size_t layout_index = TextIndexToLayoutIndex(index);
691  return Range(GetGlyphXBoundary(run, layout_index, false),
692               GetGlyphXBoundary(run, layout_index, true));
693}
694
695std::vector<Rect> RenderTextWin::GetSubstringBounds(const Range& range) {
696  DCHECK(!needs_layout_);
697  DCHECK(Range(0, text().length()).Contains(range));
698  Range layout_range(TextIndexToLayoutIndex(range.start()),
699                     TextIndexToLayoutIndex(range.end()));
700  DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range));
701
702  std::vector<Rect> rects;
703  if (layout_range.is_empty())
704    return rects;
705  std::vector<Range> bounds;
706
707  // Add a Range for each run/selection intersection.
708  // TODO(msw): The bounds should probably not always be leading the range ends.
709  for (size_t i = 0; i < runs_.size(); ++i) {
710    const internal::TextRun* run = runs_[visual_to_logical_[i]];
711    Range intersection = run->range.Intersect(layout_range);
712    if (intersection.IsValid()) {
713      DCHECK(!intersection.is_reversed());
714      Range range_x(GetGlyphXBoundary(run, intersection.start(), false),
715                    GetGlyphXBoundary(run, intersection.end(), false));
716      if (range_x.is_empty())
717        continue;
718      range_x = Range(range_x.GetMin(), range_x.GetMax());
719      // Union this with the last range if they're adjacent.
720      DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin());
721      if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
722        range_x = Range(bounds.back().GetMin(), range_x.GetMax());
723        bounds.pop_back();
724      }
725      bounds.push_back(range_x);
726    }
727  }
728  for (size_t i = 0; i < bounds.size(); ++i) {
729    std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]);
730    rects.insert(rects.end(), current_rects.begin(), current_rects.end());
731  }
732  return rects;
733}
734
735size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
736  DCHECK_LE(index, text().length());
737  ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
738  CHECK_GE(i, 0);
739  // Clamp layout indices to the length of the text actually used for layout.
740  return std::min<size_t>(GetLayoutText().length(), i);
741}
742
743size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const {
744  if (!obscured())
745    return index;
746
747  DCHECK_LE(index, GetLayoutText().length());
748  const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
749  DCHECK_LE(text_index, text().length());
750  return text_index;
751}
752
753bool RenderTextWin::IsValidCursorIndex(size_t index) {
754  if (index == 0 || index == text().length())
755    return true;
756  if (!IsValidLogicalIndex(index))
757    return false;
758  EnsureLayout();
759  // Disallow indices amid multi-character graphemes by checking glyph bounds.
760  // These characters are not surrogate-pairs, but may yield a single glyph:
761  //   \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
762  //   \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair.
763  return GetGlyphBounds(index) != GetGlyphBounds(index - 1);
764}
765
766void RenderTextWin::ResetLayout() {
767  // Layout is performed lazily as needed for drawing/metrics.
768  needs_layout_ = true;
769}
770
771void RenderTextWin::EnsureLayout() {
772  if (needs_layout_) {
773    // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
774    ItemizeLogicalText();
775    if (!runs_.empty())
776      LayoutVisualText();
777    needs_layout_ = false;
778    std::vector<internal::Line> lines;
779    set_lines(&lines);
780  }
781
782  // Compute lines if they're not valid. This is separate from the layout steps
783  // above to avoid text layout and shaping when we resize |display_rect_|.
784  if (lines().empty()) {
785    DCHECK(!needs_layout_);
786    std::vector<internal::Line> lines;
787    internal::LineBreaker line_breaker(display_rect().width() - 1,
788                                       font_list().GetBaseline(),
789                                       font_list().GetHeight(), multiline(),
790                                       GetLayoutText().c_str(),
791                                       multiline() ? &GetLineBreaks() : NULL,
792                                       runs_);
793    for (size_t i = 0; i < runs_.size(); ++i)
794      line_breaker.AddRun(visual_to_logical_[i]);
795    line_breaker.Finalize(&lines, &multiline_string_size_);
796    DCHECK(!lines.empty());
797#ifndef NDEBUG
798    CheckLineIntegrity(lines, runs_);
799#endif
800    set_lines(&lines);
801  }
802}
803
804void RenderTextWin::DrawVisualText(Canvas* canvas) {
805  DCHECK(!needs_layout_);
806  DCHECK(!lines().empty());
807
808  std::vector<SkPoint> pos;
809
810  internal::SkiaTextRenderer renderer(canvas);
811  ApplyFadeEffects(&renderer);
812  ApplyTextShadows(&renderer);
813
814  renderer.SetFontRenderParams(
815      font_list().GetPrimaryFont().GetFontRenderParams(),
816      background_is_transparent());
817
818  ApplyCompositionAndSelectionStyles();
819
820  for (size_t i = 0; i < lines().size(); ++i) {
821    const internal::Line& line = lines()[i];
822    const Vector2d line_offset = GetLineOffset(i);
823
824    // Skip painting empty lines or lines outside the display rect area.
825    if (!display_rect().Intersects(Rect(PointAtOffsetFromOrigin(line_offset),
826                                        ToCeiledSize(line.size))))
827      continue;
828
829    const Vector2d text_offset = line_offset + Vector2d(0, line.baseline);
830    int preceding_segment_widths = 0;
831
832    for (size_t j = 0; j < line.segments.size(); ++j) {
833      const internal::LineSegment* segment = &line.segments[j];
834      const int segment_width = segment->x_range.length();
835      const internal::TextRun* run = runs_[segment->run];
836      DCHECK(!segment->char_range.is_empty());
837      DCHECK(run->range.Contains(segment->char_range));
838      Range glyph_range = CharRangeToGlyphRange(*run, segment->char_range);
839      DCHECK(!glyph_range.is_empty());
840      // Skip painting segments outside the display rect area.
841      if (!multiline()) {
842        const Rect segment_bounds(PointAtOffsetFromOrigin(line_offset) +
843                                      Vector2d(preceding_segment_widths, 0),
844                                  Size(segment_width, line.size.height()));
845        if (!display_rect().Intersects(segment_bounds)) {
846          preceding_segment_widths += segment_width;
847          continue;
848        }
849      }
850
851      // |pos| contains the positions of glyphs. An extra terminal |pos| entry
852      // is added to simplify width calculations.
853      int segment_x = preceding_segment_widths;
854      pos.resize(glyph_range.length() + 1);
855      for (size_t k = glyph_range.start(); k < glyph_range.end(); ++k) {
856        pos[k - glyph_range.start()].set(
857            SkIntToScalar(text_offset.x() + run->offsets[k].du + segment_x),
858            SkIntToScalar(text_offset.y() - run->offsets[k].dv));
859        segment_x += run->advance_widths[k];
860      }
861      pos.back().set(SkIntToScalar(text_offset.x() + segment_x),
862                     SkIntToScalar(text_offset.y()));
863
864      renderer.SetTextSize(run->font.GetFontSize());
865      renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
866
867      for (BreakList<SkColor>::const_iterator it =
868               colors().GetBreak(segment->char_range.start());
869           it != colors().breaks().end() &&
870               it->first < segment->char_range.end();
871           ++it) {
872        const Range intersection =
873            colors().GetRange(it).Intersect(segment->char_range);
874        const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection);
875        // The range may be empty if a portion of a multi-character grapheme is
876        // selected, yielding two colors for a single glyph. For now, this just
877        // paints the glyph with a single style, but it should paint it twice,
878        // clipped according to selection bounds. See http://crbug.com/366786
879        if (colored_glyphs.is_empty())
880          continue;
881        DCHECK(glyph_range.Contains(colored_glyphs));
882        const SkPoint& start_pos =
883            pos[colored_glyphs.start() - glyph_range.start()];
884        const SkPoint& end_pos =
885            pos[colored_glyphs.end() - glyph_range.start()];
886
887        renderer.SetForegroundColor(it->second);
888        renderer.DrawPosText(&start_pos, &run->glyphs[colored_glyphs.start()],
889                             colored_glyphs.length());
890        renderer.DrawDecorations(start_pos.x(), text_offset.y(),
891                                 SkScalarCeilToInt(end_pos.x() - start_pos.x()),
892                                 run->underline, run->strike,
893                                 run->diagonal_strike);
894      }
895
896      preceding_segment_widths += segment_width;
897    }
898
899    renderer.EndDiagonalStrike();
900  }
901
902  UndoCompositionAndSelectionStyles();
903}
904
905void RenderTextWin::ItemizeLogicalText() {
906  runs_.clear();
907  string_width_ = 0;
908  multiline_string_size_ = Size();
909
910  // Set Uniscribe's base text direction.
911  script_state_.uBidiLevel =
912      (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0;
913
914  const base::string16& layout_text = GetLayoutText();
915  if (layout_text.empty())
916    return;
917
918  HRESULT hr = E_OUTOFMEMORY;
919  int script_items_count = 0;
920  std::vector<SCRIPT_ITEM> script_items;
921  const size_t layout_text_length = layout_text.length();
922  // Ensure that |kMaxRuns| is attempted and the loop terminates afterward.
923  for (size_t runs = kGuessRuns; hr == E_OUTOFMEMORY && runs <= kMaxRuns;
924       runs = std::max(runs + 1, std::min(runs * 2, kMaxRuns))) {
925    // Derive the array of Uniscribe script items from the logical text.
926    // ScriptItemize always adds a terminal array item so that the length of
927    // the last item can be derived from the terminal SCRIPT_ITEM::iCharPos.
928    script_items.resize(runs);
929    hr = ScriptItemize(layout_text.c_str(), layout_text_length, runs - 1,
930                       &script_control_, &script_state_, &script_items[0],
931                       &script_items_count);
932  }
933  DCHECK(SUCCEEDED(hr));
934  if (!SUCCEEDED(hr) || script_items_count <= 0)
935    return;
936
937  // Temporarily apply composition underlines and selection colors.
938  ApplyCompositionAndSelectionStyles();
939
940  // Build the list of runs from the script items and ranged styles. Use an
941  // empty color BreakList to avoid breaking runs at color boundaries.
942  BreakList<SkColor> empty_colors;
943  empty_colors.SetMax(layout_text_length);
944  internal::StyleIterator style(empty_colors, styles());
945  SCRIPT_ITEM* script_item = &script_items[0];
946  const size_t max_run_length = kMaxGlyphs / 2;
947  for (size_t run_break = 0; run_break < layout_text_length;) {
948    internal::TextRun* run = new internal::TextRun();
949    run->range.set_start(run_break);
950    run->font = font_list().GetPrimaryFont();
951    run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
952                      (style.style(ITALIC) ? Font::ITALIC : 0);
953    DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(),
954                          run->font_style, &run->font);
955    run->strike = style.style(STRIKE);
956    run->diagonal_strike = style.style(DIAGONAL_STRIKE);
957    run->underline = style.style(UNDERLINE);
958    run->script_analysis = script_item->a;
959
960    // Find the next break and advance the iterators as needed.
961    const size_t script_item_break = (script_item + 1)->iCharPos;
962    run_break = std::min(script_item_break,
963                         TextIndexToLayoutIndex(style.GetRange().end()));
964
965    // Clamp run lengths to avoid exceeding the maximum supported glyph count.
966    if ((run_break - run->range.start()) > max_run_length) {
967      run_break = run->range.start() + max_run_length;
968      if (!IsValidCodePointIndex(layout_text, run_break))
969        --run_break;
970    }
971
972    // Break runs adjacent to character substrings in certain code blocks.
973    // This avoids using their fallback fonts for more characters than needed,
974    // in cases like "\x25B6 Media Title", etc. http://crbug.com/278913
975    if (run_break > run->range.start()) {
976      run_break =
977          FindUnusualCharacter(layout_text, run->range.start(), run_break);
978    }
979
980    DCHECK(IsValidCodePointIndex(layout_text, run_break));
981
982    style.UpdatePosition(LayoutIndexToTextIndex(run_break));
983    if (script_item_break == run_break)
984      script_item++;
985    run->range.set_end(run_break);
986    runs_.push_back(run);
987  }
988
989  // Undo the temporarily applied composition underlines and selection colors.
990  UndoCompositionAndSelectionStyles();
991}
992
993void RenderTextWin::LayoutVisualText() {
994  DCHECK(!runs_.empty());
995
996  if (!cached_hdc_)
997    cached_hdc_ = CreateCompatibleDC(NULL);
998
999  HRESULT hr = E_FAIL;
1000  // Ensure ascent and descent are not smaller than ones of the font list.
1001  // Keep them tall enough to draw often-used characters.
1002  // For example, if a text field contains a Japanese character, which is
1003  // smaller than Latin ones, and then later a Latin one is inserted, this
1004  // ensures that the text baseline does not shift.
1005  int ascent = font_list().GetBaseline();
1006  int descent = font_list().GetHeight() - font_list().GetBaseline();
1007  for (size_t i = 0; i < runs_.size(); ++i) {
1008    internal::TextRun* run = runs_[i];
1009    LayoutTextRun(run);
1010
1011    ascent = std::max(ascent, run->font.GetBaseline());
1012    descent = std::max(descent,
1013                       run->font.GetHeight() - run->font.GetBaseline());
1014
1015    if (run->glyph_count > 0) {
1016      run->advance_widths.reset(new int[run->glyph_count]);
1017      run->offsets.reset(new GOFFSET[run->glyph_count]);
1018      hr = ScriptPlace(cached_hdc_,
1019                       &run->script_cache,
1020                       run->glyphs.get(),
1021                       run->glyph_count,
1022                       run->visible_attributes.get(),
1023                       &(run->script_analysis),
1024                       run->advance_widths.get(),
1025                       run->offsets.get(),
1026                       &(run->abc_widths));
1027      DCHECK(SUCCEEDED(hr));
1028    }
1029  }
1030
1031  // Build the array of bidirectional embedding levels.
1032  scoped_ptr<BYTE[]> levels(new BYTE[runs_.size()]);
1033  for (size_t i = 0; i < runs_.size(); ++i)
1034    levels[i] = runs_[i]->script_analysis.s.uBidiLevel;
1035
1036  // Get the maps between visual and logical run indices.
1037  visual_to_logical_.reset(new int[runs_.size()]);
1038  logical_to_visual_.reset(new int[runs_.size()]);
1039  hr = ScriptLayout(runs_.size(),
1040                    levels.get(),
1041                    visual_to_logical_.get(),
1042                    logical_to_visual_.get());
1043  DCHECK(SUCCEEDED(hr));
1044
1045  // Precalculate run width information.
1046  size_t preceding_run_widths = 0;
1047  for (size_t i = 0; i < runs_.size(); ++i) {
1048    internal::TextRun* run = runs_[visual_to_logical_[i]];
1049    run->preceding_run_widths = preceding_run_widths;
1050    const ABC& abc = run->abc_widths;
1051    run->width = abc.abcA + abc.abcB + abc.abcC;
1052    preceding_run_widths += run->width;
1053  }
1054  string_width_ = preceding_run_widths;
1055}
1056
1057void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
1058  const size_t run_length = run->range.length();
1059  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1060  Font original_font = run->font;
1061  internal::LinkedFontsIterator fonts(original_font);
1062  bool tried_cached_font = false;
1063  bool tried_fallback = false;
1064  // Keep track of the font that is able to display the greatest number of
1065  // characters for which ScriptShape() returned S_OK. This font will be used
1066  // in the case where no font is able to display the entire run.
1067  int best_partial_font_missing_char_count = INT_MAX;
1068  Font best_partial_font = original_font;
1069  Font current_font;
1070
1071  run->logical_clusters.reset(new WORD[run_length]);
1072  while (fonts.NextFont(&current_font)) {
1073    HRESULT hr = ShapeTextRunWithFont(run, current_font);
1074
1075    bool glyphs_missing = false;
1076    if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
1077      glyphs_missing = true;
1078    } else if (hr == S_OK) {
1079      // If |hr| is S_OK, there could still be missing glyphs in the output.
1080      // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx
1081      const int missing_count = CountCharsWithMissingGlyphs(run);
1082      // Track the font that produced the least missing glyphs.
1083      if (missing_count < best_partial_font_missing_char_count) {
1084        best_partial_font_missing_char_count = missing_count;
1085        best_partial_font = run->font;
1086      }
1087      glyphs_missing = (missing_count != 0);
1088    } else {
1089      NOTREACHED() << hr;
1090    }
1091
1092    // Use the font if it had glyphs for all characters.
1093    if (!glyphs_missing) {
1094      // Save the successful fallback font that was chosen.
1095      if (tried_fallback)
1096        successful_substitute_fonts_[original_font.GetFontName()] = run->font;
1097      return;
1098    }
1099
1100    // First, try the cached font from previous runs, if any.
1101    if (!tried_cached_font) {
1102      tried_cached_font = true;
1103
1104      std::map<std::string, Font>::const_iterator it =
1105          successful_substitute_fonts_.find(original_font.GetFontName());
1106      if (it != successful_substitute_fonts_.end()) {
1107        fonts.SetNextFont(it->second);
1108        continue;
1109      }
1110    }
1111
1112    // If there are missing glyphs, first try finding a fallback font using a
1113    // meta file, if it hasn't yet been attempted for this run.
1114    // TODO(msw|asvitkine): Support RenderText's font_list()?
1115    if (!tried_fallback) {
1116      tried_fallback = true;
1117
1118      Font fallback_font;
1119      if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length,
1120                             &fallback_font)) {
1121        fonts.SetNextFont(fallback_font);
1122        continue;
1123      }
1124    }
1125  }
1126
1127  // If a font was able to partially display the run, use that now.
1128  if (best_partial_font_missing_char_count < static_cast<int>(run_length)) {
1129    // Re-shape the run only if |best_partial_font| differs from the last font.
1130    if (best_partial_font.GetNativeFont() != run->font.GetNativeFont())
1131      ShapeTextRunWithFont(run, best_partial_font);
1132    return;
1133  }
1134
1135  // If no font was able to partially display the run, replace all glyphs
1136  // with |wgDefault| from the original font to ensure to they don't hold
1137  // garbage values.
1138  // First, clear the cache and select the original font on the HDC.
1139  ScriptFreeCache(&run->script_cache);
1140  run->font = original_font;
1141  SelectObject(cached_hdc_, run->font.GetNativeFont());
1142
1143  // Now, get the font's properties.
1144  SCRIPT_FONTPROPERTIES properties;
1145  memset(&properties, 0, sizeof(properties));
1146  properties.cBytes = sizeof(properties);
1147  HRESULT hr = ScriptGetFontProperties(cached_hdc_, &run->script_cache,
1148                                       &properties);
1149
1150  // The initial values for the "missing" glyph and the space glyph are taken
1151  // from the recommendations section of the OpenType spec:
1152  // https://www.microsoft.com/typography/otspec/recom.htm
1153  WORD missing_glyph = 0;
1154  WORD space_glyph = 3;
1155  if (hr == S_OK) {
1156    missing_glyph = properties.wgDefault;
1157    space_glyph = properties.wgBlank;
1158  }
1159
1160  // Finally, initialize |glyph_count|, |glyphs|, |visible_attributes| and
1161  // |logical_clusters| on the run (since they may not have been set yet).
1162  run->glyph_count = run_length;
1163  memset(run->visible_attributes.get(), 0,
1164         run->glyph_count * sizeof(SCRIPT_VISATTR));
1165  for (int i = 0; i < run->glyph_count; ++i)
1166    run->glyphs[i] = IsWhitespace(run_text[i]) ? space_glyph : missing_glyph;
1167  for (size_t i = 0; i < run_length; ++i) {
1168    run->logical_clusters[i] = run->script_analysis.fRTL ?
1169        run_length - 1 - i : i;
1170  }
1171
1172  // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can
1173  //            crash on certain surrogate pairs with SCRIPT_UNDEFINED.
1174  //            See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
1175  //            And http://maxradi.us/documents/uniscribe/
1176  run->script_analysis.eScript = SCRIPT_UNDEFINED;
1177}
1178
1179HRESULT RenderTextWin::ShapeTextRunWithFont(internal::TextRun* run,
1180                                            const Font& font) {
1181  // Update the run's font only if necessary. If the two fonts wrap the same
1182  // PlatformFontWin object, their native fonts will have the same value.
1183  if (run->font.GetNativeFont() != font.GetNativeFont()) {
1184    const int font_size = run->font.GetFontSize();
1185    const int font_height = run->font.GetHeight();
1186    run->font = font;
1187    DeriveFontIfNecessary(font_size, font_height, run->font_style, &run->font);
1188    ScriptFreeCache(&run->script_cache);
1189  }
1190
1191  // Select the font desired for glyph generation.
1192  SelectObject(cached_hdc_, run->font.GetNativeFont());
1193
1194  HRESULT hr = E_OUTOFMEMORY;
1195  const size_t run_length = run->range.length();
1196  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1197  // Guess the expected number of glyphs from the length of the run.
1198  // MSDN suggests this at http://msdn.microsoft.com/en-us/library/dd368564.aspx
1199  size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
1200  while (hr == E_OUTOFMEMORY && max_glyphs <= kMaxGlyphs) {
1201    run->glyph_count = 0;
1202    run->glyphs.reset(new WORD[max_glyphs]);
1203    run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
1204    hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length,
1205                     max_glyphs, &run->script_analysis, run->glyphs.get(),
1206                     run->logical_clusters.get(), run->visible_attributes.get(),
1207                     &run->glyph_count);
1208    // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward.
1209    max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs));
1210  }
1211  return hr;
1212}
1213
1214int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run) const {
1215  int chars_not_missing_glyphs = 0;
1216  SCRIPT_FONTPROPERTIES properties;
1217  memset(&properties, 0, sizeof(properties));
1218  properties.cBytes = sizeof(properties);
1219  ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties);
1220
1221  const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1222  for (size_t char_index = 0; char_index < run->range.length(); ++char_index) {
1223    const int glyph_index = run->logical_clusters[char_index];
1224    DCHECK_GE(glyph_index, 0);
1225    DCHECK_LT(glyph_index, run->glyph_count);
1226
1227    if (run->glyphs[glyph_index] == properties.wgDefault)
1228      continue;
1229
1230    // Windows Vista sometimes returns glyphs equal to wgBlank (instead of
1231    // wgDefault), with fZeroWidth set. Treat such cases as having missing
1232    // glyphs if the corresponding character is not whitespace.
1233    // See: http://crbug.com/125629
1234    if (run->glyphs[glyph_index] == properties.wgBlank &&
1235        run->visible_attributes[glyph_index].fZeroWidth &&
1236        !IsWhitespace(run_text[char_index]) &&
1237        !IsUnicodeBidiControlCharacter(run_text[char_index])) {
1238      continue;
1239    }
1240
1241    ++chars_not_missing_glyphs;
1242  }
1243
1244  DCHECK_LE(chars_not_missing_glyphs, static_cast<int>(run->range.length()));
1245  return run->range.length() - chars_not_missing_glyphs;
1246}
1247
1248size_t RenderTextWin::GetRunContainingCaret(const SelectionModel& caret) const {
1249  DCHECK(!needs_layout_);
1250  size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
1251  LogicalCursorDirection affinity = caret.caret_affinity();
1252  for (size_t run = 0; run < runs_.size(); ++run)
1253    if (RangeContainsCaret(runs_[run]->range, layout_position, affinity))
1254      return run;
1255  return runs_.size();
1256}
1257
1258size_t RenderTextWin::GetRunContainingXCoord(int x) const {
1259  DCHECK(!needs_layout_);
1260  // Find the text run containing the argument point (assumed already offset).
1261  for (size_t run = 0; run < runs_.size(); ++run) {
1262    if ((runs_[run]->preceding_run_widths <= x) &&
1263        ((runs_[run]->preceding_run_widths + runs_[run]->width) > x))
1264      return run;
1265  }
1266  return runs_.size();
1267}
1268
1269SelectionModel RenderTextWin::FirstSelectionModelInsideRun(
1270    const internal::TextRun* run) {
1271  size_t position = LayoutIndexToTextIndex(run->range.start());
1272  position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD);
1273  return SelectionModel(position, CURSOR_BACKWARD);
1274}
1275
1276SelectionModel RenderTextWin::LastSelectionModelInsideRun(
1277    const internal::TextRun* run) {
1278  size_t position = LayoutIndexToTextIndex(run->range.end());
1279  position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
1280  return SelectionModel(position, CURSOR_FORWARD);
1281}
1282
1283RenderText* RenderText::CreateNativeInstance() {
1284  return new RenderTextWin;
1285}
1286
1287}  // namespace gfx
1288