| 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 |