| // 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 NGLineBreaker_h |
| #define NGLineBreaker_h |
| |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h" |
| #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" |
| #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" |
| #include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h" |
| #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h" |
| #include "third_party/blink/renderer/platform/text/text_break_iterator.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator.h" |
| |
| namespace blink { |
| |
| class Hyphenation; |
| class NGContainerFragmentBuilder; |
| class NGInlineBreakToken; |
| class NGInlineItem; |
| class NGInlineLayoutStateStack; |
| struct NGPositionedFloat; |
| struct NGUnpositionedFloat; |
| |
| // The line breaker needs to know which mode its in to properly handle floats. |
| enum class NGLineBreakerMode { kContent, kMinContent, kMaxContent }; |
| |
| // Represents a line breaker. |
| // |
| // This class measures each NGInlineItem and determines items to form a line, |
| // so that NGInlineLayoutAlgorithm can build a line box from the output. |
| class CORE_EXPORT NGLineBreaker { |
| STACK_ALLOCATED(); |
| |
| public: |
| NGLineBreaker(NGInlineNode, |
| NGLineBreakerMode, |
| const NGConstraintSpace&, |
| Vector<NGPositionedFloat>*, |
| Vector<scoped_refptr<NGUnpositionedFloat>>*, |
| NGContainerFragmentBuilder* container_builder, |
| NGExclusionSpace*, |
| unsigned handled_float_index, |
| const NGLineLayoutOpportunity&, |
| const NGInlineBreakToken* = nullptr); |
| ~NGLineBreaker(); |
| |
| // Compute the next line break point and produces NGInlineItemResults for |
| // the line. |
| void NextLine(NGLineInfo*); |
| |
| // Create an NGInlineBreakToken for the last line returned by NextLine(). |
| scoped_refptr<NGInlineBreakToken> CreateBreakToken( |
| const NGLineInfo&, |
| std::unique_ptr<const NGInlineLayoutStateStack>) const; |
| |
| // Compute NGInlineItemResult for an open tag item. |
| // Returns true if this item has edge and may have non-zero inline size. |
| static bool ComputeOpenTagResult(const NGInlineItem&, |
| const NGConstraintSpace&, |
| NGInlineItemResult*); |
| |
| private: |
| const String& Text() const { return items_data_.text_content; } |
| const Vector<NGInlineItem>& Items() const { return items_data_.items; } |
| |
| NGInlineItemResult* AddItem(const NGInlineItem&, unsigned end_offset); |
| NGInlineItemResult* AddItem(const NGInlineItem&); |
| void SetLineEndFragment(scoped_refptr<NGPhysicalTextFragment>); |
| void ComputeCanBreakAfter(NGInlineItemResult*) const; |
| |
| void BreakLine(); |
| |
| void PrepareNextLine(); |
| |
| void UpdatePosition(); |
| void ComputeLineLocation() const; |
| |
| enum class LineBreakState { |
| // The line breaking is complete. |
| kDone, |
| |
| // Should complete the line at the earliest possible point. |
| // Trailing spaces, <br>, or close tags should be included to the line even |
| // when it is overflowing. |
| kTrailing, |
| |
| // The initial state, until the first character is found. |
| kLeading, |
| |
| // Looking for more items to fit into the current line. |
| kContinue, |
| }; |
| |
| void HandleText(const NGInlineItem&); |
| void BreakText(NGInlineItemResult*, |
| const NGInlineItem&, |
| LayoutUnit available_width); |
| void TruncateTextEnd(NGInlineItemResult*); |
| scoped_refptr<ShapeResult> ShapeText(const NGInlineItem& item, |
| unsigned start, |
| unsigned end); |
| void HandleTrailingSpaces(const NGInlineItem&); |
| void RemoveTrailingCollapsibleSpace(); |
| void AppendHyphen(const NGInlineItem& item); |
| |
| void HandleControlItem(const NGInlineItem&); |
| void HandleBidiControlItem(const NGInlineItem&); |
| void HandleAtomicInline(const NGInlineItem&); |
| void HandleFloat(const NGInlineItem&); |
| |
| void HandleOpenTag(const NGInlineItem&); |
| void HandleCloseTag(const NGInlineItem&); |
| |
| void HandleOverflow(); |
| void Rewind(unsigned new_end); |
| |
| void SetCurrentStyle(const ComputedStyle&); |
| |
| void MoveToNextOf(const NGInlineItem&); |
| void MoveToNextOf(const NGInlineItemResult&); |
| |
| void ComputeBaseDirection(); |
| bool IsTrailing(const NGInlineItem&) const; |
| |
| LayoutUnit AvailableWidth() const { |
| return line_opportunity_.AvailableInlineSize(); |
| } |
| LayoutUnit AvailableWidthToFit() const { |
| return AvailableWidth().AddEpsilon(); |
| } |
| |
| // These fields are the output of the current line. |
| // NGInlineItemResults is a pointer because the move operation is not cheap |
| // due to its inline buffer. |
| NGLineInfo* line_info_ = nullptr; |
| NGInlineItemResults* item_results_ = nullptr; |
| |
| // Represents the current offset of the input. |
| LineBreakState state_; |
| unsigned item_index_ = 0; |
| unsigned offset_ = 0; |
| |
| // The current position from inline_start. Unlike NGInlineLayoutAlgorithm |
| // that computes position in visual order, this position in logical order. |
| LayoutUnit position_; |
| NGLineLayoutOpportunity line_opportunity_; |
| |
| NGInlineNode node_; |
| |
| // True if this line is the "first formatted line". |
| // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line |
| bool is_first_formatted_line_ = false; |
| |
| bool use_first_line_style_ = false; |
| |
| // True when current box allows line wrapping. |
| bool auto_wrap_ = false; |
| |
| // True when current box has 'word-break/word-wrap: break-word'. |
| bool break_anywhere_if_overflow_ = false; |
| |
| // Force LineBreakType::kBreakCharacter by ignoring the current style. |
| // Set to find grapheme cluster boundaries for 'break-word' after overflow. |
| bool override_break_anywhere_ = false; |
| |
| // True when breaking at soft hyphens (U+00AD) is allowed. |
| bool enable_soft_hyphen_ = true; |
| |
| // True in quirks mode or limited-quirks mode, which require line-height |
| // quirks. |
| // https://quirks.spec.whatwg.org/#the-line-height-calculation-quirk |
| bool in_line_height_quirks_mode_ = false; |
| |
| // True when the line we are breaking has a list marker. |
| bool has_list_marker_ = false; |
| |
| // True if trailing collapsible spaces have been collapsed. |
| bool trailing_spaces_collapsed_ = false; |
| |
| // Set when the line ended with a forced break. Used to setup the states for |
| // the next line. |
| bool is_after_forced_break_ = false; |
| |
| bool ignore_floats_ = false; |
| |
| const NGInlineItemsData& items_data_; |
| |
| NGLineBreakerMode mode_; |
| const NGConstraintSpace& constraint_space_; |
| Vector<NGPositionedFloat>* positioned_floats_; |
| Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats_; |
| NGContainerFragmentBuilder* container_builder_; /* May be nullptr */ |
| NGExclusionSpace* exclusion_space_; |
| scoped_refptr<const ComputedStyle> current_style_; |
| |
| LazyLineBreakIterator break_iterator_; |
| HarfBuzzShaper shaper_; |
| ShapeResultSpacing<String> spacing_; |
| bool previous_line_had_forced_break_ = false; |
| const Hyphenation* hyphenation_ = nullptr; |
| |
| // Keep track of handled float items. See HandleFloat(). |
| unsigned handled_floats_end_item_index_; |
| |
| // The current base direction for the bidi algorithm. |
| // This is copied from NGInlineNode, then updated after each forced line break |
| // if 'unicode-bidi: plaintext'. |
| TextDirection base_direction_; |
| }; |
| |
| } // namespace blink |
| |
| #endif // NGLineBreaker_h |