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