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