/* * 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 #include #include // 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 face) : face_(face) {} protected: int count() override { return 1; } void getStyle(int, SkFontStyle* out_style, SkString*) override { *out_style = SkFontStyle(); } sk_sp createTypeface(int index) override { return face_; } sk_sp matchStyle(const SkFontStyle&) override { return face_; } private: sk_sp face_; }; class OneFontMgr : public SkFontMgr { public: explicit OneFontMgr(sk_sp face) : face_(face), style_set_(sk_make_sp(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 onCreateStyleSet(int index) const override { return style_set_; } sk_sp onMatchFamily(const char[]) const override { return style_set_; } sk_sp onMatchFamilyStyle(const char[], const SkFontStyle&) const override { return face_; } sk_sp onMatchFamilyStyleCharacter( const char familyName[], const SkFontStyle& style, const char* bcp47[], int bcp47Count, SkUnichar character) const override { return face_; } sk_sp onLegacyMakeTypeface(const char[], SkFontStyle) const override { return face_; } sk_sp onMakeFromData(sk_sp, int) const override { std::abort(); return nullptr; } sk_sp onMakeFromStreamIndex(std::unique_ptr, int) const override { std::abort(); return nullptr; } sk_sp onMakeFromStreamArgs( std::unique_ptr, const SkFontArguments&) const override { std::abort(); return nullptr; } sk_sp onMakeFromFile(const char[], int) const override { std::abort(); return nullptr; } private: sk_sp face_; sk_sp style_set_; }; int main(int argc, char** argv) { if (argc != 3) { printf("Usage: %s ", argv[0]); return 1; } SkFILEStream input(argv[1]); if (!input.isValid()) { printf("Cannot open input file %s\n", argv[1]); return 1; } sk_sp font_data = SkData::MakeFromStream(&input, input.getLength()); sk_sp mgr = SkFontMgr_New_Custom_Empty(); sk_sp 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(); sk_sp one_mgr = sk_make_sp(face); fontCollection->setDefaultFontManager(one_mgr); constexpr int width = 200; sk_sp 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 unicode = SkUnicodes::ICU::Make(); if (!unicode) { printf("Could not load unicode data\n"); return 1; } using skia::textlayout::ParagraphBuilder; std::unique_ptr builder = ParagraphBuilder::make(paraStyle, fontCollection, unicode); builder->addText(story); std::unique_ptr 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; }