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 = { SkString(DEFAULT_FONT_FAMILY) };
10
TextStyle(const TextStyle & other,bool placeholder)11 TextStyle::TextStyle(const TextStyle& other, bool placeholder) {
12 fColor = other.fColor;
13 fFontSize = other.fFontSize;
14 fFontFamilies = other.fFontFamilies;
15 fDecoration = other.fDecoration;
16 fHasBackground = other.fHasBackground;
17 fHasForeground = other.fHasForeground;
18 fBackground = other.fBackground;
19 fForeground = other.fForeground;
20 fHeightOverride = other.fHeightOverride;
21 fIsPlaceholder = placeholder;
22 fFontFeatures = other.fFontFeatures;
23 fHalfLeading = other.fHalfLeading;
24 }
25
equals(const TextStyle & other) const26 bool TextStyle::equals(const TextStyle& other) const {
27
28 if (fIsPlaceholder || other.fIsPlaceholder) {
29 return false;
30 }
31
32 if (fColor != other.fColor) {
33 return false;
34 }
35 if (!(fDecoration == other.fDecoration)) {
36 return false;
37 }
38 if (!(fFontStyle == other.fFontStyle)) {
39 return false;
40 }
41 if (fFontFamilies != other.fFontFamilies) {
42 return false;
43 }
44 if (fLetterSpacing != other.fLetterSpacing) {
45 return false;
46 }
47 if (fWordSpacing != other.fWordSpacing) {
48 return false;
49 }
50 if (fHeight != other.fHeight) {
51 return false;
52 }
53 if (fHalfLeading != other.fHalfLeading) {
54 return false;
55 }
56 if (fFontSize != other.fFontSize) {
57 return false;
58 }
59 if (fLocale != other.fLocale) {
60 return false;
61 }
62 if (fHasForeground != other.fHasForeground || fForeground != other.fForeground) {
63 return false;
64 }
65 if (fHasBackground != other.fHasBackground || fBackground != other.fBackground) {
66 return false;
67 }
68 if (fTextShadows.size() != other.fTextShadows.size()) {
69 return false;
70 }
71 for (size_t i = 0; i < fTextShadows.size(); ++i) {
72 if (fTextShadows[i] != other.fTextShadows[i]) {
73 return false;
74 }
75 }
76 if (fFontFeatures.size() != other.fFontFeatures.size()) {
77 return false;
78 }
79 for (size_t i = 0; i < fFontFeatures.size(); ++i) {
80 if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
81 return false;
82 }
83 }
84
85 return true;
86 }
87
equalsByFonts(const TextStyle & that) const88 bool TextStyle::equalsByFonts(const TextStyle& that) const {
89
90 return !fIsPlaceholder && !that.fIsPlaceholder &&
91 fFontStyle == that.fFontStyle &&
92 fFontFamilies == that.fFontFamilies &&
93 fFontFeatures == that.fFontFeatures &&
94 nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
95 nearlyEqual(fWordSpacing, that.fWordSpacing) &&
96 nearlyEqual(fHeight, that.fHeight) &&
97 nearlyEqual(fFontSize, that.fFontSize) &&
98 fLocale == that.fLocale;
99 }
100
matchOneAttribute(StyleType styleType,const TextStyle & other) const101 bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
102 switch (styleType) {
103 case kForeground:
104 return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
105 ( fHasForeground && other.fHasForeground && fForeground == other.fForeground);
106
107 case kBackground:
108 return (!fHasBackground && !other.fHasBackground) ||
109 ( fHasBackground && other.fHasBackground && fBackground == other.fBackground);
110
111 case kShadow:
112 if (fTextShadows.size() != other.fTextShadows.size()) {
113 return false;
114 }
115
116 for (int32_t i = 0; i < SkToInt(fTextShadows.size()); ++i) {
117 if (fTextShadows[i] != other.fTextShadows[i]) {
118 return false;
119 }
120 }
121 return true;
122
123 case kDecorations:
124 return this->fDecoration == other.fDecoration;
125
126 case kLetterSpacing:
127 return fLetterSpacing == other.fLetterSpacing;
128
129 case kWordSpacing:
130 return fWordSpacing == other.fWordSpacing;
131
132 case kAllAttributes:
133 return this->equals(other);
134
135 case kFont:
136 // TODO: should not we take typefaces in account?
137 return fFontStyle == other.fFontStyle &&
138 fLocale == other.fLocale &&
139 fFontFamilies == other.fFontFamilies &&
140 fFontSize == other.fFontSize &&
141 fHeight == other.fHeight &&
142 fHalfLeading == other.fHalfLeading;
143 default:
144 SkASSERT(false);
145 return false;
146 }
147 }
148
getFontMetrics(SkFontMetrics * metrics) const149 void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
150 SkFont font(fTypeface, fFontSize);
151 font.setEdging(SkFont::Edging::kAntiAlias);
152 font.setSubpixel(true);
153 font.setHinting(SkFontHinting::kSlight);
154 font.getMetrics(metrics);
155 if (fHeightOverride) {
156 auto multiplier = fHeight * fFontSize;
157 auto height = metrics->fDescent - metrics->fAscent + metrics->fLeading;
158 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2) * multiplier / height;
159 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2) * multiplier / height;
160
161 } else {
162 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
163 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
164 }
165 }
166
equals(const PlaceholderStyle & other) const167 bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
168 return nearlyEqual(fWidth, other.fWidth) &&
169 nearlyEqual(fHeight, other.fHeight) &&
170 fAlignment == other.fAlignment &&
171 fBaseline == other.fBaseline &&
172 (fAlignment != PlaceholderAlignment::kBaseline ||
173 nearlyEqual(fBaselineOffset, other.fBaselineOffset));
174 }
175
176 } // namespace textlayout
177 } // namespace skia
178