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
52 const std::optional<minikin::FamilyVariant>& familyVariant = paint->getFamilyVariant();
53 if (familyVariant.has_value()) {
54 minikinPaint.familyVariant = familyVariant.value();
55 } else {
56 minikinPaint.familyVariant = text_feature::deprecate_ui_fonts()
57 ? minikin::FamilyVariant::ELEGANT
58 : minikin::FamilyVariant::DEFAULT;
59 }
60 return minikinPaint;
61 }
62
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)63 minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
64 const Typeface* typeface, const uint16_t* buf,
65 size_t bufSize, size_t start, size_t count,
66 size_t contextStart, size_t contextCount,
67 minikin::MeasuredText* mt) {
68 minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
69
70 const minikin::U16StringPiece textBuf(buf, bufSize);
71 const minikin::Range range(start, start + count);
72 const minikin::Range contextRange(contextStart, contextStart + contextCount);
73 const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
74 const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
75 const minikin::RunFlag minikinRunFlag = text_feature::letter_spacing_justification()
76 ? paint->getRunFlag()
77 : minikin::RunFlag::NONE;
78
79 if (mt == nullptr) {
80 return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags,
81 minikinPaint, startHyphen, endHyphen, minikinRunFlag);
82 } else {
83 return mt->buildLayout(textBuf, range, contextRange, minikinPaint, startHyphen, endHyphen);
84 }
85 }
86
getBounds(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t bufSize,minikin::MinikinRect * out)87 void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
88 const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out) {
89 minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
90
91 const minikin::U16StringPiece textBuf(buf, bufSize);
92 const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
93 const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
94
95 minikin::getBounds(textBuf, minikin::Range(0, textBuf.size()), bidiFlags, minikinPaint,
96 startHyphen, endHyphen, out);
97 }
98
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)99 float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
100 const Typeface* typeface, const uint16_t* buf, size_t start,
101 size_t count, size_t bufSize, float* advances,
102 minikin::MinikinRect* bounds, uint32_t* clusterCount) {
103 minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
104 const minikin::U16StringPiece textBuf(buf, bufSize);
105 const minikin::Range range(start, start + count);
106 const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
107 const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
108 const minikin::RunFlag minikinRunFlag = text_feature::letter_spacing_justification()
109 ? paint->getRunFlag()
110 : minikin::RunFlag::NONE;
111
112 return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
113 endHyphen, advances, bounds, clusterCount, minikinRunFlag);
114 }
115
getFontExtent(const Paint * paint,minikin::Bidi bidiFlags,const Typeface * typeface,const uint16_t * buf,size_t start,size_t count,size_t bufSize)116 minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
117 const Typeface* typeface, const uint16_t* buf,
118 size_t start, size_t count, size_t bufSize) {
119 minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
120 const minikin::U16StringPiece textBuf(buf, bufSize);
121 const minikin::Range range(start, start + count);
122
123 return minikin::getFontExtent(textBuf, range, bidiFlags, minikinPaint);
124 }
125
hasVariationSelector(const Typeface * typeface,uint32_t codepoint,uint32_t vs)126 bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
127 const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
128 return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
129 }
130
xOffsetForTextAlign(Paint * paint,const minikin::Layout & layout)131 float MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout) {
132 switch (paint->getTextAlign()) {
133 case Paint::kCenter_Align:
134 return layout.getAdvance() * -0.5f;
135 break;
136 case Paint::kRight_Align:
137 return -layout.getAdvance();
138 break;
139 default:
140 break;
141 }
142 return 0;
143 }
144
hOffsetForTextAlign(Paint * paint,const minikin::Layout & layout,const SkPath & path)145 float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
146 const SkPath& path) {
147 float align = 0;
148 switch (paint->getTextAlign()) {
149 case Paint::kCenter_Align:
150 align = -0.5f;
151 break;
152 case Paint::kRight_Align:
153 align = -1;
154 break;
155 default:
156 return 0;
157 }
158 SkPathMeasure measure(path, false);
159 return align * (layout.getAdvance() - measure.getLength());
160 }
161 } // namespace android
162