TypefaceTest.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. * Copyright 2013 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkData.h"
  8. #include "include/core/SkFontMgr.h"
  9. #include "include/core/SkRefCnt.h"
  10. #include "include/core/SkStream.h"
  11. #include "include/core/SkTypeface.h"
  12. #include "include/ports/SkTypeface_win.h"
  13. #include "include/private/SkFixed.h"
  14. #include "src/core/SkAdvancedTypefaceMetrics.h"
  15. #include "src/core/SkFontDescriptor.h"
  16. #include "src/core/SkFontMgrPriv.h"
  17. #include "src/core/SkFontPriv.h"
  18. #include "src/core/SkMakeUnique.h"
  19. #include "src/core/SkTypefaceCache.h"
  20. #include "src/sfnt/SkOTTable_OS_2.h"
  21. #include "src/sfnt/SkSFNTHeader.h"
  22. #include "src/utils/SkUTF.h"
  23. #include "tests/Test.h"
  24. #include "tools/Resources.h"
  25. #include "tools/ToolUtils.h"
  26. #include "tools/fonts/TestEmptyTypeface.h"
  27. #include <memory>
  28. static void TypefaceStyle_test(skiatest::Reporter* reporter,
  29. uint16_t weight, uint16_t width, SkData* data)
  30. {
  31. sk_sp<SkData> dataCopy;
  32. if (!data->unique()) {
  33. dataCopy = SkData::MakeWithCopy(data->data(), data->size());
  34. data = dataCopy.get();
  35. }
  36. SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
  37. SkSFNTHeader::TableDirectoryEntry* tableEntry =
  38. SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
  39. SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr;
  40. int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
  41. for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
  42. if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) {
  43. os2TableEntry = tableEntry + tableEntryIndex;
  44. break;
  45. }
  46. }
  47. SkASSERT_RELEASE(os2TableEntry);
  48. size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset);
  49. SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset);
  50. os2Table->usWeightClass.value = SkEndian_SwapBE16(weight);
  51. using WidthType = SkOTTableOS2_V0::WidthClass::Value;
  52. os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width));
  53. sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromData(sk_ref_sp(data)));
  54. if (!newTypeface) {
  55. // Not all SkFontMgr can MakeFromStream().
  56. return;
  57. }
  58. SkFontStyle newStyle = newTypeface->fontStyle();
  59. //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF);
  60. //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F);
  61. //printf("%d, %d\n", weight, newStyle.weight());
  62. //printf("%d, %d\n", width , newStyle.width());
  63. // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently).
  64. REPORTER_ASSERT(reporter,
  65. newStyle.weight() == weight ||
  66. (weight <= 10 && newStyle.weight() == 100 * weight) ||
  67. (weight == 4 && newStyle.weight() == 350) || // GDI weirdness
  68. (weight == 5 && newStyle.weight() == 400) || // GDI weirdness
  69. (weight == 0 && newStyle.weight() == 1) || // DW weirdness
  70. (weight == 1000 && newStyle.weight() == 999) // DW weirdness
  71. );
  72. // Some back-ends (GDI) don't support width, ensure these always report 'medium'.
  73. REPORTER_ASSERT(reporter,
  74. newStyle.width() == width ||
  75. newStyle.width() == 5);
  76. }
  77. DEF_TEST(TypefaceStyle, reporter) {
  78. std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Em.ttf"));
  79. if (!stream) {
  80. REPORT_FAILURE(reporter, "fonts/Em.ttf", SkString("Cannot load resource"));
  81. return;
  82. }
  83. sk_sp<SkData> data(SkData::MakeFromStream(stream.get(), stream->getLength()));
  84. using SkFS = SkFontStyle;
  85. for (int weight = SkFS::kInvisible_Weight; weight <= SkFS::kExtraBlack_Weight; ++weight) {
  86. TypefaceStyle_test(reporter, weight, 5, data.get());
  87. }
  88. for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
  89. TypefaceStyle_test(reporter, 400, width, data.get());
  90. }
  91. }
  92. DEF_TEST(TypefaceRoundTrip, reporter) {
  93. sk_sp<SkTypeface> typeface(MakeResourceAsTypeface("fonts/7630.otf"));
  94. if (!typeface) {
  95. // Not all SkFontMgr can MakeFromStream().
  96. return;
  97. }
  98. int fontIndex;
  99. std::unique_ptr<SkStreamAsset> stream = typeface->openStream(&fontIndex);
  100. sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
  101. sk_sp<SkTypeface> typeface2 = fm->makeFromStream(std::move(stream), fontIndex);
  102. REPORTER_ASSERT(reporter, typeface2);
  103. }
  104. DEF_TEST(FontDescriptorNegativeVariationSerialize, reporter) {
  105. SkFontDescriptor desc;
  106. SkFixed axis = -SK_Fixed1;
  107. auto font = skstd::make_unique<SkMemoryStream>("a", 1, false);
  108. desc.setFontData(skstd::make_unique<SkFontData>(std::move(font), 0, &axis, 1));
  109. SkDynamicMemoryWStream stream;
  110. desc.serialize(&stream);
  111. SkFontDescriptor descD;
  112. SkFontDescriptor::Deserialize(stream.detachAsStream().get(), &descD);
  113. std::unique_ptr<SkFontData> fontData = descD.detachFontData();
  114. if (!fontData) {
  115. REPORT_FAILURE(reporter, "fontData", SkString());
  116. return;
  117. }
  118. if (fontData->getAxisCount() != 1) {
  119. REPORT_FAILURE(reporter, "fontData->getAxisCount() != 1", SkString());
  120. return;
  121. }
  122. REPORTER_ASSERT(reporter, fontData->getAxis()[0] == -SK_Fixed1);
  123. };
  124. DEF_TEST(TypefaceAxes, reporter) {
  125. std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
  126. if (!distortable) {
  127. REPORT_FAILURE(reporter, "distortable", SkString());
  128. return;
  129. }
  130. constexpr int numberOfAxesInDistortable = 1;
  131. sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
  132. // The position may be over specified. If there are multiple values for a given axis,
  133. // ensure the last one since that's what css-fonts-4 requires.
  134. const SkFontArguments::VariationPosition::Coordinate position[] = {
  135. { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f },
  136. { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
  137. };
  138. SkFontArguments params;
  139. params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
  140. // TODO: if axes are set and the back-end doesn't support them, should we create the typeface?
  141. sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
  142. if (!typeface) {
  143. // Not all SkFontMgr can makeFromStream().
  144. return;
  145. }
  146. int count = typeface->getVariationDesignPosition(nullptr, 0);
  147. if (count == -1) {
  148. return;
  149. }
  150. REPORTER_ASSERT(reporter, count == numberOfAxesInDistortable);
  151. SkFontArguments::VariationPosition::Coordinate positionRead[numberOfAxesInDistortable];
  152. count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
  153. REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(positionRead));
  154. REPORTER_ASSERT(reporter, positionRead[0].axis == position[1].axis);
  155. // Convert to fixed for "almost equal".
  156. SkFixed fixedRead = SkScalarToFixed(positionRead[0].value);
  157. SkFixed fixedOriginal = SkScalarToFixed(position[1].value);
  158. REPORTER_ASSERT(reporter, SkTAbs(fixedRead - fixedOriginal) < 2);
  159. }
  160. DEF_TEST(TypefaceVariationIndex, reporter) {
  161. std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
  162. if (!distortable) {
  163. REPORT_FAILURE(reporter, "distortable", SkString());
  164. return;
  165. }
  166. sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
  167. SkFontArguments params;
  168. // The first named variation position in Distortable is 'Thin'.
  169. params.setCollectionIndex(0x00010000);
  170. sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
  171. if (!typeface) {
  172. // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
  173. // gets one of these things make sense.
  174. return;
  175. }
  176. int count = typeface->getVariationDesignPosition(nullptr, 0);
  177. if (!(count == 1)) {
  178. REPORT_FAILURE(reporter, "count == 1", SkString());
  179. return;
  180. }
  181. SkFontArguments::VariationPosition::Coordinate positionRead[1];
  182. count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
  183. if (count == -1) {
  184. return;
  185. }
  186. if (!(count == 1)) {
  187. REPORT_FAILURE(reporter, "count == 1", SkString());
  188. return;
  189. }
  190. REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
  191. REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
  192. }
  193. DEF_TEST(Typeface, reporter) {
  194. sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
  195. sk_sp<SkTypeface> t2(SkTypeface::MakeDefault());
  196. REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
  197. REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t1.get()));
  198. REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t2.get()));
  199. REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), nullptr));
  200. REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), nullptr));
  201. }
  202. DEF_TEST(TypefaceAxesParameters, reporter) {
  203. std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
  204. if (!distortable) {
  205. REPORT_FAILURE(reporter, "distortable", SkString());
  206. return;
  207. }
  208. constexpr int numberOfAxesInDistortable = 1;
  209. constexpr SkScalar minAxisInDistortable = 0.5;
  210. constexpr SkScalar defAxisInDistortable = 1;
  211. constexpr SkScalar maxAxisInDistortable = 2;
  212. constexpr bool axisIsHiddenInDistortable = false;
  213. sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
  214. SkFontArguments params;
  215. sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
  216. if (!typeface) {
  217. // Not all SkFontMgr can makeFromStream().
  218. return;
  219. }
  220. SkFontParameters::Variation::Axis parameter[numberOfAxesInDistortable];
  221. int count = typeface->getVariationDesignParameters(parameter, SK_ARRAY_COUNT(parameter));
  222. if (count == -1) {
  223. return;
  224. }
  225. REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(parameter));
  226. REPORTER_ASSERT(reporter, parameter[0].min == minAxisInDistortable);
  227. REPORTER_ASSERT(reporter, parameter[0].def == defAxisInDistortable);
  228. REPORTER_ASSERT(reporter, parameter[0].max == maxAxisInDistortable);
  229. REPORTER_ASSERT(reporter, parameter[0].tag == SkSetFourByteTag('w','g','h','t'));
  230. REPORTER_ASSERT(reporter, parameter[0].isHidden() == axisIsHiddenInDistortable);
  231. }
  232. static bool count_proc(SkTypeface* face, void* ctx) {
  233. int* count = static_cast<int*>(ctx);
  234. *count = *count + 1;
  235. return false;
  236. }
  237. static int count(skiatest::Reporter* reporter, const SkTypefaceCache& cache) {
  238. int count = 0;
  239. sk_sp<SkTypeface> none = cache.findByProcAndRef(count_proc, &count);
  240. REPORTER_ASSERT(reporter, none == nullptr);
  241. return count;
  242. }
  243. DEF_TEST(TypefaceCache, reporter) {
  244. sk_sp<SkTypeface> t1(TestEmptyTypeface::Make());
  245. {
  246. SkTypefaceCache cache;
  247. REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
  248. {
  249. sk_sp<SkTypeface> t0(TestEmptyTypeface::Make());
  250. cache.add(t0);
  251. REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
  252. cache.add(t1);
  253. REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
  254. cache.purgeAll();
  255. REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
  256. }
  257. REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
  258. cache.purgeAll();
  259. REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
  260. }
  261. REPORTER_ASSERT(reporter, t1->unique());
  262. }
  263. static void check_serialize_behaviors(sk_sp<SkTypeface> tf, bool isLocalData,
  264. skiatest::Reporter* reporter) {
  265. if (!tf) {
  266. return;
  267. }
  268. auto data0 = tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
  269. auto data1 = tf->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
  270. auto data2 = tf->serialize(SkTypeface::SerializeBehavior::kIncludeDataIfLocal);
  271. REPORTER_ASSERT(reporter, data0->size() >= data1->size());
  272. if (isLocalData) {
  273. REPORTER_ASSERT(reporter, data0->equals(data2.get()));
  274. } else {
  275. REPORTER_ASSERT(reporter, data1->equals(data2.get()));
  276. }
  277. }
  278. DEF_TEST(Typeface_serialize, reporter) {
  279. check_serialize_behaviors(SkTypeface::MakeDefault(), false, reporter);
  280. check_serialize_behaviors(SkTypeface::MakeFromStream(
  281. GetResourceAsStream("fonts/Distortable.ttf")),
  282. true, reporter);
  283. }
  284. DEF_TEST(Typeface_glyph_to_char, reporter) {
  285. SkFont font(ToolUtils::emoji_typeface(), 12);
  286. SkASSERT(font.getTypeface());
  287. char const * text = ToolUtils::emoji_sample_text();
  288. size_t const textLen = strlen(text);
  289. size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
  290. char const * const textEnd = text + textLen;
  291. std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
  292. for (size_t i = 0; i < codepointCount; ++i) {
  293. originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
  294. }
  295. std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
  296. font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
  297. std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
  298. SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
  299. SkString familyName;
  300. font.getTypeface()->getFamilyName(&familyName);
  301. for (size_t i = 0; i < codepointCount; ++i) {
  302. #if defined(SK_BUILD_FOR_WIN)
  303. // GDI does not support character to glyph mapping outside BMP.
  304. if (gSkFontMgr_DefaultFactory == &SkFontMgr_New_GDI &&
  305. 0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0)
  306. {
  307. continue;
  308. }
  309. #endif
  310. // If two codepoints map to the same glyph then this assert is not valid.
  311. // However, the emoji test font should never have multiple characters map to the same glyph.
  312. REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
  313. "name:%s i:%d original:%d new:%d glyph:%d", familyName.c_str(), i,
  314. originalCodepoints[i], newCodepoints[i], glyphs[i]);
  315. }
  316. }
  317. // This test makes sure the legacy typeface creation does not lose its specified
  318. // style. See https://bugs.chromium.org/p/skia/issues/detail?id=8447 for more
  319. // context.
  320. DEF_TEST(LegacyMakeTypeface, reporter) {
  321. sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
  322. sk_sp<SkTypeface> typeface1 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Italic());
  323. sk_sp<SkTypeface> typeface2 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Bold());
  324. sk_sp<SkTypeface> typeface3 = fm->legacyMakeTypeface(nullptr, SkFontStyle::BoldItalic());
  325. REPORTER_ASSERT(reporter, typeface1->isItalic());
  326. REPORTER_ASSERT(reporter, !typeface1->isBold());
  327. REPORTER_ASSERT(reporter, !typeface2->isItalic());
  328. REPORTER_ASSERT(reporter, typeface2->isBold());
  329. REPORTER_ASSERT(reporter, typeface3->isItalic());
  330. REPORTER_ASSERT(reporter, typeface3->isBold());
  331. }