summaryrefslogtreecommitdiff
path: root/chromium/ui/gfx/render_text_harfbuzz.h
blob: 983b225548d886c744733802b944c7b9dd2e79a2 (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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// 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 <stddef.h>
#include <stdint.h>

#include <memory>
#include <vector>

#include "base/macros.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"

#include <hb.h>

namespace base {
namespace i18n {
class BreakIterator;
}
}

namespace gfx {

class Range;
class RangeF;
class RenderTextHarfBuzz;

namespace internal {

struct GFX_EXPORT TextRunHarfBuzz {
  // Construct the run with |template_font| since determining the details of a
  // default-constructed gfx::Font is expensive, but it will always be replaced.
  explicit TextRunHarfBuzz(const Font& template_font);
  ~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 |GetDisplayText()[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.
  // Returned value is the horizontal pixel span in text-space (assumes all runs
  // are on the same line). The returned range is never reversed.
  RangeF GetGraphemeBounds(RenderTextHarfBuzz* render_text,
                           size_t text_index) const;

  // Returns the horizontal span of the given |char_range| handling grapheme
  // boundaries within glyphs. This is a wrapper around one or more calls to
  // GetGraphemeBounds(), returning a range in the same coordinate space.
  RangeF GetGraphemeSpanForCharRange(RenderTextHarfBuzz* render_text,
                                     const Range& char_range) const;

  // Returns the glyph width for the given character range. |char_range| is in
  // text-space (0 corresponds to |GetDisplayText()[0]|).
  SkScalar GetGlyphWidthForCharRange(const Range& char_range) const;

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

  std::unique_ptr<uint16_t[]> glyphs;
  std::unique_ptr<SkPoint[]> positions;
  std::vector<uint32_t> glyph_to_char;
  size_t glyph_count;

  Font font;
  sk_sp<SkTypeface> skia_face;
  FontRenderParams render_params;
  int font_size;
  int baseline_offset;
  int baseline_type;
  bool italic;
  Font::Weight weight;
  bool strike;
  bool underline;
  bool heavy_underline;

 private:
  DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz);
};

// Manages the list of TextRunHarfBuzz and its logical <-> visual index mapping.
class TextRunList {
 public:
  TextRunList();
  ~TextRunList();

  size_t size() const { return runs_.size(); }

  // Converts the index between logical and visual index.
  size_t visual_to_logical(size_t index) const {
    return visual_to_logical_[index];
  }
  size_t logical_to_visual(size_t index) const {
    return logical_to_visual_[index];
  }

  const std::vector<std::unique_ptr<TextRunHarfBuzz>>& runs() const {
    return runs_;
  }

  // Adds the new |run| to the run list.
  void Add(std::unique_ptr<TextRunHarfBuzz> run) {
    runs_.push_back(std::move(run));
  }

  // Reset the run list.
  void Reset();

  // Initialize the index mapping.
  void InitIndexMap();

  // Precomputes the offsets for all runs.
  void ComputePrecedingRunWidths();

  // Get the total width of runs, as if they were shown on one line.
  // Do not use this when multiline is enabled.
  float width() const { return width_; }

  // Get the run index applicable to |position| (at or preceeding |position|).
  size_t GetRunIndexAt(size_t position) const;

 private:
  // Text runs in logical order.
  std::vector<std::unique_ptr<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_;

  float width_;

  DISALLOW_COPY_AND_ASSIGN(TextRunList);
};

}  // namespace internal

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

  // RenderText:
  std::unique_ptr<RenderText> CreateInstanceOfSameType() const override;
  bool MultilineSupported() const override;
  const base::string16& GetDisplayText() override;
  Size GetStringSize() override;
  SizeF GetStringSizeF() override;
  SelectionModel FindCursorPosition(const Point& point) override;
  bool IsSelectionSupported() const override;
  std::vector<FontSpan> GetFontSpansForTesting() override;
  Range GetCursorSpan(const Range& text_range) override;

  // ICU grapheme iterator for the layout text. Can be null in case of an error.
  base::i18n::BreakIterator* GetGraphemeIterator();

 protected:
  // RenderText:
  int GetDisplayTextBaseline() 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 TextIndexToDisplayIndex(size_t index) override;
  size_t DisplayIndexToTextIndex(size_t index) override;
  bool IsValidCursorIndex(size_t index) override;
  void OnLayoutTextAttributeChanged(bool text_changed) override;
  void OnDisplayTextAttributeChanged() override;
  void EnsureLayout() override;
  void DrawVisualText(internal::SkiaTextRenderer* renderer) override;

 private:
  friend class test::RenderTextTestApi;
  friend class RenderTextHarfBuzzTest;

  // 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);

  // 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
  // into |run_list_out|.
  void ItemizeTextToRuns(const base::string16& string,
                         internal::TextRunList* run_list_out);

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

  // Shape the glyphs of all runs in |run_list| using |text|.
  void ShapeRunList(const base::string16& text,
                    internal::TextRunList* run_list);

  // Shape the glyphs needed for the |run| within the |text|.
  void ShapeRun(const base::string16& text,
                internal::TextRunHarfBuzz* run);
  bool ShapeRunWithFont(const base::string16& text,
                        const Font& font,
                        const FontRenderParams& params,
                        internal::TextRunHarfBuzz* run);

  // Makes sure that text runs for layout text are shaped.
  void EnsureLayoutRunList();

  // RenderText:
  internal::TextRunList* GetRunList() override;
  const internal::TextRunList* GetRunList() const override;
  bool GetDecoratedTextForRange(const Range& range,
                                DecoratedText* decorated_text) override;
  void SetGlyphWidthForTest(float test_width) override;

  // Text run list for |layout_text_| and |display_text_|.
  // |display_run_list_| is created only when the text is elided.
  internal::TextRunList layout_run_list_;
  std::unique_ptr<internal::TextRunList> display_run_list_;

  bool update_layout_run_list_ : 1;
  bool update_display_run_list_ : 1;
  bool update_grapheme_iterator_ : 1;
  bool update_display_text_ : 1;

  // ICU grapheme iterator for the layout text. Use GetGraphemeIterator()
  // to access the iterator.
  std::unique_ptr<base::i18n::BreakIterator> grapheme_iterator_;

  // The total size of the layouted text.
  SizeF total_size_;

  // Fixed width of glyphs. This should only be set in test environments.
  float glyph_width_for_test_;

  DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzz);
};

}  // namespace gfx

#endif  // UI_GFX_RENDER_TEXT_HARFBUZZ_H_