123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- /*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "gm/gm.h"
- #include "include/core/SkCanvas.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkFont.h"
- #include "include/core/SkFontMetrics.h"
- #include "include/core/SkFontMgr.h"
- #include "include/core/SkFontStyle.h"
- #include "include/core/SkFontTypes.h"
- #include "include/core/SkGraphics.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkPath.h"
- #include "include/core/SkPoint.h"
- #include "include/core/SkRect.h"
- #include "include/core/SkRefCnt.h"
- #include "include/core/SkScalar.h"
- #include "include/core/SkSize.h"
- #include "include/core/SkString.h"
- #include "include/core/SkTypeface.h"
- #include "include/core/SkTypes.h"
- #include "src/core/SkFontPriv.h"
- #include "tools/SkMetaData.h"
- #include "tools/ToolUtils.h"
- #include <utility>
- // limit this just so we don't take too long to draw
- #define MAX_FAMILIES 30
- static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
- SkScalar y, const SkFont& font) {
- canvas->drawString(text, x, y, font, SkPaint());
- return x + font.measureText(text.c_str(), text.size(), SkTextEncoding::kUTF8);
- }
- static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
- SkScalar y, const SkFont& origFont, SkFontMgr* fm,
- const char* fontName, const char* bcp47[], int bcp47Count,
- const SkFontStyle& fontStyle) {
- SkFont font = origFont;
- // find typeface containing the requested character and draw it
- SkString ch;
- ch.appendUnichar(character);
- sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
- bcp47, bcp47Count, character));
- font.setTypeface(typeface);
- x = drawString(canvas, ch, x, y, font) + 20;
- if (nullptr == typeface) {
- return x;
- }
- // repeat the process, but this time use the family name of the typeface
- // from the first pass. This emulates the behavior in Blink where it
- // it expects to get the same glyph when following this pattern.
- SkString familyName;
- typeface->getFamilyName(&familyName);
- font.setTypeface(fm->legacyMakeTypeface(familyName.c_str(), typeface->fontStyle()));
- return drawString(canvas, ch, x, y, font) + 20;
- }
- static const char* zh = "zh";
- static const char* ja = "ja";
- class FontMgrGM : public skiagm::GM {
- sk_sp<SkFontMgr> fFM;
- void onOnceBeforeDraw() override {
- SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
- fFM = SkFontMgr::RefDefault();
- }
- SkString onShortName() override { return SkString("fontmgr_iter"); }
- SkISize onISize() override { return {1536, 768}; }
- void onDraw(SkCanvas* canvas) override {
- SkScalar y = 20;
- SkFont font;
- font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
- font.setSubpixel(true);
- font.setSize(17);
- SkFontMgr* fm = fFM.get();
- int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
- for (int i = 0; i < count; ++i) {
- SkString familyName;
- fm->getFamilyName(i, &familyName);
- font.setTypeface(nullptr);
- (void)drawString(canvas, familyName, 20, y, font);
- SkScalar x = 220;
- sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
- for (int j = 0; j < set->count(); ++j) {
- SkString sname;
- SkFontStyle fs;
- set->getStyle(j, &fs, &sname);
- sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
- font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
- x = drawString(canvas, sname, x, y, font) + 20;
- // check to see that we get different glyphs in japanese and chinese
- x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &zh, 1, fs);
- x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &ja, 1, fs);
- // check that emoji characters are found
- x = drawCharacter(canvas, 0x1f601, x, y, font, fm, familyName.c_str(), nullptr,0, fs);
- }
- y += 24;
- }
- }
- };
- class FontMgrMatchGM : public skiagm::GM {
- sk_sp<SkFontMgr> fFM;
- void onOnceBeforeDraw() override {
- fFM = SkFontMgr::RefDefault();
- SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
- }
- SkString onShortName() override { return SkString("fontmgr_match"); }
- SkISize onISize() override { return {640, 1024}; }
- void iterateFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
- SkFont f(font);
- SkScalar y = 0;
- for (int j = 0; j < fset->count(); ++j) {
- SkString sname;
- SkFontStyle fs;
- fset->getStyle(j, &fs, &sname);
- sname.appendf(" [%d %d]", fs.weight(), fs.width());
- f.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
- (void)drawString(canvas, sname, 0, y, f);
- y += 24;
- }
- }
- void exploreFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
- SkFont f(font);
- SkScalar y = 0;
- for (int weight = 100; weight <= 900; weight += 200) {
- for (int width = 1; width <= 9; width += 2) {
- SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
- sk_sp<SkTypeface> face(fset->matchStyle(fs));
- if (face) {
- SkString str;
- str.printf("request [%d %d]", fs.weight(), fs.width());
- f.setTypeface(std::move(face));
- (void)drawString(canvas, str, 0, y, f);
- y += 24;
- }
- }
- }
- }
- DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
- SkFont font;
- font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
- font.setSubpixel(true);
- font.setSize(17);
- const char* gNames[] = {
- "Helvetica Neue", "Arial", "sans"
- };
- sk_sp<SkFontStyleSet> fset;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
- fset.reset(fFM->matchFamily(gNames[i]));
- if (fset->count() > 0) {
- break;
- }
- }
- if (nullptr == fset.get()) {
- *errorMsg = "No SkFontStyleSet";
- return DrawResult::kFail;
- }
- canvas->translate(20, 40);
- this->exploreFamily(canvas, font, fset.get());
- canvas->translate(150, 0);
- this->iterateFamily(canvas, font, fset.get());
- return DrawResult::kOk;
- }
- };
- class FontMgrBoundsGM : public skiagm::GM {
- public:
- FontMgrBoundsGM(float scale, float skew) : fScaleX(scale) , fSkewX(skew) {}
- private:
- SkString onShortName() override {
- if (fScaleX != 1 || fSkewX != 0) {
- return SkStringPrintf("fontmgr_bounds_%g_%g", fScaleX, fSkewX);
- }
- return SkString("fontmgr_bounds");
- }
- void onOnceBeforeDraw() override {
- fFM = SkFontMgr::RefDefault();
- }
- bool onGetControls(SkMetaData* controls) override {
- controls->setBool("Label Bounds", fLabelBounds);
- return true;
- }
- void onSetControls(const SkMetaData& controls) override {
- controls.findBool("Label Bounds", &fLabelBounds);
- }
- static void show_bounds(SkCanvas* canvas, const SkFont& font, SkScalar x, SkScalar y,
- SkColor boundsColor, bool labelBounds)
- {
- SkRect fontBounds = SkFontPriv::GetFontBounds(font).makeOffset(x, y);
- SkPaint boundsPaint;
- boundsPaint.setAntiAlias(true);
- boundsPaint.setColor(boundsColor);
- boundsPaint.setStyle(SkPaint::kStroke_Style);
- canvas->drawRect(fontBounds, boundsPaint);
- SkFontMetrics fm;
- font.getMetrics(&fm);
- SkPaint metricsPaint(boundsPaint);
- metricsPaint.setStyle(SkPaint::kFill_Style);
- metricsPaint.setAlphaf(0.25f);
- if ((fm.fFlags & SkFontMetrics::kUnderlinePositionIsValid_Flag) &&
- (fm.fFlags & SkFontMetrics::kUnderlineThicknessIsValid_Flag))
- {
- SkRect underline{ fontBounds.fLeft, fm.fUnderlinePosition+y,
- fontBounds.fRight, fm.fUnderlinePosition+y + fm.fUnderlineThickness };
- canvas->drawRect(underline, metricsPaint);
- }
- if ((fm.fFlags & SkFontMetrics::kStrikeoutPositionIsValid_Flag) &&
- (fm.fFlags & SkFontMetrics::kStrikeoutThicknessIsValid_Flag))
- {
- SkRect strikeout{ fontBounds.fLeft, fm.fStrikeoutPosition+y - fm.fStrikeoutThickness,
- fontBounds.fRight, fm.fStrikeoutPosition+y };
- canvas->drawRect(strikeout, metricsPaint);
- }
- SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
- {
- int numGlyphs = font.getTypefaceOrDefault()->countGlyphs();
- SkRect min = {0, 0, 0, 0};
- for (int i = 0; i < numGlyphs; ++i) {
- SkGlyphID glyphId = i;
- SkRect cur;
- font.getBounds(&glyphId, 1, &cur, nullptr);
- if (cur.fLeft < min.fLeft ) { min.fLeft = cur.fLeft; left = i; }
- if (cur.fTop < min.fTop ) { min.fTop = cur.fTop ; top = i; }
- if (min.fRight < cur.fRight ) { min.fRight = cur.fRight; right = i; }
- if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
- }
- }
- SkGlyphID str[] = { left, right, top, bottom };
- SkPoint location[] = {
- {fontBounds.left(), fontBounds.centerY()},
- {fontBounds.right(), fontBounds.centerY()},
- {fontBounds.centerX(), fontBounds.top()},
- {fontBounds.centerX(), fontBounds.bottom()}
- };
- SkFont labelFont;
- labelFont.setEdging(SkFont::Edging::kAntiAlias);
- labelFont.setTypeface(ToolUtils::create_portable_typeface());
- if (labelBounds) {
- SkString name;
- font.getTypefaceOrDefault()->getFamilyName(&name);
- canvas->drawString(name, fontBounds.fLeft, fontBounds.fBottom, labelFont, SkPaint());
- }
- for (size_t i = 0; i < SK_ARRAY_COUNT(str); ++i) {
- SkPath path;
- font.getPath(str[i], &path);
- path.offset(x, y);
- SkPaint::Style style = path.isEmpty() ? SkPaint::kFill_Style : SkPaint::kStroke_Style;
- SkPaint glyphPaint;
- glyphPaint.setStyle(style);
- canvas->drawSimpleText(&str[i], sizeof(str[0]), SkTextEncoding::kGlyphID, x, y, font, glyphPaint);
- if (labelBounds) {
- SkString glyphStr;
- glyphStr.appendS32(str[i]);
- canvas->drawString(glyphStr, location[i].fX, location[i].fY, labelFont, SkPaint());
- }
- }
- }
- SkISize onISize() override { return {1024, 850}; }
- void onDraw(SkCanvas* canvas) override {
- SkFont font;
- font.setEdging(SkFont::Edging::kAntiAlias);
- font.setSubpixel(true);
- font.setSize(100);
- font.setScaleX(fScaleX);
- font.setSkewX(fSkewX);
- const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
- SkFontMgr* fm = fFM.get();
- int count = SkMin32(fm->countFamilies(), 32);
- int index = 0;
- SkScalar x = 0, y = 0;
- canvas->translate(10, 120);
- for (int i = 0; i < count; ++i) {
- sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
- for (int j = 0; j < set->count() && j < 3; ++j) {
- font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
- // Fonts with lots of glyphs are interesting, but can take a long time to find
- // the glyphs which make up the maximum extent.
- if (font.getTypefaceOrDefault() && font.getTypefaceOrDefault()->countGlyphs() < 1000) {
- SkRect fontBounds = SkFontPriv::GetFontBounds(font);
- x -= fontBounds.fLeft;
- show_bounds(canvas, font, x, y, boundsColors[index & 1], fLabelBounds);
- x += fontBounds.fRight + 20;
- index += 1;
- if (x > 900) {
- x = 0;
- y += 160;
- }
- if (y >= 700) {
- return;
- }
- }
- }
- }
- }
- sk_sp<SkFontMgr> fFM;
- const SkScalar fScaleX;
- const SkScalar fSkewX;
- bool fLabelBounds = false;
- };
- //////////////////////////////////////////////////////////////////////////////
- DEF_GM(return new FontMgrGM;)
- DEF_GM(return new FontMgrMatchGM;)
- DEF_GM(return new FontMgrBoundsGM(1, 0);)
- DEF_GM(return new FontMgrBoundsGM(0.75f, 0);)
- DEF_GM(return new FontMgrBoundsGM(1, -0.25f);)
|