1 // Copyright 2019 Google LLC.
2 #include "include/core/SkColor.h"
3 #include "include/core/SkFontStyle.h"
4 #include "modules/skparagraph/include/TextStyle.h"
5
6 namespace skia {
7 namespace textlayout {
8
9 const std::vector<SkString>* TextStyle::kDefaultFontFamilies =
10 new std::vector<SkString>{SkString(DEFAULT_FONT_FAMILY)};
11
cloneForPlaceholder()12 TextStyle TextStyle::cloneForPlaceholder() {
13 TextStyle result;
14 result.fColor = fColor;
15 result.fFontSize = fFontSize;
16 result.fFontFamilies = fFontFamilies;
17 result.fDecoration = fDecoration;
18 result.fHasBackground = fHasBackground;
19 result.fHasForeground = fHasForeground;
20 result.fBackground = fBackground;
21 result.fForeground = fForeground;
22 result.fHeightOverride = fHeightOverride;
23 result.fIsPlaceholder = true;
24 result.fFontFeatures = fFontFeatures;
25 result.fHalfLeading = fHalfLeading;
26 result.fBaselineShift = fBaselineShift;
27 result.fFontArguments = fFontArguments;
28 result.fBackgroundRect = fBackgroundRect;
29 result.fStyleId = fStyleId;
30 return result;
31 }
32
equals(const TextStyle & other) const33 bool TextStyle::equals(const TextStyle& other) const {
34
35 if (fIsPlaceholder || other.fIsPlaceholder) {
36 return false;
37 }
38
39 if (fColor != other.fColor) {
40 return false;
41 }
42 if (!(fDecoration == other.fDecoration)) {
43 return false;
44 }
45 if (!(fFontStyle == other.fFontStyle)) {
46 return false;
47 }
48 if (fFontFamilies != other.fFontFamilies) {
49 return false;
50 }
51 if (fLetterSpacing != other.fLetterSpacing) {
52 return false;
53 }
54 if (fWordSpacing != other.fWordSpacing) {
55 return false;
56 }
57 if (fHeight != other.fHeight) {
58 return false;
59 }
60 if (fHeightOverride != other.fHeightOverride) {
61 return false;
62 }
63 if (fHalfLeading != other.fHalfLeading) {
64 return false;
65 }
66 if (fBaselineShift != other.fBaselineShift) {
67 return false;
68 }
69 if (fFontSize != other.fFontSize) {
70 return false;
71 }
72 if (fLocale != other.fLocale) {
73 return false;
74 }
75 if (fHasForeground != other.fHasForeground || fForeground != other.fForeground) {
76 return false;
77 }
78 if (fHasBackground != other.fHasBackground || fBackground != other.fBackground) {
79 return false;
80 }
81 if (fTextShadows.size() != other.fTextShadows.size()) {
82 return false;
83 }
84 for (size_t i = 0; i < fTextShadows.size(); ++i) {
85 if (fTextShadows[i] != other.fTextShadows[i]) {
86 return false;
87 }
88 }
89 if (fFontFeatures.size() != other.fFontFeatures.size()) {
90 return false;
91 }
92 for (size_t i = 0; i < fFontFeatures.size(); ++i) {
93 if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
94 return false;
95 }
96 }
97 if (fFontArguments != other.fFontArguments) {
98 return false;
99 }
100
101 return true;
102 }
103
equalsByFonts(const TextStyle & that) const104 bool TextStyle::equalsByFonts(const TextStyle& that) const {
105
106 return !fIsPlaceholder && !that.fIsPlaceholder &&
107 fFontStyle == that.fFontStyle &&
108 fFontFamilies == that.fFontFamilies &&
109 fFontFeatures == that.fFontFeatures &&
110 fFontArguments == that.getFontArguments() &&
111 nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
112 nearlyEqual(fWordSpacing, that.fWordSpacing) &&
113 nearlyEqual(fHeight, that.fHeight) &&
114 nearlyEqual(fBaselineShift, that.fBaselineShift) &&
115 nearlyEqual(fFontSize, that.fFontSize) &&
116 fLocale == that.fLocale;
117 }
118
matchOneAttribute(StyleType styleType,const TextStyle & other) const119 bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
120 switch (styleType) {
121 case kForeground:
122 return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
123 ( fHasForeground && other.fHasForeground && fForeground == other.fForeground);
124
125 case kBackground:
126 return (!fHasBackground && !other.fHasBackground) ||
127 ( fHasBackground && other.fHasBackground && fBackground == other.fBackground);
128
129 case kShadow:
130 if (fTextShadows.size() != other.fTextShadows.size()) {
131 return false;
132 }
133
134 for (int32_t i = 0; i < SkToInt(fTextShadows.size()); ++i) {
135 if (fTextShadows[i] != other.fTextShadows[i]) {
136 return false;
137 }
138 }
139 return true;
140
141 case kDecorations:
142 return this->fDecoration == other.fDecoration;
143
144 case kLetterSpacing:
145 return fLetterSpacing == other.fLetterSpacing;
146
147 case kWordSpacing:
148 return fWordSpacing == other.fWordSpacing;
149
150 case kAllAttributes:
151 return this->equals(other);
152
153 case kFont:
154 // TODO: should not we take typefaces in account?
155 return fFontStyle == other.fFontStyle &&
156 fLocale == other.fLocale &&
157 fFontFamilies == other.fFontFamilies &&
158 fFontSize == other.fFontSize &&
159 fHeight == other.fHeight &&
160 fHalfLeading == other.fHalfLeading &&
161 fBaselineShift == other.fBaselineShift &&
162 fFontArguments == other.fFontArguments;
163 default:
164 SkASSERT(false);
165 return false;
166 }
167 }
168
getFontMetrics(SkFontMetrics * metrics) const169 void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
170 SkFont font(fTypeface, fFontSize);
171 font.setEdging(SkFont::Edging::kAntiAlias);
172 font.setSubpixel(true);
173 font.setHinting(SkFontHinting::kSlight);
174 font.getMetrics(metrics);
175 if (fHeightOverride) {
176 auto multiplier = fHeight * fFontSize;
177 auto height = metrics->fDescent - metrics->fAscent + metrics->fLeading;
178 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2) * multiplier / height;
179 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2) * multiplier / height;
180
181 } else {
182 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
183 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
184 }
185 // If we shift the baseline we need to make sure the shifted text fits the line
186 metrics->fAscent += fBaselineShift;
187 metrics->fDescent += fBaselineShift;
188 }
189
setFontArguments(const std::optional<SkFontArguments> & args)190 void TextStyle::setFontArguments(const std::optional<SkFontArguments>& args) {
191 if (!args) {
192 fFontArguments.reset();
193 return;
194 }
195
196 fFontArguments.emplace(*args);
197 }
198
equals(const PlaceholderStyle & other) const199 bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
200 return nearlyEqual(fWidth, other.fWidth) &&
201 nearlyEqual(fHeight, other.fHeight) &&
202 fAlignment == other.fAlignment &&
203 fBaseline == other.fBaseline &&
204 (fAlignment != PlaceholderAlignment::kBaseline ||
205 nearlyEqual(fBaselineOffset, other.fBaselineOffset));
206 }
207
208 } // namespace textlayout
209 } // namespace skia
210