diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 19270c7ec74883d7d958a29f8090815baca26164..66761bf23f2ff9128f352d5e89c42fcef55860ae 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -384,6 +384,7 @@ Int32List _encodeParagraphStyle(TextAlign textAlign, String fontFamily, double fontSize, double lineHeight, + int maxLines, String ellipsis) { Int32List result = new Int32List(5); if (textAlign != null) { @@ -414,10 +415,14 @@ Int32List _encodeParagraphStyle(TextAlign textAlign, result[0] |= 1 << 7; // Passed separately to native. } - if (ellipsis != null) { + if (maxLines != null) { result[0] |= 1 << 8; // Passed separately to native. } + if (ellipsis != null) { + result[0] |= 1 << 9; + // Passed separately to native. + } return result; } @@ -441,6 +446,7 @@ class ParagraphStyle { String fontFamily, double fontSize, double lineHeight, + int maxLines, String ellipsis }) : _encoded = _encodeParagraphStyle(textAlign, fontWeight, @@ -449,10 +455,12 @@ class ParagraphStyle { fontFamily, fontSize, lineHeight, + maxLines, ellipsis), _fontFamily = fontFamily, _fontSize = fontSize, _lineHeight = lineHeight, + _maxLines = maxLines, _ellipsis = ellipsis { assert(lineCount == null); } @@ -461,6 +469,7 @@ class ParagraphStyle { final String _fontFamily; final double _fontSize; final double _lineHeight; + final int _maxLines; final String _ellipsis; bool operator ==(dynamic other) { @@ -472,6 +481,7 @@ class ParagraphStyle { if ( _fontFamily != typedOther._fontFamily || _fontSize != typedOther._fontSize || _lineHeight != typedOther._lineHeight || + _maxLines != typedOther._maxLines || _ellipsis != typedOther._ellipsis) return false; for (int index = 0; index < _encoded.length; index += 1) { @@ -481,7 +491,7 @@ class ParagraphStyle { return true; } - int get hashCode => hashValues(hashList(_encoded), _lineHeight); + int get hashCode => hashValues(hashList(_encoded), _lineHeight, _maxLines, _ellipsis); String toString() { return 'ParagraphStyle(' @@ -492,7 +502,8 @@ class ParagraphStyle { 'fontFamily: ${ _encoded[0] & 0x20 == 0x20 ? _fontFamily : "unspecified"}, ' 'fontSize: ${ _encoded[0] & 0x40 == 0x40 ? _fontSize : "unspecified"}, ' 'lineHeight: ${ _encoded[0] & 0x80 == 0x80 ? "${_lineHeight}x" : "unspecified"}, ' - 'ellipsis: ${ _encoded[0] & 0x100 == 0x100 ? "\"$_ellipsis\"" : "unspecified"}' + 'maxLines: ${ _encoded[0] & 0x100 == 0x100 ? _maxLines : "unspecified"}, ' + 'ellipsis: ${ _encoded[0] & 0x200 == 0x200 ? "\"$_ellipsis\"" : "unspecified"}' ')'; } } @@ -716,8 +727,8 @@ abstract class Paragraph extends NativeFieldWrapperClass2 { class ParagraphBuilder extends NativeFieldWrapperClass2 { /// Creates a [ParagraphBuilder] object, which is used to create a /// [Paragraph]. - ParagraphBuilder(ParagraphStyle style) { _constructor(style._encoded, style._fontFamily, style._fontSize, style._lineHeight, style._ellipsis); } - void _constructor(Int32List encoded, String fontFamily, double fontSize, double lineHeight, String ellipsis) native "ParagraphBuilder_constructor"; + ParagraphBuilder(ParagraphStyle style) { _constructor(style._encoded, style._fontFamily, style._fontSize, style._lineHeight, style._maxLines, style._ellipsis); } + void _constructor(Int32List encoded, String fontFamily, double fontSize, double lineHeight, int maxLines, String ellipsis) native "ParagraphBuilder_constructor"; /// Applies the given style to the added text until [pop] is called. /// diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 6745698c755c7cef0910a4e7b73ae18495b3bbe6..f60a759590112dd9ec60d05965b96d441924da72 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -57,7 +57,8 @@ const int psFontStyleIndex = 3; const int psFontFamilyIndex = 5; const int psFontSizeIndex = 6; const int psLineHeightIndex = 7; -const int psEllipsisIndex = 8; +const int psMaxLinesIndex = 8; +const int psEllipsisIndex = 9; const int psTextAlignMask = 1 << psTextAlignIndex; const int psFontWeightMask = 1 << psFontWeightIndex; @@ -65,6 +66,7 @@ const int psFontStyleMask = 1 << psFontStyleIndex; const int psFontFamilyMask = 1 << psFontFamilyIndex; const int psFontSizeMask = 1 << psFontSizeIndex; const int psLineHeightMask = 1 << psLineHeightIndex; +const int psMaxLinesMask = 1 << psMaxLinesIndex; const int psEllipsisMask = 1 << psEllipsisIndex; float getComputedSizeFromSpecifiedSize(float specifiedSize) { @@ -100,6 +102,7 @@ PassRefPtr decodeParagraphStyle( const std::string& fontFamily, double fontSize, double lineHeight, + int maxLines, const std::string& ellipsis) { FTL_DCHECK(encoded.num_elements() == 5); @@ -144,10 +147,11 @@ PassRefPtr decodeParagraphStyle( if (mask & psLineHeightMask) style->setLineHeight(Length(lineHeight * 100.0, Percent)); - if (mask & psEllipsisMask) { + if (mask & psMaxLinesMask) + style->setMaxLines(maxLines); + + if (mask & psEllipsisMask) style->setEllipsis(AtomicString::fromUTF8(ellipsis.c_str())); - style->setWordBreak(BreakAllWordBreak); - } return style.release(); } @@ -175,7 +179,7 @@ FOR_EACH_BINDING(DART_NATIVE_CALLBACK) void ParagraphBuilder::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register( - {{"ParagraphBuilder_constructor", ParagraphBuilder_constructor, 6, true}, + {{"ParagraphBuilder_constructor", ParagraphBuilder_constructor, 7, true}, FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } @@ -184,20 +188,22 @@ ftl::RefPtr ParagraphBuilder::create( const std::string& fontFamily, double fontSize, double lineHeight, + int maxLines, const std::string& ellipsis) { return ftl::MakeRefCounted( - encoded, fontFamily, fontSize, lineHeight, ellipsis); + encoded, fontFamily, fontSize, lineHeight, maxLines, ellipsis); } ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, const std::string& fontFamily, double fontSize, double lineHeight, + int maxLines, const std::string& ellipsis) { createRenderView(); RefPtr paragraphStyle = decodeParagraphStyle( - m_renderView->style(), encoded, fontFamily, fontSize, lineHeight, ellipsis); + m_renderView->style(), encoded, fontFamily, fontSize, lineHeight, maxLines, ellipsis); encoded.Release(); m_renderParagraph = new RenderParagraph(); diff --git a/lib/ui/text/paragraph_builder.h b/lib/ui/text/paragraph_builder.h index 7a156f23c2d6d82161742ff790a0d9aed2aa42e2..17a9fb779a36a0145bdf787f7565da7c35eb3c8b 100644 --- a/lib/ui/text/paragraph_builder.h +++ b/lib/ui/text/paragraph_builder.h @@ -25,6 +25,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe, const std::string& fontFamily, double fontSize, double lineHeight, + int maxLines, const std::string& ellipsis); ~ParagraphBuilder() override; @@ -48,6 +49,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe, const std::string& fontFamily, double fontSize, double lineHeight, + int maxLines, const std::string& ellipsis); void createRenderView(); diff --git a/sky/engine/core/rendering/RenderParagraph.cpp b/sky/engine/core/rendering/RenderParagraph.cpp index 0c8b59aa4d25d80e30c27bd7b7bca87f180cef89..b690716f20cd2d76a2c1358afcd55de85c994298 100644 --- a/sky/engine/core/rendering/RenderParagraph.cpp +++ b/sky/engine/core/rendering/RenderParagraph.cpp @@ -23,7 +23,6 @@ #include "flutter/sky/engine/wtf/Vector.h" #include "flutter/sky/engine/wtf/unicode/CharacterNames.h" - namespace blink { using namespace WTF::Unicode; diff --git a/sky/engine/core/rendering/line/BreakingContext.cpp b/sky/engine/core/rendering/line/BreakingContext.cpp index c7f023e19292821b4dc71401cdbed3113b6fe621..0320c0ff9408f81287d3f5630f0fd776f586935d 100644 --- a/sky/engine/core/rendering/line/BreakingContext.cpp +++ b/sky/engine/core/rendering/line/BreakingContext.cpp @@ -62,6 +62,8 @@ InlineIterator BreakingContext::handleEndOfLine() } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.object())); } + m_lineInfo.incrementLineIndex(); + return m_lineBreak; } diff --git a/sky/engine/core/rendering/line/BreakingContextInlineHeaders.h b/sky/engine/core/rendering/line/BreakingContextInlineHeaders.h index c33cb7929362f5bdca4659544925eeddb7a50704..00011c298ec12b4a18e11cfdb2336d6e61a21277 100644 --- a/sky/engine/core/rendering/line/BreakingContextInlineHeaders.h +++ b/sky/engine/core/rendering/line/BreakingContextInlineHeaders.h @@ -84,7 +84,6 @@ public: void increment(); - void handleBR(); void handleOutOfFlowPositioned(Vector& positionedObjects); void handleEmptyInline(); void handleReplaced(); @@ -225,26 +224,6 @@ inline void BreakingContext::increment() m_atStart = false; } -inline void BreakingContext::handleBR() -{ - if (m_width.fitsOnLine()) { - RenderObject* br = m_current.object(); - m_lineBreak.moveToStartOf(br); - m_lineBreak.increment(); - - // A
always breaks a line, so don't let the line be collapsed - // away. Also, the space at the end of a line with a
does not - // get collapsed away. It only does this if the previous line broke - // cleanly. Otherwise the
has no effect on whether the line is - // empty or not. - if (m_startingNewParagraph) - m_lineInfo.setEmpty(false, m_block, &m_width); - m_trailingObjects.clear(); - m_lineInfo.setPreviousLineBrokeCleanly(true); - } - m_atEnd = true; -} - inline LayoutUnit borderPaddingMarginStart(RenderInline* child) { return child->marginStart() + child->paddingStart() + child->borderStart(); @@ -467,12 +446,16 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool float hyphenWidth = 0; - bool ellipsizeMode = !m_blockStyle->ellipsis().isEmpty(); + bool ellipsizeMode = false; float ellipsisWidth = 0; unsigned ellipsisBreakOffset = 0; - if (ellipsizeMode) { - ASSERT(breakAll); - ellipsisWidth = measureEllipsisWidth(renderText, font, m_blockStyle->ellipsis().string()); + if (m_lineInfo.lineIndex() == m_blockStyle->maxLines() - 1 || + m_blockStyle->maxLines() == INT_MAX) { + ellipsizeMode = !m_blockStyle->ellipsis().isEmpty(); + if (ellipsizeMode) { + ellipsisWidth = measureEllipsisWidth(renderText, font, m_blockStyle->ellipsis().string()); + breakAll = true; + } } if (m_renderTextInfo.m_text != renderText) { @@ -629,6 +612,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); m_lineBreak.increment(); m_lineInfo.setPreviousLineBrokeCleanly(true); + m_lineInfo.incrementLineIndex(); // caller only calls this if we return false return true; } diff --git a/sky/engine/core/rendering/line/LineInfo.h b/sky/engine/core/rendering/line/LineInfo.h index fbfcf051ed1d8f0e325e04b3e20926e8cc52e59a..ea4b338828b2cb5c3a944ccd4ce9d1ea5b5c0430 100644 --- a/sky/engine/core/rendering/line/LineInfo.h +++ b/sky/engine/core/rendering/line/LineInfo.h @@ -36,6 +36,7 @@ public: , m_isEmpty(true) , m_previousLineBrokeCleanly(true) , m_runsFromLeadingWhitespace(0) + , m_lineIndex(0) { } bool isFirstLine() const { return m_isFirstLine; } @@ -53,6 +54,9 @@ public: m_isEmpty = empty; } + void incrementLineIndex() { ++m_lineIndex; } + int lineIndex() const { return m_lineIndex; } + void setPreviousLineBrokeCleanly(bool previousLineBrokeCleanly) { m_previousLineBrokeCleanly = previousLineBrokeCleanly; } private: @@ -61,6 +65,7 @@ private: bool m_isEmpty; bool m_previousLineBrokeCleanly; unsigned m_runsFromLeadingWhitespace; + int m_lineIndex; }; } diff --git a/sky/engine/core/rendering/style/RenderStyle.h b/sky/engine/core/rendering/style/RenderStyle.h index 21327ba759aa29bb046fae8d5f2ee59e07290e06..e583b86ee39e24c80f8de8377ee2ba5a5afcb81e 100644 --- a/sky/engine/core/rendering/style/RenderStyle.h +++ b/sky/engine/core/rendering/style/RenderStyle.h @@ -645,6 +645,7 @@ public: // Flutter property getters const AtomicString& ellipsis() const { return rareNonInheritedData->m_ellipsis; } + int maxLines() const { return rareNonInheritedData->m_maxLines; } // attribute setter methods @@ -905,6 +906,7 @@ public: // Flutter property setters void setEllipsis(const AtomicString& e) { SET_VAR(rareNonInheritedData, m_ellipsis, e); } + void setMaxLines(int m) { SET_VAR(rareNonInheritedData, m_maxLines, m); } static ClipPathOperation* initialClipPath() { return 0; } diff --git a/sky/engine/core/rendering/style/StyleRareNonInheritedData.cpp b/sky/engine/core/rendering/style/StyleRareNonInheritedData.cpp index 25922cc87bfa8e146e6f857b019f977a031878a2..7d775642ae60fdd54744464d81bf7451f5b8ecf2 100644 --- a/sky/engine/core/rendering/style/StyleRareNonInheritedData.cpp +++ b/sky/engine/core/rendering/style/StyleRareNonInheritedData.cpp @@ -40,6 +40,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , m_textDecorationColor(StyleColor::currentColor()) , m_order(RenderStyle::initialOrder()) , m_objectPosition(RenderStyle::initialObjectPosition()) + , m_maxLines(INT_MAX) , m_transformStyle3D(RenderStyle::initialTransformStyle3D()) , m_alignContent(RenderStyle::initialAlignContent()) , m_alignItems(RenderStyle::initialAlignItems()) @@ -79,6 +80,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_textDecorationColor(o.m_textDecorationColor) , m_order(o.m_order) , m_objectPosition(o.m_objectPosition) + , m_maxLines(o.m_maxLines) , m_transformStyle3D(o.m_transformStyle3D) , m_alignContent(o.m_alignContent) , m_alignItems(o.m_alignItems) @@ -122,6 +124,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_textDecorationColor == o.m_textDecorationColor && m_order == o.m_order && m_objectPosition == o.m_objectPosition + && m_maxLines == o.m_maxLines && m_transformStyle3D == o.m_transformStyle3D && m_alignContent == o.m_alignContent && m_alignItems == o.m_alignItems diff --git a/sky/engine/core/rendering/style/StyleRareNonInheritedData.h b/sky/engine/core/rendering/style/StyleRareNonInheritedData.h index 3f88757b4f3d6f8c06104140b1220de73e99a2c2..15f7f11be807b3c813059bd332426662073b2ac9 100644 --- a/sky/engine/core/rendering/style/StyleRareNonInheritedData.h +++ b/sky/engine/core/rendering/style/StyleRareNonInheritedData.h @@ -88,6 +88,7 @@ public: LengthPoint m_objectPosition; AtomicString m_ellipsis; + int m_maxLines; unsigned m_transformStyle3D : 1; // ETransformStyle3D