1 /*
2 * Copyright 2020 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
8 #include "src/text/gpu/SDFTControl.h"
9
10 #include "include/core/SkFont.h"
11 #include "include/core/SkFontTypes.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkScalar.h"
15 #include "src/core/SkFontPriv.h"
16 #include "src/core/SkGlyph.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkWriteBuffer.h"
19
20 #include <tuple>
21
22 struct SkPoint;
23
24 namespace sktext::gpu {
25
26 #if !defined(SK_DISABLE_SDF_TEXT)
27 // DF sizes and thresholds for usage of the small and medium sizes. For example, above
28 // kSmallDFFontLimit we will use the medium size. The large size is used up until the size at
29 // which we switch over to drawing as paths as controlled by Control.
30 static const int kSmallDFFontLimit = 32;
31 static const int kMediumDFFontLimit = 72;
32 static const int kLargeDFFontLimit = 162;
33 #ifdef SK_BUILD_FOR_MAC
34 static const int kExtraLargeDFFontLimit = 256;
35 #endif
36
MinSDFTRange(bool useSDFTForSmallText,SkScalar min)37 SkScalar SDFTControl::MinSDFTRange(bool useSDFTForSmallText, SkScalar min) {
38 if (!useSDFTForSmallText) {
39 return kLargeDFFontLimit;
40 }
41 return min;
42 }
43
SDFTControl(bool ableToUseSDFT,bool useSDFTForSmallText,bool useSDFTForPerspectiveText,SkScalar min,SkScalar max)44 SDFTControl::SDFTControl(
45 bool ableToUseSDFT, bool useSDFTForSmallText, bool useSDFTForPerspectiveText,
46 SkScalar min, SkScalar max)
47 : fMinDistanceFieldFontSize{MinSDFTRange(useSDFTForSmallText, min)}
48 , fMaxDistanceFieldFontSize{max}
49 , fAbleToUseSDFT{ableToUseSDFT}
50 , fAbleToUsePerspectiveSDFT{useSDFTForPerspectiveText} {
51 SkASSERT_RELEASE(0 < min && min <= max);
52 }
53 #endif // !defined(SK_DISABLE_SDF_TEXT)
54
isDirect(SkScalar approximateDeviceTextSize,const SkPaint & paint,const SkMatrix & matrix) const55 bool SDFTControl::isDirect(SkScalar approximateDeviceTextSize, const SkPaint& paint,
56 const SkMatrix& matrix) const {
57 #if !defined(SK_DISABLE_SDF_TEXT)
58 const bool isSDFT = this->isSDFT(approximateDeviceTextSize, paint, matrix);
59 #else
60 const bool isSDFT = false;
61 #endif
62 return !isSDFT &&
63 !matrix.hasPerspective() &&
64 0 < approximateDeviceTextSize &&
65 approximateDeviceTextSize < SkGlyphDigest::kSkSideTooBigForAtlas;
66 }
67
68 #if !defined(SK_DISABLE_SDF_TEXT)
isSDFT(SkScalar approximateDeviceTextSize,const SkPaint & paint,const SkMatrix & matrix) const69 bool SDFTControl::isSDFT(SkScalar approximateDeviceTextSize, const SkPaint& paint,
70 const SkMatrix& matrix) const {
71 const bool wideStroke = paint.getStyle() == SkPaint::kStroke_Style &&
72 paint.getStrokeWidth() > 0;
73 return fAbleToUseSDFT &&
74 paint.getMaskFilter() == nullptr &&
75 (paint.getStyle() == SkPaint::kFill_Style || wideStroke) &&
76 0 < approximateDeviceTextSize &&
77 (fAbleToUsePerspectiveSDFT || !matrix.hasPerspective()) &&
78 (fMinDistanceFieldFontSize <= approximateDeviceTextSize || matrix.hasPerspective()) &&
79 approximateDeviceTextSize <= fMaxDistanceFieldFontSize;
80 }
81
82 std::tuple<SkFont, SkScalar, SDFTMatrixRange>
getSDFFont(const SkFont & font,const SkMatrix & viewMatrix,const SkPoint & textLoc) const83 SDFTControl::getSDFFont(const SkFont& font, const SkMatrix& viewMatrix,
84 const SkPoint& textLoc) const {
85 SkScalar textSize = font.getSize();
86 SkScalar scaledTextSize = SkFontPriv::ApproximateTransformedTextSize(font, viewMatrix, textLoc);
87 if (scaledTextSize <= 0 || SkScalarNearlyEqual(textSize, scaledTextSize)) {
88 scaledTextSize = textSize;
89 }
90
91 SkFont dfFont{font};
92
93 SkScalar dfMaskScaleFloor;
94 SkScalar dfMaskScaleCeil;
95 SkScalar dfMaskSize;
96 if (scaledTextSize <= kSmallDFFontLimit) {
97 dfMaskScaleFloor = fMinDistanceFieldFontSize;
98 dfMaskScaleCeil = kSmallDFFontLimit;
99 dfMaskSize = kSmallDFFontLimit;
100 } else if (scaledTextSize <= kMediumDFFontLimit) {
101 dfMaskScaleFloor = kSmallDFFontLimit;
102 dfMaskScaleCeil = kMediumDFFontLimit;
103 dfMaskSize = kMediumDFFontLimit;
104 #ifdef SK_BUILD_FOR_MAC
105 } else if (scaledTextSize <= kLargeDFFontLimit) {
106 dfMaskScaleFloor = kMediumDFFontLimit;
107 dfMaskScaleCeil = kLargeDFFontLimit;
108 dfMaskSize = kLargeDFFontLimit;
109 } else {
110 dfMaskScaleFloor = kLargeDFFontLimit;
111 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
112 dfMaskSize = kExtraLargeDFFontLimit;
113 }
114 #else
115 } else {
116 dfMaskScaleFloor = kMediumDFFontLimit;
117 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
118 dfMaskSize = kLargeDFFontLimit;
119 }
120 #endif
121
122 dfFont.setSize(dfMaskSize);
123 dfFont.setEdging(SkFont::Edging::kAntiAlias);
124 dfFont.setForceAutoHinting(false);
125 dfFont.setHinting(SkFontHinting::kNormal);
126
127 // The sub-pixel position will always happen when transforming to the screen.
128 dfFont.setSubpixel(false);
129
130 SkScalar minMatrixScale = dfMaskScaleFloor / textSize,
131 maxMatrixScale = dfMaskScaleCeil / textSize;
132 return {dfFont, textSize / dfMaskSize, {minMatrixScale, maxMatrixScale}};
133 }
134
matrixInRange(const SkMatrix & matrix) const135 bool SDFTMatrixRange::matrixInRange(const SkMatrix& matrix) const {
136 SkScalar maxScale = matrix.getMaxScale();
137 return fMatrixMin < maxScale && maxScale <= fMatrixMax;
138 }
139
flatten(SkWriteBuffer & buffer) const140 void SDFTMatrixRange::flatten(SkWriteBuffer& buffer) const {
141 buffer.writeScalar(fMatrixMin);
142 buffer.writeScalar(fMatrixMax);
143 }
144
MakeFromBuffer(SkReadBuffer & buffer)145 SDFTMatrixRange SDFTMatrixRange::MakeFromBuffer(SkReadBuffer& buffer) {
146 SkScalar min = buffer.readScalar();
147 SkScalar max = buffer.readScalar();
148 return SDFTMatrixRange{min, max};
149 }
150 #endif // !defined(SK_DISABLE_SDF_TEXT)
151
152 } // namespace sktext::gpu
153