Flutter Impeller
glyph_atlas.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 #ifndef FLUTTER_IMPELLER_TYPOGRAPHER_GLYPH_ATLAS_H_
6 #define FLUTTER_IMPELLER_TYPOGRAPHER_GLYPH_ATLAS_H_
7 
8 #include <functional>
9 #include <memory>
10 #include <optional>
11 
12 #include "flutter/fml/build_config.h"
13 
14 #if defined(OS_FUCHSIA)
15 // TODO(gaaclarke): Migrate to use absl. I couldn't get it working since absl
16 // has special logic in its GN files for Fuchsia that I couldn't sort out.
17 #define IMPELLER_TYPOGRAPHER_USE_STD_HASH
18 #else
19 #include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h"
20 #endif
21 
22 #include "impeller/core/texture.h"
23 #include "impeller/geometry/rect.h"
26 
27 namespace impeller {
28 
29 class FontGlyphAtlas;
30 
31 /// Helper for AbslHashAdapter. Tallies a hash value with fml::HashCombine.
32 template <typename T>
34  std::size_t value = 0;
35 
36  template <typename... Args>
38  const Args&... args) {
39  combiner.value = fml::HashCombine(combiner.value, args...);
40  return combiner;
41  }
42 };
43 
44 /// Adapts AbslHashValue functions to be used with std::unordered_map and the
45 /// fml hash functions.
46 template <typename T>
48  constexpr std::size_t operator()(const T& element) const {
50  combiner = AbslHashValue(std::move(combiner), element);
51  return combiner.value;
52  }
53 };
54 
55 struct FrameBounds {
56  /// The bounds of the glyph within the glyph atlas.
58  /// The local glyph bounds.
60  /// Whether [atlas_bounds] are still a placeholder and have
61  /// not yet been computed.
62  bool is_placeholder = true;
63 };
64 
65 //------------------------------------------------------------------------------
66 /// @brief A texture containing the bitmap representation of glyphs in
67 /// different fonts along with the ability to query the location of
68 /// specific font glyphs within the texture.
69 ///
70 class GlyphAtlas {
71  public:
72  //----------------------------------------------------------------------------
73  /// @brief Describes how the glyphs are represented in the texture.
74  enum class Type {
75  //--------------------------------------------------------------------------
76  /// The glyphs are reprsented at their requested size using only an 8-bit
77  /// color channel.
78  ///
79  /// This might be backed by a grey or red single channel texture, depending
80  /// on the backend capabilities.
82 
83  //--------------------------------------------------------------------------
84  /// The glyphs are reprsented at their requested size using N32 premul
85  /// colors.
86  ///
88  };
89 
90  //----------------------------------------------------------------------------
91  /// @brief Create an empty glyph atlas.
92  ///
93  /// @param[in] type How the glyphs are represented in the texture.
94  /// @param[in] initial_generation the atlas generation.
95  ///
96  GlyphAtlas(Type type, size_t initial_generation);
97 
99 
100  bool IsValid() const;
101 
102  //----------------------------------------------------------------------------
103  /// @brief Describes how the glyphs are represented in the texture.
104  ///
105  Type GetType() const;
106 
107  //----------------------------------------------------------------------------
108  /// @brief Set the texture for the glyph atlas.
109  ///
110  /// @param[in] texture The texture
111  ///
112  void SetTexture(std::shared_ptr<Texture> texture);
113 
114  //----------------------------------------------------------------------------
115  /// @brief Get the texture for the glyph atlas.
116  ///
117  /// @return The texture.
118  ///
119  const std::shared_ptr<Texture>& GetTexture() const;
120 
121  //----------------------------------------------------------------------------
122  /// @brief Record the location of a specific font-glyph pair within the
123  /// atlas.
124  ///
125  /// @param[in] pair The font-glyph pair
126  /// @param[in] rect The position in the atlas
127  /// @param[in] bounds The bounds of the glyph at scale
128  ///
130  Rect position,
131  Rect bounds);
132 
133  //----------------------------------------------------------------------------
134  /// @brief Get the number of unique font-glyph pairs in this atlas.
135  ///
136  /// @return The glyph count.
137  ///
138  size_t GetGlyphCount() const;
139 
140  //----------------------------------------------------------------------------
141  /// @brief Iterate of all the glyphs along with their locations in the
142  /// atlas.
143  ///
144  /// @param[in] iterator The iterator. Return `false` from the iterator to
145  /// stop iterating.
146  ///
147  /// @return The number of glyphs iterated over.
148  ///
149  size_t IterateGlyphs(
150  const std::function<bool(const ScaledFont& scaled_font,
151  const SubpixelGlyph& glyph,
152  const Rect& rect)>& iterator) const;
153 
154  //----------------------------------------------------------------------------
155  /// @brief Find the location of a specific font-glyph pair in the atlas.
156  ///
157  /// @param[in] pair The font-glyph pair
158  ///
159  /// @return The location of the font-glyph pair in the atlas.
160  /// `std::nullopt` if the pair is not in the atlas.
161  ///
162  std::optional<FrameBounds> FindFontGlyphBounds(
163  const FontGlyphPair& pair) const;
164 
165  //----------------------------------------------------------------------------
166  /// @brief Obtain an interface for querying the location of glyphs in the
167  /// atlas for the given font and scale. This provides a more
168  /// efficient way to look up a run of glyphs in the same font.
169  ///
170  /// @param[in] font The font
171  /// @param[in] scale The scale
172  ///
173  /// @return A pointer to a FontGlyphAtlas, or nullptr if the font and
174  /// scale are not available in the atlas. The pointer is only
175  /// valid for the lifetime of the GlyphAtlas.
176  ///
178 
179  //----------------------------------------------------------------------------
180  /// @brief Retrieve the generation id for this glyph atlas.
181  ///
182  /// The generation id is used to match with a TextFrame to
183  /// determine if the frame is guaranteed to already be populated
184  /// in the atlas.
185  size_t GetAtlasGeneration() const;
186 
187  //----------------------------------------------------------------------------
188  /// @brief Update the atlas generation.
189  void SetAtlasGeneration(size_t value);
190 
191  private:
192  const Type type_;
193  std::shared_ptr<Texture> texture_;
194  size_t generation_ = 0;
195 
196 #if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
197  using FontAtlasMap = std::unordered_map<ScaledFont,
201 #else
202  using FontAtlasMap = absl::flat_hash_map<ScaledFont,
204  absl::Hash<ScaledFont>,
206 #endif
207 
208  FontAtlasMap font_atlas_map_;
209 
210  GlyphAtlas(const GlyphAtlas&) = delete;
211 
212  GlyphAtlas& operator=(const GlyphAtlas&) = delete;
213 };
214 
215 //------------------------------------------------------------------------------
216 /// @brief A container for caching a glyph atlas across frames.
217 ///
219  public:
221 
222  virtual ~GlyphAtlasContext();
223 
224  //----------------------------------------------------------------------------
225  /// @brief Retrieve the current glyph atlas.
226  std::shared_ptr<GlyphAtlas> GetGlyphAtlas() const;
227 
228  //----------------------------------------------------------------------------
229  /// @brief Retrieve the size of the current glyph atlas.
230  const ISize& GetAtlasSize() const;
231 
232  //----------------------------------------------------------------------------
233  /// @brief Retrieve the previous (if any) rect packer.
234  std::shared_ptr<RectanglePacker> GetRectPacker() const;
235 
236  //----------------------------------------------------------------------------
237  /// @brief A y-coordinate shift that must be applied to glyphs appended
238  /// to
239  /// the atlas.
240  ///
241  /// The rectangle packer is only initialized for unfilled regions
242  /// of the atlas. The area the rectangle packer covers is offset
243  /// from the origin by this height adjustment.
244  int64_t GetHeightAdjustment() const;
245 
246  //----------------------------------------------------------------------------
247  /// @brief Update the context with a newly constructed glyph atlas.
248  void UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas,
249  ISize size,
250  int64_t height_adjustment_);
251 
252  void UpdateRectPacker(std::shared_ptr<RectanglePacker> rect_packer);
253 
254  private:
255  std::shared_ptr<GlyphAtlas> atlas_;
256  ISize atlas_size_;
257  std::shared_ptr<RectanglePacker> rect_packer_;
258  int64_t height_adjustment_;
259 
260  GlyphAtlasContext(const GlyphAtlasContext&) = delete;
261 
262  GlyphAtlasContext& operator=(const GlyphAtlasContext&) = delete;
263 };
264 
265 //------------------------------------------------------------------------------
266 /// @brief An object that can look up glyph locations within the GlyphAtlas
267 /// for a particular typeface.
268 ///
270  public:
271  FontGlyphAtlas() = default;
273 
274  //----------------------------------------------------------------------------
275  /// @brief Find the location of a glyph in the atlas.
276  ///
277  /// @param[in] glyph The glyph
278  ///
279  /// @return The location of the glyph in the atlas.
280  /// `std::nullopt` if the glyph is not in the atlas.
281  ///
282  std::optional<FrameBounds> FindGlyphBounds(const SubpixelGlyph& glyph) const;
283 
284  //----------------------------------------------------------------------------
285  /// @brief Append the frame bounds of a glyph to this atlas.
286  ///
287  /// This may indicate a placeholder glyph location to be replaced
288  /// at a later time, as indicated by FrameBounds.placeholder.
289  void AppendGlyph(const SubpixelGlyph& glyph, const FrameBounds& frame_bounds);
290 
291  private:
292  friend class GlyphAtlas;
293 
294 #if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
295  using PositionsMap = std::unordered_map<SubpixelGlyph,
296  FrameBounds,
299 #else
300  using PositionsMap = absl::flat_hash_map<SubpixelGlyph,
301  FrameBounds,
302  absl::Hash<SubpixelGlyph>,
304 #endif
305 
306  PositionsMap positions_;
307  FontGlyphAtlas(const FontGlyphAtlas&) = delete;
308 };
309 
310 } // namespace impeller
311 
312 #endif // FLUTTER_IMPELLER_TYPOGRAPHER_GLYPH_ATLAS_H_
GLenum type
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
Definition: glyph_atlas.h:269
void AppendGlyph(const SubpixelGlyph &glyph, const FrameBounds &frame_bounds)
Append the frame bounds of a glyph to this atlas.
Definition: glyph_atlas.cc:140
std::optional< FrameBounds > FindGlyphBounds(const SubpixelGlyph &glyph) const
Find the location of a glyph in the atlas.
Definition: glyph_atlas.cc:131
FontGlyphAtlas(FontGlyphAtlas &&)=default
A container for caching a glyph atlas across frames.
Definition: glyph_atlas.h:218
GlyphAtlasContext(GlyphAtlas::Type type)
Definition: glyph_atlas.cc:14
std::shared_ptr< RectanglePacker > GetRectPacker() const
Retrieve the previous (if any) rect packer.
Definition: glyph_atlas.cc:32
void UpdateRectPacker(std::shared_ptr< RectanglePacker > rect_packer)
Definition: glyph_atlas.cc:44
std::shared_ptr< GlyphAtlas > GetGlyphAtlas() const
Retrieve the current glyph atlas.
Definition: glyph_atlas.cc:20
const ISize & GetAtlasSize() const
Retrieve the size of the current glyph atlas.
Definition: glyph_atlas.cc:24
int64_t GetHeightAdjustment() const
A y-coordinate shift that must be applied to glyphs appended to the atlas.
Definition: glyph_atlas.cc:28
void UpdateGlyphAtlas(std::shared_ptr< GlyphAtlas > atlas, ISize size, int64_t height_adjustment_)
Update the context with a newly constructed glyph atlas.
Definition: glyph_atlas.cc:36
A texture containing the bitmap representation of glyphs in different fonts along with the ability to...
Definition: glyph_atlas.h:70
std::optional< FrameBounds > FindFontGlyphBounds(const FontGlyphPair &pair) const
Find the location of a specific font-glyph pair in the atlas.
Definition: glyph_atlas.cc:87
bool IsValid() const
Definition: glyph_atlas.cc:54
void SetTexture(std::shared_ptr< Texture > texture)
Set the texture for the glyph atlas.
Definition: glyph_atlas.cc:66
void SetAtlasGeneration(size_t value)
Update the atlas generation.
Definition: glyph_atlas.cc:74
FontGlyphAtlas * GetOrCreateFontGlyphAtlas(const ScaledFont &scaled_font)
Obtain an interface for querying the location of glyphs in the atlas for the given font and scale....
Definition: glyph_atlas.cc:96
Type
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.h:74
size_t GetAtlasGeneration() const
Retrieve the generation id for this glyph atlas.
Definition: glyph_atlas.cc:70
Type GetType() const
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.cc:58
const std::shared_ptr< Texture > & GetTexture() const
Get the texture for the glyph atlas.
Definition: glyph_atlas.cc:62
GlyphAtlas(Type type, size_t initial_generation)
Create an empty glyph atlas.
Definition: glyph_atlas.cc:49
size_t IterateGlyphs(const std::function< bool(const ScaledFont &scaled_font, const SubpixelGlyph &glyph, const Rect &rect)> &iterator) const
Iterate of all the glyphs along with their locations in the atlas.
Definition: glyph_atlas.cc:110
void AddTypefaceGlyphPositionAndBounds(const FontGlyphPair &pair, Rect position, Rect bounds)
Record the location of a specific font-glyph pair within the atlas.
Definition: glyph_atlas.cc:78
size_t GetGlyphCount() const
Get the number of unique font-glyph pairs in this atlas.
Definition: glyph_atlas.cc:103
int32_t value
Helper for AbslHashAdapter. Tallies a hash value with fml::HashCombine.
Definition: glyph_atlas.h:33
static AbslHashAdapterCombiner combine(AbslHashAdapterCombiner combiner, const Args &... args)
Definition: glyph_atlas.h:37
constexpr std::size_t operator()(const T &element) const
Definition: glyph_atlas.h:48
A font along with a glyph in that font rendered at a particular scale and subpixel position.
Rect atlas_bounds
The bounds of the glyph within the glyph atlas.
Definition: glyph_atlas.h:57
Rect glyph_bounds
The local glyph bounds.
Definition: glyph_atlas.h:59
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
A glyph and its subpixel position.