1 // Copyright 2016 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
7 
8 #include "third_party/blink/renderer/core/core_export.h"
9 #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
10 #include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
11 #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
12 #include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
13 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
14 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
15 #include "third_party/blink/renderer/platform/wtf/casting.h"
16 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
17 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
18 
19 namespace blink {
20 
21 class NGTextFragmentBuilder;
22 class NGPhysicalTextFragment;
23 struct PhysicalRect;
24 
25 enum class AdjustMidCluster;
26 
27 class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
28  public:
29   enum NGTextType {
30     // |text_| holds |NGNodeInlineData::text_content_|.
31     kNormalText,
32     kForcedLineBreak,
33     // Flow controls are not to be painted. In particular, a tabulation
34     // character and a soft-wrap opportunity.
35     kFlowControl,
36     kSymbolMarker,
37     // |text_| holds generated contents instead of |text_content_| in
38     // |NGNodeInlineData|, e.g. hyphen, and ellipsis.
39     // Note: Contents generated by CSS pseudo element, e.g. ::before, ::after,
40     // are not classified to this. See IsGeneratedText() for them.
41     kGeneratedText,
42     // When adding new values, make sure the bit size of |sub_type_| is large
43     // enough to store.
44   };
45 
46   NGPhysicalTextFragment(NGTextFragmentBuilder*);
47 
48   using PassKey = util::PassKey<NGPhysicalTextFragment>;
49   // For use by TrimText only
50   NGPhysicalTextFragment(PassKey,
51                          const NGPhysicalTextFragment& source,
52                          unsigned start_offset,
53                          unsigned end_offset,
54                          scoped_refptr<const ShapeResultView> shape_result);
55 
TextType()56   NGTextType TextType() const { return static_cast<NGTextType>(sub_type_); }
57   // Returns true if the text is generated (from, e.g., list marker,
58   // pseudo-element, ...) instead of from a DOM text node.
IsGeneratedText()59   bool IsGeneratedText() const { return is_generated_text_or_math_fraction_; }
60   // True if this is a forced line break.
IsLineBreak()61   bool IsLineBreak() const { return TextType() == kForcedLineBreak; }
62   // True if this is not for painting; i.e., a forced line break, a tabulation,
63   // or a soft-wrap opportunity.
IsFlowControl()64   bool IsFlowControl() const {
65     return IsLineBreak() || TextType() == kFlowControl;
66   }
67   // True if this is an ellpisis generated by `text-overflow: ellipsis`.
IsEllipsis()68   bool IsEllipsis() const {
69     return StyleVariant() == NGStyleVariant::kEllipsis;
70   }
71 
IsSymbolMarker()72   bool IsSymbolMarker() const { return TextType() == kSymbolMarker; }
73 
TextContent()74   const String& TextContent() const { return text_; }
75 
76   // ShapeResult may be nullptr if |IsFlowControl()|.
TextShapeResult()77   const ShapeResultView* TextShapeResult() const { return shape_result_.get(); }
78 
79   // Start/end offset to the text of the block container.
TextOffset()80   const NGTextOffset& TextOffset() const { return text_offset_; }
StartOffset()81   unsigned StartOffset() const { return text_offset_.start; }
EndOffset()82   unsigned EndOffset() const { return text_offset_.end; }
TextLength()83   unsigned TextLength() const { return text_offset_.Length(); }
Text()84   StringView Text() const {
85     return StringView(text_, text_offset_.start, TextLength());
86   }
87 
GetWritingMode()88   WritingMode GetWritingMode() const { return Style().GetWritingMode(); }
IsHorizontal()89   bool IsHorizontal() const {
90     return IsHorizontalWritingMode(GetWritingMode());
91   }
92 
93   // Compute the inline position from text offset, in logical coordinate
94   // relative to this fragment.
95   LayoutUnit InlinePositionForOffset(unsigned offset) const;
96 
97   // The layout box of text in (start, end) range in local coordinate.
98   // Start and end offsets must be between StartOffset() and EndOffset().
99   PhysicalRect LocalRect(unsigned start_offset, unsigned end_offset) const;
100   using NGPhysicalFragment::LocalRect;
101 
102   // The visual bounding box that includes glpyh bounding box and CSS
103   // properties, in local coordinates.
104   PhysicalRect SelfInkOverflow() const;
105 
106   scoped_refptr<const NGPhysicalTextFragment> CloneAsHiddenForPaint() const;
107 
108   // Create a new fragment that has part of the text of this fragment.
109   // All other properties are the same as this fragment.
110   scoped_refptr<const NGPhysicalTextFragment> TrimText(
111       unsigned start_offset,
112       unsigned end_offset) const;
113 
114   scoped_refptr<const NGPhysicalFragment> CloneWithoutOffset() const;
115 
PaintInfo()116   NGTextFragmentPaintInfo PaintInfo() const {
117     return NGTextFragmentPaintInfo{text_, StartOffset(), EndOffset(),
118                                    TextShapeResult()};
119   }
120 
121   // Returns the text offset in the fragment placed closest to the given point.
122   unsigned TextOffsetForPoint(const PhysicalOffset&) const;
123 
124   UBiDiLevel BidiLevel() const;
ResolvedDirection()125   TextDirection ResolvedDirection() const {
126     return static_cast<TextDirection>(base_or_resolved_direction_);
127   }
128 
129   // Compute line-relative coordinates for given offsets, this is not
130   // flow-relative:
131   // https://drafts.csswg.org/css-writing-modes-3/#line-directions
132   std::pair<LayoutUnit, LayoutUnit> LineLeftAndRightForOffsets(
133       unsigned start_offset,
134       unsigned end_offset) const;
135 
136  private:
137   LayoutUnit InlinePositionForOffset(unsigned offset,
138                                      LayoutUnit (*round)(float),
139                                      AdjustMidCluster) const;
140 
141   void ComputeSelfInkOverflow() const;
142 
143   // The text of NGInlineNode; i.e., of a parent block. The text for this
144   // fragment is a substring(start_offset_, end_offset_) of this string.
145   const String text_;
146 
147   // Start and end offset of the parent block text.
148   const NGTextOffset text_offset_;
149   const scoped_refptr<const ShapeResultView> shape_result_;
150 
151   // Fragments are immutable but allow certain expensive data, specifically ink
152   // overflow, to be cached as long as it is guaranteed to always recompute to
153   // the same value.
154   mutable std::unique_ptr<NGInkOverflow> ink_overflow_;
155 
156   friend class NGTextFragmentBuilder;
157 };
158 
159 template <>
160 struct DowncastTraits<NGPhysicalTextFragment> {
161   static bool AllowFrom(const NGPhysicalFragment& fragment) {
162     return fragment.IsText();
163   }
164 };
165 
166 }  // namespace blink
167 
168 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
169