diff --git a/lib/ui/text.dart b/lib/ui/text.dart index ff623068acd6b..a98b2414e6d3b 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -258,6 +258,7 @@ Int32List _encodeTextStyle( double height, Locale locale, Paint background, + Paint foreground, ) { final Int32List result = new Int32List(8); if (color != null) { @@ -316,6 +317,10 @@ Int32List _encodeTextStyle( result[0] |= 1 << 14; // Passed separately to native. } + if (foreground != null) { + result[0] |= 1 << 15; + // Passed separately to native. + } return result; } @@ -323,7 +328,7 @@ Int32List _encodeTextStyle( class TextStyle { /// Creates a new TextStyle object. /// - /// * `color`: The color to use when painting the text. + /// * `color`: The color to use when painting the text. If this is specified, `foreground` must be null. /// * `decoration`: The decorations to paint near the text (e.g., an underline). /// * `decorationColor`: The color in which to paint the text decorations. /// * `decorationStyle`: The style in which to paint the text decorations (e.g., dashed). @@ -337,6 +342,7 @@ class TextStyle { /// * `height`: The height of this text span, as a multiple of the font size. /// * `locale`: The locale used to select region-specific glyphs. /// * `background`: The paint drawn as a background for the text. + /// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null. TextStyle({ Color color, TextDecoration decoration, @@ -352,7 +358,12 @@ class TextStyle { double height, Locale locale, Paint background, - }) : _encoded = _encodeTextStyle( + Paint foreground, + }) : assert(color == null || foreground == null, + 'Cannot provide both a color and a foreground\n' + 'The color argument is just a shorthand for "foreground: new Paint()..color = color".' + ), + _encoded = _encodeTextStyle( color, decoration, decorationColor, @@ -367,6 +378,7 @@ class TextStyle { height, locale, background, + foreground, ), _fontFamily = fontFamily ?? '', _fontSize = fontSize, @@ -374,7 +386,8 @@ class TextStyle { _wordSpacing = wordSpacing, _height = height, _locale = locale, - _background = background; + _background = background, + _foreground = foreground; final Int32List _encoded; final String _fontFamily; @@ -384,6 +397,7 @@ class TextStyle { final double _height; final Locale _locale; final Paint _background; + final Paint _foreground; @override bool operator ==(dynamic other) { @@ -398,7 +412,8 @@ class TextStyle { _wordSpacing != typedOther._wordSpacing || _height != typedOther._height || _locale != typedOther._locale || - _background != typedOther._background) + _background != typedOther._background || + _foreground != typedOther._foreground) return false; for (int index = 0; index < _encoded.length; index += 1) { if (_encoded[index] != typedOther._encoded[index]) @@ -408,7 +423,7 @@ class TextStyle { } @override - int get hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _letterSpacing, _wordSpacing, _height, _locale, _background); + int get hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _letterSpacing, _wordSpacing, _height, _locale, _background, _foreground); @override String toString() { @@ -426,7 +441,8 @@ class TextStyle { 'wordSpacing: ${ _encoded[0] & 0x0800 == 0x0800 ? "${_wordSpacing}x" : "unspecified"}, ' 'height: ${ _encoded[0] & 0x1000 == 0x1000 ? "${_height}x" : "unspecified"}, ' 'locale: ${ _encoded[0] & 0x2000 == 0x2000 ? _locale : "unspecified"}, ' - 'background: ${ _encoded[0] & 0x4000 == 0x4000 ? _background : "unspecified"}' + 'background: ${ _encoded[0] & 0x4000 == 0x4000 ? _background : "unspecified"}, ' + 'foreground: ${ _encoded[0] & 0x8000 == 0x8000 ? _foreground : "unspecified"}' ')'; } } @@ -1025,8 +1041,8 @@ class ParagraphBuilder extends NativeFieldWrapperClass2 { /// Applies the given style to the added text until [pop] is called. /// /// See [pop] for details. - void pushStyle(TextStyle style) => _pushStyle(style._encoded, style._fontFamily, style._fontSize, style._letterSpacing, style._wordSpacing, style._height, _encodeLocale(style._locale), style._background?._objects, style._background?._data); - void _pushStyle(Int32List encoded, String fontFamily, double fontSize, double letterSpacing, double wordSpacing, double height, String locale, List backgroundObjects, ByteData backgroundData) native 'ParagraphBuilder_pushStyle'; + void pushStyle(TextStyle style) => _pushStyle(style._encoded, style._fontFamily, style._fontSize, style._letterSpacing, style._wordSpacing, style._height, _encodeLocale(style._locale), style._background?._objects, style._background?._data, style._foreground?._objects, style._foreground?._data); + void _pushStyle(Int32List encoded, String fontFamily, double fontSize, double letterSpacing, double wordSpacing, double height, String locale, List backgroundObjects, ByteData backgroundData, List foregroundObjects, ByteData foregroundData) native 'ParagraphBuilder_pushStyle'; static String _encodeLocale(Locale locale) => locale?.toString() ?? ''; diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 926819eeac8aa..c9b896294c59c 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -39,6 +39,7 @@ const int tsWordSpacingIndex = 11; const int tsHeightIndex = 12; const int tsLocaleIndex = 13; const int tsBackgroundIndex = 14; +const int tsForegroundIndex = 15; const int tsColorMask = 1 << tsColorIndex; const int tsTextDecorationMask = 1 << tsTextDecorationIndex; @@ -54,6 +55,7 @@ const int tsWordSpacingMask = 1 << tsWordSpacingIndex; const int tsHeightMask = 1 << tsHeightIndex; const int tsLocaleMask = 1 << tsLocaleIndex; const int tsBackgroundMask = 1 << tsBackgroundIndex; +const int tsForegroundMask = 1 << tsForegroundIndex; // ParagraphStyle @@ -167,7 +169,9 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, double height, const std::string& locale, Dart_Handle background_objects, - Dart_Handle background_data) { + Dart_Handle background_data, + Dart_Handle foreground_objects, + Dart_Handle foreground_data) { FXL_DCHECK(encoded.num_elements() == 8); int32_t mask = encoded[0]; @@ -235,6 +239,14 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, } } + if (mask & tsForegroundMask) { + Paint foreground(foreground_objects, foreground_data); + if (foreground.paint()) { + style.has_foreground = true; + style.foreground = *foreground.paint(); + } + } + m_paragraphBuilder->PushStyle(style); } diff --git a/lib/ui/text/paragraph_builder.h b/lib/ui/text/paragraph_builder.h index fb8e368cc30ee..723c3d78fd12d 100644 --- a/lib/ui/text/paragraph_builder.h +++ b/lib/ui/text/paragraph_builder.h @@ -43,7 +43,9 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double height, const std::string& locale, Dart_Handle background_objects, - Dart_Handle background_data); + Dart_Handle background_data, + Dart_Handle foreground_objects, + Dart_Handle foreground_data); void pop(); diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index e1bd883bf8345..78b2ef8be9deb 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -877,7 +877,12 @@ void Paragraph::Paint(SkCanvas* canvas, double x, double y) { canvas->translate(x, y); SkPaint paint; for (const PaintRecord& record : records_) { - paint.setColor(record.style().color); + if (record.style().has_foreground) { + paint = record.style().foreground; + } else { + paint.reset(); + paint.setColor(record.style().color); + } SkPoint offset = record.offset(); PaintBackground(canvas, record); canvas->drawTextBlob(record.text(), offset.x(), offset.y(), paint); @@ -1049,8 +1054,8 @@ void Paragraph::PaintBackground(SkCanvas* canvas, const PaintRecord& record) { return; const SkPaint::FontMetrics& metrics = record.metrics(); - SkRect rect(SkRect::MakeLTRB(0, metrics.fAscent, - record.GetRunWidth(), metrics.fDescent)); + SkRect rect(SkRect::MakeLTRB(0, metrics.fAscent, record.GetRunWidth(), + metrics.fDescent)); rect.offset(record.offset()); canvas->drawRect(rect, record.style().background); } @@ -1090,15 +1095,16 @@ std::vector Paragraph::GetRectsForRange(size_t start, } // Add empty rectangles representing any newline characters within the range. - for (size_t line_number = 0; line_number < line_ranges_.size(); ++line_number) { + for (size_t line_number = 0; line_number < line_ranges_.size(); + ++line_number) { const LineRange& line = line_ranges_[line_number]; if (line.start >= end) break; if (line.end_including_newline <= start) continue; if (line_boxes.find(line_number) == line_boxes.end()) { - if (line.end != line.end_including_newline && - line.end >= start && line.end_including_newline <= end) { + if (line.end != line.end_including_newline && line.end >= start && + line.end_including_newline <= end) { SkScalar x = line_widths_[line_number]; SkScalar top = (line_number > 0) ? line_heights_[line_number - 1] : 0; SkScalar bottom = line_heights_[line_number]; diff --git a/third_party/txt/src/txt/text_style.cc b/third_party/txt/src/txt/text_style.cc index 242b6f3818b77..abf9cde1b9048 100644 --- a/third_party/txt/src/txt/text_style.cc +++ b/third_party/txt/src/txt/text_style.cc @@ -49,6 +49,8 @@ bool TextStyle::equals(const TextStyle& other) const { return false; if (locale != other.locale) return false; + if (foreground != other.foreground) + return false; return true; } diff --git a/third_party/txt/src/txt/text_style.h b/third_party/txt/src/txt/text_style.h index 2b995132a36d7..6d91b5862ff19 100644 --- a/third_party/txt/src/txt/text_style.h +++ b/third_party/txt/src/txt/text_style.h @@ -49,6 +49,8 @@ class TextStyle { std::string locale; bool has_background = false; SkPaint background; + bool has_foreground = false; + SkPaint foreground; TextStyle();