OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/canvas.h" | 5 #include "ui/gfx/canvas.h" |
6 | 6 |
7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "ui/base/range/range.h" | 10 #include "ui/base/range/range.h" |
11 #include "ui/base/text/text_elider.h" | 11 #include "ui/base/text/text_elider.h" |
12 #include "ui/gfx/font.h" | 12 #include "ui/gfx/font.h" |
13 #include "ui/gfx/font_list.h" | 13 #include "ui/gfx/font_list.h" |
14 #include "ui/gfx/insets.h" | 14 #include "ui/gfx/insets.h" |
15 #include "ui/gfx/rect.h" | 15 #include "ui/gfx/rect.h" |
16 #include "ui/gfx/render_text.h" | 16 #include "ui/gfx/render_text.h" |
17 #include "ui/gfx/shadow_value.h" | 17 #include "ui/gfx/shadow_value.h" |
18 #include "ui/gfx/text_utils.h" | 18 #include "ui/gfx/text_utils.h" |
19 | 19 |
20 namespace gfx { | |
21 | |
20 namespace { | 22 namespace { |
21 | 23 |
22 // If necessary, wraps |text| with RTL/LTR directionality characters based on | 24 // If necessary, wraps |text| with RTL/LTR directionality characters based on |
23 // |flags| and |text| content. | 25 // |flags| and |text| content. |
24 // Returns true if the text will be rendered right-to-left. | 26 // Returns true if the text will be rendered right-to-left. |
25 // TODO(msw): Nix this, now that RenderTextWin supports directionality directly. | 27 // TODO(msw): Nix this, now that RenderTextWin supports directionality directly. |
26 bool AdjustStringDirection(int flags, string16* text) { | 28 bool AdjustStringDirection(int flags, string16* text) { |
27 // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now. | 29 // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now. |
28 | 30 |
29 // If the string is empty or LTR was forced, simply return false since the | 31 // If the string is empty or LTR was forced, simply return false since the |
30 // default RenderText directionality is already LTR. | 32 // default RenderText directionality is already LTR. |
31 if (text->empty() || (flags & gfx::Canvas::FORCE_LTR_DIRECTIONALITY)) | 33 if (text->empty() || (flags & Canvas::FORCE_LTR_DIRECTIONALITY)) |
32 return false; | 34 return false; |
33 | 35 |
34 // If RTL is forced, apply it to the string. | 36 // If RTL is forced, apply it to the string. |
35 if (flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY) { | 37 if (flags & Canvas::FORCE_RTL_DIRECTIONALITY) { |
36 base::i18n::WrapStringWithRTLFormatting(text); | 38 base::i18n::WrapStringWithRTLFormatting(text); |
37 return true; | 39 return true; |
38 } | 40 } |
39 | 41 |
40 // If a direction wasn't forced but the UI language is RTL and there were | 42 // If a direction wasn't forced but the UI language is RTL and there were |
41 // strong RTL characters, ensure RTL is applied. | 43 // strong RTL characters, ensure RTL is applied. |
42 if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) { | 44 if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) { |
43 base::i18n::WrapStringWithRTLFormatting(text); | 45 base::i18n::WrapStringWithRTLFormatting(text); |
44 return true; | 46 return true; |
45 } | 47 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 *bitmap.getAddr32(x, y + 1) != halo_color && | 79 *bitmap.getAddr32(x, y + 1) != halo_color && |
78 *bitmap.getAddr32(x, y + 1) != 0) | 80 *bitmap.getAddr32(x, y + 1) != 0) |
79 return true; // Touched pixel below. | 81 return true; // Touched pixel below. |
80 return false; | 82 return false; |
81 } | 83 } |
82 | 84 |
83 // Strips accelerator character prefixes in |text| if needed, based on |flags|. | 85 // Strips accelerator character prefixes in |text| if needed, based on |flags|. |
84 // Returns a range in |text| to underline or ui::Range::InvalidRange() if | 86 // Returns a range in |text| to underline or ui::Range::InvalidRange() if |
85 // underlining is not needed. | 87 // underlining is not needed. |
86 ui::Range StripAcceleratorChars(int flags, string16* text) { | 88 ui::Range StripAcceleratorChars(int flags, string16* text) { |
87 if (flags & (gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX)) { | 89 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { |
88 int char_pos = -1; | 90 int char_pos = -1; |
89 int char_span = 0; | 91 int char_span = 0; |
90 *text = gfx::RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); | 92 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); |
91 if ((flags & gfx::Canvas::SHOW_PREFIX) && char_pos != -1) | 93 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) |
92 return ui::Range(char_pos, char_pos + char_span); | 94 return ui::Range(char_pos, char_pos + char_span); |
93 } | 95 } |
94 return ui::Range::InvalidRange(); | 96 return ui::Range::InvalidRange(); |
95 } | 97 } |
96 | 98 |
97 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| | 99 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| |
98 // to no longer point to the same character in |text|, |range| is made invalid. | 100 // to no longer point to the same character in |text|, |range| is made invalid. |
99 void ElideTextAndAdjustRange(const gfx::Font& font, | 101 void ElideTextAndAdjustRange(const Font& font, |
100 int width, | 102 int width, |
101 string16* text, | 103 string16* text, |
102 ui::Range* range) { | 104 ui::Range* range) { |
103 const char16 start_char = (range->IsValid() ? text->at(range->start()) : 0); | 105 const char16 start_char = (range->IsValid() ? text->at(range->start()) : 0); |
104 *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END); | 106 *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END); |
105 if (!range->IsValid()) | 107 if (!range->IsValid()) |
106 return; | 108 return; |
107 if (range->start() >= text->length() || | 109 if (range->start() >= text->length() || |
108 text->at(range->start()) != start_char) { | 110 text->at(range->start()) != start_char) { |
109 *range = ui::Range::InvalidRange(); | 111 *range = ui::Range::InvalidRange(); |
110 } | 112 } |
111 } | 113 } |
112 | 114 |
113 // Updates |render_text| from the specified parameters. | 115 // Updates |render_text| from the specified parameters. |
114 void UpdateRenderText(const gfx::Rect& rect, | 116 void UpdateRenderText(const Rect& rect, |
115 const string16& text, | 117 const string16& text, |
116 const gfx::Font& font, | 118 const Font& font, |
117 int flags, | 119 int flags, |
118 SkColor color, | 120 SkColor color, |
119 gfx::RenderText* render_text) { | 121 RenderText* render_text) { |
120 render_text->SetFont(font); | 122 render_text->SetFont(font); |
121 render_text->SetText(text); | 123 render_text->SetText(text); |
122 render_text->SetCursorEnabled(false); | 124 render_text->SetCursorEnabled(false); |
123 | 125 |
124 gfx::Rect display_rect = rect; | 126 Rect display_rect = rect; |
125 display_rect.set_height(font.GetHeight()); | 127 display_rect.set_height(font.GetHeight()); |
126 render_text->SetDisplayRect(display_rect); | 128 render_text->SetDisplayRect(display_rect); |
127 | 129 |
128 // Set the text alignment explicitly based on the directionality of the UI, | 130 // Set the text alignment explicitly based on the directionality of the UI, |
129 // if not specified. | 131 // if not specified. |
130 if (!(flags & (gfx::Canvas::TEXT_ALIGN_CENTER | | 132 if (!(flags & (Canvas::TEXT_ALIGN_CENTER | |
131 gfx::Canvas::TEXT_ALIGN_RIGHT | | 133 Canvas::TEXT_ALIGN_RIGHT | |
132 gfx::Canvas::TEXT_ALIGN_LEFT))) { | 134 Canvas::TEXT_ALIGN_LEFT))) { |
133 flags |= gfx::Canvas::DefaultCanvasTextAlignment(); | 135 flags |= Canvas::DefaultCanvasTextAlignment(); |
134 } | 136 } |
135 | 137 |
136 if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT) | 138 if (flags & Canvas::TEXT_ALIGN_RIGHT) |
137 render_text->SetHorizontalAlignment(gfx::ALIGN_RIGHT); | 139 render_text->SetHorizontalAlignment(ALIGN_RIGHT); |
138 else if (flags & gfx::Canvas::TEXT_ALIGN_CENTER) | 140 else if (flags & Canvas::TEXT_ALIGN_CENTER) |
139 render_text->SetHorizontalAlignment(gfx::ALIGN_CENTER); | 141 render_text->SetHorizontalAlignment(ALIGN_CENTER); |
140 else | 142 else |
141 render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 143 render_text->SetHorizontalAlignment(ALIGN_LEFT); |
142 | 144 |
143 if (flags & gfx::Canvas::NO_SUBPIXEL_RENDERING) | 145 if (flags & Canvas::NO_SUBPIXEL_RENDERING) |
144 render_text->set_background_is_transparent(true); | 146 render_text->set_background_is_transparent(true); |
145 | 147 |
146 gfx::StyleRange style; | 148 render_text->SetColor(color); |
147 style.foreground = color; | 149 render_text->SetStyle(BOLD, (font.GetStyle() & Font::BOLD) != 0); |
148 style.font_style = font.GetStyle(); | 150 render_text->SetStyle(ITALIC, (font.GetStyle() & Font::ITALIC) != 0); |
149 if (font.GetStyle() & gfx::Font::UNDERLINED) | 151 render_text->SetStyle(UNDERLINE, (font.GetStyle() & Font::UNDERLINE) != 0); |
150 style.underline = true; | |
151 render_text->set_default_style(style); | |
152 render_text->ApplyDefaultStyle(); | |
153 } | |
154 | |
155 // Adds an underline style to |render_text| over |range|. | |
156 void ApplyUnderlineStyle(const ui::Range& range, gfx::RenderText* render_text) { | |
157 gfx::StyleRange style = render_text->default_style(); | |
158 if (range.IsValid() && !style.underline) { | |
159 style.range = range; | |
160 style.underline = true; | |
161 render_text->ApplyStyleRange(style); | |
162 } | |
163 } | 152 } |
164 | 153 |
165 // Returns updated |flags| to match platform-specific expected behavior. | 154 // Returns updated |flags| to match platform-specific expected behavior. |
166 int AdjustPlatformSpecificFlags(const string16& text, int flags) { | 155 int AdjustPlatformSpecificFlags(const string16& text, int flags) { |
167 #if defined(OS_LINUX) | 156 #if defined(OS_LINUX) |
168 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string | 157 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string |
169 // without passing MULTI_LINE. | 158 // without passing MULTI_LINE. |
170 if (text.find('\n') != string16::npos) | 159 if (text.find('\n') != string16::npos) |
171 flags |= gfx::Canvas::MULTI_LINE; | 160 flags |= Canvas::MULTI_LINE; |
172 #endif | 161 #endif |
173 | 162 |
174 return flags; | 163 return flags; |
175 } | 164 } |
176 | 165 |
177 } // namespace | 166 } // namespace |
178 | 167 |
179 namespace gfx { | |
180 | |
181 // static | 168 // static |
182 void Canvas::SizeStringInt(const string16& text, | 169 void Canvas::SizeStringInt(const string16& text, |
183 const gfx::Font& font, | 170 const Font& font, |
184 int* width, int* height, | 171 int* width, int* height, |
185 int flags) { | 172 int flags) { |
186 DCHECK_GE(*width, 0); | 173 DCHECK_GE(*width, 0); |
187 DCHECK_GE(*height, 0); | 174 DCHECK_GE(*height, 0); |
188 | 175 |
189 flags = AdjustPlatformSpecificFlags(text, flags); | 176 flags = AdjustPlatformSpecificFlags(text, flags); |
190 | 177 |
191 string16 adjusted_text = text; | 178 string16 adjusted_text = text; |
192 #if defined(OS_WIN) | 179 #if defined(OS_WIN) |
193 AdjustStringDirection(flags, &adjusted_text); | 180 AdjustStringDirection(flags, &adjusted_text); |
194 #endif | 181 #endif |
195 | 182 |
196 if ((flags & MULTI_LINE) && *width != 0) { | 183 if ((flags & MULTI_LINE) && *width != 0) { |
197 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; | 184 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; |
198 if (flags & CHARACTER_BREAK) | 185 if (flags & CHARACTER_BREAK) |
199 wrap_behavior = ui::WRAP_LONG_WORDS; | 186 wrap_behavior = ui::WRAP_LONG_WORDS; |
200 else if (!(flags & NO_ELLIPSIS)) | 187 else if (!(flags & NO_ELLIPSIS)) |
201 wrap_behavior = ui::ELIDE_LONG_WORDS; | 188 wrap_behavior = ui::ELIDE_LONG_WORDS; |
202 | 189 |
203 gfx::Rect rect(*width, INT_MAX); | 190 Rect rect(*width, INT_MAX); |
204 std::vector<string16> strings; | 191 std::vector<string16> strings; |
205 ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(), | 192 ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(), |
206 wrap_behavior, &strings); | 193 wrap_behavior, &strings); |
207 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 194 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
208 UpdateRenderText(rect, string16(), font, flags, 0, render_text.get()); | 195 UpdateRenderText(rect, string16(), font, flags, 0, render_text.get()); |
209 | 196 |
210 int h = 0; | 197 int h = 0; |
211 int w = 0; | 198 int w = 0; |
212 for (size_t i = 0; i < strings.size(); ++i) { | 199 for (size_t i = 0; i < strings.size(); ++i) { |
213 StripAcceleratorChars(flags, &strings[i]); | 200 StripAcceleratorChars(flags, &strings[i]); |
214 render_text->SetText(strings[i]); | 201 render_text->SetText(strings[i]); |
215 const Size string_size = render_text->GetStringSize(); | 202 const Size string_size = render_text->GetStringSize(); |
216 w = std::max(w, string_size.width()); | 203 w = std::max(w, string_size.width()); |
217 h += string_size.height(); | 204 h += string_size.height(); |
218 } | 205 } |
219 *width = w; | 206 *width = w; |
220 *height = h; | 207 *height = h; |
221 } else { | 208 } else { |
222 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| | 209 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| |
223 // will inexplicably fail with result E_INVALIDARG. Guard against this. | 210 // will inexplicably fail with result E_INVALIDARG. Guard against this. |
224 const size_t kMaxRenderTextLength = 5000; | 211 const size_t kMaxRenderTextLength = 5000; |
225 if (adjusted_text.length() >= kMaxRenderTextLength) { | 212 if (adjusted_text.length() >= kMaxRenderTextLength) { |
226 *width = adjusted_text.length() * font.GetAverageCharacterWidth(); | 213 *width = adjusted_text.length() * font.GetAverageCharacterWidth(); |
227 *height = font.GetHeight(); | 214 *height = font.GetHeight(); |
228 } else { | 215 } else { |
229 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 216 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
230 gfx::Rect rect(*width, *height); | 217 Rect rect(*width, *height); |
231 StripAcceleratorChars(flags, &adjusted_text); | 218 StripAcceleratorChars(flags, &adjusted_text); |
232 UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get()); | 219 UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get()); |
233 const Size string_size = render_text->GetStringSize(); | 220 const Size string_size = render_text->GetStringSize(); |
234 *width = string_size.width(); | 221 *width = string_size.width(); |
235 *height = string_size.height(); | 222 *height = string_size.height(); |
236 } | 223 } |
237 } | 224 } |
238 } | 225 } |
239 | 226 |
240 void Canvas::DrawStringWithShadows(const string16& text, | 227 void Canvas::DrawStringWithShadows(const string16& text, |
241 const gfx::Font& font, | 228 const Font& font, |
242 SkColor color, | 229 SkColor color, |
243 const gfx::Rect& text_bounds, | 230 const Rect& text_bounds, |
244 int flags, | 231 int flags, |
245 const ShadowValues& shadows) { | 232 const ShadowValues& shadows) { |
246 if (!IntersectsClipRect(text_bounds)) | 233 if (!IntersectsClipRect(text_bounds)) |
247 return; | 234 return; |
248 | 235 |
249 flags = AdjustPlatformSpecificFlags(text, flags); | 236 flags = AdjustPlatformSpecificFlags(text, flags); |
250 | 237 |
251 gfx::Rect clip_rect(text_bounds); | 238 Rect clip_rect(text_bounds); |
252 clip_rect.Inset(ShadowValue::GetMargin(shadows)); | 239 clip_rect.Inset(ShadowValue::GetMargin(shadows)); |
253 | 240 |
254 canvas_->save(SkCanvas::kClip_SaveFlag); | 241 canvas_->save(SkCanvas::kClip_SaveFlag); |
255 ClipRect(clip_rect); | 242 ClipRect(clip_rect); |
256 | 243 |
257 gfx::Rect rect(text_bounds); | 244 Rect rect(text_bounds); |
258 string16 adjusted_text = text; | 245 string16 adjusted_text = text; |
259 | 246 |
260 #if defined(OS_WIN) | 247 #if defined(OS_WIN) |
261 AdjustStringDirection(flags, &adjusted_text); | 248 AdjustStringDirection(flags, &adjusted_text); |
262 #endif | 249 #endif |
263 | 250 |
264 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 251 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
265 render_text->SetTextShadows(shadows); | 252 render_text->SetTextShadows(shadows); |
266 | 253 |
267 if (flags & MULTI_LINE) { | 254 if (flags & MULTI_LINE) { |
(...skipping 13 matching lines...) Expand all Loading... | |
281 for (size_t i = 0; i < strings.size(); i++) { | 268 for (size_t i = 0; i < strings.size(); i++) { |
282 ui::Range range = StripAcceleratorChars(flags, &strings[i]); | 269 ui::Range range = StripAcceleratorChars(flags, &strings[i]); |
283 UpdateRenderText(rect, strings[i], font, flags, color, render_text.get()); | 270 UpdateRenderText(rect, strings[i], font, flags, color, render_text.get()); |
284 const int line_height = render_text->GetStringSize().height(); | 271 const int line_height = render_text->GetStringSize().height(); |
285 | 272 |
286 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 | 273 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 |
287 #if !defined(OS_WIN) | 274 #if !defined(OS_WIN) |
288 if (i == 0) { | 275 if (i == 0) { |
289 // TODO(msw|asvitkine): Support multi-line text with varied heights. | 276 // TODO(msw|asvitkine): Support multi-line text with varied heights. |
290 const int aggregate_height = strings.size() * line_height; | 277 const int aggregate_height = strings.size() * line_height; |
291 rect += gfx::Vector2d(0, (text_bounds.height() - aggregate_height) / 2); | 278 rect += Vector2d(0, (text_bounds.height() - aggregate_height) / 2); |
292 } | 279 } |
293 #endif | 280 #endif |
294 | 281 |
295 rect.set_height(line_height); | 282 rect.set_height(line_height); |
296 | 283 |
297 ApplyUnderlineStyle(range, render_text.get()); | 284 render_text->ApplyStyle(UNDERLINE, true, range); |
Alexei Svitkine (slow)
2013/01/22 19:20:21
Only do this if range.IsValid(). See comment for S
msw
2013/01/22 22:27:24
Done.
| |
298 render_text->SetDisplayRect(rect); | 285 render_text->SetDisplayRect(rect); |
299 render_text->Draw(this); | 286 render_text->Draw(this); |
300 rect += gfx::Vector2d(0, line_height); | 287 rect += Vector2d(0, line_height); |
301 } | 288 } |
302 } else { | 289 } else { |
303 ui::Range range = StripAcceleratorChars(flags, &adjusted_text); | 290 ui::Range range = StripAcceleratorChars(flags, &adjusted_text); |
304 bool elide_text = ((flags & NO_ELLIPSIS) == 0); | 291 bool elide_text = ((flags & NO_ELLIPSIS) == 0); |
305 | 292 |
306 #if defined(OS_LINUX) | 293 #if defined(OS_LINUX) |
307 // On Linux, eliding really means fading the end of the string. But only | 294 // On Linux, eliding really means fading the end of the string. But only |
308 // for LTR text. RTL text is still elided (on the left) with "...". | 295 // for LTR text. RTL text is still elided (on the left) with "...". |
309 if (elide_text) { | 296 if (elide_text) { |
310 render_text->SetText(adjusted_text); | 297 render_text->SetText(adjusted_text); |
311 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { | 298 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { |
312 render_text->set_fade_tail(true); | 299 render_text->set_fade_tail(true); |
313 elide_text = false; | 300 elide_text = false; |
314 } | 301 } |
315 } | 302 } |
316 #endif | 303 #endif |
317 | 304 |
318 if (elide_text) { | 305 if (elide_text) { |
319 ElideTextAndAdjustRange(font, | 306 ElideTextAndAdjustRange(font, |
320 text_bounds.width(), | 307 text_bounds.width(), |
321 &adjusted_text, | 308 &adjusted_text, |
322 &range); | 309 &range); |
323 } | 310 } |
324 | 311 |
325 UpdateRenderText(rect, adjusted_text, font, flags, color, | 312 UpdateRenderText(rect, adjusted_text, font, flags, color, |
326 render_text.get()); | 313 render_text.get()); |
327 | 314 |
328 const int line_height = render_text->GetStringSize().height(); | 315 const int line_height = render_text->GetStringSize().height(); |
329 // Center the text vertically. | 316 // Center the text vertically. |
330 rect += gfx::Vector2d(0, (text_bounds.height() - line_height) / 2); | 317 rect += Vector2d(0, (text_bounds.height() - line_height) / 2); |
331 rect.set_height(line_height); | 318 rect.set_height(line_height); |
332 render_text->SetDisplayRect(rect); | 319 render_text->SetDisplayRect(rect); |
333 | 320 render_text->ApplyStyle(UNDERLINE, true, range); |
Alexei Svitkine (slow)
2013/01/22 19:20:21
Only do this if range.IsValid(). See comment for S
msw
2013/01/22 22:27:24
Done.
| |
334 ApplyUnderlineStyle(range, render_text.get()); | |
335 render_text->Draw(this); | 321 render_text->Draw(this); |
336 } | 322 } |
337 | 323 |
338 canvas_->restore(); | 324 canvas_->restore(); |
339 } | 325 } |
340 | 326 |
341 void Canvas::DrawStringWithHalo(const string16& text, | 327 void Canvas::DrawStringWithHalo(const string16& text, |
342 const gfx::Font& font, | 328 const Font& font, |
343 SkColor text_color, | 329 SkColor text_color, |
344 SkColor halo_color_in, | 330 SkColor halo_color_in, |
345 int x, int y, int w, int h, | 331 int x, int y, int w, int h, |
346 int flags) { | 332 int flags) { |
347 // Some callers will have semitransparent halo colors, which we don't handle | 333 // Some callers will have semitransparent halo colors, which we don't handle |
348 // (since the resulting image can have 1-bit transparency only). | 334 // (since the resulting image can have 1-bit transparency only). |
349 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); | 335 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); |
350 | 336 |
351 // Create a temporary buffer filled with the halo color. It must leave room | 337 // Create a temporary buffer filled with the halo color. It must leave room |
352 // for the 1-pixel border around the text. | 338 // for the 1-pixel border around the text. |
353 Size size(w + 2, h + 2); | 339 Size size(w + 2, h + 2); |
354 Canvas text_canvas(size, scale_factor(), true); | 340 Canvas text_canvas(size, scale_factor(), true); |
355 SkPaint bkgnd_paint; | 341 SkPaint bkgnd_paint; |
356 bkgnd_paint.setColor(halo_color); | 342 bkgnd_paint.setColor(halo_color); |
357 text_canvas.DrawRect(gfx::Rect(size), bkgnd_paint); | 343 text_canvas.DrawRect(Rect(size), bkgnd_paint); |
358 | 344 |
359 // Draw the text into the temporary buffer. This will have correct | 345 // Draw the text into the temporary buffer. This will have correct |
360 // ClearType since the background color is the same as the halo color. | 346 // ClearType since the background color is the same as the halo color. |
361 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); | 347 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); |
362 | 348 |
363 uint32_t halo_premul = SkPreMultiplyColor(halo_color); | 349 uint32_t halo_premul = SkPreMultiplyColor(halo_color); |
364 SkBitmap& text_bitmap = const_cast<SkBitmap&>( | 350 SkBitmap& text_bitmap = const_cast<SkBitmap&>( |
365 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); | 351 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); |
366 | 352 |
367 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { | 353 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { |
368 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); | 354 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); |
369 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { | 355 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { |
370 if (text_row[cur_x] == halo_premul) { | 356 if (text_row[cur_x] == halo_premul) { |
371 // This pixel was not touched by the text routines. See if it borders | 357 // This pixel was not touched by the text routines. See if it borders |
372 // a touched pixel in any of the 4 directions (not diagonally). | 358 // a touched pixel in any of the 4 directions (not diagonally). |
373 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) | 359 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) |
374 text_row[cur_x] = 0; // Make transparent. | 360 text_row[cur_x] = 0; // Make transparent. |
375 } else { | 361 } else { |
376 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. | 362 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. |
377 } | 363 } |
378 } | 364 } |
379 } | 365 } |
380 | 366 |
381 // Draw the halo bitmap with blur. | 367 // Draw the halo bitmap with blur. |
382 gfx::ImageSkia text_image = gfx::ImageSkia(gfx::ImageSkiaRep(text_bitmap, | 368 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, |
383 text_canvas.scale_factor())); | 369 text_canvas.scale_factor())); |
384 DrawImageInt(text_image, x - 1, y - 1); | 370 DrawImageInt(text_image, x - 1, y - 1); |
385 } | 371 } |
386 | 372 |
387 void Canvas::DrawFadeTruncatingString( | 373 void Canvas::DrawFadeTruncatingString( |
388 const string16& text, | 374 const string16& text, |
389 TruncateFadeMode truncate_mode, | 375 TruncateFadeMode truncate_mode, |
390 size_t desired_characters_to_truncate_from_head, | 376 size_t desired_characters_to_truncate_from_head, |
391 const gfx::Font& font, | 377 const Font& font, |
392 SkColor color, | 378 SkColor color, |
393 const gfx::Rect& display_rect) { | 379 const Rect& display_rect) { |
394 int flags = NO_ELLIPSIS; | 380 int flags = NO_ELLIPSIS; |
395 | 381 |
396 // If the whole string fits in the destination then just draw it directly. | 382 // If the whole string fits in the destination then just draw it directly. |
397 if (GetStringWidth(text, font) <= display_rect.width()) { | 383 if (GetStringWidth(text, font) <= display_rect.width()) { |
398 DrawStringInt(text, font, color, display_rect.x(), display_rect.y(), | 384 DrawStringInt(text, font, color, display_rect.x(), display_rect.y(), |
399 display_rect.width(), display_rect.height(), flags); | 385 display_rect.width(), display_rect.height(), flags); |
400 return; | 386 return; |
401 } | 387 } |
402 | 388 |
403 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 389 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
(...skipping 30 matching lines...) Expand all Loading... | |
434 | 420 |
435 render_text->set_fade_tail(true); | 421 render_text->set_fade_tail(true); |
436 render_text->set_fade_head(true); | 422 render_text->set_fade_head(true); |
437 break; | 423 break; |
438 } | 424 } |
439 | 425 |
440 // Default to left alignment unless right alignment was chosen above. | 426 // Default to left alignment unless right alignment was chosen above. |
441 if (!(flags & TEXT_ALIGN_RIGHT)) | 427 if (!(flags & TEXT_ALIGN_RIGHT)) |
442 flags |= TEXT_ALIGN_LEFT; | 428 flags |= TEXT_ALIGN_LEFT; |
443 | 429 |
444 gfx::Rect rect = display_rect; | 430 Rect rect = display_rect; |
445 UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get()); | 431 UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get()); |
446 | 432 |
447 const int line_height = render_text->GetStringSize().height(); | 433 const int line_height = render_text->GetStringSize().height(); |
448 // Center the text vertically. | 434 // Center the text vertically. |
449 rect += gfx::Vector2d(0, (display_rect.height() - line_height) / 2); | 435 rect += Vector2d(0, (display_rect.height() - line_height) / 2); |
450 rect.set_height(line_height); | 436 rect.set_height(line_height); |
451 render_text->SetDisplayRect(rect); | 437 render_text->SetDisplayRect(rect); |
452 | 438 |
453 canvas_->save(SkCanvas::kClip_SaveFlag); | 439 canvas_->save(SkCanvas::kClip_SaveFlag); |
454 ClipRect(display_rect); | 440 ClipRect(display_rect); |
455 render_text->Draw(this); | 441 render_text->Draw(this); |
456 canvas_->restore(); | 442 canvas_->restore(); |
457 } | 443 } |
458 | 444 |
459 } // namespace gfx | 445 } // namespace gfx |
OLD | NEW |