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 #include "modules/skparagraph/src/Run.h"
6 
7 namespace skia {
8 namespace textlayout {
9 
10 const std::vector<SkString>* TextStyle::kDefaultFontFamilies =
11         new std::vector<SkString>{SkString(DEFAULT_FONT_FAMILY)};
12 
cloneForPlaceholder()13 TextStyle TextStyle::cloneForPlaceholder() {
14     TextStyle result;
15     result.fColor = fColor;
16     result.fFontSize = fFontSize;
17     result.fFontFamilies = fFontFamilies;
18     result.fDecoration = fDecoration;
19     result.fHasBackground = fHasBackground;
20     result.fHasForeground = fHasForeground;
21     result.fBackground = fBackground;
22     result.fForeground = fForeground;
23     result.fHeightOverride = fHeightOverride;
24     result.fIsPlaceholder = true;
25     result.fFontFeatures = fFontFeatures;
26     result.fHalfLeading = fHalfLeading;
27     result.fBaselineShift = fBaselineShift;
28     result.fFontArguments = fFontArguments;
29     result.fBackgroundRect = fBackgroundRect;
30     result.fStyleId = fStyleId;
31     return result;
32 }
33 
equals(const TextStyle& other) const34 bool TextStyle::equals(const TextStyle& other) const {
35 
36     if (fIsPlaceholder || other.fIsPlaceholder) {
37         return false;
38     }
39 
40     if (fColor != other.fColor) {
41         return false;
42     }
43     if (!(fDecoration == other.fDecoration)) {
44         return false;
45     }
46     if (!(fFontStyle == other.fFontStyle)) {
47         return false;
48     }
49     if (fFontFamilies != other.fFontFamilies) {
50         return false;
51     }
52     if (fLetterSpacing != other.fLetterSpacing) {
53         return false;
54     }
55     if (fWordSpacing != other.fWordSpacing) {
56         return false;
57     }
58     if (fHeight != other.fHeight) {
59         return false;
60     }
61     if (fHeightOverride != other.fHeightOverride) {
62         return false;
63     }
64     if (fHalfLeading != other.fHalfLeading) {
65         return false;
66     }
67     if (fBaselineShift != other.fBaselineShift) {
68         return false;
69     }
70     if (fFontSize != other.fFontSize) {
71         return false;
72     }
73     if (fLocale != other.fLocale) {
74         return false;
75     }
76     if (fHasForeground != other.fHasForeground || fForeground != other.fForeground) {
77         return false;
78     }
79     if (fHasBackground != other.fHasBackground || fBackground != other.fBackground) {
80         return false;
81     }
82     if (fTextShadows.size() != other.fTextShadows.size()) {
83         return false;
84     }
85     for (size_t i = 0; i < fTextShadows.size(); ++i) {
86         if (fTextShadows[i] != other.fTextShadows[i]) {
87             return false;
88         }
89     }
90     if (fFontFeatures.size() != other.fFontFeatures.size()) {
91         return false;
92     }
93     for (size_t i = 0; i < fFontFeatures.size(); ++i) {
94         if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
95             return false;
96         }
97     }
98     if (fFontArguments != other.fFontArguments) {
99         return false;
100     }
101     if (fStyleId != other.fStyleId || fBackgroundRect != other.fBackgroundRect) {
102         return false;
103     }
104 
105     return true;
106 }
107 
equalsByFonts(const TextStyle& that) const108 bool TextStyle::equalsByFonts(const TextStyle& that) const {
109 
110     return !fIsPlaceholder && !that.fIsPlaceholder &&
111            fFontStyle == that.fFontStyle &&
112            fFontFamilies == that.fFontFamilies &&
113            fFontFeatures == that.fFontFeatures &&
114            fFontArguments == that.getFontArguments() &&
115            nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
116            nearlyEqual(fWordSpacing, that.fWordSpacing) &&
117            nearlyEqual(fHeight, that.fHeight) &&
118            nearlyEqual(fBaselineShift, that.fBaselineShift) &&
119            nearlyEqual(fFontSize, that.fFontSize) &&
120            fLocale == that.fLocale &&
121            fStyleId == that.fStyleId &&
122            fBackgroundRect == that.fBackgroundRect;
123 }
124 
matchOneAttribute(StyleType styleType, const TextStyle& other) const125 bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
126     switch (styleType) {
127         case kForeground:
128             return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
129                    ( fHasForeground &&  other.fHasForeground && fForeground == other.fForeground);
130 
131         case kBackground:
132             return (!fHasBackground && !other.fHasBackground) ||
133                    ( fHasBackground &&  other.fHasBackground && fBackground == other.fBackground);
134 
135         case kShadow:
136             if (fTextShadows.size() != other.fTextShadows.size()) {
137                 return false;
138             }
139 
140             for (int32_t i = 0; i < SkToInt(fTextShadows.size()); ++i) {
141                 if (fTextShadows[i] != other.fTextShadows[i]) {
142                     return false;
143                 }
144             }
145             return true;
146 
147         case kDecorations:
148             return this->fDecoration == other.fDecoration;
149 
150         case kLetterSpacing:
151             return fLetterSpacing == other.fLetterSpacing;
152 
153         case kWordSpacing:
154             return fWordSpacing == other.fWordSpacing;
155 
156         case kAllAttributes:
157             return this->equals(other);
158 
159         case kFont:
160             // TODO: should not we take typefaces in account?
161             return fFontStyle == other.fFontStyle &&
162                    fLocale == other.fLocale &&
163                    fFontFamilies == other.fFontFamilies &&
164                    fFontSize == other.fFontSize &&
165                    fHeight == other.fHeight &&
166                    fHalfLeading == other.fHalfLeading &&
167                    fBaselineShift == other.fBaselineShift &&
168                    fFontArguments == other.fFontArguments &&
169                    fStyleId == other.fStyleId &&
170                    fBackgroundRect == other.fBackgroundRect;
171         default:
172             SkASSERT(false);
173             return false;
174     }
175 }
176 
177 #ifndef USE_SKIA_TXT
getFontMetrics(SkFontMetrics* metrics) const178 void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
179 #else
180 void TextStyle::getFontMetrics(RSFontMetrics* metrics) const {
181 #endif
182 #ifndef USE_SKIA_TXT
183     SkFont font(fTypeface, fFontSize);
184     font.setEdging(SkFont::Edging::kAntiAlias);
185     font.setSubpixel(true);
186     font.setHinting(SkFontHinting::kSlight);
187 #ifdef OHOS_SUPPORT
188     auto compressFont = font;
189     scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
190     compressFont.getMetrics(metrics);
191     metricsIncludeFontPadding(metrics, font);
192 #else
193     font.getMetrics(metrics);
194 #endif
195 #else
196     RSFont font(fTypeface, fFontSize, 1, 0);
197     font.SetEdging(RSDrawing::FontEdging::ANTI_ALIAS);
198     font.SetHinting(RSDrawing::FontHinting::SLIGHT);
199     font.SetSubpixel(true);
200 #ifdef OHOS_SUPPORT
201     auto compressFont = font;
202     scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
203     compressFont.GetMetrics(metrics);
204     metricsIncludeFontPadding(metrics, font);
205 #else
206     font.GetMetrics(metrics);
207 #endif
208 #endif
209     if (fHeightOverride) {
210         auto multiplier = fHeight * fFontSize;
211         auto height = metrics->fDescent - metrics->fAscent + metrics->fLeading;
212         metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2) * multiplier / height;
213         metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2) * multiplier / height;
214 
215     } else {
216         metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
217         metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
218     }
219     // If we shift the baseline we need to make sure the shifted text fits the line
220     metrics->fAscent += fBaselineShift;
221     metrics->fDescent += fBaselineShift;
222 }
223 
224 void TextStyle::setFontArguments(const std::optional<SkFontArguments>& args) {
225     if (!args) {
226         fFontArguments.reset();
227         return;
228     }
229 
230     fFontArguments.emplace(*args);
231 }
232 
233 bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
234     return nearlyEqual(fWidth, other.fWidth) &&
235            nearlyEqual(fHeight, other.fHeight) &&
236            fAlignment == other.fAlignment &&
237            fBaseline == other.fBaseline &&
238            (fAlignment != PlaceholderAlignment::kBaseline ||
239             nearlyEqual(fBaselineOffset, other.fBaselineOffset));
240 }
241 
242 }  // namespace textlayout
243 }  // namespace skia
244