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_
|