aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorFlorin Malita <fmalita@chromium.org>2018-11-01 11:16:18 -0400
committerSkia Commit-Bot <skia-commit-bot@chromium.org>2018-11-04 15:19:46 +0000
commit0a8b4e1acbd6100e81f3d825ce3d087928744010 (patch)
tree66a36149b57dec6a09cf3679713985683b356934 /modules
parent16d91aaf44faa8ca02305a4572c80d05b43f2883 (diff)
downloadskqp-0a8b4e1acbd6100e81f3d825ce3d087928744010.tar.gz
[skottie] Add support for explicit text line breaks
To support wacky explicit AE line breaking: * add sksg::TextBlob (SG node backed by externally-built text blobs) * add skottie::TextAdapter logic to handle \r line breaks and construct the blob explicitly Change-Id: I2eed9adf28a8c3c1f7de5bbec3d32abd7ddbd484 Reviewed-on: https://skia-review.googlesource.com/c/167384 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'modules')
-rw-r--r--modules/skottie/src/SkottieAdapter.cpp87
-rw-r--r--modules/skottie/src/SkottieAdapter.h19
-rw-r--r--modules/sksg/include/SkSGText.h30
-rw-r--r--modules/sksg/src/SkSGText.cpp27
4 files changed, 139 insertions, 24 deletions
diff --git a/modules/skottie/src/SkottieAdapter.cpp b/modules/skottie/src/SkottieAdapter.cpp
index b317c75061..1426b79c9f 100644
--- a/modules/skottie/src/SkottieAdapter.cpp
+++ b/modules/skottie/src/SkottieAdapter.cpp
@@ -7,6 +7,7 @@
#include "SkottieAdapter.h"
+#include "SkFont.h"
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkRRect.h"
@@ -19,7 +20,10 @@
#include "SkSGText.h"
#include "SkSGTransform.h"
#include "SkSGTrimEffect.h"
+#include "SkTextBlob.h"
+#include "SkTextUtils.h"
#include "SkTo.h"
+#include "SkUTF.h"
#include "SkottieValue.h"
#include <cmath>
@@ -179,7 +183,7 @@ void TrimEffectAdapter::apply() {
TextAdapter::TextAdapter(sk_sp<sksg::Group> root)
: fRoot(std::move(root))
- , fTextNode(sksg::Text::Make(nullptr, SkString()))
+ , fTextNode(sksg::TextBlob::Make())
, fFillColor(sksg::Color::Make(SK_ColorTRANSPARENT))
, fStrokeColor(sksg::Color::Make(SK_ColorTRANSPARENT))
, fFillNode(sksg::Draw::Make(fTextNode, fFillColor))
@@ -198,21 +202,80 @@ TextAdapter::TextAdapter(sk_sp<sksg::Group> root)
//
// * where the text node is shared
- fTextNode->setFlags(fTextNode->getFlags() |
- SkPaint::kAntiAlias_Flag |
- SkPaint::kSubpixelText_Flag);
- fTextNode->setHinting(SkPaint::kNo_Hinting);
-
+ fFillColor->setAntiAlias(true);
+ fStrokeColor->setAntiAlias(true);
fStrokeColor->setStyle(SkPaint::kStroke_Style);
}
-void TextAdapter::apply() {
- // Push text props to the scene graph.
- fTextNode->setTypeface(fText.fTypeface);
- fTextNode->setText(fText.fText);
- fTextNode->setSize(fText.fTextSize);
- fTextNode->setAlign(fText.fAlign);
+sk_sp<SkTextBlob> TextAdapter::makeBlob() const {
+ // TODO: convert to SkFont (missing getFontSpacing, measureText).
+ SkPaint font;
+ font.setTypeface(fText.fTypeface);
+ font.setTextSize(fText.fTextSize);
+ font.setHinting(SkPaint::kNo_Hinting);
+ font.setSubpixelText(true);
+ font.setAntiAlias(true);
+ font.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+
+ const auto align_fract = [](SkTextUtils::Align align) {
+ switch (align) {
+ case SkTextUtils::kLeft_Align: return 0.0f;
+ case SkTextUtils::kCenter_Align: return -0.5f;
+ case SkTextUtils::kRight_Align: return -1.0f;
+ }
+ return 0.0f; // go home, msvc...
+ }(fText.fAlign);
+
+ const auto line_spacing = font.getFontSpacing();
+ const auto blob_font = SkFont::LEGACY_ExtractFromPaint(font);
+ float y_off = 0;
+ SkSTArray<256, SkGlyphID, true> line_glyph_buffer;
+ SkTextBlobBuilder builder;
+
+ const auto& push_line = [&](const char* start, const char* end) {
+ if (end > start) {
+ const auto len = SkToSizeT(end - start);
+ line_glyph_buffer.reset(font.textToGlyphs(start, len, nullptr));
+ SkAssertResult(font.textToGlyphs(start, len, line_glyph_buffer.data())
+ == line_glyph_buffer.count());
+
+ const auto x_off = align_fract != 0
+ ? align_fract * font.measureText(start, len)
+ : 0;
+ const auto& buf = builder.allocRun(blob_font, line_glyph_buffer.count(), x_off, y_off);
+ if (!buf.glyphs) {
+ return;
+ }
+
+ memcpy(buf.glyphs, line_glyph_buffer.data(),
+ SkToSizeT(line_glyph_buffer.count()) * sizeof(SkGlyphID));
+
+ y_off += line_spacing;
+ }
+ };
+
+ const auto& is_line_break = [](SkUnichar uch) {
+ // TODO: other explicit breaks?
+ return uch == '\r';
+ };
+ const char* ptr = fText.fText.c_str();
+ const char* line_start = ptr;
+ const char* end = ptr + fText.fText.size();
+
+ while (ptr < end) {
+ if (is_line_break(SkUTF::NextUTF8(&ptr, end))) {
+ push_line(line_start, ptr - 1);
+ line_start = ptr;
+ }
+ }
+ push_line(line_start, ptr);
+
+ return builder.make();
+}
+
+void TextAdapter::apply() {
+ fTextNode->setBlob(this->makeBlob());
fFillColor->setColor(fText.fFillColor);
fStrokeColor->setColor(fText.fStrokeColor);
fStrokeColor->setStrokeWidth(fText.fStrokeWidth);
diff --git a/modules/skottie/src/SkottieAdapter.h b/modules/skottie/src/SkottieAdapter.h
index f9a40fdadc..a162e06f81 100644
--- a/modules/skottie/src/SkottieAdapter.h
+++ b/modules/skottie/src/SkottieAdapter.h
@@ -24,7 +24,7 @@ class Matrix;
class Path;
class RadialGradient;
class RRect;
-class Text;
+class TextBlob;
class TrimEffect;
};
@@ -175,16 +175,17 @@ public:
private:
void apply();
+ sk_sp<SkTextBlob> makeBlob() const;
- sk_sp<sksg::Group> fRoot;
- sk_sp<sksg::Text> fTextNode;
- sk_sp<sksg::Color> fFillColor,
- fStrokeColor;
- sk_sp<sksg::Draw> fFillNode,
- fStrokeNode;
+ sk_sp<sksg::Group> fRoot;
+ sk_sp<sksg::TextBlob> fTextNode;
+ sk_sp<sksg::Color> fFillColor,
+ fStrokeColor;
+ sk_sp<sksg::Draw> fFillNode,
+ fStrokeNode;
- bool fHadFill : 1, // - state cached from the prev apply()
- fHadStroke : 1; // /
+ bool fHadFill : 1, // - state cached from the prev apply()
+ fHadStroke : 1; // /
using INHERITED = SkRefCnt;
};
diff --git a/modules/sksg/include/SkSGText.h b/modules/sksg/include/SkSGText.h
index 09683e9c3b..cce9c5a3f8 100644
--- a/modules/sksg/include/SkSGText.h
+++ b/modules/sksg/include/SkSGText.h
@@ -13,11 +13,11 @@
#include "SkPaintDefaults.h"
#include "SkPoint.h"
#include "SkString.h"
+#include "SkTextBlob.h"
#include "SkTextUtils.h"
class SkCanvas;
class SkPaint;
-class SkTextBlob;
class SkTypeface;
namespace sksg {
@@ -50,7 +50,7 @@ protected:
SkPath onAsPath() const override;
private:
- explicit Text(sk_sp<SkTypeface>, const SkString&);
+ Text(sk_sp<SkTypeface>, const SkString&);
SkPoint alignedPosition(SkScalar advance) const;
@@ -69,6 +69,32 @@ private:
using INHERITED = GeometryNode;
};
+/**
+ * Concrete Geometry node, wrapping an external SkTextBlob.
+ */
+class TextBlob final : public GeometryNode {
+public:
+ static sk_sp<TextBlob> Make(sk_sp<SkTextBlob> = nullptr);
+ ~TextBlob() override;
+
+ SG_ATTRIBUTE(Blob , sk_sp<SkTextBlob>, fBlob )
+ SG_ATTRIBUTE(Position, SkPoint , fPosition)
+
+protected:
+ void onClip(SkCanvas*, bool antiAlias) const override;
+ void onDraw(SkCanvas*, const SkPaint&) const override;
+
+ SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
+
+private:
+ explicit TextBlob(sk_sp<SkTextBlob>);
+
+ sk_sp<SkTextBlob> fBlob;
+ SkPoint fPosition = SkPoint::Make(0, 0);
+
+ using INHERITED = GeometryNode;
+};
} // namespace sksg
#endif // SkSGText_DEFINED
diff --git a/modules/sksg/src/SkSGText.cpp b/modules/sksg/src/SkSGText.cpp
index f63fcf035d..81a909366d 100644
--- a/modules/sksg/src/SkSGText.cpp
+++ b/modules/sksg/src/SkSGText.cpp
@@ -11,7 +11,6 @@
#include "SkPaint.h"
#include "SkPath.h"
#include "SkTArray.h"
-#include "SkTextBlob.h"
#include "SkTypeface.h"
namespace sksg {
@@ -100,4 +99,30 @@ void Text::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipPath(this->asPath(), antiAlias);
}
+sk_sp<TextBlob> TextBlob::Make(sk_sp<SkTextBlob> blob) {
+ return sk_sp<TextBlob>(new TextBlob(std::move(blob)));
+}
+
+TextBlob::TextBlob(sk_sp<SkTextBlob> blob)
+ : fBlob(std::move(blob)) {}
+
+TextBlob::~TextBlob() = default;
+
+SkRect TextBlob::onRevalidate(InvalidationController*, const SkMatrix&) {
+ return fBlob ? fBlob->bounds() : SkRect::MakeEmpty();
+}
+
+void TextBlob::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
+ canvas->drawTextBlob(fBlob, fPosition.x(), fPosition.y(), paint);
+}
+
+SkPath TextBlob::onAsPath() const {
+ // TODO
+ return SkPath();
+}
+
+void TextBlob::onClip(SkCanvas* canvas, bool antiAlias) const {
+ canvas->clipPath(this->asPath(), antiAlias);
+}
+
} // namespace sksg