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/SubRunControl.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 SubRunControl::MinSDFTRange(bool useSDFTForSmallText, SkScalar min) {
38 if (!useSDFTForSmallText) {
39 return kLargeDFFontLimit;
40 }
41 return min;
42 }
43
SubRunControl(bool ableToUseSDFT,bool useSDFTForSmallText,bool useSDFTForPerspectiveText,SkScalar min,SkScalar max,bool forcePathAA)44 SubRunControl::SubRunControl(
45 bool ableToUseSDFT, bool useSDFTForSmallText, bool useSDFTForPerspectiveText,
46 SkScalar min, SkScalar max,
47 bool forcePathAA)
48 : fMinDistanceFieldFontSize{MinSDFTRange(useSDFTForSmallText, min)}
49 , fMaxDistanceFieldFontSize{max}
50 , fAbleToUseSDFT{ableToUseSDFT}
51 , fAbleToUsePerspectiveSDFT{useSDFTForPerspectiveText}
52 , fForcePathAA{forcePathAA} {
53 SkASSERT_RELEASE(0 < min && min <= max);
54 }
55 #endif // !defined(SK_DISABLE_SDF_TEXT)
56
isDirect(SkScalar approximateDeviceTextSize,const SkPaint & paint,const SkMatrix & matrix) const57 bool SubRunControl::isDirect(SkScalar approximateDeviceTextSize, const SkPaint& paint,
58 const SkMatrix& matrix) const {
59 #if !defined(SK_DISABLE_SDF_TEXT)
60 const bool isSDFT = this->isSDFT(approximateDeviceTextSize, paint, matrix);
61 #else
62 const bool isSDFT = false;
63 #endif
64 return !isSDFT &&
65 !matrix.hasPerspective() &&
66 0 < approximateDeviceTextSize &&
67 approximateDeviceTextSize < SkGlyphDigest::kSkSideTooBigForAtlas;
68 }
69
70 #if !defined(SK_DISABLE_SDF_TEXT)
isSDFT(SkScalar approximateDeviceTextSize,const SkPaint & paint,const SkMatrix & matrix) const71 bool SubRunControl::isSDFT(SkScalar approximateDeviceTextSize, const SkPaint& paint,
72 const SkMatrix& matrix) const {
73 const bool wideStroke = paint.getStyle() == SkPaint::kStroke_Style &&
74 paint.getStrokeWidth() > 0;
75 return fAbleToUseSDFT &&
76 paint.getMaskFilter() == nullptr &&
77 (paint.getStyle() == SkPaint::kFill_Style || wideStroke) &&
78 0 < approximateDeviceTextSize &&
79 (fAbleToUsePerspectiveSDFT || !matrix.hasPerspective()) &&
80 (fMinDistanceFieldFontSize <= approximateDeviceTextSize || matrix.hasPerspective()) &&
81 approximateDeviceTextSize <= fMaxDistanceFieldFontSize;
82 }
83
84 std::tuple<SkFont, SkScalar, SDFTMatrixRange>
getSDFFont(const SkFont & font,const SkMatrix & viewMatrix,const SkPoint & textLoc) const85 SubRunControl::getSDFFont(const SkFont& font, const SkMatrix& viewMatrix,
86 const SkPoint& textLoc) const {
87 SkScalar textSize = font.getSize();
88 SkScalar scaledTextSize = SkFontPriv::ApproximateTransformedTextSize(font, viewMatrix, textLoc);
89 if (scaledTextSize <= 0 || SkScalarNearlyEqual(textSize, scaledTextSize)) {
90 scaledTextSize = textSize;
91 }
92
93 SkFont dfFont{font};
94
95 SkScalar dfMaskScaleFloor;
96 SkScalar dfMaskScaleCeil;
97 SkScalar dfMaskSize;
98 if (scaledTextSize <= kSmallDFFontLimit) {
99 dfMaskScaleFloor = fMinDistanceFieldFontSize;
100 dfMaskScaleCeil = kSmallDFFontLimit;
101 dfMaskSize = kSmallDFFontLimit;
102 } else if (scaledTextSize <= kMediumDFFontLimit) {
103 dfMaskScaleFloor = kSmallDFFontLimit;
104 dfMaskScaleCeil = kMediumDFFontLimit;
105 dfMaskSize = kMediumDFFontLimit;
106 #ifdef SK_BUILD_FOR_MAC
107 } else if (scaledTextSize <= kLargeDFFontLimit) {
108 dfMaskScaleFloor = kMediumDFFontLimit;
109 dfMaskScaleCeil = kLargeDFFontLimit;
110 dfMaskSize = kLargeDFFontLimit;
111 } else {
112 dfMaskScaleFloor = kLargeDFFontLimit;
113 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
114 dfMaskSize = kExtraLargeDFFontLimit;
115 }
116 #else
117 } else {
118 dfMaskScaleFloor = kMediumDFFontLimit;
119 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
120 dfMaskSize = kLargeDFFontLimit;
121 }
122 #endif
123
124 dfFont.setSize(dfMaskSize);
125 dfFont.setEdging(SkFont::Edging::kAntiAlias);
126 dfFont.setForceAutoHinting(false);
127 dfFont.setHinting(SkFontHinting::kNormal);
128
129 // The sub-pixel position will always happen when transforming to the screen.
130 dfFont.setSubpixel(false);
131
132 SkScalar minMatrixScale = dfMaskScaleFloor / textSize,
133 maxMatrixScale = dfMaskScaleCeil / textSize;
134 return {dfFont, textSize / dfMaskSize, {minMatrixScale, maxMatrixScale}};
135 }
136
matrixInRange(const SkMatrix & matrix) const137 bool SDFTMatrixRange::matrixInRange(const SkMatrix& matrix) const {
138 SkScalar maxScale = matrix.getMaxScale();
139 return fMatrixMin < maxScale && maxScale <= fMatrixMax;
140 }
141
flatten(SkWriteBuffer & buffer) const142 void SDFTMatrixRange::flatten(SkWriteBuffer& buffer) const {
143 buffer.writeScalar(fMatrixMin);
144 buffer.writeScalar(fMatrixMax);
145 }
146
MakeFromBuffer(SkReadBuffer & buffer)147 SDFTMatrixRange SDFTMatrixRange::MakeFromBuffer(SkReadBuffer& buffer) {
148 SkScalar min = buffer.readScalar();
149 SkScalar max = buffer.readScalar();
150 return SDFTMatrixRange{min, max};
151 }
152 #endif // !defined(SK_DISABLE_SDF_TEXT)
153
154 } // namespace sktext::gpu
155