summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
blob: c24971a7498ebbd18f51902cac69f500f39a2485 (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
// Copyright 2017 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 NGOffsetMappingBuilder_h
#define NGOffsetMappingBuilder_h

#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

class LayoutObject;

// This is the helper class for constructing the DOM-to-TextContent offset
// mapping. It holds an offset mapping, and provides APIs to modify the mapping
// step by step until the construction is finished.
// Design doc: https://goo.gl/CJbxky
// TODO(xiaochengh): Change the mock implemetation to a real one.
class CORE_EXPORT NGOffsetMappingBuilder {
  STACK_ALLOCATED();

 public:
  // A scope-like object that, mappings appended inside the scope are marked as
  // from the given source node. When multiple scopes nest, only the inner-most
  // scope is effective. Note that at most one of the nested scopes may have a
  // non-null node.
  //
  // Example:
  //
  // NGOffsetMappingBuilder builder;
  //
  // {
  //   NGOffsetMappingBuilder::SourceNodeScope scope(&builder, node);
  //
  //   // These 3 characters are marked as from source node |node|.
  //   builder.AppendIdentity(3);
  //
  //   {
  //     NGOffsetMappingBuilder::SourceNodeScope unset_scope(&builder, nullptr);
  //
  //     // This character is marked as having no source node.
  //     builder.AppendCollapsed(1);
  //   }
  //
  //   // These 2 characters are marked as from source node |node|.
  //   builder.AppendIdentity(2);
  //
  //   // Not allowed.
  //   // NGOffsetMappingBuilder::SourceNodeScope scope(&builder, node2);
  // }
  //
  // // This character is marked as having no source node.
  // builder.AppendIdentity(1);
  class SourceNodeScope {
    STACK_ALLOCATED();

   public:
    SourceNodeScope(NGOffsetMappingBuilder* builder, const LayoutObject* node);
    ~SourceNodeScope();

   private:
    NGOffsetMappingBuilder* const builder_ = nullptr;
    base::AutoReset<Persistent<const Node>> layout_object_auto_reset_;
    base::AutoReset<unsigned> appended_length_auto_reset_;

    DISALLOW_COPY_AND_ASSIGN(SourceNodeScope);
  };

  NGOffsetMappingBuilder();

  void ReserveCapacity(unsigned capacity);

  // Append an identity offset mapping of the specified length with null
  // annotation to the builder.
  void AppendIdentityMapping(unsigned length);

  // Append a collapsed offset mapping from the specified length with null
  // annotation to the builder.
  void AppendCollapsedMapping(unsigned length);

  // TODO(xiaochengh): Add the following API when we start to fix offset mapping
  // for text-transform.
  // Append an expanded offset mapping to the specified length with null
  // annotation to the builder.
  // void AppendExpandedMapping(unsigned length);

  // This function should only be called by NGInlineItemsBuilder during
  // whitespace collapsing, and in the case that the target string of the
  // currently held mapping:
  // (i)  has at least |space_offset + 1| characters,
  // (ii) character at |space_offset| in destination string is a collapsible
  //      whitespace,
  // This function changes the space into collapsed.
  void CollapseTrailingSpace(unsigned space_offset);

  // Concatenate the offset mapping held by another builder to this builder.
  // TODO(xiaochengh): Implement when adding support for 'text-transform'
  // void Concatenate(const NGOffsetMappingBuilder&);

  // Composite the offset mapping held by another builder to this builder.
  // TODO(xiaochengh): Implement when adding support for 'text-transform'
  // void Composite(const NGOffsetMappingBuilder&);

  // Set the destination string of the offset mapping.
  void SetDestinationString(String);

  // Called when entering a non-atomic inline node (e.g., SPAN), before
  // collecting any of its inline descendants.
  void EnterInline(const LayoutObject&);

  // Called when exiting a non-atomic inline node (e.g., SPAN), after having
  // collected all of its inline descendants.
  void ExitInline(const LayoutObject&);

  // Finalize and return the offset mapping.
  // This method can only be called once, as it can invalidate the stored data.
  NGOffsetMapping Build();

 private:
  // Helper function for CollapseTrailingSpace() to maintain unit ranges.
  void ShiftRanges(unsigned position, int delta);

  Persistent<const Node> current_node_ = nullptr;
  unsigned current_offset_ = 0;
  bool has_open_unit_ = false;
#if DCHECK_IS_ON()
  bool has_nonnull_node_scope_ = false;
#endif

  // Length of the current destination string.
  unsigned destination_length_ = 0;

  // Mapping units of the current mapping function.
  Vector<NGOffsetMappingUnit> mapping_units_;

  // Unit ranges of the current mapping function.
  NGOffsetMapping::RangeMap unit_ranges_;

  // Unit range starts of currently entered inline elements.
  Vector<unsigned> open_inlines_;

  // The destination string of the offset mapping.
  String destination_string_;

  friend class SourceNodeScope;

  DISALLOW_COPY_AND_ASSIGN(NGOffsetMappingBuilder);
};

}  // namespace blink

#endif  // OffsetMappingBuilder_h