xref: /aosp_15_r20/frameworks/base/libs/hwui/hwui/MinikinUtils.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "MinikinUtils.h"
18 
19 #include <log/log.h>
20 #include <minikin/FamilyVariant.h>
21 #include <minikin/MeasuredText.h>
22 #include <minikin/Measurement.h>
23 
24 #include <optional>
25 #include <string>
26 
27 #include "FeatureFlags.h"
28 #include "Paint.h"
29 #include "SkPathMeasure.h"
30 #include "Typeface.h"
31 
32 namespace android {
33 
prepareMinikinPaint(const Paint * paint,const Typeface * typeface)34 minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint,
35                                                         const Typeface* typeface) {
36     const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
37     const SkFont& font = paint->getSkFont();
38 
39     minikin::MinikinPaint minikinPaint(resolvedFace->fFontCollection);
40     /* Prepare minikin Paint */
41     minikinPaint.size =
42             font.isLinearMetrics() ? font.getSize() : static_cast<int>(font.getSize());
43     minikinPaint.scaleX = font.getScaleX();
44     minikinPaint.skewX = font.getSkewX();
45     minikinPaint.letterSpacing = paint->getLetterSpacing();
46     minikinPaint.wordSpacing = paint->getWordSpacing();
47     minikinPaint.fontFlags = MinikinFontSkia::packFontFlags(font);
48     minikinPaint.localeListId = paint->getMinikinLocaleListId();
49     minikinPaint.fontStyle = resolvedFace->fStyle;
50     minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
51     if (!resolvedFace->fIsVariationInstance) {
52         // This is an optimization for direct private API use typically done by System UI.
53         // In the public API surface, if Typeface is already configured for variation instance
54         // (Target SDK <= 35) the font variation settings of Paint is not set.
55         // On the other hand, if Typeface is not configured so (Target SDK >= 36), the font
56         // variation settings are configured dynamically.
57         minikinPaint.fontVariationSettings = paint->getFontVariationOverride();
58     }
59     minikinPaint.verticalText = paint->isVerticalText();
60 
61     const std::optional<minikin::FamilyVariant>& familyVariant = paint->getFamilyVariant();
62     if (familyVariant.has_value()) {
63         minikinPaint.familyVariant = familyVariant.value();
64     } else {
65         minikinPaint.familyVariant = minikin::FamilyVariant::ELEGANT;
66     }
67     return minikinPaint;
68 }
69 
doLayout(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t bufSize,size_t start,size_t count,size_t contextStart,size_t contextCount,minikin::MeasuredText * mt)70 minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
71                                        const Typeface* typeface, const uint16_t* buf,
72                                        size_t bufSize, size_t start, size_t count,
73                                        size_t contextStart, size_t contextCount,
74                                        minikin::MeasuredText* mt) {
75     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
76 
77     const minikin::U16StringPiece textBuf(buf, bufSize);
78     const minikin::Range range(start, start + count);
79     const minikin::Range contextRange(contextStart, contextStart + contextCount);
80     const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
81     const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
82     const minikin::RunFlag minikinRunFlag = text_feature::letter_spacing_justification()
83                                                     ? paint->getRunFlag()
84                                                     : minikin::RunFlag::NONE;
85 
86     if (mt == nullptr) {
87         return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags,
88                                minikinPaint, startHyphen, endHyphen, minikinRunFlag);
89     } else {
90         return mt->buildLayout(textBuf, range, contextRange, minikinPaint, startHyphen, endHyphen);
91     }
92 }
93 
getBounds(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t bufSize,minikin::MinikinRect * out)94 void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
95                              const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out) {
96     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
97 
98     const minikin::U16StringPiece textBuf(buf, bufSize);
99     const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
100     const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
101 
102     minikin::getBounds(textBuf, minikin::Range(0, textBuf.size()), bidiFlags, minikinPaint,
103         startHyphen, endHyphen, out);
104 }
105 
measureText(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t start,size_t count,size_t bufSize,float * advances,minikin::MinikinRect * bounds,uint32_t * clusterCount)106 float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
107                                 const Typeface* typeface, const uint16_t* buf, size_t start,
108                                 size_t count, size_t bufSize, float* advances,
109                                 minikin::MinikinRect* bounds, uint32_t* clusterCount) {
110     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
111     const minikin::U16StringPiece textBuf(buf, bufSize);
112     const minikin::Range range(start, start + count);
113     const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
114     const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
115     const minikin::RunFlag minikinRunFlag = text_feature::letter_spacing_justification()
116                                                     ? paint->getRunFlag()
117                                                     : minikin::RunFlag::NONE;
118 
119     return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
120                                         endHyphen, advances, bounds, clusterCount, minikinRunFlag);
121 }
122 
getFontExtent(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t start,size_t count,size_t bufSize)123 minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
124                                                    const Typeface* typeface, const uint16_t* buf,
125                                                    size_t start, size_t count, size_t bufSize) {
126     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
127     const minikin::U16StringPiece textBuf(buf, bufSize);
128     const minikin::Range range(start, start + count);
129 
130     return minikin::getFontExtent(textBuf, range, bidiFlags, minikinPaint);
131 }
132 
hasVariationSelector(const Typeface * typeface,uint32_t codepoint,uint32_t vs)133 bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
134     const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
135     return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
136 }
137 
xOffsetForTextAlign(Paint * paint,const minikin::Layout & layout)138 float MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout) {
139     switch (paint->getTextAlign()) {
140         case Paint::kCenter_Align:
141             return layout.getAdvance() * -0.5f;
142             break;
143         case Paint::kRight_Align:
144             return -layout.getAdvance();
145             break;
146         default:
147             break;
148     }
149     return 0;
150 }
151 
hOffsetForTextAlign(Paint * paint,const minikin::Layout & layout,const SkPath & path)152 float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
153                                         const SkPath& path) {
154     float align = 0;
155     switch (paint->getTextAlign()) {
156         case Paint::kCenter_Align:
157             align = -0.5f;
158             break;
159         case Paint::kRight_Align:
160             align = -1;
161             break;
162         default:
163             return 0;
164     }
165     SkPathMeasure measure(path, false);
166     return align * (layout.getAdvance() - measure.getLength());
167 }
168 }  // namespace android
169