summaryrefslogtreecommitdiffstats
path: root/ui/gfx/render_text_harfbuzz.h
blob: 7f3a1dcef7396fb5b5f84af79d7d12a7a63a3c15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_RENDER_TEXT_HARFBUZZ_H_
#define UI_GFX_RENDER_TEXT_HARFBUZZ_H_

#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "third_party/harfbuzz-ng/src/hb.h"
#include "third_party/icu/source/common/unicode/ubidi.h"
#include "third_party/icu/source/common/unicode/uscript.h"
#include "ui/gfx/render_text.h"

namespace base {
namespace i18n {
class BreakIterator;
}
}

namespace gfx {

namespace internal {

// TODO(ckocagil): Make Range a template class and RangeF an instance of it.
typedef std::pair<float, float> RangeF;

// Applies std::round to the start and end values of the given RangeF.
Range GFX_EXPORT RoundRangeF(const RangeF& range_f);

struct GFX_EXPORT TextRunHarfBuzz {
  TextRunHarfBuzz();
  ~TextRunHarfBuzz();

  // Returns the index of the first glyph that corresponds to the character at
  // |pos|.
  size_t CharToGlyph(size_t pos) const;

  // Returns the corresponding glyph range of the given character range.
  // |range| is in text-space (0 corresponds to |GetLayoutText()[0]|). Returned
  // value is in run-space (0 corresponds to the first glyph in the run).
  Range CharRangeToGlyphRange(const Range& range) const;

  // Returns the number of missing glyphs in the shaped text run.
  size_t CountMissingGlyphs() const;

  // Writes the character and glyph ranges of the cluster containing |pos|.
  void GetClusterAt(size_t pos, Range* chars, Range* glyphs) const;

  // Returns the grapheme bounds at |text_index|. Handles multi-grapheme glyphs.
  RangeF GetGraphemeBounds(base::i18n::BreakIterator* grapheme_iterator,
                           size_t text_index);

  // Returns whether the given shaped run contains any missing glyphs.
  bool HasMissingGlyphs() const;

  float width;
  float preceding_run_widths;
  Range range;
  bool is_rtl;
  UBiDiLevel level;
  UScriptCode script;

  scoped_ptr<uint16[]> glyphs;
  scoped_ptr<SkPoint[]> positions;
  std::vector<uint32> glyph_to_char;
  size_t glyph_count;

  std::string family;
  skia::RefPtr<SkTypeface> skia_face;
  FontRenderParams render_params;
  int font_size;
  int font_style;
  bool strike;
  bool diagonal_strike;
  bool underline;

 private:
  DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz);
};

}  // namespace internal

class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
 public:
  RenderTextHarfBuzz();
  ~RenderTextHarfBuzz() override;

  // Overridden from RenderText.
  scoped_ptr<RenderText> CreateInstanceOfSameType() const override;
  Size GetStringSize() override;
  SizeF GetStringSizeF() override;
  SelectionModel FindCursorPosition(const Point& point) override;
  std::vector<FontSpan> GetFontSpansForTesting() override;
  Range GetGlyphBounds(size_t index) override;

 protected:
  // Overridden from RenderText.
  int GetLayoutTextBaseline() override;
  SelectionModel AdjacentCharSelectionModel(
      const SelectionModel& selection,
      VisualCursorDirection direction) override;
  SelectionModel AdjacentWordSelectionModel(
      const SelectionModel& selection,
      VisualCursorDirection direction) override;
  std::vector<Rect> GetSubstringBounds(const Range& range) override;
  size_t TextIndexToLayoutIndex(size_t index) const override;
  size_t LayoutIndexToTextIndex(size_t index) const override;
  bool IsValidCursorIndex(size_t index) override;
  void ResetLayout() override;
  void EnsureLayout() override;
  void DrawVisualText(Canvas* canvas) override;

 private:
  friend class RenderTextTest;
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_RunDirection);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_BreakRunsByEmoji);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_SubglyphGraphemeCases);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_SubglyphGraphemePartition);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_NonExistentFont);
  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UniscribeFallback);

  // Return the run index that contains the argument; or the length of the
  // |runs_| vector if argument exceeds the text length or width.
  size_t GetRunContainingCaret(const SelectionModel& caret) const;
  size_t GetRunContainingXCoord(float x, float* offset) const;

  // Given a |run|, returns the SelectionModel that contains the logical first
  // or last caret position inside (not at a boundary of) the run.
  // The returned value represents a cursor/caret position without a selection.
  SelectionModel FirstSelectionModelInsideRun(
      const internal::TextRunHarfBuzz* run);
  SelectionModel LastSelectionModelInsideRun(
      const internal::TextRunHarfBuzz* run);

  // Break the text into logical runs and populate the visual <-> logical maps.
  void ItemizeText();

  // Helper method for ShapeRun() that calls ShapeRunWithFont() with |run|,
  // |family|, and |render_params|, returning true if the family provides all
  // needed glyphs and false otherwise. Additionally updates |best_family|,
  // |best_render_params|, and |best_missing_glyphs| if |family| has fewer than
  // |best_missing_glyphs| missing glyphs.
  bool CompareFamily(internal::TextRunHarfBuzz* run,
                     const std::string& family,
                     const gfx::FontRenderParams& render_params,
                     std::string* best_family,
                     gfx::FontRenderParams* best_render_params,
                     size_t* best_missing_glyphs);

  // Shape the glyphs needed for the text |run|.
  void ShapeRun(internal::TextRunHarfBuzz* run);
  bool ShapeRunWithFont(internal::TextRunHarfBuzz* run,
                        const std::string& font_family,
                        const FontRenderParams& params);

  // Text runs in logical order.
  ScopedVector<internal::TextRunHarfBuzz> runs_;

  // Maps visual run indices to logical run indices and vice versa.
  std::vector<int32_t> visual_to_logical_;
  std::vector<int32_t> logical_to_visual_;

  bool needs_layout_;

  // ICU grapheme iterator for the layout text. Valid when |!needs_layout_|. Can
  // be NULL in case of an error.
  scoped_ptr<base::i18n::BreakIterator> grapheme_iterator_;

  DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzz);
};

}  // namespace gfx

#endif  // UI_GFX_RENDER_TEXT_HARFBUZZ_H_