Add support for Decoration Styles, remove usage of separate decoration records.

Change-Id: I8fe929b0814b22e37e1517a7ddafb70a1c6b3d37
This commit is contained in:
Gary Qian
2017-06-20 18:28:09 -07:00
parent 3f5ae2f4a3
commit b4c8d2c134
5 changed files with 89 additions and 50 deletions

View File

@@ -22,16 +22,19 @@ namespace txt {
PaintRecord::~PaintRecord() = default;
PaintRecord::PaintRecord(SkColor color,
TextStyle style,
SkPoint offset,
sk_sp<SkTextBlob> text,
SkPaint::FontMetrics metrics)
: color_(color),
style_(style),
offset_(offset),
text_(std::move(text)),
metrics_(metrics) {}
PaintRecord::PaintRecord(PaintRecord&& other) {
color_ = other.color_;
style_ = other.style_;
offset_ = other.offset_;
text_ = std::move(other.text_);
metrics_ = other.metrics_;
@@ -39,6 +42,7 @@ PaintRecord::PaintRecord(PaintRecord&& other) {
PaintRecord& PaintRecord::operator=(PaintRecord&& other) {
color_ = other.color_;
style_ = other.style_;
offset_ = other.offset_;
text_ = std::move(other.text_);
metrics_ = other.metrics_;

View File

@@ -19,6 +19,7 @@
#include "lib/ftl/logging.h"
#include "lib/ftl/macros.h"
#include "lib/txt/src/text_style.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTextBlob.h"
@@ -31,6 +32,7 @@ class PaintRecord {
~PaintRecord();
PaintRecord(SkColor color,
TextStyle style,
SkPoint offset,
sk_sp<SkTextBlob> text,
SkPaint::FontMetrics metrics);
@@ -47,8 +49,11 @@ class PaintRecord {
const SkPaint::FontMetrics& metrics() const { return metrics_; }
const TextStyle& style() const { return style_; }
private:
SkColor color_;
TextStyle style_;
SkPoint offset_;
sk_sp<SkTextBlob> text_;
SkPaint::FontMetrics metrics_;

View File

@@ -31,6 +31,8 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkDiscretePathEffect.h"
namespace txt {
namespace {
@@ -230,11 +232,9 @@ void Paragraph::Layout(double width,
// run.
SkPaint::FontMetrics metrics;
paint.getFontMetrics(&metrics);
records_.push_back(PaintRecord{run.style.color, SkPoint::Make(x, y_),
builder.make(), metrics});
decorations_.push_back(
std::make_tuple(run.style.decoration, run.style.decoration_color,
run.style.decoration_style, run.style.font_weight));
records_.push_back(PaintRecord{run.style.color, run.style,
SkPoint::Make(x, y_), builder.make(),
metrics});
if (max_line_spacing < -metrics.fAscent * run.style.height)
max_line_spacing = -metrics.fAscent * run.style.height;
@@ -290,48 +290,87 @@ void Paragraph::SetParagraphStyle(const ParagraphStyle& style) {
}
void Paragraph::Paint(SkCanvas* canvas, double x, double y) {
int i = 0;
for (const auto& record : records_) {
SkPaint paint;
paint.setColor(record.color());
const SkPoint& offset = record.offset();
canvas->drawTextBlob(record.text(), x + offset.x(), y + offset.y(), paint);
PaintDecorations(canvas, x + offset.x(), y + offset.y(), decorations_[i],
PaintDecorations(canvas, x + offset.x(), y + offset.y(), record.style(),
record.metrics(), record.text());
i++;
}
}
void Paragraph::PaintDecorations(
SkCanvas* canvas,
double x,
double y,
std::tuple<TextDecoration, SkColor, TextDecorationStyle, FontWeight>
decoration,
SkPaint::FontMetrics metrics,
SkTextBlob* blob) {
if (std::get<0>(decoration) != TextDecoration::kNone) {
void Paragraph::PaintDecorations(SkCanvas* canvas,
double x,
double y,
TextStyle style,
SkPaint::FontMetrics metrics,
SkTextBlob* blob) {
if (style.decoration != TextDecoration::kNone) {
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(std::get<1>(decoration));
paint.setColor(style.decoration_color);
paint.setAntiAlias(true);
// This is set to 2 for the double line style
int decoration_count = 1;
switch (style.decoration_style) {
case TextDecorationStyle::kSolid:
break;
case TextDecorationStyle::kDouble: {
decoration_count = 2;
break;
}
case TextDecorationStyle::kDotted: {
const SkScalar intervals[] = {3.0f, 5.0f, 3.0f, 5.0f};
size_t count = sizeof(intervals) / sizeof(intervals[0]);
paint.setPathEffect(SkPathEffect::MakeCompose(
SkDashPathEffect::Make(intervals, count, 0.0f),
SkDiscretePathEffect::Make(0, 0)));
break;
}
case TextDecorationStyle::kDashed: {
const SkScalar intervals[] = {10.0f, 5.0f, 10.0f, 5.0f};
size_t count = sizeof(intervals) / sizeof(intervals[0]);
paint.setPathEffect(SkPathEffect::MakeCompose(
SkDashPathEffect::Make(intervals, count, 0.0f),
SkDiscretePathEffect::Make(0, 0)));
break;
}
case TextDecorationStyle::kWavy: {
// TODO(garyq): Wave currently does a random wave instead of an ordered
// wave.
const SkScalar intervals[] = {1};
size_t count = sizeof(intervals) / sizeof(intervals[0]);
paint.setPathEffect(SkPathEffect::MakeCompose(
SkDashPathEffect::Make(intervals, count, 0.0f),
SkDiscretePathEffect::Make(metrics.fAvgCharWidth / 10.0f,
metrics.fAvgCharWidth / 10.0f)));
break;
}
}
double width = blob->bounds().fRight + blob->bounds().fLeft;
if (std::get<0>(decoration) & 0x1) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y + metrics.fUnderlineThickness, x + width,
y + metrics.fUnderlineThickness, paint);
}
if (std::get<0>(decoration) & 0x2) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y + metrics.fAscent, x + width, y + metrics.fAscent,
paint);
}
if (std::get<0>(decoration) & 0x4) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y - metrics.fCapHeight / 2.5, x + width,
y - metrics.fCapHeight / 2.5, paint);
for (int i = 0; i < decoration_count; i++) {
double y_offset = i * metrics.fUnderlineThickness * 3.0f;
if (style.decoration & 0x1) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y + metrics.fUnderlineThickness + y_offset,
x + width, y + metrics.fUnderlineThickness + y_offset,
paint);
}
if (style.decoration & 0x2) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y + metrics.fAscent + y_offset, x + width,
y + metrics.fAscent + y_offset, paint);
}
if (style.decoration & 0x4) {
paint.setStrokeWidth(metrics.fUnderlineThickness);
canvas->drawLine(x, y - metrics.fXHeight / 2 + y_offset, x + width,
y - metrics.fXHeight / 2 + y_offset, paint);
}
}
}
}

View File

@@ -75,9 +75,6 @@ class Paragraph {
StyledRuns runs_;
minikin::LineBreaker breaker_;
std::vector<PaintRecord> records_;
std::vector<
std::tuple<TextDecoration, SkColor, TextDecorationStyle, FontWeight>>
decorations_;
ParagraphStyle paragraph_style_;
SkScalar y_ = 0.0f; // Height of the paragraph after Layout().
double width_ = 0.0f;
@@ -91,14 +88,12 @@ class Paragraph {
void AddRunsToLineBreaker(const std::string& rootdir = "");
void PaintDecorations(
SkCanvas* canvas,
double x,
double y,
std::tuple<TextDecoration, SkColor, TextDecorationStyle, FontWeight>
decoration,
SkPaint::FontMetrics metrics,
SkTextBlob* blob);
void PaintDecorations(SkCanvas* canvas,
double x,
double y,
TextStyle style,
SkPaint::FontMetrics metrics,
SkTextBlob* blob);
FTL_DISALLOW_COPY_AND_ASSIGN(Paragraph);
};

View File

@@ -19,6 +19,8 @@
namespace txt {
// Multiple decorations can be applied at once. Ex: Underline and overline is
// (0x1 | 0x2)
enum TextDecoration {
kNone = 0x0,
kUnderline = 0x1,
@@ -26,13 +28,7 @@ enum TextDecoration {
kLineThrough = 0x4,
};
enum TextDecorationStyle {
kSolid,
kDouble, // "double" is reserved.
kDotted,
kDashed,
kWavy
};
enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
} // namespace txt