blob: 0958ea239ae909c51da5ea21abfb704390f520dc [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkAlphaType.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/encode/SkJpegEncoder.h"
#include "include/ports/SkFontMgr_empty.h"
#include "modules/skparagraph/include/DartTypes.h"
#include "modules/skparagraph/include/FontCollection.h"
#include "modules/skparagraph/include/Paragraph.h"
#include "modules/skparagraph/include/ParagraphBuilder.h"
#include "modules/skparagraph/include/ParagraphStyle.h"
#include "modules/skunicode/include/SkUnicode_icu.h"
#include <cstdio>
#include <cstdlib>
#include <memory>
// https://www.gutenberg.org/ebooks/72339
constexpr const char* story =
"The landing port at Titan had not changed much in five years.\n"
"The ship settled down on the scarred blast shield, beside the same trio "
"of squat square buildings, and quickly disgorged its scanty quota of "
"cargo and a lone passenger into the flexible tube that linked the loading "
"hatch with the main building.\n"
"As soon as the tube was disconnected, the ship screamed off through the "
"murky atmosphere, seemingly glad to get away from Titan and head back to "
"the more comfortable and settled parts of the Solar System.";
class OneFontStyleSet : public SkFontStyleSet {
public:
explicit OneFontStyleSet(sk_sp<SkTypeface> face) : face_(face) {}
protected:
int count() override { return 1; }
void getStyle(int, SkFontStyle* out_style, SkString*) override {
*out_style = SkFontStyle();
}
sk_sp<SkTypeface> createTypeface(int index) override { return face_; }
sk_sp<SkTypeface> matchStyle(const SkFontStyle&) override { return face_; }
private:
sk_sp<SkTypeface> face_;
};
class OneFontMgr : public SkFontMgr {
public:
explicit OneFontMgr(sk_sp<SkTypeface> face)
: face_(face), style_set_(sk_make_sp<OneFontStyleSet>(face)) {}
protected:
int onCountFamilies() const override { return 1; }
void onGetFamilyName(int index, SkString* familyName) const override {
*familyName = SkString("the-only-font-I-have");
}
sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
return style_set_;
}
sk_sp<SkFontStyleSet> onMatchFamily(const char[]) const override {
return style_set_;
}
sk_sp<SkTypeface> onMatchFamilyStyle(const char[],
const SkFontStyle&) const override {
return face_;
}
sk_sp<SkTypeface> onMatchFamilyStyleCharacter(
const char familyName[], const SkFontStyle& style, const char* bcp47[],
int bcp47Count, SkUnichar character) const override {
return face_;
}
sk_sp<SkTypeface> onLegacyMakeTypeface(const char[],
SkFontStyle) const override {
return face_;
}
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int) const override {
std::abort();
return nullptr;
}
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
int) const override {
std::abort();
return nullptr;
}
sk_sp<SkTypeface> onMakeFromStreamArgs(
std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override {
std::abort();
return nullptr;
}
sk_sp<SkTypeface> onMakeFromFile(const char[], int) const override {
std::abort();
return nullptr;
}
private:
sk_sp<SkTypeface> face_;
sk_sp<SkFontStyleSet> style_set_;
};
int main(int argc, char** argv) {
if (argc != 3) {
printf("Usage: %s <font.ttf> <name.png>", argv[0]);
return 1;
}
SkFILEStream input(argv[1]);
if (!input.isValid()) {
printf("Cannot open input file %s\n", argv[1]);
return 1;
}
sk_sp<SkData> font_data = SkData::MakeFromStream(&input, input.getLength());
sk_sp<SkFontMgr> mgr = SkFontMgr_New_Custom_Empty();
sk_sp<SkTypeface> face = mgr->makeFromData(font_data);
if (!face) {
printf("input font %s was not parsable by Freetype\n", argv[1]);
return 1;
}
SkFILEWStream output(argv[2]);
if (!output.isValid()) {
printf("Cannot open output file %s\n", argv[2]);
return 1;
}
auto fontCollection = sk_make_sp<skia::textlayout::FontCollection>();
sk_sp<SkFontMgr> one_mgr = sk_make_sp<OneFontMgr>(face);
fontCollection->setDefaultFontManager(one_mgr);
constexpr int width = 200;
sk_sp<SkSurface> surface =
SkSurfaces::Raster(SkImageInfo::MakeN32(width, 200, kOpaque_SkAlphaType));
SkCanvas* canvas = surface->getCanvas();
canvas->clear(SK_ColorWHITE);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorBLACK);
skia::textlayout::TextStyle style;
style.setForegroundColor(paint);
style.setFontFamilies({SkString("sans-serif")});
style.setFontSize(10.5);
skia::textlayout::ParagraphStyle paraStyle;
paraStyle.setTextStyle(style);
paraStyle.setTextAlign(skia::textlayout::TextAlign::kRight);
sk_sp<SkUnicode> unicode = SkUnicodes::ICU::Make();
if (!unicode) {
printf("Could not load unicode data\n");
return 1;
}
using skia::textlayout::ParagraphBuilder;
std::unique_ptr<ParagraphBuilder> builder =
ParagraphBuilder::make(paraStyle, fontCollection, unicode);
builder->addText(story);
std::unique_ptr<skia::textlayout::Paragraph> paragraph = builder->Build();
paragraph->layout(width - 20);
paragraph->paint(canvas, 10, 10);
SkPixmap pixmap;
if (surface->peekPixels(&pixmap)) {
if (!SkJpegEncoder::Encode(&output, pixmap, {})) {
printf("Cannot write output\n");
return 1;
}
} else {
printf("Cannot readback on surface\n");
return 1;
}
return 0;
}