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/gpu/text/GrSDFTControl.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/SkGlyphRunPainter.h"
17
18 #include <tuple>
19
20 // DF sizes and thresholds for usage of the small and medium sizes. For example, above
21 // kSmallDFFontLimit we will use the medium size. The large size is used up until the size at
22 // which we switch over to drawing as paths as controlled by Control.
23 static const int kSmallDFFontLimit = 32;
24 static const int kMediumDFFontLimit = 72;
25 static const int kLargeDFFontLimit = 162;
26 #ifdef SK_BUILD_FOR_MAC
27 static const int kExtraLargeDFFontLimit = 256;
28 #endif
29
MinSDFTRange(bool useSDFTForSmallText,SkScalar min)30 SkScalar GrSDFTControl::MinSDFTRange(bool useSDFTForSmallText, SkScalar min) {
31 if (!useSDFTForSmallText) {
32 return kLargeDFFontLimit;
33 }
34 return min;
35 }
36
GrSDFTControl(bool ableToUseSDFT,bool useSDFTForSmallText,SkScalar min,SkScalar max)37 GrSDFTControl::GrSDFTControl(
38 bool ableToUseSDFT, bool useSDFTForSmallText, SkScalar min, SkScalar max)
39 : fMinDistanceFieldFontSize{MinSDFTRange(useSDFTForSmallText, min)}
40 , fMaxDistanceFieldFontSize{max}
41 , fAbleToUseSDFT{ableToUseSDFT} {
42 SkASSERT_RELEASE(0 < min && min <= max);
43 }
44
isDirect(SkScalar approximateDeviceTextSize,const SkPaint & paint) const45 bool GrSDFTControl::isDirect(SkScalar approximateDeviceTextSize, const SkPaint& paint) const {
46 return !isSDFT(approximateDeviceTextSize, paint) &&
47 approximateDeviceTextSize < SkStrikeCommon::kSkSideTooBigForAtlas;
48 }
49
isSDFT(SkScalar approximateDeviceTextSize,const SkPaint & paint) const50 bool GrSDFTControl::isSDFT(SkScalar approximateDeviceTextSize, const SkPaint& paint) const {
51 return fAbleToUseSDFT &&
52 paint.getMaskFilter() == nullptr &&
53 paint.getStyle() == SkPaint::kFill_Style &&
54 fMinDistanceFieldFontSize <= approximateDeviceTextSize &&
55 approximateDeviceTextSize <= fMaxDistanceFieldFontSize;
56 }
57
scaled_text_size(const SkScalar textSize,const SkMatrix & viewMatrix)58 SkScalar scaled_text_size(const SkScalar textSize, const SkMatrix& viewMatrix) {
59 SkScalar scaledTextSize = textSize;
60
61 if (viewMatrix.hasPerspective()) {
62 // for perspective, we simply force to the medium size
63 // TODO: compute a size based on approximate screen area
64 scaledTextSize = kMediumDFFontLimit;
65 } else {
66 SkScalar maxScale = viewMatrix.getMaxScale();
67 // if we have non-unity scale, we need to choose our base text size
68 // based on the SkPaint's text size multiplied by the max scale factor
69 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
70 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
71 scaledTextSize *= maxScale;
72 }
73 }
74
75 return scaledTextSize;
76 }
77
78 std::tuple<SkFont, SkScalar, GrSDFTMatrixRange>
getSDFFont(const SkFont & font,const SkMatrix & viewMatrix) const79 GrSDFTControl::getSDFFont(const SkFont& font, const SkMatrix& viewMatrix) const {
80 SkScalar textSize = font.getSize();
81 SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix);
82
83 SkFont dfFont{font};
84
85 SkScalar dfMaskScaleFloor;
86 SkScalar dfMaskScaleCeil;
87 if (scaledTextSize <= kSmallDFFontLimit) {
88 dfMaskScaleFloor = fMinDistanceFieldFontSize;
89 dfMaskScaleCeil = kSmallDFFontLimit;
90 } else if (scaledTextSize <= kMediumDFFontLimit) {
91 dfMaskScaleFloor = kSmallDFFontLimit;
92 dfMaskScaleCeil = kMediumDFFontLimit;
93 #ifdef SK_BUILD_FOR_MAC
94 } else if (scaledTextSize <= kLargeDFFontLimit) {
95 dfMaskScaleFloor = kMediumDFFontLimit;
96 dfMaskScaleCeil = kLargeDFFontLimit;
97 } else {
98 dfMaskScaleFloor = kLargeDFFontLimit;
99 dfMaskScaleCeil = kExtraLargeDFFontLimit;
100 }
101 #else
102 } else {
103 dfMaskScaleFloor = kMediumDFFontLimit;
104 dfMaskScaleCeil = kLargeDFFontLimit;
105 }
106 #endif
107
108 dfFont.setSize(SkIntToScalar(dfMaskScaleCeil));
109 dfFont.setEdging(SkFont::Edging::kAntiAlias);
110 dfFont.setForceAutoHinting(false);
111 dfFont.setHinting(SkFontHinting::kNormal);
112
113 // The sub-pixel position will always happen when transforming to the screen.
114 dfFont.setSubpixel(false);
115
116 SkScalar minMatrixScale = dfMaskScaleFloor / textSize,
117 maxMatrixScale = dfMaskScaleCeil / textSize;
118 return {dfFont, textSize / dfMaskScaleCeil, {minMatrixScale, maxMatrixScale}};
119 }
120
matrixInRange(const SkMatrix & matrix) const121 bool GrSDFTMatrixRange::matrixInRange(const SkMatrix& matrix) const {
122 SkScalar maxScale = matrix.getMaxScale();
123 return fMatrixMin < maxScale && maxScale <= fMatrixMax;
124 }
125