SkStrikeSpec.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Copyright 2019 The Android Open Source Project
  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 "src/core/SkStrikeSpec.h"
  8. #include "include/core/SkGraphics.h"
  9. #include "src/core/SkDraw.h"
  10. #include "src/core/SkFontPriv.h"
  11. #include "src/core/SkStrikeCache.h"
  12. #include "src/core/SkTLazy.h"
  13. SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
  14. const SkSurfaceProps& surfaceProps,
  15. SkScalerContextFlags scalerContextFlags,
  16. const SkMatrix& deviceMatrix) {
  17. SkStrikeSpec storage;
  18. storage.commonSetup(font, paint, surfaceProps, scalerContextFlags, deviceMatrix);
  19. return storage;
  20. }
  21. SkStrikeSpec SkStrikeSpec::MakePath(const SkFont& font, const SkPaint& paint,
  22. const SkSurfaceProps& surfaceProps,
  23. SkScalerContextFlags scalerContextFlags) {
  24. SkStrikeSpec storage;
  25. // setup our std runPaint, in hopes of getting hits in the cache
  26. SkPaint pathPaint{paint};
  27. SkFont pathFont{font};
  28. // The factor to get from the size stored in the strike to the size needed for
  29. // the source.
  30. storage.fStrikeToSourceRatio = pathFont.setupForAsPaths(&pathPaint);
  31. // The sub-pixel position will always happen when transforming to the screen.
  32. pathFont.setSubpixel(false);
  33. storage.commonSetup(pathFont, pathPaint, surfaceProps, scalerContextFlags, SkMatrix::I());
  34. return storage;
  35. }
  36. SkStrikeSpec SkStrikeSpec::MakeSourceFallback(
  37. const SkFont& font,
  38. const SkPaint& paint,
  39. const SkSurfaceProps& surfaceProps,
  40. SkScalerContextFlags scalerContextFlags,
  41. SkScalar maxSourceGlyphDimension) {
  42. SkStrikeSpec storage;
  43. // Subtract 2 to account for the bilerp pad around the glyph
  44. SkScalar maxAtlasDimension = SkStrikeCommon::kSkSideTooBigForAtlas - 2;
  45. SkScalar runFontTextSize = font.getSize();
  46. // Scale the text size down so the long side of all the glyphs will fit in the atlas.
  47. SkScalar fallbackTextSize = SkScalarFloorToScalar(
  48. (maxAtlasDimension / maxSourceGlyphDimension) * runFontTextSize);
  49. SkFont fallbackFont{font};
  50. fallbackFont.setSize(fallbackTextSize);
  51. // No sub-pixel needed. The transform to the screen will take care of sub-pixel positioning.
  52. fallbackFont.setSubpixel(false);
  53. // The scale factor to go from strike size to the source size for glyphs.
  54. storage.fStrikeToSourceRatio = runFontTextSize / fallbackTextSize;
  55. storage.commonSetup(fallbackFont, paint, surfaceProps, scalerContextFlags, SkMatrix::I());
  56. return storage;
  57. }
  58. SkStrikeSpec SkStrikeSpec::MakeCanonicalized(const SkFont& font, const SkPaint* paint) {
  59. SkStrikeSpec storage;
  60. SkPaint canonicalizedPaint;
  61. if (paint != nullptr) {
  62. canonicalizedPaint = *paint;
  63. }
  64. const SkFont* canonicalizedFont = &font;
  65. SkTLazy<SkFont> pathFont;
  66. if (ShouldDrawAsPath(canonicalizedPaint, font, SkMatrix::I())) {
  67. canonicalizedFont = pathFont.set(font);
  68. storage.fStrikeToSourceRatio = pathFont->setupForAsPaths(nullptr);
  69. canonicalizedPaint.reset();
  70. }
  71. storage.commonSetup(*canonicalizedFont,
  72. canonicalizedPaint,
  73. SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
  74. kFakeGammaAndBoostContrast,
  75. SkMatrix::I());
  76. return storage;
  77. }
  78. SkStrikeSpec SkStrikeSpec::MakeWithNoDevice(const SkFont& font, const SkPaint* paint) {
  79. SkStrikeSpec storage;
  80. SkPaint setupPaint;
  81. if (paint != nullptr) {
  82. setupPaint = *paint;
  83. }
  84. storage.commonSetup(font,
  85. setupPaint,
  86. SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
  87. kFakeGammaAndBoostContrast,
  88. SkMatrix::I());
  89. return storage;
  90. }
  91. SkStrikeSpec SkStrikeSpec::MakeDefault() {
  92. SkFont defaultFont;
  93. return MakeCanonicalized(defaultFont);
  94. }
  95. bool SkStrikeSpec::ShouldDrawAsPath(
  96. const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix) {
  97. // hairline glyphs are fast enough so we don't need to cache them
  98. if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
  99. return true;
  100. }
  101. // we don't cache perspective
  102. if (viewMatrix.hasPerspective()) {
  103. return true;
  104. }
  105. SkMatrix textMatrix = SkFontPriv::MakeTextMatrix(font);
  106. textMatrix.postConcat(viewMatrix);
  107. // we have a self-imposed maximum, just for memory-usage sanity
  108. SkScalar limit = SkMinScalar(SkGraphics::GetFontCachePointSizeLimit(), 1024);
  109. SkScalar maxSizeSquared = limit * limit;
  110. auto distance = [&textMatrix](int XIndex, int YIndex) {
  111. return textMatrix[XIndex] * textMatrix[XIndex] + textMatrix[YIndex] * textMatrix[YIndex];
  112. };
  113. return distance(SkMatrix::kMScaleX, SkMatrix::kMSkewY ) > maxSizeSquared
  114. || distance(SkMatrix::kMSkewX, SkMatrix::kMScaleY) > maxSizeSquared;
  115. }
  116. SkStrikeSpec SkStrikeSpec::MakePDFVector(const SkTypeface& typeface, int* size) {
  117. SkFont font;
  118. font.setHinting(SkFontHinting::kNone);
  119. font.setEdging(SkFont::Edging::kAlias);
  120. font.setTypeface(sk_ref_sp(&typeface));
  121. int unitsPerEm = typeface.getUnitsPerEm();
  122. if (unitsPerEm <= 0) {
  123. unitsPerEm = 1024;
  124. }
  125. if (size) {
  126. *size = unitsPerEm;
  127. }
  128. font.setSize((SkScalar)unitsPerEm);
  129. SkStrikeSpec storage;
  130. storage.commonSetup(font,
  131. SkPaint(),
  132. SkSurfaceProps(0, kUnknown_SkPixelGeometry),
  133. kFakeGammaAndBoostContrast,
  134. SkMatrix::I());
  135. return storage;
  136. }
  137. #if SK_SUPPORT_GPU
  138. std::tuple<SkStrikeSpec, SkScalar, SkScalar>
  139. SkStrikeSpec::MakeSDFT(const SkFont& font, const SkPaint& paint,
  140. const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix,
  141. const GrTextContext::Options& options) {
  142. SkStrikeSpec storage;
  143. SkPaint dfPaint = GrTextContext::InitDistanceFieldPaint(paint);
  144. SkFont dfFont = GrTextContext::InitDistanceFieldFont(
  145. font, deviceMatrix, options, &storage.fStrikeToSourceRatio);
  146. // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the
  147. // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
  148. SkScalerContextFlags flags = SkScalerContextFlags::kNone;
  149. SkScalar minScale, maxScale;
  150. std::tie(minScale, maxScale) = GrTextContext::InitDistanceFieldMinMaxScale(
  151. font.getSize(), deviceMatrix, options);
  152. storage.commonSetup(dfFont, dfPaint, surfaceProps, flags, SkMatrix::I());
  153. return std::tie(storage, minScale, maxScale);
  154. }
  155. sk_sp<GrTextStrike> SkStrikeSpec::findOrCreateGrStrike(GrStrikeCache* cache) const {
  156. return cache->getStrike(*fAutoDescriptor.getDesc());
  157. }
  158. #endif
  159. void SkStrikeSpec::commonSetup(const SkFont& font, const SkPaint& paint,
  160. const SkSurfaceProps& surfaceProps,
  161. SkScalerContextFlags scalerContextFlags,
  162. const SkMatrix& deviceMatrix) {
  163. SkScalerContextEffects effects;
  164. SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
  165. font, paint, surfaceProps, scalerContextFlags, deviceMatrix,
  166. &fAutoDescriptor, &effects);
  167. fMaskFilter = sk_ref_sp(effects.fMaskFilter);
  168. fPathEffect = sk_ref_sp(effects.fPathEffect);
  169. fTypeface = font.refTypefaceOrDefault();
  170. }
  171. SkScopedStrike SkStrikeSpec::findOrCreateScopedStrike(SkStrikeCacheInterface* cache) const {
  172. SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
  173. return cache->findOrCreateScopedStrike(*fAutoDescriptor.getDesc(), effects, *fTypeface);
  174. }
  175. SkExclusiveStrikePtr SkStrikeSpec::findOrCreateExclusiveStrike(SkStrikeCache* cache) const {
  176. SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
  177. return cache->findOrCreateStrikeExclusive(*fAutoDescriptor.getDesc(), effects, *fTypeface);
  178. }
  179. SkBulkGlyphMetrics::SkBulkGlyphMetrics(const SkStrikeSpec& spec)
  180. : fStrike{spec.findOrCreateExclusiveStrike()} { }
  181. SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
  182. fGlyphs.reset(glyphIDs.size());
  183. return fStrike->metrics(glyphIDs, fGlyphs.get());
  184. }
  185. SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
  186. : fStrike{spec.findOrCreateExclusiveStrike()} { }
  187. SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
  188. fGlyphs.reset(glyphIDs.size());
  189. return fStrike->preparePaths(glyphIDs, fGlyphs.get());
  190. }
  191. SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
  192. : fStrike{spec.findOrCreateExclusiveStrike()} { }
  193. SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
  194. fGlyphs.reset(glyphIDs.size());
  195. return fStrike->prepareImages(glyphIDs, fGlyphs.get());
  196. }