File: shape_result_view.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (344 lines) | stat: -rw-r--r-- 15,827 bytes parent folder | download | duplicates (5)
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_

#include "base/containers/span.h"
#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data.h"
#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data_range.h"
#include "third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

class ShapeResult;

// Class representing a read-only composite of views into one or more existing
// shape results.
// Implemented as a list of ref counted RunInfo instances and a start/end
// offset for each, represented using the internal RunInfoPart struct.
// This allows lines to be reference sections of the overall paragraph shape
// results without the memory or computational overhead of a copy.
//
// The example below shows the shape result and the individual lines as
// ShapeResultView instances pointing to the original paragraph results for
// the string "Pack my box with five dozen liquor jugs.":
//  ╔═════════════════════════════════════════════════════╗
//  ║ Paragraph with single run, no re-shaping for lines. ║
//  ╟─────────────────────────────────────────────────────╢
//  ║ runs_ ╭───────────────────────────────────────────╮ ║
//  ║   1:  │ Pack my box with five dozen liquor jugs.  │ ║
//  ║       ╰───────────────────────────────────────────╯ ║
//  ║ lines ╭───────────────────────────────────────────╮ ║
//  ║   1:  │ Pack my box with    -> view, run 1:  0-16 │ ║
//  ║   2:  │ five dozen liquor   -> view, run 1: 17-34 │ ║
//  ║   3:  │ jugs.               -> view, run 1: 35-40 │ ║
//  ║       ╰───────────────────────────────────────────╯ ║
//  ╚═════════════════════════════════════════════════════╝
//
// In cases where a portion of the line needs re-shaping the new results are
// added as separate runs at the beginning and/or end of the runs_ vector with a
// reference to zero or more sub-runs in the middle representing the original
// content that could be reused.
//
// In the example below the end of the first line "Jack!" needs to be re-shaped:
//  ╔═════════════════════════════════════════════════════╗
//  ║ Paragraph with single run, requiring re-shape.      ║
//  ╟─────────────────────────────────────────────────────╢
//  ║ runs_ ╭───────────────────────────────────────────╮ ║
//  ║   1:  │ "Now fax quiz Jack!" my brave ghost pled. │ ║
//  ║       ╰───────────────────────────────────────────╯ ║
//  ║ lines ╭───────────────────────────────────────────╮ ║
//  ║   1:  │ "Now fax quiz     -> view, run 1:  0-14   │ ║
//  ║   1:  │ Jack!             -> new result/run       │ ║
//  ║   2:  │ my brave ghost    -> view, run 1: 21-35   │ ║
//  ║   3:  │ pled.             -> view, run 1: 41-36   │ ║
//  ║       ╰───────────────────────────────────────────╯ ║
//  ╚═════════════════════════════════════════════════════╝
//
// In this case the beginning of the first line would be represented as a part
// referencing a range in the original ShapeResult while the last word
// would be a separate result owned by the ShapeResultView instance. The second
// and third lines would again be represented as parts.
class PLATFORM_EXPORT ShapeResultView final
    : public GarbageCollected<ShapeResultView> {
 public:
  // Create a new ShapeResultView from a pre-defined list of segments.
  // The segments list is assumed to be in logical order.
  struct Segment {
    STACK_ALLOCATED();

   public:
    Segment() = default;
    Segment(const ShapeResult* result, unsigned start_index, unsigned end_index)
        : result(result),
          view(nullptr),
          start_index(start_index),
          end_index(end_index) {}
    Segment(const ShapeResultView* view,
            unsigned start_index,
            unsigned end_index)
        : result(nullptr),
          view(view),
          start_index(start_index),
          end_index(end_index) {}
    const ShapeResult* result;
    const ShapeResultView* view;
    unsigned start_index;
    unsigned end_index;
  };
  static ShapeResultView* Create(base::span<const Segment> segments);

  // Creates a new ShapeResultView from a single segment.
  static ShapeResultView* Create(const ShapeResult*);
  static ShapeResultView* Create(const ShapeResult*,
                                 unsigned start_index,
                                 unsigned end_index);
  static ShapeResultView* Create(const ShapeResultView*,
                                 unsigned start_index,
                                 unsigned end_index);

  struct InitData;
  explicit ShapeResultView(const InitData& data);
  ShapeResultView(const ShapeResultView&) = delete;
  ShapeResultView& operator=(const ShapeResultView&) = delete;
  ~ShapeResultView() = default;

  void Trace(Visitor* visitor) const { visitor->Trace(parts_); }

  ShapeResult* CreateShapeResult() const;

  unsigned StartIndex() const { return start_index_ + char_index_offset_; }
  unsigned EndIndex() const { return StartIndex() + num_characters_; }
  unsigned NumCharacters() const { return num_characters_; }
  float Width() const { return width_; }
  LayoutUnit SnappedWidth() const { return LayoutUnit::FromFloatCeil(width_); }
  TextDirection Direction() const {
    return static_cast<TextDirection>(direction_);
  }
  bool IsLtr() const { return blink::IsLtr(Direction()); }
  bool IsRtl() const { return blink::IsRtl(Direction()); }
  bool HasVerticalOffsets() const { return has_vertical_offsets_; }

  unsigned NumGlyphs() const;
  HeapHashSet<Member<const SimpleFontData>> UsedFonts() const;

  unsigned PreviousSafeToBreakOffset(unsigned index) const;

  float ForEachGlyph(float initial_advance, GlyphCallback, void* context) const;
  float ForEachGlyph(float initial_advance,
                     unsigned from,
                     unsigned to,
                     unsigned index_offset,
                     GlyphCallback,
                     void* context) const;

  float ForEachGraphemeClusters(const StringView& text,
                                float initial_advance,
                                unsigned from,
                                unsigned to,
                                unsigned index_offset,
                                GraphemeClusterCallback,
                                void* context) const;

  // Computes and returns the ink bounds (or visual overflow rect). This is
  // quite expensive and involves measuring each glyph and accumulating the
  // bounds.
  gfx::RectF ComputeInkBounds() const;

  void GetRunFontData(HeapVector<ShapeResult::RunFontData>*) const;

  void ExpandRangeToIncludePartialGlyphs(unsigned* from, unsigned* to) const;

  struct RunInfoPart {
    DISALLOW_NEW();

   public:
    RunInfoPart(const ShapeResultRun* run,
                GlyphDataRange range,
                unsigned start_index,
                unsigned offset,
                unsigned num_characters,
                float width);

    PLATFORM_EXPORT void Trace(Visitor*) const;

    using const_iterator = const HarfBuzzRunGlyphData*;
    const_iterator begin() const { return range_.begin(); }
    const_iterator end() const { return range_.end(); }
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    const_reverse_iterator rbegin() const {
      return const_reverse_iterator(end());
    }
    const_reverse_iterator rend() const {
      return const_reverse_iterator(begin());
    }
    const HarfBuzzRunGlyphData& GlyphAt(unsigned index) const {
      return *(UNSAFE_TODO(range_.begin() + index));
    }
    template <bool has_non_zero_glyph_offsets>
    GlyphOffsetIterator<has_non_zero_glyph_offsets> GetGlyphOffsets() const {
      return GlyphOffsetIterator<has_non_zero_glyph_offsets>(range_);
    }
    bool HasGlyphOffsets() const { return range_.HasOffsets(); }
    // The end character index of |this| without considering offsets in
    // |ShapeResultView|. This is analogous to:
    //   GlyphAt(IsRtl() ? -1 : NumGlyphs()).character_index
    // if such |HarfBuzzRunGlyphData| is available.
    unsigned CharacterIndexOfEndGlyph() const {
      return num_characters_ + offset_;
    }

    unsigned NumCharacters() const { return num_characters_; }
    unsigned NumGlyphs() const { return range_.size(); }
    float Width() const { return width_; }

    unsigned PreviousSafeToBreakOffset(unsigned offset) const;

    // Common signatures with RunInfo, to templatize algorithms.
    const ShapeResultRun* GetRunInfo() const { return run_.Get(); }
    const GlyphDataRange& GetGlyphDataRange() const { return range_; }
    GlyphDataRange FindGlyphDataRange(unsigned start_character_index,
                                      unsigned end_character_index) const;
    unsigned OffsetToRunStartIndex() const { return offset_; }

    // The helper function for implementing |PopulateRunInfoParts()| for
    // handling iterating over |Vector<scoped_refptr<RunInfo>>| and
    // |base::span<RunInfoPart>|.
    const RunInfoPart* Get() const { return this; }

    template <typename RunType, typename ShapeResultType>
    static unsigned ComputeStart(const RunType& run,
                                 const ShapeResultType& result) {
      const unsigned part_start =
          run.start_index_ + result.StartIndexOffsetForRun();
      if (result.IsLtr()) {
        return part_start;
      }
      // Under RTL and multiple parts, A RunInfoPart may have an
      // offset_ greater than start_index. In this case, run_start
      // would result in an invalid negative value.
      return std::max(part_start, run.OffsetToRunStartIndex());
    }

    template <typename RunType, typename ShapeResultType>
    static std::optional<std::pair<unsigned, unsigned>> ComputeStartEnd(
        const RunType& run,
        const ShapeResultType& result,
        const Segment& segment) {
      if (!run.GetRunInfo()) {
        return std::nullopt;
      }
      const unsigned part_start = ComputeStart(run, result);
      if (segment.end_index <= part_start) {
        return std::nullopt;
      }
      if (!run.num_characters_) {
        return {{part_start, part_start}};
      }
      const unsigned part_end = part_start + run.num_characters_;
      if (segment.start_index >= part_end) {
        return std::nullopt;
      }
      return {{part_start, part_end}};
    }

    Member<const ShapeResultRun> run_;
    GlyphDataRange range_;

    // Start index for partial run, adjusted to ensure that runs are continuous.
    unsigned start_index_;

    // Offset relative to start index for the original run.
    unsigned offset_;

    unsigned num_characters_;
    float width_;
  };

 private:
  void PopulateRunInfoParts(const Segment& segment);

  // Populates `parts_` and accumulates `num_characters_`, and `width_` from
  // runs in `result`.
  template <class ShapeResultType>
  void PopulateRunInfoParts(const ShapeResultType& result,
                            const Segment& segment);

  unsigned CharacterIndexOffsetForGlyphData(const RunInfoPart&) const;

  template <bool is_horizontal_run, bool has_glyph_offsets>
  void ComputePartInkBounds(const ShapeResultView::RunInfoPart&,
                            float run_advance,
                            gfx::RectF* ink_bounds) const;

  template <bool is_horizontal_run, bool has_glyph_offsets>
  void ComputePartInkBoundsScalar(const ShapeResultView::RunInfoPart&,
                                  float run_advance,
                                  gfx::RectF* ink_bounds) const;
#if defined(USE_SIMD_FOR_COMPUTING_GLYPH_BOUNDS)
  template <bool is_horizontal_run, bool has_non_zero_glyph_offsets>
  void ComputePartInkBoundsVectorized(const ShapeResultView::RunInfoPart&,
                                      float run_advance,
                                      gfx::RectF* ink_bounds) const;
#endif  // defined(USE_SIMD_FOR_COMPUTING_GLYPH_BOUNDS)

  // Common signatures with ShapeResult, to templatize algorithms.
  base::span<const RunInfoPart> RunsOrParts() const { return parts_; }

  unsigned StartIndexOffsetForRun() const { return char_index_offset_; }

  HeapVector<RunInfoPart, 1> parts_;

  const unsigned start_index_;

  // Once `parts_` is populated `width_` and `num_characters_` are immutable.
  float width_ = 0;
  unsigned num_characters_ : 30 = 0;

  // Overall direction for the TextRun, dictates which order each individual
  // sub run (represented by RunInfo structs in the m_runs vector) can
  // have a different text direction.
  const unsigned direction_ : 1;

  // Tracks whether any runs contain glyphs with a y-offset != 0.
  const unsigned has_vertical_offsets_ : 1;

  // Offset of the first component added to the view. Used for compatibility
  // with ShapeResult::SubRange
  const unsigned char_index_offset_;

 private:
  friend class ShapeResult;

  template <bool has_glyph_offsets>
  float ForEachGlyphImpl(float initial_advance,
                         GlyphCallback,
                         void* context,
                         const RunInfoPart& part) const;

  template <bool has_glyph_offsets>
  float ForEachGlyphImpl(float initial_advance,
                         unsigned from,
                         unsigned to,
                         unsigned index_offset,
                         GlyphCallback,
                         void* context,
                         const RunInfoPart& part) const;
};

}  // namespace blink

WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
    blink::ShapeResultView::RunInfoPart)

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_