1 /*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkSGText.h"
9
10 #include "SkCanvas.h"
11 #include "SkPaint.h"
12 #include "SkPath.h"
13 #include "SkTArray.h"
14 #include "SkTypeface.h"
15
16 namespace sksg {
17
Make(sk_sp<SkTypeface> tf,const SkString & text)18 sk_sp<Text> Text::Make(sk_sp<SkTypeface> tf, const SkString& text) {
19 return sk_sp<Text>(new Text(std::move(tf), text));
20 }
21
Text(sk_sp<SkTypeface> tf,const SkString & text)22 Text::Text(sk_sp<SkTypeface> tf, const SkString& text)
23 : fTypeface(std::move(tf))
24 , fText(text) {}
25
26 Text::~Text() = default;
27
alignedPosition(SkScalar advance) const28 SkPoint Text::alignedPosition(SkScalar advance) const {
29 auto aligned = fPosition;
30
31 switch (fAlign) {
32 case SkTextUtils::kLeft_Align:
33 break;
34 case SkTextUtils::kCenter_Align:
35 aligned.offset(-advance / 2, 0);
36 break;
37 case SkTextUtils::kRight_Align:
38 aligned.offset(-advance, 0);
39 break;
40 }
41
42 return aligned;
43 }
44
onRevalidate(InvalidationController *,const SkMatrix &)45 SkRect Text::onRevalidate(InvalidationController*, const SkMatrix&) {
46 // TODO: we could potentially track invals which don't require rebuilding the blob.
47
48 SkFont font;
49 font.setTypeface(fTypeface);
50 font.setSize(fSize);
51 font.setScaleX(fScaleX);
52 font.setSkewX(fSkewX);
53 font.setEdging(fEdging);
54 font.setHinting(fHinting);
55
56 // N.B.: fAlign is applied externally (in alignedPosition()), because
57 // 1) SkTextBlob has some trouble computing accurate bounds with alignment.
58 // 2) SkPaint::Align is slated for deprecation.
59
60 fBlob = SkTextBlob::MakeFromText(fText.c_str(), fText.size(), font, kUTF8_SkTextEncoding);
61 if (!fBlob) {
62 return SkRect::MakeEmpty();
63 }
64
65 const auto& bounds = fBlob->bounds();
66 const auto aligned_pos = this->alignedPosition(bounds.width());
67
68 return bounds.makeOffset(aligned_pos.x(), aligned_pos.y());
69 }
70
onDraw(SkCanvas * canvas,const SkPaint & paint) const71 void Text::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
72 const auto aligned_pos = this->alignedPosition(this->bounds().width());
73 canvas->drawTextBlob(fBlob, aligned_pos.x(), aligned_pos.y(), paint);
74 }
75
onContains(const SkPoint & p) const76 bool Text::onContains(const SkPoint& p) const {
77 return this->asPath().contains(p.x(), p.y());
78 }
79
onAsPath() const80 SkPath Text::onAsPath() const {
81 // TODO
82 return SkPath();
83 }
84
onClip(SkCanvas * canvas,bool antiAlias) const85 void Text::onClip(SkCanvas* canvas, bool antiAlias) const {
86 canvas->clipPath(this->asPath(), antiAlias);
87 }
88
Make(sk_sp<SkTextBlob> blob)89 sk_sp<TextBlob> TextBlob::Make(sk_sp<SkTextBlob> blob) {
90 return sk_sp<TextBlob>(new TextBlob(std::move(blob)));
91 }
92
TextBlob(sk_sp<SkTextBlob> blob)93 TextBlob::TextBlob(sk_sp<SkTextBlob> blob)
94 : fBlob(std::move(blob)) {}
95
96 TextBlob::~TextBlob() = default;
97
onRevalidate(InvalidationController *,const SkMatrix &)98 SkRect TextBlob::onRevalidate(InvalidationController*, const SkMatrix&) {
99 return fBlob ? fBlob->bounds() : SkRect::MakeEmpty();
100 }
101
onDraw(SkCanvas * canvas,const SkPaint & paint) const102 void TextBlob::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
103 canvas->drawTextBlob(fBlob, fPosition.x(), fPosition.y(), paint);
104 }
105
onContains(const SkPoint & p) const106 bool TextBlob::onContains(const SkPoint& p) const {
107 return this->asPath().contains(p.x(), p.y());
108 }
109
onAsPath() const110 SkPath TextBlob::onAsPath() const {
111 // TODO
112 return SkPath();
113 }
114
onClip(SkCanvas * canvas,bool antiAlias) const115 void TextBlob::onClip(SkCanvas* canvas, bool antiAlias) const {
116 canvas->clipPath(this->asPath(), antiAlias);
117 }
118
119 } // namespace sksg
120