From af78a942179143e4646871fc797e2ce17c23a594 Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Fri, 23 Mar 2018 14:39:42 +0000 Subject: Revert "Add color fonts." This reverts commit c912d6133c66df7cde3d64adc76941856a12da64. Reason for revert: Causing TSAN issues. Original change's description: > Add color fonts. > > BUG=skia:7624 > > Change-Id: Id2b7449048591892ff802484d5e3745a7e1402bb > Reviewed-on: https://skia-review.googlesource.com/109521 > Commit-Queue: Ben Wagner > Reviewed-by: Mike Klein > Reviewed-by: Herb Derby TBR=mtklein@google.com,bungeman@google.com,herb@google.com Change-Id: I2ccd1f00e91bb92b7059323c95da0dd3de954164 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia:7624 Reviewed-on: https://skia-review.googlesource.com/116141 Reviewed-by: Jim Van Verth Commit-Queue: Jim Van Verth --- BUILD.gn | 18 +- gm/fontmgr.cpp | 7 +- public.bzl | 6 +- resources/fonts/cbdt.ttf | Bin 18020 -> 0 bytes resources/fonts/colr.ttf | Bin 2996 -> 0 bytes resources/fonts/sbix.ttf | Bin 17956 -> 0 bytes resources/fonts/svg/diamond.svg | 22 - resources/fonts/svg/empty.svg | 10 - resources/fonts/svg/notdef.svg | 29 - resources/fonts/svg/smile.svg | 44 -- src/ports/SkFontHost_win.cpp | 7 - tools/fonts/SkTestFontMgr.cpp | 28 +- tools/fonts/SkTestSVGTypeface.cpp | 1302 -------------------------------- tools/fonts/SkTestSVGTypeface.h | 132 ---- tools/fonts/SkTestScalerContext.cpp | 267 +++++++ tools/fonts/SkTestScalerContext.h | 102 +++ tools/fonts/SkTestTypeface.cpp | 274 ------- tools/fonts/SkTestTypeface.h | 116 --- tools/fonts/create_test_font_color.cpp | 37 - tools/fonts/sk_tool_utils_font.cpp | 41 +- tools/sk_tool_utils.cpp | 24 +- tools/sk_tool_utils.h | 13 +- 22 files changed, 414 insertions(+), 2065 deletions(-) delete mode 100644 resources/fonts/cbdt.ttf delete mode 100644 resources/fonts/colr.ttf delete mode 100644 resources/fonts/sbix.ttf delete mode 100644 resources/fonts/svg/diamond.svg delete mode 100644 resources/fonts/svg/empty.svg delete mode 100644 resources/fonts/svg/notdef.svg delete mode 100644 resources/fonts/svg/smile.svg delete mode 100644 tools/fonts/SkTestSVGTypeface.cpp delete mode 100644 tools/fonts/SkTestSVGTypeface.h create mode 100644 tools/fonts/SkTestScalerContext.cpp create mode 100644 tools/fonts/SkTestScalerContext.h delete mode 100644 tools/fonts/SkTestTypeface.cpp delete mode 100644 tools/fonts/SkTestTypeface.h delete mode 100644 tools/fonts/create_test_font_color.cpp diff --git a/BUILD.gn b/BUILD.gn index 95a9bbaf7e..cc7468fb22 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1277,11 +1277,7 @@ if (skia_enable_tools) { "tools/debugger/SkObjectParser.cpp", "tools/fonts/SkRandomScalerContext.cpp", "tools/fonts/SkTestFontMgr.cpp", - "tools/fonts/SkTestFontMgr.h", - "tools/fonts/SkTestSVGTypeface.cpp", - "tools/fonts/SkTestSVGTypeface.h", - "tools/fonts/SkTestTypeface.cpp", - "tools/fonts/SkTestTypeface.h", + "tools/fonts/SkTestScalerContext.cpp", "tools/fonts/sk_tool_utils_font.cpp", "tools/picture_utils.cpp", "tools/random_parse_path.cpp", @@ -1301,7 +1297,6 @@ if (skia_enable_tools) { } deps = [ ":common_flags", - ":experimental_svg_model", ":flags", "//third_party/libpng", ] @@ -1672,17 +1667,6 @@ if (skia_enable_tools) { ] } - test_app("create_test_font_color") { - sources = [ - "tools/fonts/create_test_font_color.cpp", - ] - deps = [ - ":flags", - ":skia", - ":tool_utils" - ] - } - test_app("get_images_from_skps") { sources = [ "tools/get_images_from_skps.cpp", diff --git a/gm/fontmgr.cpp b/gm/fontmgr.cpp index 58c569c300..a0b2f5b44a 100644 --- a/gm/fontmgr.cpp +++ b/gm/fontmgr.cpp @@ -9,7 +9,6 @@ #include "sk_tool_utils.h" #include "SkCanvas.h" #include "SkFontMgr.h" -#include "SkPath.h" #include "SkGraphics.h" #include "SkTypeface.h" @@ -225,7 +224,6 @@ public: fontBounds.offset(x, y); SkPaint boundsPaint(glyphPaint); boundsPaint.setColor(boundsColor); - boundsPaint.setStyle(SkPaint::kStroke_Style); canvas->drawRect(fontBounds, boundsPaint); SkPaint::FontMetrics fm; @@ -266,10 +264,6 @@ public: } SkGlyphID str[] = { left, right, top, bottom }; for (size_t i = 0; i < SK_ARRAY_COUNT(str); ++i) { - SkPath path; - glyphPaint.getTextPath(&str[i], sizeof(str[0]), x, y, &path); - SkPaint::Style style = path.isEmpty() ? SkPaint::kFill_Style : SkPaint::kStroke_Style; - glyphPaint.setStyle(style); canvas->drawText(&str[i], sizeof(str[0]), x, y, glyphPaint); } } @@ -288,6 +282,7 @@ protected: paint.setAntiAlias(true); paint.setSubpixelText(true); paint.setTextSize(100); + paint.setStyle(SkPaint::kStroke_Style); paint.setTextScaleX(fScaleX); paint.setTextSkewX(fSkewX); diff --git a/public.bzl b/public.bzl index 407ad1ce4c..fbd005bf0f 100644 --- a/public.bzl +++ b/public.bzl @@ -457,10 +457,8 @@ DM_SRCS_ALL = struct( "tools/fonts/SkRandomScalerContext.h", "tools/fonts/SkTestFontMgr.cpp", "tools/fonts/SkTestFontMgr.h", - "tools/fonts/SkTestSVGTypeface.cpp", - "tools/fonts/SkTestSVGTypeface.h", - "tools/fonts/SkTestTypeface.cpp", - "tools/fonts/SkTestTypeface.h", + "tools/fonts/SkTestScalerContext.cpp", + "tools/fonts/SkTestScalerContext.h", "tools/fonts/sk_tool_utils_font.cpp", "tools/fonts/test_font_monospace.inc", "tools/fonts/test_font_sans_serif.inc", diff --git a/resources/fonts/cbdt.ttf b/resources/fonts/cbdt.ttf deleted file mode 100644 index bed498f07e..0000000000 Binary files a/resources/fonts/cbdt.ttf and /dev/null differ diff --git a/resources/fonts/colr.ttf b/resources/fonts/colr.ttf deleted file mode 100644 index 42e2a08096..0000000000 Binary files a/resources/fonts/colr.ttf and /dev/null differ diff --git a/resources/fonts/sbix.ttf b/resources/fonts/sbix.ttf deleted file mode 100644 index 5eed8a917b..0000000000 Binary files a/resources/fonts/sbix.ttf and /dev/null differ diff --git a/resources/fonts/svg/diamond.svg b/resources/fonts/svg/diamond.svg deleted file mode 100644 index 826cb749f3..0000000000 --- a/resources/fonts/svg/diamond.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - diff --git a/resources/fonts/svg/empty.svg b/resources/fonts/svg/empty.svg deleted file mode 100644 index d470cc5a4c..0000000000 --- a/resources/fonts/svg/empty.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/resources/fonts/svg/notdef.svg b/resources/fonts/svg/notdef.svg deleted file mode 100644 index 3fbb9a02ff..0000000000 --- a/resources/fonts/svg/notdef.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - diff --git a/resources/fonts/svg/smile.svg b/resources/fonts/svg/smile.svg deleted file mode 100644 index 41d26b5e29..0000000000 --- a/resources/fonts/svg/smile.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index abe1550a01..f0eb7b7d9b 100644 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -830,13 +830,6 @@ uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) { HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, nullptr, si, &numItems), "Could not itemize character."); - // Disable any attempt at shaping. - // Without this ScriptShape may return 0x80040200 (USP_E_SCRIPT_NOT_IN_FONT) - // when all that is desired here is a simple cmap lookup. - for (SCRIPT_ITEM& item : si) { - item.a.eScript = SCRIPT_UNDEFINED; - } - // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs. static const int maxGlyphs = 2; SCRIPT_VISATTR vsa[maxGlyphs]; diff --git a/tools/fonts/SkTestFontMgr.cpp b/tools/fonts/SkTestFontMgr.cpp index 4513a2f8d1..3b5d1589f2 100644 --- a/tools/fonts/SkTestFontMgr.cpp +++ b/tools/fonts/SkTestFontMgr.cpp @@ -8,8 +8,6 @@ #include "SkFontDescriptor.h" #include "SkTestFontMgr.h" #include "sk_tool_utils.h" -#include "SkTestTypeface.h" -#include "SkTestSVGTypeface.h" namespace { @@ -17,28 +15,6 @@ static constexpr const char* kFamilyNames[] = { "Toy Liberation Sans", "Toy Liberation Serif", "Toy Liberation Mono", - "Emoji", -}; - -class JustOneTypefaceStyleSet final : public SkFontStyleSet { -public: - explicit JustOneTypefaceStyleSet(sk_sp typeface) : fTypeface(std::move(typeface)) {} - int count() override { return 1; } - - void getStyle(int index, SkFontStyle* style, SkString* name) override { - if (style) { *style = SkFontStyle::Normal(); } - if (name) { *name = "Normal"; } - } - - SkTypeface* createTypeface(int index) override { - return SkRef(fTypeface.get()); - } - - SkTypeface* matchStyle(const SkFontStyle& pattern) override { - return this->matchStyleCSS3(pattern); - } -private: - sk_sp fTypeface; }; class FontStyleSet final : public SkFontStyleSet { @@ -93,7 +69,6 @@ public: fFamilies[0] = sk_make_sp(0); fFamilies[1] = sk_make_sp(1); fFamilies[2] = sk_make_sp(2); - fFamilies[3] = sk_make_sp(SkTestSVGTypeface::Default()); } int onCountFamilies() const override { return SK_ARRAY_COUNT(fFamilies); } @@ -111,7 +86,6 @@ public: if (strstr(familyName, "ans")) { return this->createStyleSet(0); } if (strstr(familyName, "erif")) { return this->createStyleSet(1); } if (strstr(familyName, "ono")) { return this->createStyleSet(2); } - if (strstr(familyName, "oji")) { return this->createStyleSet(3); } } return this->createStyleSet(0); } @@ -164,7 +138,7 @@ public: } private: - sk_sp fFamilies[4]; + sk_sp fFamilies[3]; }; } diff --git a/tools/fonts/SkTestSVGTypeface.cpp b/tools/fonts/SkTestSVGTypeface.cpp deleted file mode 100644 index a4e3e4975e..0000000000 --- a/tools/fonts/SkTestSVGTypeface.cpp +++ /dev/null @@ -1,1302 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "Resources.h" -#include "SkAdvancedTypefaceMetrics.h" -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkColor.h" -#include "SkData.h" -#include "SkEncodedImageFormat.h" -#include "SkFontDescriptor.h" -#include "SkFontStyle.h" -#include "SkGeometry.h" -#include "SkGlyph.h" -#include "SkImage.h" -#include "SkImageInfo.h" -#include "SkMask.h" -#include "SkMatrix.h" -#include "SkNoDrawCanvas.h" -#include "SkOTUtils.h" -#include "SkPaintPriv.h" -#include "SkPath.h" -#include "SkPathPriv.h" -#include "SkPathEffect.h" -#include "SkPathOps.h" -#include "SkPixmap.h" -#include "SkPointPriv.h" -#include "SkRRect.h" -#include "SkSVGDOM.h" -#include "SkScalerContext.h" -#include "SkSize.h" -#include "SkStream.h" -#include "SkSurface.h" -#include "SkTestSVGTypeface.h" -#include "SkTDArray.h" -#include "SkTemplates.h" -#include "SkUtils.h" - -#include - -class SkDescriptor; - -SkTestSVGTypeface::SkTestSVGTypeface(const char* name, - int upem, - const SkPaint::FontMetrics& fontMetrics, - const SkSVGTestTypefaceGlyphData* data, int dataCount, - const SkFontStyle& style) - : SkTypeface(style, false) - , fName(name) - , fUpem(upem) - , fFontMetrics(fontMetrics) - , fGlyphs(dataCount) -{ - for (int i = 0; i < dataCount; ++i) { - const SkSVGTestTypefaceGlyphData& datum = data[i]; - std::unique_ptr stream = GetResourceAsStream(datum.fSvgResourcePath); - fCMap.set(datum.fUnicode, i); - if (!stream) { - fGlyphs.emplace_back(nullptr, datum); - continue; - } - sk_sp svg = SkSVGDOM::MakeFromStream(*stream.get()); - if (!svg) { - fGlyphs.emplace_back(nullptr, datum); - continue; - } - - const SkSize& sz = svg->containerSize(); - if (sz.isEmpty()) { - fGlyphs.emplace_back(nullptr, datum); - continue; - } - - fGlyphs.emplace_back(std::move(svg), datum); - } -} - -SkTestSVGTypeface::~SkTestSVGTypeface() {} - -SkTestSVGTypeface::Glyph::Glyph(sk_sp svg, const SkSVGTestTypefaceGlyphData& data) - : fSvg(std::move(svg)), fOrigin(data.fOrigin), fAdvance(data.fAdvance) {} -SkTestSVGTypeface::Glyph::~Glyph() {} - -void SkTestSVGTypeface::getAdvance(SkGlyph* glyph) const { - SkGlyphID glyphID = glyph->getGlyphID(); - glyphID = glyphID < fGlyphs.count() ? glyphID : 0; - - glyph->fAdvanceX = fGlyphs[glyphID].fAdvance; - glyph->fAdvanceY = 0; -} - -void SkTestSVGTypeface::getFontMetrics(SkPaint::FontMetrics* metrics) const { - *metrics = fFontMetrics; -} - -void SkTestSVGTypeface::getPath(SkGlyphID glyphID, SkPath* path) const { - path->reset(); -} - -void SkTestSVGTypeface::onFilterRec(SkScalerContextRec* rec) const { - rec->setHinting(SkPaint::kNo_Hinting); -} - -std::unique_ptr SkTestSVGTypeface::onGetAdvancedMetrics() const { - std::unique_ptr info(new SkAdvancedTypefaceMetrics); - info->fFontName.set(fName); - int glyphCount = this->onCountGlyphs(); - - SkTDArray& toUnicode = info->fGlyphToUnicode; - toUnicode.setCount(glyphCount); - SkASSERT(glyphCount == SkToInt(fGlyphs.count())); - fCMap.foreach([&toUnicode](const SkUnichar& c, const SkGlyphID& g) { - toUnicode[g] = c; - }); - return info; -} - -void SkTestSVGTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { - desc->setFamilyName(fName.c_str()); - desc->setStyle(this->fontStyle()); - *isLocal = false; -} - -int SkTestSVGTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const { - auto utf8 = (const char*)chars; - auto utf16 = (const uint16_t*)chars; - auto utf32 = (const SkUnichar*)chars; - - for (int i = 0; i < glyphCount; i++) { - SkUnichar ch; - switch (encoding) { - case kUTF8_Encoding: ch = SkUTF8_NextUnichar(&utf8 ); break; - case kUTF16_Encoding: ch = SkUTF16_NextUnichar(&utf16); break; - case kUTF32_Encoding: ch = *utf32++; break; - } - if (glyphs) { - SkGlyphID* g = fCMap.find(ch); - glyphs[i] = g ? *g : 0; - } - } - return glyphCount; -} - -void SkTestSVGTypeface::onGetFamilyName(SkString* familyName) const { - *familyName = fName; -} - -SkTypeface::LocalizedStrings* SkTestSVGTypeface::onCreateFamilyNameIterator() const { - SkString familyName(fName); - SkString language("und"); //undetermined - return new SkOTUtils::LocalizedStrings_SingleName(familyName, language); -} - -class SkTestSVGScalerContext : public SkScalerContext { -public: - SkTestSVGScalerContext(sk_sp face, const SkScalerContextEffects& effects, - const SkDescriptor* desc) - : SkScalerContext(std::move(face), effects, desc) - { - fRec.getSingleMatrix(&fMatrix); - SkScalar upem = this->geTestSVGTypeface()->fUpem; - fMatrix.preScale(1.f/upem, 1.f/upem); - } - -protected: - SkTestSVGTypeface* geTestSVGTypeface() const { - return static_cast(this->getTypeface()); - } - - unsigned generateGlyphCount() override { - return this->geTestSVGTypeface()->onCountGlyphs(); - } - - uint16_t generateCharToGlyph(SkUnichar u) override { - uint16_t g; - (void) this->geTestSVGTypeface()->onCharsToGlyphs(&u, SkTypeface::kUTF32_Encoding, &g, 1); - return g; - } - - void generateAdvance(SkGlyph* glyph) override { - this->geTestSVGTypeface()->getAdvance(glyph); - - const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), - SkFloatToScalar(glyph->fAdvanceY)); - glyph->fAdvanceX = SkScalarToFloat(advance.fX); - glyph->fAdvanceY = SkScalarToFloat(advance.fY); - } - - void generateMetrics(SkGlyph* glyph) override { - SkGlyphID glyphID = glyph->getGlyphID(); - glyphID = glyphID < this->geTestSVGTypeface()->fGlyphs.count() ? glyphID : 0; - - glyph->zeroMetrics(); - glyph->fMaskFormat = SkMask::kARGB32_Format; - this->generateAdvance(glyph); - - SkTestSVGTypeface::Glyph& glyphData = this->geTestSVGTypeface()->fGlyphs[glyphID]; - if (!glyphData.fSvg) { - return; - } - - SkSize containerSize = glyphData.fSvg->containerSize(); - SkRect newBounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY, - containerSize.fWidth, containerSize.fHeight); - fMatrix.mapRect(&newBounds); - SkScalar dx = SkFixedToScalar(glyph->getSubXFixed()); - SkScalar dy = SkFixedToScalar(glyph->getSubYFixed()); - newBounds.offset(dx, dy); - - SkIRect ibounds; - newBounds.roundOut(&ibounds); - glyph->fLeft = ibounds.fLeft; - glyph->fTop = ibounds.fTop; - glyph->fWidth = ibounds.width(); - glyph->fHeight = ibounds.height(); - } - - void generateImage(const SkGlyph& glyph) override { - SkGlyphID glyphID = glyph.getGlyphID(); - glyphID = glyphID < this->geTestSVGTypeface()->fGlyphs.count() ? glyphID : 0; - - SkBitmap bm; - // TODO: this should be SkImageInfo::MakeS32 when that passes all the tests. - bm.installPixels(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType), - glyph.fImage, glyph.rowBytes()); - bm.eraseColor(0); - - SkTestSVGTypeface::Glyph& glyphData = this->geTestSVGTypeface()->fGlyphs[glyphID]; - - SkScalar dx = SkFixedToScalar(glyph.getSubXFixed()); - SkScalar dy = SkFixedToScalar(glyph.getSubYFixed()); - - SkCanvas canvas(bm); - canvas.translate(-glyph.fLeft, -glyph.fTop); - canvas.translate(dx, dy); - canvas.concat(fMatrix); - canvas.translate(glyphData.fOrigin.fX, -glyphData.fOrigin.fY); - - if (glyphData.fSvg) { - glyphData.fSvg->render(&canvas); - } - } - - void generatePath(SkGlyphID glyph, SkPath* path) override { - this->geTestSVGTypeface()->getPath(glyph, path); - path->transform(fMatrix); - } - - void generateFontMetrics(SkPaint::FontMetrics* metrics) override { - this->geTestSVGTypeface()->getFontMetrics(metrics); - SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); - } - -private: - SkMatrix fMatrix; -}; - -SkScalerContext* SkTestSVGTypeface::onCreateScalerContext( - const SkScalerContextEffects& e, const SkDescriptor* desc) const -{ - return new SkTestSVGScalerContext(sk_ref_sp(const_cast(this)), e, desc); -} - -// Recommended that the first four be .notdef, .null, CR, space -constexpr const static SkSVGTestTypefaceGlyphData gGlyphs[] = { - {"fonts/svg/notdef.svg", {100,800}, 800, 0x0}, // .notdef - {"fonts/svg/empty.svg", {0,0}, 800, 0x0020}, // space - {"fonts/svg/diamond.svg", {100, 800}, 800, 0x2662}, // β™’ - {"fonts/svg/smile.svg", {0,800}, 800, 0x1F600}, // πŸ˜€ -}; - -sk_sp SkTestSVGTypeface::Default() { - SkPaint::FontMetrics metrics; - metrics.fFlags = SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag | - SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag | - SkPaint::FontMetrics::kStrikeoutThicknessIsValid_Flag | - SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag; - metrics.fTop = -800; - metrics.fAscent = -800; - metrics.fDescent = 200; - metrics.fBottom = 200; - metrics.fLeading = 100; - metrics.fAvgCharWidth = 1000; - metrics.fMaxCharWidth = 1000; - metrics.fXMin = 0; - metrics.fXMax = 1000; - metrics.fXHeight = 500; - metrics.fCapHeight = 700; - metrics.fUnderlineThickness = 40; - metrics.fUnderlinePosition = 20; - metrics.fStrikeoutThickness = 20; - metrics.fStrikeoutPosition = -400; - return sk_make_sp("Emoji", 1000, metrics, gGlyphs, SK_ARRAY_COUNT(gGlyphs), - SkFontStyle::Normal()); -} - -void SkTestSVGTypeface::exportTtxCommon(SkWStream* out, const char* type, - const SkTArray* glyfInfo) const -{ - int totalGlyphs = fGlyphs.count(); - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - out->writeText(" writeHexAsText(i, 4); - out->writeText("\"/>\n"); - } - if (glyfInfo) { - for (int i = 0; i < fGlyphs.count(); ++i) { - for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) { - out->writeText(" writeHexAsText(i, 4); - out->writeText("l"); - out->writeHexAsText(j, 4); - out->writeText("\"/>\n"); - ++totalGlyphs; - } - } - } - out->writeText(" \n"); - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(fUpem); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - // TODO: not recalculated for bitmap fonts? - out->writeText(" writeScalarAsText(fFontMetrics.fXMin); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fBottom); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fFontMetrics.fXMax); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fTop); - out->writeText("\"/>\n"); - - char macStyle[16] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) { - macStyle[0xF - 0x0] = '1'; // Bold - } - switch (this->fontStyle().slant()) { - case SkFontStyle::kUpright_Slant: - break; - case SkFontStyle::kItalic_Slant: - macStyle[0xF - 0x1] = '1'; // Italic - break; - case SkFontStyle::kOblique_Slant: - macStyle[0xF - 0x1] = '1'; // Italic - break; - default: - SK_ABORT("Unknown slant."); - } - if (this->fontStyle().width() <= SkFontStyle::kCondensed_Width) { - macStyle[0xF - 0x5] = '1'; // Condensed - } else if (this->fontStyle().width() >= SkFontStyle::kExpanded_Width) { - macStyle[0xF - 0x6] = '1'; // Extended - } - out->writeText(" write(macStyle, 8); - out->writeText(" "); - out->write(macStyle + 8, 8); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(-fFontMetrics.fAscent); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(-fFontMetrics.fDescent); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(fFontMetrics.fLeading); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(fFontMetrics.fXMax - fFontMetrics.fXMin); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - - // Some of this table is going to be re-calculated, but we have to write it out anyway. - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(totalGlyphs); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(fFontMetrics.fAvgCharWidth); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(this->fontStyle().weight()); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(this->fontStyle().width()); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(fFontMetrics.fStrikeoutThickness); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fStrikeoutPosition); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - char fsSelection[16] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - fsSelection[0xF - 0x7] = '1'; // Use typo metrics - if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) { - fsSelection[0xF - 0x5] = '1'; // Bold - } - switch (this->fontStyle().slant()) { - case SkFontStyle::kUpright_Slant: - if (this->fontStyle().weight() < SkFontStyle::Bold().weight()) { - fsSelection[0xF - 0x6] = '1'; // Not bold or italic, is regular - } - break; - case SkFontStyle::kItalic_Slant: - fsSelection[0xF - 0x0] = '1'; // Italic - break; - case SkFontStyle::kOblique_Slant: - fsSelection[0xF - 0x0] = '1'; // Italic - fsSelection[0xF - 0x9] = '1'; // Oblique - break; - default: - SK_ABORT("Unknown slant."); - } - out->writeText(" write(fsSelection, 8); - out->writeText(" "); - out->write(fsSelection + 8, 8); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fAscent); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fDescent); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fFontMetrics.fLeading); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fFontMetrics.fAscent); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fFontMetrics.fDescent); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(fFontMetrics.fXHeight); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fFontMetrics.fCapHeight); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - out->writeText(" writeHexAsText(i, 4); - out->writeText("\" width=\""); - out->writeDecAsText(fGlyphs[i].fAdvance); - out->writeText("\" lsb=\""); - int lsb = fGlyphs[i].fOrigin.fX; - if (glyfInfo) { - lsb += (*glyfInfo)[i].fBounds.fLeft; - } - out->writeDecAsText(lsb); - out->writeText("\"/>\n"); - } - if (glyfInfo) { - for (int i = 0; i < fGlyphs.count(); ++i) { - for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) { - out->writeText(" writeHexAsText(i, 4); - out->writeText("l"); - out->writeHexAsText(j, 4); - out->writeText("\" width=\""); - out->writeDecAsText(fGlyphs[i].fAdvance); - out->writeText("\" lsb=\""); - int32_t lsb = fGlyphs[i].fOrigin.fX + (*glyfInfo)[i].fLayers[j].fBounds.fLeft; - out->writeDecAsText(lsb); - out->writeText("\"/>\n"); - } - } - } - out->writeText(" \n"); - - bool hasNonBMP = false; - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - fCMap.foreach([&out, &hasNonBMP](const SkUnichar& c, const SkGlyphID& g) { - if (0xFFFF < c) { - hasNonBMP = true; - return; - } - out->writeText(" writeHexAsText(c, 4); - out->writeText("\" name=\"glyf"); - out->writeHexAsText(g, 4); - out->writeText("\"/>\n"); - }); - out->writeText(" \n"); - if (hasNonBMP) { - out->writeText(" \n"); - fCMap.foreach([&out](const SkUnichar& c, const SkGlyphID& g) { - out->writeText(" writeHexAsText(c, 6); - out->writeText("\" name=\"glyf"); - out->writeHexAsText(g, 4); - out->writeText("\"/>\n"); - }); - out->writeText(" \n"); - } - out->writeText(" \n"); - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" "); - out->writeText(fName.c_str()); - out->writeText(" "); - out->writeText(type); - out->writeText("\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" Regular\n"); - out->writeText(" \n"); - out->writeText(" \n"); - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(fFontMetrics.fUnderlinePosition); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fFontMetrics.fUnderlineThickness); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); -} - -void SkTestSVGTypeface::exportTtxCbdt(SkWStream* out) const { - out->writeText("\n"); - out->writeText("\n"); - this->exportTtxCommon(out, "CBDT"); - - int strikeSizes[3] = { 16, 64, 128 }; - - SkPaint paint; - paint.setTypeface(sk_ref_sp(const_cast(this))); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - out->writeText(" \n"); - out->writeText("
\n"); - for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) { - paint.setTextSize(strikeSizes[strikeIndex]); - out->writeText(" writeDecAsText(strikeIndex); - out->writeText("\">\n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - SkGlyphID gid = i; - SkScalar advance; - SkRect bounds; - paint.getTextWidths(&gid, sizeof(gid), &advance, &bounds); - SkIRect ibounds = bounds.roundOut(); - if (ibounds.isEmpty()) { - continue; - } - SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height()); - sk_sp surface(SkSurface::MakeRaster(image_info)); - SkASSERT(surface); - SkCanvas* canvas = surface->getCanvas(); - canvas->clear(0); - SkPixmap pix; - surface->peekPixels(&pix); - canvas->drawText(&gid, sizeof(gid), -bounds.fLeft, -bounds.fTop, paint); - canvas->flush(); - sk_sp image = surface->makeImageSnapshot(); - sk_sp data = image->encodeToData(SkEncodedImageFormat::kPNG, 100); - - out->writeText(" writeHexAsText(i, 4); - out->writeText("\">\n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(image->height()); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(image->width()); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(bounds.fLeft); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-bounds.fTop); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(advance); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" "); - uint8_t const * bytes = data->bytes(); - for (size_t i = 0; i < data->size(); ++i) { - if ((i % 0x10) == 0x0) { - out->writeText("\n "); - } else if (((i - 1) % 0x4) == 0x3) { - out->writeText(" "); - } - out->writeHexAsText(bytes[i], 2); - } - out->writeText("\n"); - out->writeText(" \n"); - out->writeText(" \n"); - } - out->writeText(" \n"); - } - out->writeText(" \n"); - - SkPaint::FontMetrics fm; - out->writeText(" \n"); - out->writeText("
\n"); - for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) { - paint.setTextSize(strikeSizes[strikeIndex]); - paint.getFontMetrics(&fm); - out->writeText(" writeDecAsText(strikeIndex); - out->writeText("\">\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(-fm.fTop); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fm.fBottom); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fm.fXMax - fm.fXMin); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeScalarAsText(-fm.fTop); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(-fm.fBottom); - out->writeText("\"/>\n"); - out->writeText(" writeScalarAsText(fm.fXMax - fm.fXMin); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(strikeSizes[strikeIndex]); - out->writeText("\"/>\n"); - out->writeText(" writeDecAsText(strikeSizes[strikeIndex]); - out->writeText("\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - SkGlyphID gid = i; - SkRect bounds; - paint.getTextWidths(&gid, sizeof(gid), nullptr, &bounds); - if (bounds.isEmpty()) { - continue; - } - out->writeText(" writeHexAsText(i, 4); - out->writeText("\"/>\n"); - } - out->writeText(" \n"); - out->writeText(" \n"); - } - out->writeText(" \n"); - - out->writeText("\n"); -} - -/** - * UnitsPerEm is generally 1000 here. Versions of macOS older than 10.13 - * have problems in CoreText determining the glyph bounds of bitmap glyphs - * with unitsPerEm set to 1024 or numbers not divisible by 100 when the - * contour is not closed. The bounds of sbix fonts on macOS appear to be those - * of the outline in the 'glyf' table. If this countour is closed it will be - * drawn, as the 'glyf' outline is to be drawn on top of any bitmap. (There is - * a bit which is supposed to control this, but it cannot be relied on.) So - * make the glyph contour ta degenerate line with points at the edge of the - * bounding box of the glyph. - */ -void SkTestSVGTypeface::exportTtxSbix(SkWStream* out) const { - out->writeText("\n"); - out->writeText("\n"); - this->exportTtxCommon(out, "sbix"); - - SkPaint paint; - paint.setTypeface(sk_ref_sp(const_cast(this))); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - const SkTestSVGTypeface::Glyph& glyphData = this->fGlyphs[i]; - - SkSize containerSize = glyphData.fSvg ? glyphData.fSvg->containerSize() - : SkSize::MakeEmpty(); - SkRect bounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY, - containerSize.fWidth, containerSize.fHeight); - SkIRect ibounds = bounds.roundOut(); - out->writeText(" writeHexAsText(i, 4); - out->writeText("\" xMin=\""); - out->writeDecAsText(ibounds.fLeft); - out->writeText("\" yMin=\""); - out->writeDecAsText(-ibounds.fBottom); - out->writeText("\" xMax=\""); - out->writeDecAsText(ibounds.fRight); - out->writeText("\" yMax=\""); - out->writeDecAsText(-ibounds.fTop); - out->writeText("\">\n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(ibounds.fLeft); - out->writeText("\" y=\""); - out->writeDecAsText(-ibounds.fBottom); - out->writeText("\" on=\"1\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(ibounds.fRight); - out->writeText("\" y=\""); - out->writeDecAsText(-ibounds.fTop); - out->writeText("\" on=\"1\"/>\n"); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - } - out->writeText(" \n"); - - // The loca table will be re-calculated, but if we don't write one we don't get one. - out->writeText(" \n"); - - int strikeSizes[3] = { 16, 64, 128 }; - - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" \n"); - for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) { - paint.setTextSize(strikeSizes[strikeIndex]); - out->writeText(" \n"); - out->writeText(" writeDecAsText(strikeSizes[strikeIndex]); - out->writeText("\"/>\n"); - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - SkGlyphID gid = i; - SkScalar advance; - SkRect bounds; - paint.getTextWidths(&gid, sizeof(gid), &advance, &bounds); - SkIRect ibounds = bounds.roundOut(); - if (ibounds.isEmpty()) { - continue; - } - SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height()); - sk_sp surface(SkSurface::MakeRaster(image_info)); - SkASSERT(surface); - SkCanvas* canvas = surface->getCanvas(); - canvas->clear(0); - SkPixmap pix; - surface->peekPixels(&pix); - canvas->drawText(&gid, sizeof(gid), -bounds.fLeft, -bounds.fTop, paint); - canvas->flush(); - sk_sp image = surface->makeImageSnapshot(); - sk_sp data = image->encodeToData(SkEncodedImageFormat::kPNG, 100); - - out->writeText(" writeHexAsText(i, 4); - out->writeText("\" graphicType=\"png \" originOffsetX=\""); - out->writeDecAsText(bounds.fLeft); - out->writeText("\" originOffsetY=\""); - out->writeScalarAsText(bounds.fBottom); - out->writeText("\">\n"); - - out->writeText(" "); - uint8_t const * bytes = data->bytes(); - for (size_t i = 0; i < data->size(); ++i) { - if ((i % 0x10) == 0x0) { - out->writeText("\n "); - } else if (((i - 1) % 0x4) == 0x3) { - out->writeText(" "); - } - out->writeHexAsText(bytes[i], 2); - } - out->writeText("\n"); - out->writeText(" \n"); - out->writeText(" \n"); - } - out->writeText(" \n"); - } - out->writeText(" \n"); - out->writeText("\n"); -} - -namespace { - -void convert_noninflect_cubic_to_quads(const SkPoint p[4], - SkScalar toleranceSqd, - SkTArray* quads, - int sublevel = 0) -{ - // Notation: Point a is always p[0]. Point b is p[1] unless p[1] == p[0], in which case it is - // p[2]. Point d is always p[3]. Point c is p[2] unless p[2] == p[3], in which case it is p[1]. - - SkVector ab = p[1] - p[0]; - SkVector dc = p[2] - p[3]; - - if (SkPointPriv::LengthSqd(ab) < SK_ScalarNearlyZero) { - if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) { - SkPoint* degQuad = quads->push_back_n(3); - degQuad[0] = p[0]; - degQuad[1] = p[0]; - degQuad[2] = p[3]; - return; - } - ab = p[2] - p[0]; - } - if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) { - dc = p[1] - p[3]; - } - - static const SkScalar kLengthScale = 3 * SK_Scalar1 / 2; - static const int kMaxSubdivs = 10; - - ab.scale(kLengthScale); - dc.scale(kLengthScale); - - // e0 and e1 are extrapolations along vectors ab and dc. - SkVector c0 = p[0]; - c0 += ab; - SkVector c1 = p[3]; - c1 += dc; - - SkScalar dSqd = sublevel > kMaxSubdivs ? 0 : SkPointPriv::DistanceToSqd(c0, c1); - if (dSqd < toleranceSqd) { - SkPoint cAvg = c0; - cAvg += c1; - cAvg.scale(SK_ScalarHalf); - - SkPoint* pts = quads->push_back_n(3); - pts[0] = p[0]; - pts[1] = cAvg; - pts[2] = p[3]; - return; - } - SkPoint choppedPts[7]; - SkChopCubicAtHalf(p, choppedPts); - convert_noninflect_cubic_to_quads(choppedPts + 0, toleranceSqd, quads, sublevel + 1); - convert_noninflect_cubic_to_quads(choppedPts + 3, toleranceSqd, quads, sublevel + 1); -} - -void convertCubicToQuads(const SkPoint p[4], SkScalar tolScale, SkTArray* quads) { - if (!p[0].isFinite() || !p[1].isFinite() || !p[2].isFinite() || !p[3].isFinite()) { - return; - } - SkPoint chopped[10]; - int count = SkChopCubicAtInflections(p, chopped); - - const SkScalar tolSqd = SkScalarSquare(tolScale); - - for (int i = 0; i < count; ++i) { - SkPoint* cubic = chopped + 3*i; - convert_noninflect_cubic_to_quads(cubic, tolSqd, quads); - } -} - -void path_to_quads(const SkPath& path, SkPath* quadPath) { - quadPath->reset(); - SkTArray qPts; - SkAutoConicToQuads converter; - const SkPoint* quadPts; - SkPath::RawIter iter(path); - uint8_t verb; - SkPoint pts[4]; - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { - switch (verb) { - case SkPath::kMove_Verb: - quadPath->moveTo(pts[0].fX, pts[0].fY); - break; - case SkPath::kLine_Verb: - quadPath->lineTo(pts[1].fX, pts[1].fY); - break; - case SkPath::kQuad_Verb: - quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); - break; - case SkPath::kCubic_Verb: - qPts.reset(); - convertCubicToQuads(pts, SK_Scalar1, &qPts); - for (int i = 0; i < qPts.count(); i += 3) { - quadPath->quadTo(qPts[i+1].fX, qPts[i+1].fY, qPts[i+2].fX, qPts[i+2].fY); - } - break; - case SkPath::kConic_Verb: - quadPts = converter.computeQuads(pts, iter.conicWeight(), SK_Scalar1); - for (int i = 0; i < converter.countQuads(); ++i) { - quadPath->quadTo(quadPts[i*2+1].fX, quadPts[i*2+1].fY, - quadPts[i*2+2].fX, quadPts[i*2+2].fY); - } - break; - case SkPath::kClose_Verb: - quadPath->close(); - break; - default: - SkDEBUGFAIL("bad verb"); - return; - } - } -} - -class SkCOLRCanvas : public SkNoDrawCanvas { -public: - SkCOLRCanvas(SkRect glyphBounds, SkGlyphID glyphId, - SkTestSVGTypeface::GlyfInfo* glyf, SkTHashMap* colors, - SkWStream* out) - : SkNoDrawCanvas(glyphBounds.roundOut().width(), glyphBounds.roundOut().height()) - , fOut(out) - , fGlyphId(glyphId) - , fBaselineOffset(glyphBounds.top()) - , fLayerId(0) - , fGlyf(glyf) - , fColors(colors) - { } - - void writePoint(SkScalar x, SkScalar y, bool on) { - fOut->writeText(" writeDecAsText(SkScalarRoundToInt(x)); - fOut->writeText("\" y=\""); - fOut->writeDecAsText(SkScalarRoundToInt(y)); - fOut->writeText("\" on=\""); - fOut->write8(on ? '1' : '0'); - fOut->writeText("\"/>\n"); - } - SkIRect writePath(const SkPath& path, bool layer) { - // Convert to quads. - SkPath quads; - path_to_quads(path, &quads); - - SkRect bounds = quads.computeTightBounds(); - SkIRect ibounds = bounds.roundOut(); - // The bounds will be re-calculated anyway. - fOut->writeText(" writeHexAsText(fGlyphId, 4); - if (layer) { - fOut->writeText("l"); - fOut->writeHexAsText(fLayerId, 4); - } - fOut->writeText("\" xMin=\""); - fOut->writeDecAsText(ibounds.fLeft); - fOut->writeText("\" yMin=\""); - fOut->writeDecAsText(ibounds.fTop); - fOut->writeText("\" xMax=\""); - fOut->writeDecAsText(ibounds.fRight); - fOut->writeText("\" yMax=\""); - fOut->writeDecAsText(ibounds.fBottom); - fOut->writeText("\">\n"); - - SkPath::RawIter iter(quads); - uint8_t verb; - SkPoint pts[4]; - bool contourOpen = false; - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { - switch (verb) { - case SkPath::kMove_Verb: - if (contourOpen) { - fOut->writeText(" \n"); - contourOpen = false; - } - break; - case SkPath::kLine_Verb: - if (!contourOpen) { - fOut->writeText(" \n"); - this->writePoint(pts[0].fX, pts[0].fY, true); - contourOpen = true; - } - this->writePoint(pts[1].fX, pts[1].fY, true); - break; - case SkPath::kQuad_Verb: - if (!contourOpen) { - fOut->writeText(" \n"); - this->writePoint(pts[0].fX, pts[0].fY, true); - contourOpen = true; - } - this->writePoint(pts[1].fX, pts[1].fY, false); - this->writePoint(pts[2].fX, pts[2].fY, true); - break; - case SkPath::kClose_Verb: - if (contourOpen) { - fOut->writeText(" \n"); - contourOpen = false; - } - break; - default: - SkDEBUGFAIL("bad verb"); - return ibounds; - } - } - if (contourOpen) { - fOut->writeText(" \n"); - } - - // Required to write out an instructions tag. - fOut->writeText(" \n"); - fOut->writeText(" \n"); - return ibounds; - } - - void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - SkPath path; - path.addRect(rect); - this->drawPath(path, paint); - } - - void onDrawOval(const SkRect& oval, const SkPaint& paint) override { - SkPath path; - path.addOval(oval); - this->drawPath(path, paint); - } - - void onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, - const SkPaint& paint) override - { - SkPath path; - bool fillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect(); - SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, - fillNoPathEffect); - this->drawPath(path, paint); - } - - void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override { - SkPath path; - path.addRRect(rrect); - this->drawPath(path, paint); - } - - void onDrawPath(const SkPath& platonicPath, const SkPaint& originalPaint) override { - SkPaint paint = originalPaint; - SkPath path = platonicPath; - - // Apply the path effect. - if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { - bool fill = paint.getFillPath(path, &path); - - paint.setPathEffect(nullptr); - if (fill) { - paint.setStyle(SkPaint::kFill_Style); - } else { - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(0); - } - } - - // Apply the matrix. - SkMatrix m = this->getTotalMatrix(); - // If done to the canvas then everything would get clipped out. - m.postTranslate(0, fBaselineOffset); // put the baseline at 0 - m.postScale(1, -1); // and flip it since OpenType is y-up. - path.transform(m); - - // While creating the default glyf, union with dark colors and intersect with bright colors. - SkColor color = paint.getColor(); - if ((SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color)) / 3 > 0x20) { - fBasePath.add(path, SkPathOp::kDifference_SkPathOp); - } else { - fBasePath.add(path, SkPathOp::kUnion_SkPathOp); - } - - SkIRect bounds = this->writePath(path, true); - - // The CPAL table has the concept of a 'current color' which is index 0xFFFF. - // Mark any layer drawn in 'currentColor' as having this special index. - // The value of 'currentColor' here should a color which causes this layer to union into the - // default glyf. - constexpr SkColor currentColor = 0xFF2B0000; - - int colorIndex; - if (color == currentColor) { - colorIndex = 0xFFFF; - } else { - int* colorIndexPtr = fColors->find(color); - if (colorIndexPtr) { - colorIndex = *colorIndexPtr; - } else { - colorIndex = fColors->count(); - fColors->set(color, colorIndex); - } - } - fGlyf->fLayers.emplace_back(colorIndex, bounds); - - ++fLayerId; - } - - void finishGlyph() { - SkPath baseGlyph; - fBasePath.resolve(&baseGlyph); - fGlyf->fBounds = this->writePath(baseGlyph, false); - } - -private: - SkWStream * const fOut; - SkGlyphID fGlyphId; - SkScalar fBaselineOffset; - int fLayerId; - SkOpBuilder fBasePath; - SkTestSVGTypeface::GlyfInfo* fGlyf; - SkTHashMap* fColors; -}; - -} // namespace - -void SkTestSVGTypeface::exportTtxColr(SkWStream* out) const { - out->writeText("\n"); - out->writeText("\n"); - - SkTHashMap colors; - SkTArray glyfInfos(fGlyphs.count()); - - // Need to know all the glyphs up front for the common tables. - SkDynamicMemoryWStream glyfOut; - glyfOut.writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - const SkTestSVGTypeface::Glyph& glyphData = this->fGlyphs[i]; - - SkSize containerSize = glyphData.fSvg ? glyphData.fSvg->containerSize() - : SkSize::MakeEmpty(); - SkRect bounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY, - containerSize.fWidth, containerSize.fHeight); - SkCOLRCanvas canvas(bounds, i, &glyfInfos.emplace_back(), &colors, &glyfOut); - if (glyphData.fSvg) { - glyphData.fSvg->render(&canvas); - } - canvas.finishGlyph(); - } - glyfOut.writeText(" \n"); - - this->exportTtxCommon(out, "COLR", &glyfInfos); - - // The loca table will be re-calculated, but if we don't write one we don't get one. - out->writeText(" \n"); - - std::unique_ptr glyfStream = glyfOut.detachAsStream(); - out->writeStream(glyfStream.get(), glyfStream->getLength()); - - out->writeText(" \n"); - out->writeText(" \n"); - for (int i = 0; i < fGlyphs.count(); ++i) { - if (glyfInfos[i].fBounds.isEmpty() || glyfInfos[i].fLayers.empty()) { - continue; - } - out->writeText(" writeHexAsText(i, 4); - out->writeText("\">\n"); - for (int j = 0; j < glyfInfos[i].fLayers.count(); ++j) { - const int colorIndex = glyfInfos[i].fLayers[j].fLayerColorIndex; - out->writeText(" writeDecAsText(colorIndex); - out->writeText("\" name=\"glyf"); - out->writeHexAsText(i, 4); - out->writeText("l"); - out->writeHexAsText(j, 4); - out->writeText("\"/>\n"); - } - out->writeText(" \n"); - } - out->writeText(" \n"); - - // The colors must be written in order, the 'index' is ignored by ttx. - SkAutoTMalloc colorsInOrder(colors.count()); - colors.foreach([&colorsInOrder](const SkColor& c, const int* i) { - colorsInOrder[*i] = c; - }); - out->writeText(" \n"); - out->writeText(" \n"); - out->writeText(" writeDecAsText(colors.count()); - out->writeText("\"/>\n"); - out->writeText(" \n"); - for (int i = 0; i < colors.count(); ++i) { - SkColor c = colorsInOrder[i]; - out->writeText(" writeDecAsText(i); - out->writeText("\" value=\"#"); - out->writeHexAsText(SkColorGetR(c), 2); - out->writeHexAsText(SkColorGetG(c), 2); - out->writeHexAsText(SkColorGetB(c), 2); - out->writeHexAsText(SkColorGetA(c), 2); - out->writeText("\"/>\n"); - } - out->writeText(" \n"); - out->writeText(" \n"); - - out->writeText("\n"); -} diff --git a/tools/fonts/SkTestSVGTypeface.h b/tools/fonts/SkTestSVGTypeface.h deleted file mode 100644 index 86c828511b..0000000000 --- a/tools/fonts/SkTestSVGTypeface.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTestSVGTypeface_DEFINED -#define SkTestSVGTypeface_DEFINED - -#include "SkFontArguments.h" -#include "SkPaint.h" -#include "SkPoint.h" -#include "SkRect.h" -#include "SkRefCnt.h" -#include "SkScalar.h" -#include "SkString.h" -#include "SkTArray.h" -#include "SkTHash.h" -#include "SkTypeface.h" -#include "SkTypes.h" - -#include - -class SkDescriptor; -class SkFontDescriptor; -class SkFontStyle; -class SkGlyph; -class SkPath; -class SkScalerContext; -class SkStreamAsset; -class SkSVGDOM; -class SkWStream; -struct SkAdvancedTypefaceMetrics; -struct SkScalerContextEffects; -struct SkScalerContextRec; - -struct SkSVGTestTypefaceGlyphData { - const char* fSvgResourcePath; - SkPoint fOrigin; - SkScalar fAdvance; - SkUnichar fUnicode; //TODO: this limits to 1:1 -}; - -class SkTestSVGTypeface : public SkTypeface { -public: - SkTestSVGTypeface(const char* name, - int upem, - const SkPaint::FontMetrics& metrics, - const SkSVGTestTypefaceGlyphData* data, int dataCount, - const SkFontStyle& style); - ~SkTestSVGTypeface() override; - void getAdvance(SkGlyph* glyph) const; - void getFontMetrics(SkPaint::FontMetrics* metrics) const; - void getPath(SkGlyphID glyph, SkPath* path) const; - - static sk_sp Default(); - void exportTtxCbdt(SkWStream*) const; - void exportTtxSbix(SkWStream*) const; - void exportTtxColr(SkWStream*) const; - - struct GlyfLayerInfo { - GlyfLayerInfo(int layerColorIndex, SkIRect bounds) - : fLayerColorIndex(layerColorIndex) - , fBounds(bounds) {} - int fLayerColorIndex; - SkIRect fBounds; - }; - struct GlyfInfo { - GlyfInfo() : fBounds(SkIRect::MakeEmpty()) {} - SkIRect fBounds; - SkTArray fLayers; - }; -protected: - void exportTtxCommon(SkWStream*, const char* type, const SkTArray* = nullptr) const; - - SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, - const SkDescriptor* desc) const override; - void onFilterRec(SkScalerContextRec* rec) const override; - std::unique_ptr onGetAdvancedMetrics() const override; - - SkStreamAsset* onOpenStream(int* ttcIndex) const override { - return nullptr; - } - - void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override; - - int onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const override; - - int onCountGlyphs() const override { - return fGlyphs.count(); - } - - int onGetUPEM() const override { - return fUpem; - } - - void onGetFamilyName(SkString* familyName) const override; - SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; - - int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], - int coordinateCount) const override - { - return 0; - } - - int onGetTableTags(SkFontTableTag tags[]) const override { - return 0; - } - - size_t onGetTableData(SkFontTableTag tag, size_t offset, - size_t length, void* data) const override { - return 0; - } -private: - struct Glyph { - Glyph(sk_sp svg, const SkSVGTestTypefaceGlyphData& data); - ~Glyph(); - sk_sp fSvg; - SkPoint fOrigin; - SkScalar fAdvance; - }; - SkString fName; - int fUpem; - const SkPaint::FontMetrics fFontMetrics; - SkTArray fGlyphs; - SkTHashMap fCMap; - friend class SkTestSVGScalerContext; -}; - -#endif diff --git a/tools/fonts/SkTestScalerContext.cpp b/tools/fonts/SkTestScalerContext.cpp new file mode 100644 index 0000000000..f74b1bd57a --- /dev/null +++ b/tools/fonts/SkTestScalerContext.cpp @@ -0,0 +1,267 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAdvancedTypefaceMetrics.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkDescriptor.h" +#include "SkFontDescriptor.h" +#include "SkGlyph.h" +#include "SkMakeUnique.h" +#include "SkMask.h" +#include "SkOTUtils.h" +#include "SkPaintPriv.h" +#include "SkScalerContext.h" +#include "SkTestScalerContext.h" +#include "SkTypefaceCache.h" +#include "SkUtils.h" + +SkTestFont::SkTestFont(const SkTestFontData& fontData) + : INHERITED() + , fCharCodes(fontData.fCharCodes) + , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0) + , fWidths(fontData.fWidths) + , fMetrics(fontData.fMetrics) + , fName(fontData.fName) + , fPaths(nullptr) +{ + init(fontData.fPoints, fontData.fVerbs); +} + +SkTestFont::~SkTestFont() { + for (unsigned index = 0; index < fCharCodesCount; ++index) { + delete fPaths[index]; + } + delete[] fPaths; +} + +int SkTestFont::codeToIndex(SkUnichar charCode) const { + for (unsigned index = 0; index < fCharCodesCount; ++index) { + if (fCharCodes[index] == (unsigned) charCode) { + return (int) index; + } + } + return 0; +} + +void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) { + fPaths = new SkPath* [fCharCodesCount]; + for (unsigned index = 0; index < fCharCodesCount; ++index) { + SkPath* path = new SkPath; + SkPath::Verb verb; + while ((verb = (SkPath::Verb) *verbs++) != SkPath::kDone_Verb) { + switch (verb) { + case SkPath::kMove_Verb: + path->moveTo(pts[0], pts[1]); + pts += 2; + break; + case SkPath::kLine_Verb: + path->lineTo(pts[0], pts[1]); + pts += 2; + break; + case SkPath::kQuad_Verb: + path->quadTo(pts[0], pts[1], pts[2], pts[3]); + pts += 4; + break; + case SkPath::kCubic_Verb: + path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + pts += 6; + break; + case SkPath::kClose_Verb: + path->close(); + break; + default: + SkDEBUGFAIL("bad verb"); + return; + } + } + // This should make SkPath::getBounds() queries threadsafe. + path->updateBoundsCache(); + fPaths[index] = path; + } +} + +SkTestTypeface::SkTestTypeface(sk_sp testFont, const SkFontStyle& style) + : SkTypeface(style, false) + , fTestFont(std::move(testFont)) { +} + +void SkTestTypeface::getAdvance(SkGlyph* glyph) { + // TODO(benjaminwagner): Update users to use floats. + glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]); + glyph->fAdvanceY = 0; +} + +void SkTestTypeface::getFontMetrics(SkPaint::FontMetrics* metrics) { + *metrics = fTestFont->fMetrics; +} + +void SkTestTypeface::getMetrics(SkGlyph* glyph) { + SkGlyphID glyphID = glyph->getGlyphID(); + glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0; + + // TODO(benjaminwagner): Update users to use floats. + glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyphID]); + glyph->fAdvanceY = 0; +} + +void SkTestTypeface::getPath(SkGlyphID glyphID, SkPath* path) { + glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0; + *path = *fTestFont->fPaths[glyphID]; +} + +void SkTestTypeface::onFilterRec(SkScalerContextRec* rec) const { + rec->setHinting(SkPaint::kNo_Hinting); +} + +std::unique_ptr SkTestTypeface::onGetAdvancedMetrics() const { // pdf only + std::unique_ptr info(new SkAdvancedTypefaceMetrics); + info->fFontName.set(fTestFont->fName); + int glyphCount = this->onCountGlyphs(); + + SkTDArray& toUnicode = info->fGlyphToUnicode; + toUnicode.setCount(glyphCount); + SkASSERT(glyphCount == SkToInt(fTestFont->fCharCodesCount)); + for (int gid = 0; gid < glyphCount; ++gid) { + toUnicode[gid] = SkToS32(fTestFont->fCharCodes[gid]); + } + return info; +} + +void SkTestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + desc->setFamilyName(fTestFont->fName); + desc->setStyle(this->fontStyle()); + *isLocal = false; +} + +int SkTestTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, + uint16_t glyphs[], int glyphCount) const { + auto utf8 = (const char*)chars; + auto utf16 = (const uint16_t*)chars; + auto utf32 = (const SkUnichar*)chars; + + for (int i = 0; i < glyphCount; i++) { + SkUnichar ch; + switch (encoding) { + case kUTF8_Encoding: ch = SkUTF8_NextUnichar(&utf8 ); break; + case kUTF16_Encoding: ch = SkUTF16_NextUnichar(&utf16); break; + case kUTF32_Encoding: ch = *utf32++; break; + } + if (glyphs) { + glyphs[i] = fTestFont->codeToIndex(ch); + } + } + return glyphCount; +} + +void SkTestTypeface::onGetFamilyName(SkString* familyName) const { + *familyName = fTestFont->fName; +} + +SkTypeface::LocalizedStrings* SkTestTypeface::onCreateFamilyNameIterator() const { + SkString familyName(fTestFont->fName); + SkString language("und"); //undetermined + return new SkOTUtils::LocalizedStrings_SingleName(familyName, language); +} + +class SkTestScalerContext : public SkScalerContext { +public: + SkTestScalerContext(sk_sp face, const SkScalerContextEffects& effects, + const SkDescriptor* desc) + : SkScalerContext(std::move(face), effects, desc) + { + fRec.getSingleMatrix(&fMatrix); + this->forceGenerateImageFromPath(); + } + +protected: + SkTestTypeface* getTestTypeface() const { + return static_cast(this->getTypeface()); + } + + unsigned generateGlyphCount() override { + return this->getTestTypeface()->onCountGlyphs(); + } + + uint16_t generateCharToGlyph(SkUnichar uni) override { + uint16_t glyph; + (void) this->getTestTypeface()->onCharsToGlyphs((const void *) &uni, + SkTypeface::kUTF32_Encoding, &glyph, 1); + return glyph; + } + + void generateAdvance(SkGlyph* glyph) override { + this->getTestTypeface()->getAdvance(glyph); + + const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), + SkFloatToScalar(glyph->fAdvanceY)); + glyph->fAdvanceX = SkScalarToFloat(advance.fX); + glyph->fAdvanceY = SkScalarToFloat(advance.fY); + } + + void generateMetrics(SkGlyph* glyph) override { + this->getTestTypeface()->getMetrics(glyph); + + const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), + SkFloatToScalar(glyph->fAdvanceY)); + glyph->fAdvanceX = SkScalarToFloat(advance.fX); + glyph->fAdvanceY = SkScalarToFloat(advance.fY); + + SkPath path; + this->getTestTypeface()->getPath(glyph->getGlyphID(), &path); + path.transform(fMatrix); + + SkRect storage; + const SkPaint paint; + const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), + &storage, + SkPaint::kFill_Style); + SkIRect ibounds; + newBounds.roundOut(&ibounds); + glyph->fLeft = ibounds.fLeft; + glyph->fTop = ibounds.fTop; + glyph->fWidth = ibounds.width(); + glyph->fHeight = ibounds.height(); + } + + void generateImage(const SkGlyph& glyph) override { + SkPath path; + this->getTestTypeface()->getPath(glyph.getGlyphID(), &path); + + SkBitmap bm; + bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), + glyph.fImage, glyph.rowBytes()); + bm.eraseColor(0); + + SkCanvas canvas(bm); + canvas.translate(-SkIntToScalar(glyph.fLeft), + -SkIntToScalar(glyph.fTop)); + canvas.concat(fMatrix); + SkPaint paint; + paint.setAntiAlias(true); + canvas.drawPath(path, paint); + } + + void generatePath(SkGlyphID glyph, SkPath* path) override { + this->getTestTypeface()->getPath(glyph, path); + path->transform(fMatrix); + } + + void generateFontMetrics(SkPaint::FontMetrics* metrics) override { + this->getTestTypeface()->getFontMetrics(metrics); + SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); + } + +private: + SkMatrix fMatrix; +}; + +SkScalerContext* SkTestTypeface::onCreateScalerContext( + const SkScalerContextEffects& effects, const SkDescriptor* desc) const +{ + return new SkTestScalerContext(sk_ref_sp(const_cast(this)), effects, desc); +} diff --git a/tools/fonts/SkTestScalerContext.h b/tools/fonts/SkTestScalerContext.h new file mode 100644 index 0000000000..e62210b2e3 --- /dev/null +++ b/tools/fonts/SkTestScalerContext.h @@ -0,0 +1,102 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTestScalerContext_DEFINED +#define SkTestScalerContext_DEFINED + +#include "SkFixed.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" +#include "SkTypeface.h" + +class SkTestFont; + +struct SkTestFontData { + const SkScalar* fPoints; + const unsigned char* fVerbs; + const unsigned* fCharCodes; + const size_t fCharCodesCount; + const SkFixed* fWidths; + const SkPaint::FontMetrics& fMetrics; + const char* fName; + SkFontStyle fStyle; + sk_sp fCachedFont; +}; + +class SkTestFont : public SkRefCnt { +public: + SkTestFont(const SkTestFontData& ); + virtual ~SkTestFont(); + int codeToIndex(SkUnichar charCode) const; + void init(const SkScalar* pts, const unsigned char* verbs); +private: + const unsigned* fCharCodes; + const size_t fCharCodesCount; + const SkFixed* fWidths; + const SkPaint::FontMetrics& fMetrics; + const char* fName; + SkPath** fPaths; + friend class SkTestTypeface; + typedef SkRefCnt INHERITED; +}; + + +class SkTestTypeface : public SkTypeface { +public: + SkTestTypeface(sk_sp, const SkFontStyle& style); + void getAdvance(SkGlyph* glyph); + void getFontMetrics(SkPaint::FontMetrics* metrics); + void getMetrics(SkGlyph* glyph); + void getPath(SkGlyphID glyph, SkPath* path); +protected: + SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor* desc) const override; + void onFilterRec(SkScalerContextRec* rec) const override; + std::unique_ptr onGetAdvancedMetrics() const override; + + SkStreamAsset* onOpenStream(int* ttcIndex) const override { + return nullptr; + } + + void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override; + + int onCharsToGlyphs(const void* chars, Encoding encoding, + uint16_t glyphs[], int glyphCount) const override; + + int onCountGlyphs() const override { + return (int) fTestFont->fCharCodesCount; + } + + int onGetUPEM() const override { + return 2048; + } + + void onGetFamilyName(SkString* familyName) const override; + SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override + { + return 0; + } + + int onGetTableTags(SkFontTableTag tags[]) const override { + return 0; + } + + size_t onGetTableData(SkFontTableTag tag, size_t offset, + size_t length, void* data) const override { + return 0; + } +private: + sk_sp fTestFont; + friend class SkTestScalerContext; +}; + +#endif diff --git a/tools/fonts/SkTestTypeface.cpp b/tools/fonts/SkTestTypeface.cpp deleted file mode 100644 index 52751c9f59..0000000000 --- a/tools/fonts/SkTestTypeface.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkAdvancedTypefaceMetrics.h" -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkFontDescriptor.h" -#include "SkGlyph.h" -#include "SkImageInfo.h" -#include "SkMatrix.h" -#include "SkOTUtils.h" -#include "SkPaintPriv.h" -#include "SkPath.h" -#include "SkPoint.h" -#include "SkRect.h" -#include "SkScalerContext.h" -#include "SkString.h" -#include "SkTestTypeface.h" -#include "SkTDArray.h" -#include "SkUtils.h" - -#include - -class SkDescriptor; - -SkTestFont::SkTestFont(const SkTestFontData& fontData) - : INHERITED() - , fCharCodes(fontData.fCharCodes) - , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0) - , fWidths(fontData.fWidths) - , fMetrics(fontData.fMetrics) - , fName(fontData.fName) - , fPaths(nullptr) -{ - init(fontData.fPoints, fontData.fVerbs); -} - -SkTestFont::~SkTestFont() { - for (unsigned index = 0; index < fCharCodesCount; ++index) { - delete fPaths[index]; - } - delete[] fPaths; -} - -int SkTestFont::codeToIndex(SkUnichar charCode) const { - for (unsigned index = 0; index < fCharCodesCount; ++index) { - if (fCharCodes[index] == (unsigned) charCode) { - return (int) index; - } - } - return 0; -} - -void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) { - fPaths = new SkPath* [fCharCodesCount]; - for (unsigned index = 0; index < fCharCodesCount; ++index) { - SkPath* path = new SkPath; - SkPath::Verb verb; - while ((verb = (SkPath::Verb) *verbs++) != SkPath::kDone_Verb) { - switch (verb) { - case SkPath::kMove_Verb: - path->moveTo(pts[0], pts[1]); - pts += 2; - break; - case SkPath::kLine_Verb: - path->lineTo(pts[0], pts[1]); - pts += 2; - break; - case SkPath::kQuad_Verb: - path->quadTo(pts[0], pts[1], pts[2], pts[3]); - pts += 4; - break; - case SkPath::kCubic_Verb: - path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); - pts += 6; - break; - case SkPath::kClose_Verb: - path->close(); - break; - default: - SkDEBUGFAIL("bad verb"); - return; - } - } - // This should make SkPath::getBounds() queries threadsafe. - path->updateBoundsCache(); - fPaths[index] = path; - } -} - -SkTestTypeface::SkTestTypeface(sk_sp testFont, const SkFontStyle& style) - : SkTypeface(style, false) - , fTestFont(std::move(testFont)) { -} - -void SkTestTypeface::getAdvance(SkGlyph* glyph) { - // TODO(benjaminwagner): Update users to use floats. - glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]); - glyph->fAdvanceY = 0; -} - -void SkTestTypeface::getFontMetrics(SkPaint::FontMetrics* metrics) { - *metrics = fTestFont->fMetrics; -} - -void SkTestTypeface::getMetrics(SkGlyph* glyph) { - SkGlyphID glyphID = glyph->getGlyphID(); - glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0; - - // TODO(benjaminwagner): Update users to use floats. - glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyphID]); - glyph->fAdvanceY = 0; -} - -void SkTestTypeface::getPath(SkGlyphID glyphID, SkPath* path) { - glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0; - *path = *fTestFont->fPaths[glyphID]; -} - -void SkTestTypeface::onFilterRec(SkScalerContextRec* rec) const { - rec->setHinting(SkPaint::kNo_Hinting); -} - -std::unique_ptr SkTestTypeface::onGetAdvancedMetrics() const { // pdf only - std::unique_ptr info(new SkAdvancedTypefaceMetrics); - info->fFontName.set(fTestFont->fName); - int glyphCount = this->onCountGlyphs(); - - SkTDArray& toUnicode = info->fGlyphToUnicode; - toUnicode.setCount(glyphCount); - SkASSERT(glyphCount == SkToInt(fTestFont->fCharCodesCount)); - for (int gid = 0; gid < glyphCount; ++gid) { - toUnicode[gid] = SkToS32(fTestFont->fCharCodes[gid]); - } - return info; -} - -void SkTestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { - desc->setFamilyName(fTestFont->fName); - desc->setStyle(this->fontStyle()); - *isLocal = false; -} - -int SkTestTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const { - auto utf8 = (const char*)chars; - auto utf16 = (const uint16_t*)chars; - auto utf32 = (const SkUnichar*)chars; - - for (int i = 0; i < glyphCount; i++) { - SkUnichar ch; - switch (encoding) { - case kUTF8_Encoding: ch = SkUTF8_NextUnichar(&utf8 ); break; - case kUTF16_Encoding: ch = SkUTF16_NextUnichar(&utf16); break; - case kUTF32_Encoding: ch = *utf32++; break; - } - if (glyphs) { - glyphs[i] = fTestFont->codeToIndex(ch); - } - } - return glyphCount; -} - -void SkTestTypeface::onGetFamilyName(SkString* familyName) const { - *familyName = fTestFont->fName; -} - -SkTypeface::LocalizedStrings* SkTestTypeface::onCreateFamilyNameIterator() const { - SkString familyName(fTestFont->fName); - SkString language("und"); //undetermined - return new SkOTUtils::LocalizedStrings_SingleName(familyName, language); -} - -class SkTestScalerContext : public SkScalerContext { -public: - SkTestScalerContext(sk_sp face, const SkScalerContextEffects& effects, - const SkDescriptor* desc) - : SkScalerContext(std::move(face), effects, desc) - { - fRec.getSingleMatrix(&fMatrix); - this->forceGenerateImageFromPath(); - } - -protected: - SkTestTypeface* getTestTypeface() const { - return static_cast(this->getTypeface()); - } - - unsigned generateGlyphCount() override { - return this->getTestTypeface()->onCountGlyphs(); - } - - uint16_t generateCharToGlyph(SkUnichar uni) override { - uint16_t glyph; - (void) this->getTestTypeface()->onCharsToGlyphs((const void *) &uni, - SkTypeface::kUTF32_Encoding, &glyph, 1); - return glyph; - } - - void generateAdvance(SkGlyph* glyph) override { - this->getTestTypeface()->getAdvance(glyph); - - const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), - SkFloatToScalar(glyph->fAdvanceY)); - glyph->fAdvanceX = SkScalarToFloat(advance.fX); - glyph->fAdvanceY = SkScalarToFloat(advance.fY); - } - - void generateMetrics(SkGlyph* glyph) override { - this->getTestTypeface()->getMetrics(glyph); - - const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), - SkFloatToScalar(glyph->fAdvanceY)); - glyph->fAdvanceX = SkScalarToFloat(advance.fX); - glyph->fAdvanceY = SkScalarToFloat(advance.fY); - - SkPath path; - this->getTestTypeface()->getPath(glyph->getGlyphID(), &path); - path.transform(fMatrix); - - SkRect storage; - const SkPaint paint; - const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), - &storage, - SkPaint::kFill_Style); - SkIRect ibounds; - newBounds.roundOut(&ibounds); - glyph->fLeft = ibounds.fLeft; - glyph->fTop = ibounds.fTop; - glyph->fWidth = ibounds.width(); - glyph->fHeight = ibounds.height(); - } - - void generateImage(const SkGlyph& glyph) override { - SkPath path; - this->getTestTypeface()->getPath(glyph.getGlyphID(), &path); - - SkBitmap bm; - bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), - glyph.fImage, glyph.rowBytes()); - bm.eraseColor(0); - - SkCanvas canvas(bm); - canvas.translate(-SkIntToScalar(glyph.fLeft), - -SkIntToScalar(glyph.fTop)); - canvas.concat(fMatrix); - SkPaint paint; - paint.setAntiAlias(true); - canvas.drawPath(path, paint); - } - - void generatePath(SkGlyphID glyph, SkPath* path) override { - this->getTestTypeface()->getPath(glyph, path); - path->transform(fMatrix); - } - - void generateFontMetrics(SkPaint::FontMetrics* metrics) override { - this->getTestTypeface()->getFontMetrics(metrics); - SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); - } - -private: - SkMatrix fMatrix; -}; - -SkScalerContext* SkTestTypeface::onCreateScalerContext( - const SkScalerContextEffects& effects, const SkDescriptor* desc) const -{ - return new SkTestScalerContext(sk_ref_sp(const_cast(this)), effects, desc); -} diff --git a/tools/fonts/SkTestTypeface.h b/tools/fonts/SkTestTypeface.h deleted file mode 100644 index b520fb6e5c..0000000000 --- a/tools/fonts/SkTestTypeface.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkTestTypeface_DEFINED -#define SkTestTypeface_DEFINED - -#include "SkFixed.h" -#include "SkFontArguments.h" -#include "SkFontStyle.h" -#include "SkPaint.h" -#include "SkRefCnt.h" -#include "SkScalar.h" -#include "SkTypeface.h" -#include "SkTypes.h" - -#include - -class SkDescriptor; -class SkFontDescriptor; -class SkGlyph; -class SkPath; -class SkScalerContext; -class SkStreamAsset; -class SkString; -class SkTestFont; -struct SkAdvancedTypefaceMetrics; -struct SkScalerContextEffects; -struct SkScalerContextRec; - -struct SkTestFontData { - const SkScalar* fPoints; - const unsigned char* fVerbs; - const unsigned* fCharCodes; - const size_t fCharCodesCount; - const SkFixed* fWidths; - const SkPaint::FontMetrics& fMetrics; - const char* fName; - SkFontStyle fStyle; - sk_sp fCachedFont; -}; - -class SkTestFont : public SkRefCnt { -public: - SkTestFont(const SkTestFontData& ); - virtual ~SkTestFont(); - int codeToIndex(SkUnichar charCode) const; - void init(const SkScalar* pts, const unsigned char* verbs); -private: - const unsigned* fCharCodes; - const size_t fCharCodesCount; - const SkFixed* fWidths; - const SkPaint::FontMetrics& fMetrics; - const char* fName; - SkPath** fPaths; - friend class SkTestTypeface; - typedef SkRefCnt INHERITED; -}; - - -class SkTestTypeface : public SkTypeface { -public: - SkTestTypeface(sk_sp, const SkFontStyle& style); - void getAdvance(SkGlyph* glyph); - void getFontMetrics(SkPaint::FontMetrics* metrics); - void getMetrics(SkGlyph* glyph); - void getPath(SkGlyphID glyph, SkPath* path); -protected: - SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, - const SkDescriptor* desc) const override; - void onFilterRec(SkScalerContextRec* rec) const override; - std::unique_ptr onGetAdvancedMetrics() const override; - - SkStreamAsset* onOpenStream(int* ttcIndex) const override { - return nullptr; - } - - void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override; - - int onCharsToGlyphs(const void* chars, Encoding encoding, - uint16_t glyphs[], int glyphCount) const override; - - int onCountGlyphs() const override { - return (int) fTestFont->fCharCodesCount; - } - - int onGetUPEM() const override { - return 2048; - } - - void onGetFamilyName(SkString* familyName) const override; - SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; - - int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], - int coordinateCount) const override - { - return 0; - } - - int onGetTableTags(SkFontTableTag tags[]) const override { - return 0; - } - - size_t onGetTableData(SkFontTableTag tag, size_t offset, - size_t length, void* data) const override { - return 0; - } -private: - sk_sp fTestFont; - friend class SkTestScalerContext; -}; - -#endif diff --git a/tools/fonts/create_test_font_color.cpp b/tools/fonts/create_test_font_color.cpp deleted file mode 100644 index c3f2e08f3f..0000000000 --- a/tools/fonts/create_test_font_color.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -// running create_test_font_color generates ./.ttx -// which are read by fonttools ttx to produce native fonts. - -#include "SkCommandLineFlags.h" -#include "SkRefCnt.h" -#include "SkStream.h" -#include "SkTestSVGTypeface.h" - -int main(int argc, char** argv) { - SkCommandLineFlags::Parse(argc, argv); - - sk_sp typeface = SkTestSVGTypeface::Default(); - - SkFILEWStream cbdt("cbdt.ttx"); - typeface->exportTtxCbdt(&cbdt); - cbdt.flush(); - cbdt.fsync(); - - SkFILEWStream sbix("sbix.ttx"); - typeface->exportTtxSbix(&sbix); - sbix.flush(); - sbix.fsync(); - - SkFILEWStream colr("colr.ttx"); - typeface->exportTtxColr(&colr); - colr.flush(); - colr.fsync(); - - return 0; -} diff --git a/tools/fonts/sk_tool_utils_font.cpp b/tools/fonts/sk_tool_utils_font.cpp index 4d5b86aa0a..d2aac851bb 100644 --- a/tools/fonts/sk_tool_utils_font.cpp +++ b/tools/fonts/sk_tool_utils_font.cpp @@ -11,7 +11,7 @@ #include "SkFontStyle.h" #include "SkMutex.h" #include "SkOSFile.h" -#include "SkTestTypeface.h" +#include "SkTestScalerContext.h" #include "SkUtils.h" #include "sk_tool_utils.h" @@ -70,23 +70,42 @@ sk_sp create_font(const char* name, SkFontStyle style) { } sk_sp emoji_typeface() { - const char* filename; #if defined(SK_BUILD_FOR_WIN) - filename = "fonts/colr.ttf"; -#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) - filename = "fonts/sbix.ttf"; -#else - filename = "fonts/cbdt.ttf"; -#endif - sk_sp typeface = MakeResourceAsTypeface(filename); + sk_sp fm(SkFontMgr::RefDefault()); + const char *colorEmojiFontName = "Segoe UI Emoji"; + sk_sp typeface(fm->matchFamilyStyle(colorEmojiFontName, SkFontStyle())); if (typeface) { return typeface; } - return SkTypeface::MakeFromName("Emoji", SkFontStyle()); + sk_sp fallback(fm->matchFamilyStyleCharacter( + colorEmojiFontName, SkFontStyle(), nullptr /* bcp47 */, 0 /* bcp47Count */, + 0x1f4b0 /* character: πŸ’° */)); + if (fallback) { + return fallback; + } + // If we don't have Segoe UI Emoji and can't find a fallback, try Segoe UI Symbol. + // Windows 7 does not have Segoe UI Emoji; Segoe UI Symbol has the (non - color) emoji. + return SkTypeface::MakeFromName("Segoe UI Symbol", SkFontStyle()); + +#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + return SkTypeface::MakeFromName("Apple Color Emoji", SkFontStyle()); + +#else + return MakeResourceAsTypeface("fonts/Funkster.ttf"); + +#endif } const char* emoji_sample_text() { - return "\xF0\x9F\x98\x80" " " "\xE2\x99\xA2"; // πŸ˜€ β™’ +#if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + return "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85" // πŸ’°πŸ‘πŸŽ… + "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80" // πŸͺπŸ•πŸš€ + "\xF0\x9F\x9A\xBB" "\xF0\x9F\x92\xA9" "\xF0\x9F\x93\xB7" // πŸš»πŸ’©πŸ“· + "\xF0\x9F\x93\xA6" // πŸ“¦ + "\xF0\x9F\x87\xBA" "\xF0\x9F\x87\xB8" "\xF0\x9F\x87\xA6"; // πŸ‡ΊπŸ‡ΈπŸ‡¦ +#else + return "Hamburgefons"; +#endif } static const char* platform_os_name() { diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp index 99b03a4391..2eb8dba833 100644 --- a/tools/sk_tool_utils.cpp +++ b/tools/sk_tool_utils.cpp @@ -5,29 +5,19 @@ * found in the LICENSE file. */ +#include "sk_tool_utils.h" + +#include "Resources.h" #include "SkBitmap.h" -#include "SkBlendMode.h" #include "SkCanvas.h" -#include "SkColorData.h" -#include "SkColorPriv.h" -#include "SkFloatingPoint.h" #include "SkImage.h" -#include "SkMatrix.h" -#include "SkPM4f.h" -#include "SkPaint.h" -#include "SkPath.h" #include "SkPixelRef.h" -#include "SkPixmap.h" -#include "SkPoint.h" -#include "SkRRect.h" +#include "SkPM4f.h" +#include "SkPoint3.h" #include "SkShader.h" #include "SkSurface.h" +#include "SkTestScalerContext.h" #include "SkTextBlob.h" -#include "sk_tool_utils.h" - -#include -#include -#include namespace sk_tool_utils { @@ -169,7 +159,7 @@ SkPath make_star(const SkRect& bounds, int numPts, int step) { #pragma optimize("", off) #endif void make_big_path(SkPath& path) { - #include "BigPathBench.inc" // IWYU pragma: keep + #include "BigPathBench.inc" } static float gaussian2d_value(int x, int y, float sigma) { diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h index 30d195d479..6c1adf8e26 100644 --- a/tools/sk_tool_utils.h +++ b/tools/sk_tool_utils.h @@ -9,33 +9,26 @@ #define sk_tool_utils_DEFINED #include "SkColor.h" -#include "SkData.h" -#include "SkEncodedImageFormat.h" -#include "SkFontStyle.h" #include "SkImageEncoder.h" #include "SkImageInfo.h" #include "SkRandom.h" -#include "SkRect.h" #include "SkRefCnt.h" -#include "SkScalar.h" #include "SkStream.h" -#include "SkTArray.h" #include "SkTDArray.h" -#include "SkTypes.h" +#include "SkTypeface.h" class SkBitmap; class SkCanvas; -class SkFontStyle; +class SkColorFilter; class SkImage; class SkPaint; class SkPath; -class SkPixmap; class SkRRect; class SkShader; class SkSurface; class SkSurfaceProps; +class SkTestFont; class SkTextBlobBuilder; -class SkTypeface; namespace sk_tool_utils { -- cgit v1.2.3