OLD | NEW |
| (Empty) |
1 /* libs/graphics/views/SkTextBox.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkTextBox.h" | |
19 #include "SkGlyphCache.h" | |
20 #include "SkUtils.h" | |
21 #include "SkAutoKern.h" | |
22 | |
23 static inline int is_ws(int c) | |
24 { | |
25 return !((c - 1) >> 5); | |
26 } | |
27 | |
28 static size_t linebreak(const char text[], const char stop[], const SkPaint& pai
nt, SkScalar margin) | |
29 { | |
30 const char* start = text; | |
31 | |
32 SkAutoGlyphCache ac(paint, NULL); | |
33 SkGlyphCache* cache = ac.getCache(); | |
34 SkFixed w = 0; | |
35 SkFixed limit = SkScalarToFixed(margin); | |
36 SkAutoKern autokern; | |
37 | |
38 const char* word_start = text; | |
39 int prevWS = true; | |
40 | |
41 while (text < stop) | |
42 { | |
43 const char* prevText = text; | |
44 SkUnichar uni = SkUTF8_NextUnichar(&text); | |
45 int currWS = is_ws(uni); | |
46 const SkGlyph& glyph = cache->getUnicharMetrics(uni); | |
47 | |
48 if (!currWS && prevWS) | |
49 word_start = prevText; | |
50 prevWS = currWS; | |
51 | |
52 w += autokern.adjust(glyph) + glyph.fAdvanceX; | |
53 if (w > limit) | |
54 { | |
55 if (currWS) // eat the rest of the whitespace | |
56 { | |
57 while (text < stop && is_ws(SkUTF8_ToUnichar(text))) | |
58 text += SkUTF8_CountUTF8Bytes(text); | |
59 } | |
60 else // backup until a whitespace (or 1 char) | |
61 { | |
62 if (word_start == start) | |
63 { | |
64 if (prevText > start) | |
65 text = prevText; | |
66 } | |
67 else | |
68 text = word_start; | |
69 } | |
70 break; | |
71 } | |
72 } | |
73 return text - start; | |
74 } | |
75 | |
76 int SkTextLineBreaker::CountLines(const char text[], size_t len, const SkPaint&
paint, SkScalar width) | |
77 { | |
78 const char* stop = text + len; | |
79 int count = 0; | |
80 | |
81 if (width > 0) | |
82 { | |
83 do { | |
84 count += 1; | |
85 text += linebreak(text, stop, paint, width); | |
86 } while (text < stop); | |
87 } | |
88 return count; | |
89 } | |
90 | |
91 ////////////////////////////////////////////////////////////////////////////// | |
92 | |
93 SkTextBox::SkTextBox() | |
94 { | |
95 fBox.setEmpty(); | |
96 fSpacingMul = SK_Scalar1; | |
97 fSpacingAdd = 0; | |
98 fMode = kLineBreak_Mode; | |
99 fSpacingAlign = kStart_SpacingAlign; | |
100 } | |
101 | |
102 void SkTextBox::setMode(Mode mode) | |
103 { | |
104 SkASSERT((unsigned)mode < kModeCount); | |
105 fMode = SkToU8(mode); | |
106 } | |
107 | |
108 void SkTextBox::setSpacingAlign(SpacingAlign align) | |
109 { | |
110 SkASSERT((unsigned)align < kSpacingAlignCount); | |
111 fSpacingAlign = SkToU8(align); | |
112 } | |
113 | |
114 void SkTextBox::getBox(SkRect* box) const | |
115 { | |
116 if (box) | |
117 *box = fBox; | |
118 } | |
119 | |
120 void SkTextBox::setBox(const SkRect& box) | |
121 { | |
122 fBox = box; | |
123 } | |
124 | |
125 void SkTextBox::setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bot
tom) | |
126 { | |
127 fBox.set(left, top, right, bottom); | |
128 } | |
129 | |
130 void SkTextBox::getSpacing(SkScalar* mul, SkScalar* add) const | |
131 { | |
132 if (mul) | |
133 *mul = fSpacingMul; | |
134 if (add) | |
135 *add = fSpacingAdd; | |
136 } | |
137 | |
138 void SkTextBox::setSpacing(SkScalar mul, SkScalar add) | |
139 { | |
140 fSpacingMul = mul; | |
141 fSpacingAdd = add; | |
142 } | |
143 | |
144 ////////////////////////////////////////////////////////////////////////////////
///////////// | |
145 | |
146 void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPa
int& paint) | |
147 { | |
148 SkASSERT(canvas && &paint && (text || len == 0)); | |
149 | |
150 SkScalar marginWidth = fBox.width(); | |
151 | |
152 if (marginWidth <= 0 || len == 0) | |
153 return; | |
154 | |
155 const char* textStop = text + len; | |
156 | |
157 SkScalar x, y, scaledSpacing, height, fontHeight; | |
158 SkPaint::FontMetrics metrics; | |
159 | |
160 switch (paint.getTextAlign()) { | |
161 case SkPaint::kLeft_Align: | |
162 x = 0; | |
163 break; | |
164 case SkPaint::kCenter_Align: | |
165 x = SkScalarHalf(marginWidth); | |
166 break; | |
167 default: | |
168 x = marginWidth; | |
169 break; | |
170 } | |
171 x += fBox.fLeft; | |
172 | |
173 fontHeight = paint.getFontMetrics(&metrics); | |
174 scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd; | |
175 height = fBox.height(); | |
176 | |
177 // compute Y position for first line | |
178 { | |
179 SkScalar textHeight = fontHeight; | |
180 | |
181 if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign) | |
182 { | |
183 int count = SkTextLineBreaker::CountLines(text, textStop - text, pai
nt, marginWidth); | |
184 SkASSERT(count > 0); | |
185 textHeight += scaledSpacing * (count - 1); | |
186 } | |
187 | |
188 switch (fSpacingAlign) { | |
189 case kStart_SpacingAlign: | |
190 y = 0; | |
191 break; | |
192 case kCenter_SpacingAlign: | |
193 y = SkScalarHalf(height - textHeight); | |
194 break; | |
195 default: | |
196 SkASSERT(fSpacingAlign == kEnd_SpacingAlign); | |
197 y = height - textHeight; | |
198 break; | |
199 } | |
200 y += fBox.fTop - metrics.fAscent; | |
201 } | |
202 | |
203 for (;;) | |
204 { | |
205 len = linebreak(text, textStop, paint, marginWidth); | |
206 if (y + metrics.fDescent + metrics.fLeading > 0) | |
207 canvas->drawText(text, len, x, y, paint); | |
208 text += len; | |
209 if (text >= textStop) | |
210 break; | |
211 y += scaledSpacing; | |
212 if (y + metrics.fAscent >= height) | |
213 break; | |
214 } | |
215 } | |
216 | |
OLD | NEW |