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/gfx/font_list.h" | 10 #include "ui/gfx/font_list.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 *bitmap.getAddr32(x, y - 1) != 0) | 77 *bitmap.getAddr32(x, y - 1) != 0) |
78 return true; // Touched pixel above. | 78 return true; // Touched pixel above. |
79 if (y < bitmap.height() - 1 && | 79 if (y < bitmap.height() - 1 && |
80 *bitmap.getAddr32(x, y + 1) != halo_color && | 80 *bitmap.getAddr32(x, y + 1) != halo_color && |
81 *bitmap.getAddr32(x, y + 1) != 0) | 81 *bitmap.getAddr32(x, y + 1) != 0) |
82 return true; // Touched pixel below. | 82 return true; // Touched pixel below. |
83 return false; | 83 return false; |
84 } | 84 } |
85 | 85 |
86 // Strips accelerator character prefixes in |text| if needed, based on |flags|. | 86 // Strips accelerator character prefixes in |text| if needed, based on |flags|. |
87 // Returns a range in |text| to underline or gfx::Range::InvalidRange() if | 87 // Returns a range in |text| to underline or Range::InvalidRange() if |
88 // underlining is not needed. | 88 // underlining is not needed. |
89 Range StripAcceleratorChars(int flags, base::string16* text) { | 89 Range StripAcceleratorChars(int flags, base::string16* text) { |
90 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { | 90 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { |
91 int char_pos = -1; | 91 int char_pos = -1; |
92 int char_span = 0; | 92 int char_span = 0; |
93 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); | 93 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); |
94 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) | 94 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) |
95 return Range(char_pos, char_pos + char_span); | 95 return Range(char_pos, char_pos + char_span); |
96 } | 96 } |
97 return Range::InvalidRange(); | 97 return Range::InvalidRange(); |
98 } | 98 } |
99 | 99 |
100 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| | 100 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| |
101 // to no longer point to the same character in |text|, |range| is made invalid. | 101 // to no longer point to the same character in |text|, |range| is made invalid. |
102 void ElideTextAndAdjustRange(const FontList& font_list, | 102 void ElideTextAndAdjustRange(const FontList& font_list, |
103 int width, | 103 int width, |
104 base::string16* text, | 104 base::string16* text, |
105 Range* range) { | 105 Range* range) { |
106 const base::char16 start_char = | 106 const base::char16 start_char = |
107 (range->IsValid() ? text->at(range->start()) : 0); | 107 (range->IsValid() ? text->at(range->start()) : 0); |
108 *text = gfx::ElideText(*text, font_list, width, gfx::ELIDE_AT_END); | 108 *text = ElideText(*text, font_list, width, ELIDE_TAIL); |
109 if (!range->IsValid()) | 109 if (!range->IsValid()) |
110 return; | 110 return; |
111 if (range->start() >= text->length() || | 111 if (range->start() >= text->length() || |
112 text->at(range->start()) != start_char) { | 112 text->at(range->start()) != start_char) { |
113 *range = Range::InvalidRange(); | 113 *range = Range::InvalidRange(); |
114 } | 114 } |
115 } | 115 } |
116 | 116 |
117 // Updates |render_text| from the specified parameters. | 117 // Updates |render_text| from the specified parameters. |
118 void UpdateRenderText(const Rect& rect, | 118 void UpdateRenderText(const Rect& rect, |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 int flags) { | 164 int flags) { |
165 DCHECK_GE(*width, 0); | 165 DCHECK_GE(*width, 0); |
166 DCHECK_GE(*height, 0); | 166 DCHECK_GE(*height, 0); |
167 | 167 |
168 base::string16 adjusted_text = text; | 168 base::string16 adjusted_text = text; |
169 #if defined(OS_WIN) | 169 #if defined(OS_WIN) |
170 AdjustStringDirection(flags, &adjusted_text); | 170 AdjustStringDirection(flags, &adjusted_text); |
171 #endif | 171 #endif |
172 | 172 |
173 if ((flags & MULTI_LINE) && *width != 0) { | 173 if ((flags & MULTI_LINE) && *width != 0) { |
174 gfx::WordWrapBehavior wrap_behavior = gfx::TRUNCATE_LONG_WORDS; | 174 WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS; |
175 if (flags & CHARACTER_BREAK) | 175 if (flags & CHARACTER_BREAK) |
176 wrap_behavior = gfx::WRAP_LONG_WORDS; | 176 wrap_behavior = WRAP_LONG_WORDS; |
177 else if (!(flags & NO_ELLIPSIS)) | 177 else if (!(flags & NO_ELLIPSIS)) |
178 wrap_behavior = gfx::ELIDE_LONG_WORDS; | 178 wrap_behavior = ELIDE_LONG_WORDS; |
179 | 179 |
180 Rect rect(*width, INT_MAX); | 180 Rect rect(*width, INT_MAX); |
181 std::vector<base::string16> strings; | 181 std::vector<base::string16> strings; |
182 gfx::ElideRectangleText(adjusted_text, font_list, | 182 ElideRectangleText(adjusted_text, font_list, rect.width(), rect.height(), |
183 rect.width(), rect.height(), | 183 wrap_behavior, &strings); |
184 wrap_behavior, &strings); | |
185 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 184 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
186 UpdateRenderText(rect, base::string16(), font_list, flags, 0, | 185 UpdateRenderText(rect, base::string16(), font_list, flags, 0, |
187 render_text.get()); | 186 render_text.get()); |
188 | 187 |
189 float h = 0; | 188 float h = 0; |
190 float w = 0; | 189 float w = 0; |
191 for (size_t i = 0; i < strings.size(); ++i) { | 190 for (size_t i = 0; i < strings.size(); ++i) { |
192 StripAcceleratorChars(flags, &strings[i]); | 191 StripAcceleratorChars(flags, &strings[i]); |
193 render_text->SetText(strings[i]); | 192 render_text->SetText(strings[i]); |
194 const SizeF& string_size = render_text->GetStringSizeF(); | 193 const SizeF& string_size = render_text->GetStringSizeF(); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 base::string16 adjusted_text = text; | 236 base::string16 adjusted_text = text; |
238 | 237 |
239 #if defined(OS_WIN) | 238 #if defined(OS_WIN) |
240 AdjustStringDirection(flags, &adjusted_text); | 239 AdjustStringDirection(flags, &adjusted_text); |
241 #endif | 240 #endif |
242 | 241 |
243 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 242 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
244 render_text->SetTextShadows(shadows); | 243 render_text->SetTextShadows(shadows); |
245 | 244 |
246 if (flags & MULTI_LINE) { | 245 if (flags & MULTI_LINE) { |
247 gfx::WordWrapBehavior wrap_behavior = gfx::IGNORE_LONG_WORDS; | 246 WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS; |
248 if (flags & CHARACTER_BREAK) | 247 if (flags & CHARACTER_BREAK) |
249 wrap_behavior = gfx::WRAP_LONG_WORDS; | 248 wrap_behavior = WRAP_LONG_WORDS; |
250 else if (!(flags & NO_ELLIPSIS)) | 249 else if (!(flags & NO_ELLIPSIS)) |
251 wrap_behavior = gfx::ELIDE_LONG_WORDS; | 250 wrap_behavior = ELIDE_LONG_WORDS; |
252 | 251 |
253 std::vector<base::string16> strings; | 252 std::vector<base::string16> strings; |
254 gfx::ElideRectangleText(adjusted_text, | 253 ElideRectangleText(adjusted_text, font_list, text_bounds.width(), |
255 font_list, | 254 text_bounds.height(), wrap_behavior, &strings); |
256 text_bounds.width(), text_bounds.height(), | |
257 wrap_behavior, | |
258 &strings); | |
259 | 255 |
260 for (size_t i = 0; i < strings.size(); i++) { | 256 for (size_t i = 0; i < strings.size(); i++) { |
261 Range range = StripAcceleratorChars(flags, &strings[i]); | 257 Range range = StripAcceleratorChars(flags, &strings[i]); |
262 UpdateRenderText(rect, strings[i], font_list, flags, color, | 258 UpdateRenderText(rect, strings[i], font_list, flags, color, |
263 render_text.get()); | 259 render_text.get()); |
264 int line_padding = 0; | 260 int line_padding = 0; |
265 if (line_height > 0) | 261 if (line_height > 0) |
266 line_padding = line_height - render_text->GetStringSize().height(); | 262 line_padding = line_height - render_text->GetStringSize().height(); |
267 else | 263 else |
268 line_height = render_text->GetStringSize().height(); | 264 line_height = render_text->GetStringSize().height(); |
(...skipping 18 matching lines...) Expand all Loading... |
287 } else { | 283 } else { |
288 Range range = StripAcceleratorChars(flags, &adjusted_text); | 284 Range range = StripAcceleratorChars(flags, &adjusted_text); |
289 bool elide_text = ((flags & NO_ELLIPSIS) == 0); | 285 bool elide_text = ((flags & NO_ELLIPSIS) == 0); |
290 | 286 |
291 #if defined(OS_LINUX) | 287 #if defined(OS_LINUX) |
292 // On Linux, eliding really means fading the end of the string. But only | 288 // On Linux, eliding really means fading the end of the string. But only |
293 // for LTR text. RTL text is still elided (on the left) with "...". | 289 // for LTR text. RTL text is still elided (on the left) with "...". |
294 if (elide_text) { | 290 if (elide_text) { |
295 render_text->SetText(adjusted_text); | 291 render_text->SetText(adjusted_text); |
296 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { | 292 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { |
297 render_text->set_fade_tail(true); | 293 render_text->SetElideBehavior(FADE_TAIL); |
298 elide_text = false; | 294 elide_text = false; |
299 } | 295 } |
300 } | 296 } |
301 #endif | 297 #endif |
302 | 298 |
303 if (elide_text) { | 299 if (elide_text) { |
304 ElideTextAndAdjustRange(font_list, | 300 ElideTextAndAdjustRange(font_list, text_bounds.width(), &adjusted_text, |
305 text_bounds.width(), | |
306 &adjusted_text, | |
307 &range); | 301 &range); |
308 } | 302 } |
309 | 303 |
310 UpdateRenderText(rect, adjusted_text, font_list, flags, color, | 304 UpdateRenderText(rect, adjusted_text, font_list, flags, color, |
311 render_text.get()); | 305 render_text.get()); |
312 | 306 |
313 const int text_height = render_text->GetStringSize().height(); | 307 const int text_height = render_text->GetStringSize().height(); |
314 // Center the text vertically. | |
315 rect += Vector2d(0, (text_bounds.height() - text_height) / 2); | 308 rect += Vector2d(0, (text_bounds.height() - text_height) / 2); |
316 rect.set_height(text_height); | 309 rect.set_height(text_height); |
317 render_text->SetDisplayRect(rect); | 310 render_text->SetDisplayRect(rect); |
318 if (range.IsValid()) | 311 if (range.IsValid()) |
319 render_text->ApplyStyle(UNDERLINE, true, range); | 312 render_text->ApplyStyle(UNDERLINE, true, range); |
320 render_text->Draw(this); | 313 render_text->Draw(this); |
321 } | 314 } |
322 | 315 |
323 canvas_->restore(); | 316 canvas_->restore(); |
324 } | 317 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 } | 357 } |
365 } | 358 } |
366 } | 359 } |
367 | 360 |
368 // Draw the halo bitmap with blur. | 361 // Draw the halo bitmap with blur. |
369 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, | 362 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, |
370 text_canvas.image_scale())); | 363 text_canvas.image_scale())); |
371 DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1); | 364 DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1); |
372 } | 365 } |
373 | 366 |
374 void Canvas::DrawFadeTruncatingStringRect( | 367 void Canvas::DrawFadedString(const base::string16& text, |
375 const base::string16& text, | 368 const FontList& font_list, |
376 TruncateFadeMode truncate_mode, | 369 SkColor color, |
377 const FontList& font_list, | 370 const Rect& display_rect, |
378 SkColor color, | 371 int flags) { |
379 const Rect& display_rect) { | |
380 DrawFadeTruncatingStringRectWithFlags( | |
381 text, truncate_mode, font_list, color, display_rect, NO_ELLIPSIS); | |
382 } | |
383 | |
384 void Canvas::DrawFadeTruncatingStringRectWithFlags( | |
385 const base::string16& text, | |
386 TruncateFadeMode truncate_mode, | |
387 const FontList& font_list, | |
388 SkColor color, | |
389 const Rect& display_rect, | |
390 int flags) { | |
391 // If the whole string fits in the destination then just draw it directly. | 372 // If the whole string fits in the destination then just draw it directly. |
392 if (GetStringWidth(text, font_list) <= display_rect.width()) { | 373 if (GetStringWidth(text, font_list) <= display_rect.width()) { |
393 DrawStringRectWithFlags(text, font_list, color, display_rect, flags); | 374 DrawStringRectWithFlags(text, font_list, color, display_rect, flags); |
394 return; | 375 return; |
395 } | 376 } |
396 | 377 |
| 378 // Align to content directionality instead of centering and fading both ends. |
| 379 if (!(flags & TEXT_ALIGN_LEFT) && !(flags & TEXT_ALIGN_RIGHT)) { |
| 380 flags &= ~TEXT_ALIGN_CENTER; |
| 381 const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) == |
| 382 base::i18n::RIGHT_TO_LEFT; |
| 383 flags |= is_rtl ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT; |
| 384 } |
| 385 flags |= NO_ELLIPSIS; |
| 386 |
397 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 387 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
398 const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) == | |
399 base::i18n::RIGHT_TO_LEFT; | |
400 | |
401 switch (truncate_mode) { | |
402 case TruncateFadeTail: | |
403 render_text->set_fade_tail(true); | |
404 if (is_rtl) | |
405 flags |= TEXT_ALIGN_RIGHT; | |
406 break; | |
407 case TruncateFadeHead: | |
408 render_text->set_fade_head(true); | |
409 if (!is_rtl) | |
410 flags |= TEXT_ALIGN_RIGHT; | |
411 break; | |
412 } | |
413 | |
414 // Default to left alignment unless right alignment was chosen above. | |
415 if (!(flags & TEXT_ALIGN_RIGHT)) | |
416 flags |= TEXT_ALIGN_LEFT; | |
417 | |
418 Rect rect = display_rect; | 388 Rect rect = display_rect; |
419 UpdateRenderText(rect, text, font_list, flags, color, render_text.get()); | 389 UpdateRenderText(rect, text, font_list, flags, color, render_text.get()); |
| 390 render_text->SetElideBehavior(FADE_TAIL); |
420 | 391 |
421 const int line_height = render_text->GetStringSize().height(); | 392 const int line_height = render_text->GetStringSize().height(); |
422 // Center the text vertically. | |
423 rect += Vector2d(0, (display_rect.height() - line_height) / 2); | 393 rect += Vector2d(0, (display_rect.height() - line_height) / 2); |
424 rect.set_height(line_height); | 394 rect.set_height(line_height); |
425 render_text->SetDisplayRect(rect); | 395 render_text->SetDisplayRect(rect); |
426 | 396 |
427 canvas_->save(); | 397 canvas_->save(); |
428 ClipRect(display_rect); | 398 ClipRect(display_rect); |
429 render_text->Draw(this); | 399 render_text->Draw(this); |
430 canvas_->restore(); | 400 canvas_->restore(); |
431 } | 401 } |
432 | 402 |
433 } // namespace gfx | 403 } // namespace gfx |
OLD | NEW |