xref: /aosp_15_r20/external/skia/example/external_client/src/shape_text.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 Google LLC
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 "include/core/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkFontMgr.h"
13 #include "include/core/SkFontStyle.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkPixmap.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkStream.h"
18 #include "include/core/SkSurface.h"
19 #include "include/core/SkTypeface.h"
20 #include "include/core/SkTypes.h"
21 #include "include/encode/SkJpegEncoder.h"
22 #include "include/ports/SkFontMgr_empty.h"
23 #include "modules/skparagraph/include/DartTypes.h"
24 #include "modules/skparagraph/include/FontCollection.h"
25 #include "modules/skparagraph/include/Paragraph.h"
26 #include "modules/skparagraph/include/ParagraphBuilder.h"
27 #include "modules/skparagraph/include/ParagraphStyle.h"
28 #include "modules/skunicode/include/SkUnicode_icu.h"
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <memory>
33 
34 // https://www.gutenberg.org/ebooks/72339
35 constexpr const char* story =
36     "The landing port at Titan had not changed much in five years.\n"
37     "The ship settled down on the scarred blast shield, beside the same trio "
38     "of squat square buildings, and quickly disgorged its scanty quota of "
39     "cargo and a lone passenger into the flexible tube that linked the loading "
40     "hatch with the main building.\n"
41     "As soon as the tube was disconnected, the ship screamed off through the "
42     "murky atmosphere, seemingly glad to get away from Titan and head back to "
43     "the more comfortable and settled parts of the Solar System.";
44 
45 class OneFontStyleSet : public SkFontStyleSet {
46  public:
OneFontStyleSet(sk_sp<SkTypeface> face)47   explicit OneFontStyleSet(sk_sp<SkTypeface> face) : face_(face) {}
48 
49  protected:
count()50   int count() override { return 1; }
getStyle(int,SkFontStyle * out_style,SkString *)51   void getStyle(int, SkFontStyle* out_style, SkString*) override {
52     *out_style = SkFontStyle();
53   }
createTypeface(int index)54   sk_sp<SkTypeface> createTypeface(int index) override { return face_; }
matchStyle(const SkFontStyle &)55   sk_sp<SkTypeface> matchStyle(const SkFontStyle&) override { return face_; }
56 
57  private:
58   sk_sp<SkTypeface> face_;
59 };
60 
61 class OneFontMgr : public SkFontMgr {
62  public:
OneFontMgr(sk_sp<SkTypeface> face)63   explicit OneFontMgr(sk_sp<SkTypeface> face)
64       : face_(face), style_set_(sk_make_sp<OneFontStyleSet>(face)) {}
65 
66  protected:
onCountFamilies() const67   int onCountFamilies() const override { return 1; }
onGetFamilyName(int index,SkString * familyName) const68   void onGetFamilyName(int index, SkString* familyName) const override {
69     *familyName = SkString("the-only-font-I-have");
70   }
onCreateStyleSet(int index) const71   sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
72     return style_set_;
73   }
onMatchFamily(const char[]) const74   sk_sp<SkFontStyleSet> onMatchFamily(const char[]) const override {
75     return style_set_;
76   }
77 
onMatchFamilyStyle(const char[],const SkFontStyle &) const78   sk_sp<SkTypeface> onMatchFamilyStyle(const char[],
79                                        const SkFontStyle&) const override {
80     return face_;
81   }
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const82   sk_sp<SkTypeface> onMatchFamilyStyleCharacter(
83       const char familyName[], const SkFontStyle& style, const char* bcp47[],
84       int bcp47Count, SkUnichar character) const override {
85     return face_;
86   }
onLegacyMakeTypeface(const char[],SkFontStyle) const87   sk_sp<SkTypeface> onLegacyMakeTypeface(const char[],
88                                          SkFontStyle) const override {
89     return face_;
90   }
91 
onMakeFromData(sk_sp<SkData>,int) const92   sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int) const override {
93     std::abort();
94     return nullptr;
95   }
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,int) const96   sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
97                                           int) const override {
98     std::abort();
99     return nullptr;
100   }
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,const SkFontArguments &) const101   sk_sp<SkTypeface> onMakeFromStreamArgs(
102       std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override {
103     std::abort();
104     return nullptr;
105   }
onMakeFromFile(const char[],int) const106   sk_sp<SkTypeface> onMakeFromFile(const char[], int) const override {
107     std::abort();
108     return nullptr;
109   }
110 
111  private:
112   sk_sp<SkTypeface> face_;
113   sk_sp<SkFontStyleSet> style_set_;
114 };
115 
main(int argc,char ** argv)116 int main(int argc, char** argv) {
117   if (argc != 3) {
118     printf("Usage: %s <font.ttf> <name.jpg>", argv[0]);
119     return 1;
120   }
121 
122   SkFILEStream input(argv[1]);
123   if (!input.isValid()) {
124     printf("Cannot open input file %s\n", argv[1]);
125     return 1;
126   }
127   sk_sp<SkData> font_data = SkData::MakeFromStream(&input, input.getLength());
128   sk_sp<SkFontMgr> mgr = SkFontMgr_New_Custom_Empty();
129   sk_sp<SkTypeface> face = mgr->makeFromData(font_data);
130   if (!face) {
131     printf("input font %s was not parsable by Freetype\n", argv[1]);
132     return 1;
133   }
134 
135   SkFILEWStream output(argv[2]);
136   if (!output.isValid()) {
137     printf("Cannot open output file %s\n", argv[2]);
138     return 1;
139   }
140 
141   auto fontCollection = sk_make_sp<skia::textlayout::FontCollection>();
142   sk_sp<SkFontMgr> one_mgr = sk_make_sp<OneFontMgr>(face);
143   fontCollection->setDefaultFontManager(one_mgr);
144 
145   constexpr int width = 200;
146   sk_sp<SkSurface> surface =
147       SkSurfaces::Raster(SkImageInfo::MakeN32(width, 200, kOpaque_SkAlphaType));
148   SkCanvas* canvas = surface->getCanvas();
149   canvas->clear(SK_ColorWHITE);
150 
151   SkPaint paint;
152   paint.setAntiAlias(true);
153   paint.setColor(SK_ColorBLACK);
154 
155   skia::textlayout::TextStyle style;
156   style.setForegroundColor(paint);
157   style.setFontFamilies({SkString("sans-serif")});
158   style.setFontSize(10.5);
159   skia::textlayout::ParagraphStyle paraStyle;
160   paraStyle.setTextStyle(style);
161   paraStyle.setTextAlign(skia::textlayout::TextAlign::kRight);
162 
163   sk_sp<SkUnicode> unicode = SkUnicodes::ICU::Make();
164   if (!unicode) {
165     printf("Could not load unicode data\n");
166     return 1;
167   }
168   using skia::textlayout::ParagraphBuilder;
169   std::unique_ptr<ParagraphBuilder> builder =
170       ParagraphBuilder::make(paraStyle, fontCollection, unicode);
171   builder->addText(story);
172 
173   std::unique_ptr<skia::textlayout::Paragraph> paragraph = builder->Build();
174   paragraph->layout(width - 20);
175   paragraph->paint(canvas, 10, 10);
176 
177   SkPixmap pixmap;
178   if (surface->peekPixels(&pixmap)) {
179     if (!SkJpegEncoder::Encode(&output, pixmap, {})) {
180       printf("Cannot write output\n");
181       return 1;
182     }
183   } else {
184     printf("Cannot readback on surface\n");
185     return 1;
186   }
187 
188   return 0;
189 }
190