Provide an SkPaint that describes the background of a text style (flutter/engine#5153)
Fixes https://github.com/flutter/flutter/issues/11961
This commit is contained in:
@@ -12,9 +12,7 @@
|
||||
#include "third_party/skia/include/core/SkShader.h"
|
||||
#include "third_party/skia/include/core/SkString.h"
|
||||
|
||||
using namespace blink;
|
||||
|
||||
namespace tonic {
|
||||
namespace blink {
|
||||
|
||||
// Indices for 32bit values.
|
||||
constexpr int kIsAntiAliasIndex = 0;
|
||||
@@ -52,17 +50,10 @@ constexpr double kStrokeMiterLimitDefault = 4.0;
|
||||
// Must be kept in sync with the MaskFilter private constants in painting.dart.
|
||||
enum MaskFilterType { Null, Blur };
|
||||
|
||||
Paint DartConverter<Paint>::FromArguments(Dart_NativeArguments args,
|
||||
int index,
|
||||
Dart_Handle& exception) {
|
||||
Dart_Handle paint_objects = Dart_GetNativeArgument(args, index);
|
||||
FXL_DCHECK(!LogIfError(paint_objects));
|
||||
|
||||
Dart_Handle paint_data = Dart_GetNativeArgument(args, index + 1);
|
||||
FXL_DCHECK(!LogIfError(paint_data));
|
||||
|
||||
Paint result;
|
||||
SkPaint& paint = result.paint_;
|
||||
Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) {
|
||||
is_null_ = Dart_IsNull(paint_data);
|
||||
if (is_null_)
|
||||
return;
|
||||
|
||||
if (!Dart_IsNull(paint_objects)) {
|
||||
FXL_DCHECK(Dart_IsList(paint_objects));
|
||||
@@ -72,12 +63,12 @@ Paint DartConverter<Paint>::FromArguments(Dart_NativeArguments args,
|
||||
FXL_CHECK(length == kObjectCount);
|
||||
Dart_Handle values[kObjectCount];
|
||||
if (Dart_IsError(Dart_ListGetRange(paint_objects, 0, kObjectCount, values)))
|
||||
return result;
|
||||
return;
|
||||
|
||||
Dart_Handle shader = values[kShaderIndex];
|
||||
if (!Dart_IsNull(shader)) {
|
||||
Shader* decoded = DartConverter<Shader*>::FromDart(shader);
|
||||
paint.setShader(decoded->shader());
|
||||
Shader* decoded = tonic::DartConverter<Shader*>::FromDart(shader);
|
||||
paint_.setShader(decoded->shader());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,49 +78,49 @@ Paint DartConverter<Paint>::FromArguments(Dart_NativeArguments args,
|
||||
const uint32_t* uint_data = static_cast<const uint32_t*>(byte_data.data());
|
||||
const float* float_data = static_cast<const float*>(byte_data.data());
|
||||
|
||||
paint.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0);
|
||||
paint_.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0);
|
||||
|
||||
uint32_t encoded_color = uint_data[kColorIndex];
|
||||
if (encoded_color) {
|
||||
SkColor color = encoded_color ^ kColorDefault;
|
||||
paint.setColor(color);
|
||||
paint_.setColor(color);
|
||||
}
|
||||
|
||||
uint32_t encoded_blend_mode = uint_data[kBlendModeIndex];
|
||||
if (encoded_blend_mode) {
|
||||
uint32_t blend_mode = encoded_blend_mode ^ kBlendModeDefault;
|
||||
paint.setBlendMode(static_cast<SkBlendMode>(blend_mode));
|
||||
paint_.setBlendMode(static_cast<SkBlendMode>(blend_mode));
|
||||
}
|
||||
|
||||
uint32_t style = uint_data[kStyleIndex];
|
||||
if (style)
|
||||
paint.setStyle(static_cast<SkPaint::Style>(style));
|
||||
paint_.setStyle(static_cast<SkPaint::Style>(style));
|
||||
|
||||
float stroke_width = float_data[kStrokeWidthIndex];
|
||||
if (stroke_width != 0.0)
|
||||
paint.setStrokeWidth(stroke_width);
|
||||
paint_.setStrokeWidth(stroke_width);
|
||||
|
||||
uint32_t stroke_cap = uint_data[kStrokeCapIndex];
|
||||
if (stroke_cap)
|
||||
paint.setStrokeCap(static_cast<SkPaint::Cap>(stroke_cap));
|
||||
paint_.setStrokeCap(static_cast<SkPaint::Cap>(stroke_cap));
|
||||
|
||||
uint32_t stroke_join = uint_data[kStrokeJoinIndex];
|
||||
if (stroke_join)
|
||||
paint.setStrokeJoin(static_cast<SkPaint::Join>(stroke_join));
|
||||
paint_.setStrokeJoin(static_cast<SkPaint::Join>(stroke_join));
|
||||
|
||||
float stroke_miter_limit = float_data[kStrokeMiterLimitIndex];
|
||||
if (stroke_miter_limit != 0.0)
|
||||
paint.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault);
|
||||
paint_.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault);
|
||||
|
||||
uint32_t filter_quality = uint_data[kFilterQualityIndex];
|
||||
if (filter_quality)
|
||||
paint.setFilterQuality(static_cast<SkFilterQuality>(filter_quality));
|
||||
paint_.setFilterQuality(static_cast<SkFilterQuality>(filter_quality));
|
||||
|
||||
if (uint_data[kColorFilterIndex]) {
|
||||
SkColor color = uint_data[kColorFilterColorIndex];
|
||||
SkBlendMode blend_mode =
|
||||
static_cast<SkBlendMode>(uint_data[kColorFilterBlendModeIndex]);
|
||||
paint.setColorFilter(SkColorFilter::MakeModeFilter(color, blend_mode));
|
||||
paint_.setColorFilter(SkColorFilter::MakeModeFilter(color, blend_mode));
|
||||
}
|
||||
|
||||
switch (uint_data[kMaskFilterIndex]) {
|
||||
@@ -139,18 +130,29 @@ Paint DartConverter<Paint>::FromArguments(Dart_NativeArguments args,
|
||||
SkBlurStyle blur_style =
|
||||
static_cast<SkBlurStyle>(uint_data[kMaskFilterBlurStyleIndex]);
|
||||
double sigma = float_data[kMaskFilterSigmaIndex];
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma));
|
||||
paint_.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma));
|
||||
break;
|
||||
}
|
||||
|
||||
result.is_null_ = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
PaintData DartConverter<PaintData>::FromArguments(Dart_NativeArguments args,
|
||||
int index,
|
||||
Dart_Handle& exception) {
|
||||
return PaintData();
|
||||
} // namespace blink
|
||||
|
||||
namespace tonic {
|
||||
|
||||
blink::Paint DartConverter<blink::Paint>::FromArguments(
|
||||
Dart_NativeArguments args, int index, Dart_Handle& exception) {
|
||||
Dart_Handle paint_objects = Dart_GetNativeArgument(args, index);
|
||||
FXL_DCHECK(!LogIfError(paint_objects));
|
||||
|
||||
Dart_Handle paint_data = Dart_GetNativeArgument(args, index + 1);
|
||||
FXL_DCHECK(!LogIfError(paint_data));
|
||||
|
||||
return blink::Paint(paint_objects, paint_data);
|
||||
}
|
||||
|
||||
blink::PaintData DartConverter<blink::PaintData>::FromArguments(
|
||||
Dart_NativeArguments args, int index, Dart_Handle& exception) {
|
||||
return blink::PaintData();
|
||||
}
|
||||
|
||||
} // namespace tonic
|
||||
|
||||
@@ -12,13 +12,16 @@ namespace blink {
|
||||
|
||||
class Paint {
|
||||
public:
|
||||
Paint() = default;
|
||||
Paint(Dart_Handle paint_objects, Dart_Handle paint_data);
|
||||
|
||||
const SkPaint* paint() const { return is_null_ ? nullptr : &paint_; }
|
||||
|
||||
private:
|
||||
friend struct tonic::DartConverter<Paint>;
|
||||
|
||||
SkPaint paint_;
|
||||
bool is_null_;
|
||||
bool is_null_ = true;
|
||||
};
|
||||
|
||||
// The PaintData argument is a placeholder to receive encoded data for Paint
|
||||
|
||||
@@ -257,6 +257,7 @@ Int32List _encodeTextStyle(
|
||||
double wordSpacing,
|
||||
double height,
|
||||
Locale locale,
|
||||
Paint background,
|
||||
) {
|
||||
final Int32List result = new Int32List(8);
|
||||
if (color != null) {
|
||||
@@ -311,6 +312,10 @@ Int32List _encodeTextStyle(
|
||||
result[0] |= 1 << 13;
|
||||
// Passed separately to native.
|
||||
}
|
||||
if (background != null) {
|
||||
result[0] |= 1 << 14;
|
||||
// Passed separately to native.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -331,6 +336,7 @@ class TextStyle {
|
||||
/// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box.
|
||||
/// * `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.
|
||||
TextStyle({
|
||||
Color color,
|
||||
TextDecoration decoration,
|
||||
@@ -345,6 +351,7 @@ class TextStyle {
|
||||
double wordSpacing,
|
||||
double height,
|
||||
Locale locale,
|
||||
Paint background,
|
||||
}) : _encoded = _encodeTextStyle(
|
||||
color,
|
||||
decoration,
|
||||
@@ -359,13 +366,15 @@ class TextStyle {
|
||||
wordSpacing,
|
||||
height,
|
||||
locale,
|
||||
background,
|
||||
),
|
||||
_fontFamily = fontFamily ?? '',
|
||||
_fontSize = fontSize,
|
||||
_letterSpacing = letterSpacing,
|
||||
_wordSpacing = wordSpacing,
|
||||
_height = height,
|
||||
_locale = locale;
|
||||
_locale = locale,
|
||||
_background = background;
|
||||
|
||||
final Int32List _encoded;
|
||||
final String _fontFamily;
|
||||
@@ -374,6 +383,7 @@ class TextStyle {
|
||||
final double _wordSpacing;
|
||||
final double _height;
|
||||
final Locale _locale;
|
||||
final Paint _background;
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
@@ -387,7 +397,8 @@ class TextStyle {
|
||||
_letterSpacing != typedOther._letterSpacing ||
|
||||
_wordSpacing != typedOther._wordSpacing ||
|
||||
_height != typedOther._height ||
|
||||
_locale != typedOther._locale)
|
||||
_locale != typedOther._locale ||
|
||||
_background != typedOther._background)
|
||||
return false;
|
||||
for (int index = 0; index < _encoded.length; index += 1) {
|
||||
if (_encoded[index] != typedOther._encoded[index])
|
||||
@@ -397,7 +408,7 @@ class TextStyle {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _letterSpacing, _wordSpacing, _height, _locale);
|
||||
int get hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _letterSpacing, _wordSpacing, _height, _locale, _background);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -414,7 +425,8 @@ class TextStyle {
|
||||
'letterSpacing: ${ _encoded[0] & 0x0400 == 0x0400 ? "${_letterSpacing}x" : "unspecified"}, '
|
||||
'wordSpacing: ${ _encoded[0] & 0x0800 == 0x0800 ? "${_wordSpacing}x" : "unspecified"}, '
|
||||
'height: ${ _encoded[0] & 0x1000 == 0x1000 ? "${_height}x" : "unspecified"}, '
|
||||
'locale: ${ _encoded[0] & 0x2000 == 0x2000 ? _locale : "unspecified"}'
|
||||
'locale: ${ _encoded[0] & 0x2000 == 0x2000 ? _locale : "unspecified"}, '
|
||||
'background: ${ _encoded[0] & 0x4000 == 0x4000 ? _background : "unspecified"}'
|
||||
')';
|
||||
}
|
||||
}
|
||||
@@ -1013,8 +1025,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));
|
||||
void _pushStyle(Int32List encoded, String fontFamily, double fontSize, double letterSpacing, double wordSpacing, double height, String locale) 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);
|
||||
void _pushStyle(Int32List encoded, String fontFamily, double fontSize, double letterSpacing, double wordSpacing, double height, String locale, List<dynamic> backgroundObjects, ByteData backgroundData) native 'ParagraphBuilder_pushStyle';
|
||||
|
||||
static String _encodeLocale(Locale locale) => locale?.toString() ?? '';
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ const int tsLetterSpacingIndex = 10;
|
||||
const int tsWordSpacingIndex = 11;
|
||||
const int tsHeightIndex = 12;
|
||||
const int tsLocaleIndex = 13;
|
||||
const int tsBackgroundIndex = 14;
|
||||
|
||||
const int tsColorMask = 1 << tsColorIndex;
|
||||
const int tsTextDecorationMask = 1 << tsTextDecorationIndex;
|
||||
@@ -56,6 +57,7 @@ const int tsLetterSpacingMask = 1 << tsLetterSpacingIndex;
|
||||
const int tsWordSpacingMask = 1 << tsWordSpacingIndex;
|
||||
const int tsHeightMask = 1 << tsHeightIndex;
|
||||
const int tsLocaleMask = 1 << tsLocaleIndex;
|
||||
const int tsBackgroundMask = 1 << tsBackgroundIndex;
|
||||
|
||||
// ParagraphStyle
|
||||
|
||||
@@ -290,7 +292,9 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
|
||||
double letterSpacing,
|
||||
double wordSpacing,
|
||||
double height,
|
||||
const std::string& locale) {
|
||||
const std::string& locale,
|
||||
Dart_Handle background_objects,
|
||||
Dart_Handle background_data) {
|
||||
FXL_DCHECK(encoded.num_elements() == 8);
|
||||
|
||||
int32_t mask = encoded[0];
|
||||
@@ -351,6 +355,14 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
|
||||
style.locale = locale;
|
||||
}
|
||||
|
||||
if (mask & tsBackgroundMask) {
|
||||
Paint background(background_objects, background_data);
|
||||
if (background.paint()) {
|
||||
style.has_background = true;
|
||||
style.background = *background.paint();
|
||||
}
|
||||
}
|
||||
|
||||
m_paragraphBuilder->PushStyle(style);
|
||||
} else {
|
||||
// Blink Version.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_BUILDER_H_
|
||||
|
||||
#include <memory>
|
||||
#include "flutter/lib/ui/painting/paint.h"
|
||||
#include "flutter/lib/ui/text/paragraph.h"
|
||||
#include "flutter/sky/engine/core/rendering/RenderObject.h"
|
||||
#include "flutter/sky/engine/wtf/OwnPtr.h"
|
||||
@@ -43,7 +44,9 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe<ParagraphBuilder>,
|
||||
double letterSpacing,
|
||||
double wordSpacing,
|
||||
double height,
|
||||
const std::string& locale);
|
||||
const std::string& locale,
|
||||
Dart_Handle background_objects,
|
||||
Dart_Handle background_data);
|
||||
|
||||
void pop();
|
||||
|
||||
|
||||
@@ -862,6 +862,7 @@ void Paragraph::Paint(SkCanvas* canvas, double x, double y) {
|
||||
for (const PaintRecord& record : records_) {
|
||||
paint.setColor(record.style().color);
|
||||
SkPoint offset = record.offset();
|
||||
PaintBackground(canvas, record);
|
||||
canvas->drawTextBlob(record.text(), offset.x(), offset.y(), paint);
|
||||
PaintDecorations(canvas, record);
|
||||
}
|
||||
@@ -1026,6 +1027,17 @@ void Paragraph::PaintDecorations(SkCanvas* canvas, const PaintRecord& record) {
|
||||
}
|
||||
}
|
||||
|
||||
void Paragraph::PaintBackground(SkCanvas* canvas, const PaintRecord& record) {
|
||||
if (!record.style().has_background)
|
||||
return;
|
||||
|
||||
const SkPaint::FontMetrics& metrics = record.metrics();
|
||||
SkRect rect(SkRect::MakeLTRB(0, metrics.fAscent,
|
||||
record.GetRunWidth(), metrics.fDescent));
|
||||
rect.offset(record.offset());
|
||||
canvas->drawRect(rect, record.style().background);
|
||||
}
|
||||
|
||||
std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(size_t start,
|
||||
size_t end) const {
|
||||
std::map<size_t, std::vector<Paragraph::TextBox>> line_boxes;
|
||||
|
||||
@@ -310,6 +310,9 @@ class Paragraph {
|
||||
// Creates and draws the decorations onto the canvas.
|
||||
void PaintDecorations(SkCanvas* canvas, const PaintRecord& record);
|
||||
|
||||
// Draws the background onto the canvas.
|
||||
void PaintBackground(SkCanvas* canvas, const PaintRecord& record);
|
||||
|
||||
FXL_DISALLOW_COPY_AND_ASSIGN(Paragraph);
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "text_baseline.h"
|
||||
#include "text_decoration.h"
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
#include "third_party/skia/include/core/SkPaint.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
@@ -46,6 +47,8 @@ class TextStyle {
|
||||
double word_spacing = 0.0;
|
||||
double height = 1.0;
|
||||
std::string locale;
|
||||
bool has_background = false;
|
||||
SkPaint background;
|
||||
|
||||
TextStyle();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user