1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/text/GrSDFTControl.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
11cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h"
12cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
13cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
14cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
15cb93a386Sopenharmony_ci#include "include/core/SkSurfaceProps.h"
16cb93a386Sopenharmony_ci#include "src/core/SkGlyphRunPainter.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci#include <tuple>
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci// DF sizes and thresholds for usage of the small and medium sizes. For example, above
21cb93a386Sopenharmony_ci// kSmallDFFontLimit we will use the medium size. The large size is used up until the size at
22cb93a386Sopenharmony_ci// which we switch over to drawing as paths as controlled by Control.
23cb93a386Sopenharmony_cistatic const int kSmallDFFontSize = 32;
24cb93a386Sopenharmony_cistatic const int kSmallDFFontLimit = 32;
25cb93a386Sopenharmony_cistatic const int kMediumDFFontSize = 72;
26cb93a386Sopenharmony_cistatic const int kMediumDFFontLimit = 72;
27cb93a386Sopenharmony_cistatic const int kLargeDFFontSize = 162;
28cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
29cb93a386Sopenharmony_cistatic const int kLargeDFFontLimit = 162;
30cb93a386Sopenharmony_cistatic const int kExtraLargeDFFontSize = 256;
31cb93a386Sopenharmony_ci#endif
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ciSkScalar GrSDFTControl::MinSDFTRange(bool useSDFTForSmallText, SkScalar min) {
34cb93a386Sopenharmony_ci    if (!useSDFTForSmallText) {
35cb93a386Sopenharmony_ci        return kLargeDFFontSize;
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci    return min;
38cb93a386Sopenharmony_ci}
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ciGrSDFTControl::GrSDFTControl(
41cb93a386Sopenharmony_ci        bool ableToUseSDFT, bool useSDFTForSmallText, SkScalar min, SkScalar max)
42cb93a386Sopenharmony_ci        : fMinDistanceFieldFontSize{MinSDFTRange(useSDFTForSmallText, min)}
43cb93a386Sopenharmony_ci        , fMaxDistanceFieldFontSize{max}
44cb93a386Sopenharmony_ci        , fAbleToUseSDFT{ableToUseSDFT} {
45cb93a386Sopenharmony_ci    SkASSERT_RELEASE(0 < min && min <= max);
46cb93a386Sopenharmony_ci}
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ciauto GrSDFTControl::drawingType(
49cb93a386Sopenharmony_ci        const SkFont& font, const SkPaint& paint, const SkMatrix& viewMatrix) const -> DrawingType {
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci    // Use paths as the first choice for hairlines and perspective.
52cb93a386Sopenharmony_ci    if ((paint.getStyle() == SkPaint::kStroke_Style && paint.getStrokeWidth() == 0)
53cb93a386Sopenharmony_ci            || viewMatrix.hasPerspective()) {
54cb93a386Sopenharmony_ci        return kPath;
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci    SkScalar maxScale = viewMatrix.getMaxScale();
58cb93a386Sopenharmony_ci    SkScalar scaledTextSize = maxScale * font.getSize();
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    // If we can't use SDFT, then make a simple choice between direct or path.
61cb93a386Sopenharmony_ci    if (!fAbleToUseSDFT || paint.getMaskFilter() || paint.getStyle() != SkPaint::kFill_Style) {
62cb93a386Sopenharmony_ci        constexpr int kAboveIsPath = SkStrikeCommon::kSkSideTooBigForAtlas;
63cb93a386Sopenharmony_ci        return scaledTextSize < kAboveIsPath ? kDirect : kPath;
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    // Hinted text looks far better at small resolutions
67cb93a386Sopenharmony_ci    // Scaling up beyond 2x yields undesirable artifacts
68cb93a386Sopenharmony_ci#ifdef SKIA_OHOS_FOR_OHOS_TRACE
69cb93a386Sopenharmony_ci    if (scaledTextSize <= fMaxDistanceFieldFontSize) {
70cb93a386Sopenharmony_ci#else
71cb93a386Sopenharmony_ci    if (scaledTextSize < fMinDistanceFieldFontSize) {
72cb93a386Sopenharmony_ci#endif
73cb93a386Sopenharmony_ci        return kDirect;
74cb93a386Sopenharmony_ci    } else if (fMaxDistanceFieldFontSize < scaledTextSize) {
75cb93a386Sopenharmony_ci        return kPath;
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    return kSDFT;
79cb93a386Sopenharmony_ci}
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ciSkScalar scaled_text_size(const SkScalar textSize, const SkMatrix& viewMatrix) {
82cb93a386Sopenharmony_ci    SkScalar scaledTextSize = textSize;
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci    if (viewMatrix.hasPerspective()) {
85cb93a386Sopenharmony_ci        // for perspective, we simply force to the medium size
86cb93a386Sopenharmony_ci        // TODO: compute a size based on approximate screen area
87cb93a386Sopenharmony_ci        scaledTextSize = kMediumDFFontLimit;
88cb93a386Sopenharmony_ci    } else {
89cb93a386Sopenharmony_ci        SkScalar maxScale = viewMatrix.getMaxScale();
90cb93a386Sopenharmony_ci        // if we have non-unity scale, we need to choose our base text size
91cb93a386Sopenharmony_ci        // based on the SkPaint's text size multiplied by the max scale factor
92cb93a386Sopenharmony_ci        // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
93cb93a386Sopenharmony_ci        if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
94cb93a386Sopenharmony_ci            scaledTextSize *= maxScale;
95cb93a386Sopenharmony_ci        }
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    return scaledTextSize;
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ciSkFont GrSDFTControl::getSDFFont(const SkFont& font,
102cb93a386Sopenharmony_ci                                 const SkMatrix& viewMatrix,
103cb93a386Sopenharmony_ci                                 SkScalar* textRatio) const {
104cb93a386Sopenharmony_ci    SkScalar textSize = font.getSize();
105cb93a386Sopenharmony_ci    SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix);
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci    SkFont dfFont{font};
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci    if (scaledTextSize <= kSmallDFFontLimit) {
110cb93a386Sopenharmony_ci        *textRatio = textSize / kSmallDFFontSize;
111cb93a386Sopenharmony_ci        dfFont.setSize(SkIntToScalar(kSmallDFFontSize));
112cb93a386Sopenharmony_ci    } else if (scaledTextSize <= kMediumDFFontLimit) {
113cb93a386Sopenharmony_ci        *textRatio = textSize / kMediumDFFontSize;
114cb93a386Sopenharmony_ci        dfFont.setSize(SkIntToScalar(kMediumDFFontSize));
115cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
116cb93a386Sopenharmony_ci    } else if (scaledTextSize <= kLargeDFFontLimit) {
117cb93a386Sopenharmony_ci        *textRatio = textSize / kLargeDFFontSize;
118cb93a386Sopenharmony_ci        dfFont.setSize(SkIntToScalar(kLargeDFFontSize));
119cb93a386Sopenharmony_ci    } else {
120cb93a386Sopenharmony_ci        *textRatio = textSize / kExtraLargeDFFontSize;
121cb93a386Sopenharmony_ci        dfFont.setSize(SkIntToScalar(kExtraLargeDFFontSize));
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci#else
124cb93a386Sopenharmony_ci    } else {
125cb93a386Sopenharmony_ci        *textRatio = textSize / kLargeDFFontSize;
126cb93a386Sopenharmony_ci        dfFont.setSize(SkIntToScalar(kLargeDFFontSize));
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci#endif
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    dfFont.setEdging(SkFont::Edging::kAntiAlias);
131cb93a386Sopenharmony_ci    dfFont.setForceAutoHinting(false);
132cb93a386Sopenharmony_ci    dfFont.setHinting(SkFontHinting::kNormal);
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    // The sub-pixel position will always happen when transforming to the screen.
135cb93a386Sopenharmony_ci    dfFont.setSubpixel(false);
136cb93a386Sopenharmony_ci    return dfFont;
137cb93a386Sopenharmony_ci}
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_cistd::pair<SkScalar, SkScalar> GrSDFTControl::computeSDFMinMaxScale(
140cb93a386Sopenharmony_ci        SkScalar textSize, const SkMatrix& viewMatrix) const {
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci    SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix);
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci    // We have three sizes of distance field text, and within each size 'bucket' there is a floor
145cb93a386Sopenharmony_ci    // and ceiling.  A scale outside of this range would require regenerating the distance fields
146cb93a386Sopenharmony_ci    SkScalar dfMaskScaleFloor;
147cb93a386Sopenharmony_ci    SkScalar dfMaskScaleCeil;
148cb93a386Sopenharmony_ci    if (scaledTextSize <= kSmallDFFontLimit) {
149cb93a386Sopenharmony_ci        dfMaskScaleFloor = fMinDistanceFieldFontSize;
150cb93a386Sopenharmony_ci        dfMaskScaleCeil = kSmallDFFontLimit;
151cb93a386Sopenharmony_ci    } else if (scaledTextSize <= kMediumDFFontLimit) {
152cb93a386Sopenharmony_ci        dfMaskScaleFloor = kSmallDFFontLimit;
153cb93a386Sopenharmony_ci        dfMaskScaleCeil = kMediumDFFontLimit;
154cb93a386Sopenharmony_ci    } else {
155cb93a386Sopenharmony_ci        dfMaskScaleFloor = kMediumDFFontLimit;
156cb93a386Sopenharmony_ci        dfMaskScaleCeil = fMaxDistanceFieldFontSize;
157cb93a386Sopenharmony_ci    }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    // Because there can be multiple runs in the blob, we want the overall maxMinScale, and
160cb93a386Sopenharmony_ci    // minMaxScale to make regeneration decisions.  Specifically, we want the maximum minimum scale
161cb93a386Sopenharmony_ci    // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can
162cb93a386Sopenharmony_ci    // tolerate before we'd have to move to a large mip size.  When we actually test these values
163cb93a386Sopenharmony_ci    // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test
164cb93a386Sopenharmony_ci    // against these values to decide if we can reuse or not(ie, will a given scale change our mip
165cb93a386Sopenharmony_ci    // level)
166cb93a386Sopenharmony_ci    SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ci    return std::make_pair(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
169cb93a386Sopenharmony_ci}
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci
172