| 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/views/controls/label.h" | 5 #include "ui/views/controls/label.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cmath> | 10 #include <cmath> |
| 11 #include <limits> | 11 #include <limits> |
| 12 #include <utility> | 12 #include <utility> |
| 13 #include <vector> | 13 #include <vector> |
| 14 | 14 |
| 15 #include "base/i18n/rtl.h" | 15 #include "base/i18n/rtl.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/ptr_util.h" |
| 17 #include "base/profiler/scoped_tracker.h" | 18 #include "base/profiler/scoped_tracker.h" |
| 18 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 20 #include "ui/accessibility/ax_node_data.h" | 21 #include "ui/accessibility/ax_node_data.h" |
| 22 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| 23 #include "ui/base/cursor/cursor.h" |
| 21 #include "ui/base/default_style.h" | 24 #include "ui/base/default_style.h" |
| 22 #include "ui/base/material_design/material_design_controller.h" | 25 #include "ui/base/material_design/material_design_controller.h" |
| 23 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
| 24 #include "ui/gfx/canvas.h" | 27 #include "ui/gfx/canvas.h" |
| 25 #include "ui/gfx/color_utils.h" | 28 #include "ui/gfx/color_utils.h" |
| 26 #include "ui/gfx/geometry/insets.h" | 29 #include "ui/gfx/geometry/insets.h" |
| 27 #include "ui/gfx/text_elider.h" | 30 #include "ui/gfx/text_elider.h" |
| 28 #include "ui/native_theme/native_theme.h" | 31 #include "ui/native_theme/native_theme.h" |
| 32 #include "ui/views/focus/focus_manager.h" |
| 33 #include "ui/views/native_cursor.h" |
| 34 #include "ui/views/selection_controller.h" |
| 29 | 35 |
| 30 namespace views { | 36 namespace views { |
| 31 // static | 37 // static |
| 32 const char Label::kViewClassName[] = "Label"; | 38 const char Label::kViewClassName[] = "Label"; |
| 33 const int Label::kFocusBorderPadding = 1; | 39 const int Label::kFocusBorderPadding = 1; |
| 34 | 40 |
| 35 Label::Label() : Label(base::string16()) { | 41 Label::Label() : Label(base::string16()) { |
| 36 } | 42 } |
| 37 | 43 |
| 38 Label::Label(const base::string16& text) : Label(text, GetDefaultFontList()) { | 44 Label::Label(const base::string16& text) : Label(text, GetDefaultFontList()) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 | 99 |
| 94 void Label::SetBackgroundColor(SkColor color) { | 100 void Label::SetBackgroundColor(SkColor color) { |
| 95 if (background_color_set_ && background_color_ == color) | 101 if (background_color_set_ && background_color_ == color) |
| 96 return; | 102 return; |
| 97 is_first_paint_text_ = true; | 103 is_first_paint_text_ = true; |
| 98 background_color_ = color; | 104 background_color_ = color; |
| 99 background_color_set_ = true; | 105 background_color_set_ = true; |
| 100 RecalculateColors(); | 106 RecalculateColors(); |
| 101 } | 107 } |
| 102 | 108 |
| 109 void Label::SetSelectionTextColor(SkColor color) { |
| 110 if (selection_text_color_set_ && requested_selection_text_color_ == color) |
| 111 return; |
| 112 is_first_paint_text_ = true; |
| 113 requested_selection_text_color_ = color; |
| 114 selection_text_color_set_ = true; |
| 115 RecalculateColors(); |
| 116 } |
| 117 |
| 118 void Label::SetSelectionBackgroundColor(SkColor color) { |
| 119 if (selection_background_color_set_ && selection_background_color_ == color) |
| 120 return; |
| 121 is_first_paint_text_ = true; |
| 122 selection_background_color_ = color; |
| 123 selection_background_color_set_ = true; |
| 124 RecalculateColors(); |
| 125 } |
| 126 |
| 103 void Label::SetShadows(const gfx::ShadowValues& shadows) { | 127 void Label::SetShadows(const gfx::ShadowValues& shadows) { |
| 104 // TODO(mukai): early exit if the specified shadows are same. | 128 // TODO(mukai): early exit if the specified shadows are same. |
| 105 is_first_paint_text_ = true; | 129 is_first_paint_text_ = true; |
| 106 render_text_->set_shadows(shadows); | 130 render_text_->set_shadows(shadows); |
| 107 ResetLayout(); | 131 ResetLayout(); |
| 108 } | 132 } |
| 109 | 133 |
| 110 void Label::SetSubpixelRenderingEnabled(bool subpixel_rendering_enabled) { | 134 void Label::SetSubpixelRenderingEnabled(bool subpixel_rendering_enabled) { |
| 111 if (subpixel_rendering_enabled_ == subpixel_rendering_enabled) | 135 if (subpixel_rendering_enabled_ == subpixel_rendering_enabled) |
| 112 return; | 136 return; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 140 void Label::SetMultiLine(bool multi_line) { | 164 void Label::SetMultiLine(bool multi_line) { |
| 141 DCHECK(!multi_line || (elide_behavior_ == gfx::ELIDE_TAIL || | 165 DCHECK(!multi_line || (elide_behavior_ == gfx::ELIDE_TAIL || |
| 142 elide_behavior_ == gfx::NO_ELIDE)); | 166 elide_behavior_ == gfx::NO_ELIDE)); |
| 143 if (this->multi_line() == multi_line) | 167 if (this->multi_line() == multi_line) |
| 144 return; | 168 return; |
| 145 is_first_paint_text_ = true; | 169 is_first_paint_text_ = true; |
| 146 multi_line_ = multi_line; | 170 multi_line_ = multi_line; |
| 147 if (render_text_->MultilineSupported()) | 171 if (render_text_->MultilineSupported()) |
| 148 render_text_->SetMultiline(multi_line); | 172 render_text_->SetMultiline(multi_line); |
| 149 render_text_->SetReplaceNewlineCharsWithSymbols(!multi_line); | 173 render_text_->SetReplaceNewlineCharsWithSymbols(!multi_line); |
| 174 if (multi_line) |
| 175 SetSelectable(false); |
| 150 ResetLayout(); | 176 ResetLayout(); |
| 151 } | 177 } |
| 152 | 178 |
| 153 void Label::SetObscured(bool obscured) { | 179 void Label::SetObscured(bool obscured) { |
| 154 if (this->obscured() == obscured) | 180 if (this->obscured() == obscured) |
| 155 return; | 181 return; |
| 156 is_first_paint_text_ = true; | 182 is_first_paint_text_ = true; |
| 157 render_text_->SetObscured(obscured); | 183 render_text_->SetObscured(obscured); |
| 158 ResetLayout(); | 184 ResetLayout(); |
| 159 } | 185 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 } | 223 } |
| 198 | 224 |
| 199 void Label::SetMaximumWidth(int max_width) { | 225 void Label::SetMaximumWidth(int max_width) { |
| 200 DCHECK(multi_line()); | 226 DCHECK(multi_line()); |
| 201 DCHECK_EQ(0, fixed_width_); | 227 DCHECK_EQ(0, fixed_width_); |
| 202 max_width_ = max_width; | 228 max_width_ = max_width; |
| 203 SizeToPreferredSize(); | 229 SizeToPreferredSize(); |
| 204 } | 230 } |
| 205 | 231 |
| 206 base::string16 Label::GetDisplayTextForTesting() { | 232 base::string16 Label::GetDisplayTextForTesting() { |
| 207 lines_.clear(); | 233 ClearRenderTextLines(); |
| 208 MaybeBuildRenderTextLines(); | 234 MaybeBuildRenderTextLines(); |
| 209 base::string16 result; | 235 base::string16 result; |
| 210 if (lines_.empty()) | 236 if (lines_.empty()) |
| 211 return result; | 237 return result; |
| 212 result.append(lines_[0]->GetDisplayText()); | 238 result.append(lines_[0]->GetDisplayText()); |
| 213 for (size_t i = 1; i < lines_.size(); ++i) { | 239 for (size_t i = 1; i < lines_.size(); ++i) { |
| 214 result.append(1, '\n'); | 240 result.append(1, '\n'); |
| 215 result.append(lines_[i]->GetDisplayText()); | 241 result.append(lines_[i]->GetDisplayText()); |
| 216 } | 242 } |
| 217 return result; | 243 return result; |
| 218 } | 244 } |
| 219 | 245 |
| 246 bool Label::IsSelectionSupported() const { |
| 247 return !multi_line() && render_text_->IsSelectionSupported(); |
| 248 } |
| 249 |
| 250 bool Label::SetSelectable(bool value) { |
| 251 if (value == selectable()) |
| 252 return true; |
| 253 |
| 254 if (!value) { |
| 255 ClearSelection(); |
| 256 selection_controller_.reset(); |
| 257 return true; |
| 258 } |
| 259 |
| 260 if (!IsSelectionSupported()) |
| 261 return false; |
| 262 |
| 263 selection_controller_ = base::MakeUnique<SelectionController>(this); |
| 264 return true; |
| 265 } |
| 266 |
| 267 bool Label::HasSelection() const { |
| 268 const gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 269 return render_text ? !render_text->selection().is_empty() : false; |
| 270 } |
| 271 |
| 272 void Label::SelectAll() { |
| 273 gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 274 if (!render_text) |
| 275 return; |
| 276 render_text->SelectAll(false); |
| 277 SchedulePaint(); |
| 278 } |
| 279 |
| 280 void Label::ClearSelection() { |
| 281 gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 282 if (!render_text) |
| 283 return; |
| 284 render_text->ClearSelection(); |
| 285 SchedulePaint(); |
| 286 } |
| 287 |
| 288 void Label::SelectRange(const gfx::Range& range) { |
| 289 gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 290 if (render_text && render_text->SelectRange(range)) |
| 291 SchedulePaint(); |
| 292 } |
| 293 |
| 220 gfx::Insets Label::GetInsets() const { | 294 gfx::Insets Label::GetInsets() const { |
| 221 gfx::Insets insets = View::GetInsets(); | 295 gfx::Insets insets = View::GetInsets(); |
| 222 if (focus_behavior() != FocusBehavior::NEVER) { | 296 if (focus_behavior() != FocusBehavior::NEVER) { |
| 223 insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding, | 297 insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding, |
| 224 kFocusBorderPadding, kFocusBorderPadding); | 298 kFocusBorderPadding, kFocusBorderPadding); |
| 225 } | 299 } |
| 226 return insets; | 300 return insets; |
| 227 } | 301 } |
| 228 | 302 |
| 229 int Label::GetBaseline() const { | 303 int Label::GetBaseline() const { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 height = render_text_->GetStringSize().height(); | 363 height = render_text_->GetStringSize().height(); |
| 290 } else { | 364 } else { |
| 291 std::vector<base::string16> lines = GetLinesForWidth(w); | 365 std::vector<base::string16> lines = GetLinesForWidth(w); |
| 292 height = lines.size() * std::max(line_height(), font_list().GetHeight()); | 366 height = lines.size() * std::max(line_height(), font_list().GetHeight()); |
| 293 } | 367 } |
| 294 height -= gfx::ShadowValue::GetMargin(render_text_->shadows()).height(); | 368 height -= gfx::ShadowValue::GetMargin(render_text_->shadows()).height(); |
| 295 return height + GetInsets().height(); | 369 return height + GetInsets().height(); |
| 296 } | 370 } |
| 297 | 371 |
| 298 void Label::Layout() { | 372 void Label::Layout() { |
| 299 lines_.clear(); | 373 ClearRenderTextLines(); |
| 300 } | 374 } |
| 301 | 375 |
| 302 const char* Label::GetClassName() const { | 376 const char* Label::GetClassName() const { |
| 303 return kViewClassName; | 377 return kViewClassName; |
| 304 } | 378 } |
| 305 | 379 |
| 306 View* Label::GetTooltipHandlerForPoint(const gfx::Point& point) { | 380 View* Label::GetTooltipHandlerForPoint(const gfx::Point& point) { |
| 307 if (!handles_tooltips_ || | 381 if (!handles_tooltips_ || |
| 308 (tooltip_text_.empty() && !ShouldShowDefaultTooltip())) | 382 (tooltip_text_.empty() && !ShouldShowDefaultTooltip())) |
| 309 return NULL; | 383 return NULL; |
| 310 | 384 |
| 311 return HitTestPoint(point) ? this : NULL; | 385 return HitTestPoint(point) ? this : NULL; |
| 312 } | 386 } |
| 313 | 387 |
| 314 bool Label::CanProcessEventsWithinSubtree() const { | 388 bool Label::CanProcessEventsWithinSubtree() const { |
| 315 // Send events to the parent view for handling. | 389 return !!GetRenderTextForSelectionController(); |
| 316 return false; | |
| 317 } | 390 } |
| 318 | 391 |
| 319 void Label::GetAccessibleNodeData(ui::AXNodeData* node_data) { | 392 void Label::GetAccessibleNodeData(ui::AXNodeData* node_data) { |
| 320 node_data->role = ui::AX_ROLE_STATIC_TEXT; | 393 node_data->role = ui::AX_ROLE_STATIC_TEXT; |
| 321 node_data->AddStateFlag(ui::AX_STATE_READ_ONLY); | 394 node_data->AddStateFlag(ui::AX_STATE_READ_ONLY); |
| 322 // Note that |render_text_| is never elided (see the comment in Init() too). | 395 // Note that |render_text_| is never elided (see the comment in Init() too). |
| 323 node_data->SetName(render_text_->GetDisplayText()); | 396 node_data->SetName(render_text_->GetDisplayText()); |
| 324 } | 397 } |
| 325 | 398 |
| 326 bool Label::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const { | 399 bool Label::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 343 | 416 |
| 344 void Label::OnEnabledChanged() { | 417 void Label::OnEnabledChanged() { |
| 345 ApplyTextColors(); | 418 ApplyTextColors(); |
| 346 View::OnEnabledChanged(); | 419 View::OnEnabledChanged(); |
| 347 } | 420 } |
| 348 | 421 |
| 349 std::unique_ptr<gfx::RenderText> Label::CreateRenderText( | 422 std::unique_ptr<gfx::RenderText> Label::CreateRenderText( |
| 350 const base::string16& text, | 423 const base::string16& text, |
| 351 gfx::HorizontalAlignment alignment, | 424 gfx::HorizontalAlignment alignment, |
| 352 gfx::DirectionalityMode directionality, | 425 gfx::DirectionalityMode directionality, |
| 353 gfx::ElideBehavior elide_behavior) { | 426 gfx::ElideBehavior elide_behavior) const { |
| 354 std::unique_ptr<gfx::RenderText> render_text( | 427 std::unique_ptr<gfx::RenderText> render_text( |
| 355 render_text_->CreateInstanceOfSameType()); | 428 render_text_->CreateInstanceOfSameType()); |
| 356 render_text->SetHorizontalAlignment(alignment); | 429 render_text->SetHorizontalAlignment(alignment); |
| 357 render_text->SetDirectionalityMode(directionality); | 430 render_text->SetDirectionalityMode(directionality); |
| 358 render_text->SetElideBehavior(elide_behavior); | 431 render_text->SetElideBehavior(elide_behavior); |
| 359 render_text->SetObscured(obscured()); | 432 render_text->SetObscured(obscured()); |
| 360 render_text->SetMinLineHeight(line_height()); | 433 render_text->SetMinLineHeight(line_height()); |
| 361 render_text->SetFontList(font_list()); | 434 render_text->SetFontList(font_list()); |
| 362 render_text->set_shadows(shadows()); | 435 render_text->set_shadows(shadows()); |
| 363 render_text->SetCursorEnabled(false); | 436 render_text->SetCursorEnabled(false); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 382 // TODO(ckocagil): Remove ScopedTracker below once crbug.com/441028 is | 455 // TODO(ckocagil): Remove ScopedTracker below once crbug.com/441028 is |
| 383 // fixed. | 456 // fixed. |
| 384 tracked_objects::ScopedTracker tracking_profile( | 457 tracked_objects::ScopedTracker tracking_profile( |
| 385 FROM_HERE_WITH_EXPLICIT_FUNCTION("441028 First PaintText()")); | 458 FROM_HERE_WITH_EXPLICIT_FUNCTION("441028 First PaintText()")); |
| 386 | 459 |
| 387 is_first_paint_text_ = false; | 460 is_first_paint_text_ = false; |
| 388 PaintText(canvas); | 461 PaintText(canvas); |
| 389 } else { | 462 } else { |
| 390 PaintText(canvas); | 463 PaintText(canvas); |
| 391 } | 464 } |
| 392 if (HasFocus() && !ui::MaterialDesignController::IsSecondaryUiMaterial()) | 465 |
| 466 // Check for IsAccessibilityFocusable() to prevent drawing a focus rect for |
| 467 // non-focusable labels with selection, which are given focus explicitly in |
| 468 // OnMousePressed. |
| 469 if (HasFocus() && !ui::MaterialDesignController::IsSecondaryUiMaterial() && |
| 470 IsAccessibilityFocusable()) { |
| 393 canvas->DrawFocusRect(GetFocusBounds()); | 471 canvas->DrawFocusRect(GetFocusBounds()); |
| 472 } |
| 394 } | 473 } |
| 395 | 474 |
| 396 void Label::OnNativeThemeChanged(const ui::NativeTheme* theme) { | 475 void Label::OnNativeThemeChanged(const ui::NativeTheme* theme) { |
| 397 UpdateColorsFromTheme(theme); | 476 UpdateColorsFromTheme(theme); |
| 398 } | 477 } |
| 399 | 478 |
| 479 gfx::NativeCursor Label::GetCursor(const ui::MouseEvent& event) { |
| 480 return GetRenderTextForSelectionController() ? GetNativeIBeamCursor() |
| 481 : gfx::kNullCursor; |
| 482 } |
| 483 |
| 484 void Label::OnFocus() { |
| 485 gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 486 if (render_text) { |
| 487 render_text->set_focused(true); |
| 488 SchedulePaint(); |
| 489 } |
| 490 View::OnFocus(); |
| 491 } |
| 492 |
| 493 void Label::OnBlur() { |
| 494 gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 495 if (render_text) { |
| 496 render_text->set_focused(false); |
| 497 SchedulePaint(); |
| 498 } |
| 499 View::OnBlur(); |
| 500 } |
| 501 |
| 502 bool Label::OnMousePressed(const ui::MouseEvent& event) { |
| 503 if (!GetRenderTextForSelectionController()) |
| 504 return false; |
| 505 |
| 506 // RequestFocus() won't work when the label has FocusBehavior::NEVER. Hence |
| 507 // explicitly set the focused view. |
| 508 // TODO(karandeepb): If a widget with a label having FocusBehavior::NEVER as |
| 509 // the currently focused view (due to selection) was to lose focus, focus |
| 510 // won't be restored to the label (and hence a text selection won't be drawn) |
| 511 // when the widget gets focus again. Fix this. |
| 512 // Tracked in https://crbug.com/630365. |
| 513 if ((event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) && |
| 514 GetFocusManager()) { |
| 515 GetFocusManager()->SetFocusedView(this); |
| 516 } |
| 517 |
| 518 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 519 if (event.IsOnlyMiddleMouseButton() && GetFocusManager()) |
| 520 GetFocusManager()->SetFocusedView(this); |
| 521 #endif |
| 522 |
| 523 return selection_controller_->OnMousePressed(event, false); |
| 524 } |
| 525 |
| 526 bool Label::OnMouseDragged(const ui::MouseEvent& event) { |
| 527 if (!GetRenderTextForSelectionController()) |
| 528 return false; |
| 529 |
| 530 return selection_controller_->OnMouseDragged(event); |
| 531 } |
| 532 |
| 533 void Label::OnMouseReleased(const ui::MouseEvent& event) { |
| 534 if (!GetRenderTextForSelectionController()) |
| 535 return; |
| 536 |
| 537 selection_controller_->OnMouseReleased(event); |
| 538 } |
| 539 |
| 540 void Label::OnMouseCaptureLost() { |
| 541 if (!GetRenderTextForSelectionController()) |
| 542 return; |
| 543 |
| 544 selection_controller_->OnMouseCaptureLost(); |
| 545 } |
| 546 |
| 400 void Label::OnDeviceScaleFactorChanged(float device_scale_factor) { | 547 void Label::OnDeviceScaleFactorChanged(float device_scale_factor) { |
| 401 View::OnDeviceScaleFactorChanged(device_scale_factor); | 548 View::OnDeviceScaleFactorChanged(device_scale_factor); |
| 402 // When the device scale factor is changed, some font rendering parameters is | 549 // When the device scale factor is changed, some font rendering parameters is |
| 403 // changed (especially, hinting). The bounding box of the text has to be | 550 // changed (especially, hinting). The bounding box of the text has to be |
| 404 // re-computed based on the new parameters. See crbug.com/441439 | 551 // re-computed based on the new parameters. See crbug.com/441439 |
| 405 ResetLayout(); | 552 ResetLayout(); |
| 406 } | 553 } |
| 407 | 554 |
| 408 void Label::VisibilityChanged(View* starting_from, bool is_visible) { | 555 void Label::VisibilityChanged(View* starting_from, bool is_visible) { |
| 409 if (!is_visible) | 556 if (!is_visible) |
| 410 lines_.clear(); | 557 ClearRenderTextLines(); |
| 558 } |
| 559 |
| 560 gfx::RenderText* Label::GetRenderTextForSelectionController() { |
| 561 return const_cast<gfx::RenderText*>( |
| 562 static_cast<const Label*>(this)->GetRenderTextForSelectionController()); |
| 563 } |
| 564 |
| 565 bool Label::IsReadOnly() const { |
| 566 return true; |
| 567 } |
| 568 |
| 569 bool Label::SupportsDrag() const { |
| 570 // TODO(crbug.com/661379): Labels should support dragging selected text. |
| 571 return false; |
| 572 } |
| 573 |
| 574 bool Label::HasTextBeingDragged() const { |
| 575 return false; |
| 576 } |
| 577 |
| 578 void Label::SetTextBeingDragged(bool value) { |
| 579 NOTREACHED(); |
| 580 } |
| 581 |
| 582 int Label::GetViewHeight() const { |
| 583 return height(); |
| 584 } |
| 585 |
| 586 int Label::GetViewWidth() const { |
| 587 return width(); |
| 588 } |
| 589 |
| 590 int Label::GetDragSelectionDelay() const { |
| 591 // Labels don't need to use a repeating timer to update the drag selection. |
| 592 // Since the cursor is disabled for labels, a selection outside the display |
| 593 // area won't change the text in the display area. It is expected that all the |
| 594 // text will fit in the display area for labels anyway. |
| 595 return 0; |
| 596 } |
| 597 |
| 598 void Label::OnBeforePointerAction() {} |
| 599 |
| 600 void Label::OnAfterPointerAction(bool text_changed, bool selection_changed) { |
| 601 DCHECK(!text_changed); |
| 602 if (selection_changed) |
| 603 SchedulePaint(); |
| 604 } |
| 605 |
| 606 bool Label::PasteSelectionClipboard() { |
| 607 NOTREACHED(); |
| 608 return false; |
| 609 } |
| 610 |
| 611 void Label::UpdateSelectionClipboard() { |
| 612 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 613 if (!obscured()) { |
| 614 const gfx::RenderText* render_text = GetRenderTextForSelectionController(); |
| 615 DCHECK(render_text); |
| 616 const base::string16 selected_text = |
| 617 render_text->GetTextFromRange(render_text->selection()); |
| 618 ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_SELECTION) |
| 619 .WriteText(selected_text); |
| 620 } |
| 621 #endif |
| 622 } |
| 623 |
| 624 const gfx::RenderText* Label::GetRenderTextForSelectionController() const { |
| 625 if (!selectable()) |
| 626 return nullptr; |
| 627 MaybeBuildRenderTextLines(); |
| 628 |
| 629 // This may happen when the content bounds of the view are empty. |
| 630 if (lines_.empty()) |
| 631 return nullptr; |
| 632 |
| 633 DCHECK_EQ(1u, lines_.size()); |
| 634 return lines_[0].get(); |
| 411 } | 635 } |
| 412 | 636 |
| 413 void Label::Init(const base::string16& text, const gfx::FontList& font_list) { | 637 void Label::Init(const base::string16& text, const gfx::FontList& font_list) { |
| 414 render_text_.reset(gfx::RenderText::CreateInstance()); | 638 render_text_.reset(gfx::RenderText::CreateInstance()); |
| 415 render_text_->SetHorizontalAlignment(gfx::ALIGN_CENTER); | 639 render_text_->SetHorizontalAlignment(gfx::ALIGN_CENTER); |
| 416 render_text_->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT); | 640 render_text_->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT); |
| 417 // NOTE: |render_text_| should not be elided at all. This is used to keep some | 641 // NOTE: |render_text_| should not be elided at all. This is used to keep some |
| 418 // properties and to compute the size of the string. | 642 // properties and to compute the size of the string. |
| 419 render_text_->SetElideBehavior(gfx::NO_ELIDE); | 643 render_text_->SetElideBehavior(gfx::NO_ELIDE); |
| 420 render_text_->SetFontList(font_list); | 644 render_text_->SetFontList(font_list); |
| 421 render_text_->SetCursorEnabled(false); | 645 render_text_->SetCursorEnabled(false); |
| 422 render_text_->SetWordWrapBehavior(gfx::TRUNCATE_LONG_WORDS); | 646 render_text_->SetWordWrapBehavior(gfx::TRUNCATE_LONG_WORDS); |
| 423 | 647 |
| 424 elide_behavior_ = gfx::ELIDE_TAIL; | 648 elide_behavior_ = gfx::ELIDE_TAIL; |
| 649 stored_selection_range_ = gfx::Range::InvalidRange(); |
| 425 enabled_color_set_ = disabled_color_set_ = background_color_set_ = false; | 650 enabled_color_set_ = disabled_color_set_ = background_color_set_ = false; |
| 651 selection_text_color_set_ = selection_background_color_set_ = false; |
| 426 subpixel_rendering_enabled_ = true; | 652 subpixel_rendering_enabled_ = true; |
| 427 auto_color_readability_ = true; | 653 auto_color_readability_ = true; |
| 428 multi_line_ = false; | 654 multi_line_ = false; |
| 429 UpdateColorsFromTheme(GetNativeTheme()); | 655 UpdateColorsFromTheme(GetNativeTheme()); |
| 430 handles_tooltips_ = true; | 656 handles_tooltips_ = true; |
| 431 collapse_when_hidden_ = false; | 657 collapse_when_hidden_ = false; |
| 432 fixed_width_ = 0; | 658 fixed_width_ = 0; |
| 433 max_width_ = 0; | 659 max_width_ = 0; |
| 434 is_first_paint_text_ = true; | 660 is_first_paint_text_ = true; |
| 435 SetText(text); | 661 SetText(text); |
| 436 } | 662 } |
| 437 | 663 |
| 438 void Label::ResetLayout() { | 664 void Label::ResetLayout() { |
| 439 InvalidateLayout(); | 665 InvalidateLayout(); |
| 440 PreferredSizeChanged(); | 666 PreferredSizeChanged(); |
| 441 SchedulePaint(); | 667 SchedulePaint(); |
| 442 lines_.clear(); | 668 ClearRenderTextLines(); |
| 443 } | 669 } |
| 444 | 670 |
| 445 void Label::MaybeBuildRenderTextLines() { | 671 void Label::MaybeBuildRenderTextLines() const { |
| 446 if (!lines_.empty()) | 672 if (!lines_.empty()) |
| 447 return; | 673 return; |
| 448 | 674 |
| 449 gfx::Rect rect = GetContentsBounds(); | 675 gfx::Rect rect = GetContentsBounds(); |
| 450 if (focus_behavior() != FocusBehavior::NEVER) | 676 if (focus_behavior() != FocusBehavior::NEVER) |
| 451 rect.Inset(kFocusBorderPadding, kFocusBorderPadding); | 677 rect.Inset(kFocusBorderPadding, kFocusBorderPadding); |
| 452 if (rect.IsEmpty()) | 678 if (rect.IsEmpty()) |
| 453 return; | 679 return; |
| 454 rect.Inset(-gfx::ShadowValue::GetMargin(shadows())); | 680 rect.Inset(-gfx::ShadowValue::GetMargin(shadows())); |
| 455 | 681 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 468 // Text eliding is not supported for multi-lined Labels. | 694 // Text eliding is not supported for multi-lined Labels. |
| 469 // TODO(mukai): Add multi-lined elided text support. | 695 // TODO(mukai): Add multi-lined elided text support. |
| 470 gfx::ElideBehavior elide_behavior = | 696 gfx::ElideBehavior elide_behavior = |
| 471 multi_line() ? gfx::NO_ELIDE : elide_behavior_; | 697 multi_line() ? gfx::NO_ELIDE : elide_behavior_; |
| 472 if (!multi_line() || render_text_->MultilineSupported()) { | 698 if (!multi_line() || render_text_->MultilineSupported()) { |
| 473 std::unique_ptr<gfx::RenderText> render_text = | 699 std::unique_ptr<gfx::RenderText> render_text = |
| 474 CreateRenderText(text(), alignment, directionality, elide_behavior); | 700 CreateRenderText(text(), alignment, directionality, elide_behavior); |
| 475 render_text->SetDisplayRect(rect); | 701 render_text->SetDisplayRect(rect); |
| 476 render_text->SetMultiline(multi_line()); | 702 render_text->SetMultiline(multi_line()); |
| 477 render_text->SetWordWrapBehavior(render_text_->word_wrap_behavior()); | 703 render_text->SetWordWrapBehavior(render_text_->word_wrap_behavior()); |
| 704 |
| 705 // Setup render text for selection controller. |
| 706 if (selectable()) { |
| 707 render_text->set_focused(HasFocus()); |
| 708 if (stored_selection_range_.IsValid()) |
| 709 render_text->SelectRange(stored_selection_range_); |
| 710 } |
| 711 |
| 478 lines_.push_back(std::move(render_text)); | 712 lines_.push_back(std::move(render_text)); |
| 479 } else { | 713 } else { |
| 480 std::vector<base::string16> lines = GetLinesForWidth(rect.width()); | 714 std::vector<base::string16> lines = GetLinesForWidth(rect.width()); |
| 481 if (lines.size() > 1) | 715 if (lines.size() > 1) |
| 482 rect.set_height(std::max(line_height(), font_list().GetHeight())); | 716 rect.set_height(std::max(line_height(), font_list().GetHeight())); |
| 483 | 717 |
| 484 const int bottom = GetContentsBounds().bottom(); | 718 const int bottom = GetContentsBounds().bottom(); |
| 485 for (size_t i = 0; i < lines.size() && rect.y() <= bottom; ++i) { | 719 for (size_t i = 0; i < lines.size() && rect.y() <= bottom; ++i) { |
| 486 std::unique_ptr<gfx::RenderText> line = | 720 std::unique_ptr<gfx::RenderText> line = |
| 487 CreateRenderText(lines[i], alignment, directionality, elide_behavior); | 721 CreateRenderText(lines[i], alignment, directionality, elide_behavior); |
| 488 line->SetDisplayRect(rect); | 722 line->SetDisplayRect(rect); |
| 489 lines_.push_back(std::move(line)); | 723 lines_.push_back(std::move(line)); |
| 490 rect.set_y(rect.y() + rect.height()); | 724 rect.set_y(rect.y() + rect.height()); |
| 491 } | 725 } |
| 492 // Append the remaining text to the last visible line. | 726 // Append the remaining text to the last visible line. |
| 493 for (size_t i = lines_.size(); i < lines.size(); ++i) | 727 for (size_t i = lines_.size(); i < lines.size(); ++i) |
| 494 lines_.back()->SetText(lines_.back()->text() + lines[i]); | 728 lines_.back()->SetText(lines_.back()->text() + lines[i]); |
| 495 } | 729 } |
| 730 |
| 731 stored_selection_range_ = gfx::Range::InvalidRange(); |
| 496 ApplyTextColors(); | 732 ApplyTextColors(); |
| 497 } | 733 } |
| 498 | 734 |
| 499 gfx::Rect Label::GetFocusBounds() { | 735 gfx::Rect Label::GetFocusBounds() const { |
| 500 MaybeBuildRenderTextLines(); | 736 MaybeBuildRenderTextLines(); |
| 501 | 737 |
| 502 gfx::Rect focus_bounds; | 738 gfx::Rect focus_bounds; |
| 503 if (lines_.empty()) { | 739 if (lines_.empty()) { |
| 504 focus_bounds = gfx::Rect(GetTextSize()); | 740 focus_bounds = gfx::Rect(GetTextSize()); |
| 505 } else { | 741 } else { |
| 506 for (size_t i = 0; i < lines_.size(); ++i) { | 742 for (size_t i = 0; i < lines_.size(); ++i) { |
| 507 gfx::Point origin; | 743 gfx::Point origin; |
| 508 origin += lines_[i]->GetLineOffset(0); | 744 origin += lines_[i]->GetLineOffset(0); |
| 509 focus_bounds.Union(gfx::Rect(origin, lines_[i]->GetStringSize())); | 745 focus_bounds.Union(gfx::Rect(origin, lines_[i]->GetStringSize())); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 | 800 |
| 565 void Label::RecalculateColors() { | 801 void Label::RecalculateColors() { |
| 566 actual_enabled_color_ = auto_color_readability_ ? | 802 actual_enabled_color_ = auto_color_readability_ ? |
| 567 color_utils::GetReadableColor(requested_enabled_color_, | 803 color_utils::GetReadableColor(requested_enabled_color_, |
| 568 background_color_) : | 804 background_color_) : |
| 569 requested_enabled_color_; | 805 requested_enabled_color_; |
| 570 actual_disabled_color_ = auto_color_readability_ ? | 806 actual_disabled_color_ = auto_color_readability_ ? |
| 571 color_utils::GetReadableColor(requested_disabled_color_, | 807 color_utils::GetReadableColor(requested_disabled_color_, |
| 572 background_color_) : | 808 background_color_) : |
| 573 requested_disabled_color_; | 809 requested_disabled_color_; |
| 810 actual_selection_text_color_ = |
| 811 auto_color_readability_ |
| 812 ? color_utils::GetReadableColor(requested_selection_text_color_, |
| 813 selection_background_color_) |
| 814 : requested_selection_text_color_; |
| 574 | 815 |
| 575 ApplyTextColors(); | 816 ApplyTextColors(); |
| 576 SchedulePaint(); | 817 SchedulePaint(); |
| 577 } | 818 } |
| 578 | 819 |
| 579 void Label::ApplyTextColors() { | 820 void Label::ApplyTextColors() const { |
| 580 SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_; | 821 SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_; |
| 581 bool subpixel_rendering_suppressed = | 822 bool subpixel_rendering_suppressed = |
| 582 SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_; | 823 SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_; |
| 583 for (size_t i = 0; i < lines_.size(); ++i) { | 824 for (size_t i = 0; i < lines_.size(); ++i) { |
| 584 lines_[i]->SetColor(color); | 825 lines_[i]->SetColor(color); |
| 826 lines_[i]->set_selection_color(actual_selection_text_color_); |
| 827 lines_[i]->set_selection_background_focused_color( |
| 828 selection_background_color_); |
| 585 lines_[i]->set_subpixel_rendering_suppressed(subpixel_rendering_suppressed); | 829 lines_[i]->set_subpixel_rendering_suppressed(subpixel_rendering_suppressed); |
| 586 } | 830 } |
| 587 } | 831 } |
| 588 | 832 |
| 589 void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) { | 833 void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) { |
| 590 if (!enabled_color_set_) { | 834 if (!enabled_color_set_) { |
| 591 requested_enabled_color_ = theme->GetSystemColor( | 835 requested_enabled_color_ = theme->GetSystemColor( |
| 592 ui::NativeTheme::kColorId_LabelEnabledColor); | 836 ui::NativeTheme::kColorId_LabelEnabledColor); |
| 593 } | 837 } |
| 594 if (!disabled_color_set_) { | 838 if (!disabled_color_set_) { |
| 595 requested_disabled_color_ = theme->GetSystemColor( | 839 requested_disabled_color_ = theme->GetSystemColor( |
| 596 ui::NativeTheme::kColorId_LabelDisabledColor); | 840 ui::NativeTheme::kColorId_LabelDisabledColor); |
| 597 } | 841 } |
| 598 if (!background_color_set_) { | 842 if (!background_color_set_) { |
| 599 background_color_ = | 843 background_color_ = |
| 600 theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground); | 844 theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground); |
| 601 } | 845 } |
| 846 if (!selection_text_color_set_) { |
| 847 requested_selection_text_color_ = theme->GetSystemColor( |
| 848 ui::NativeTheme::kColorId_LabelTextSelectionColor); |
| 849 } |
| 850 if (!selection_background_color_set_) { |
| 851 selection_background_color_ = theme->GetSystemColor( |
| 852 ui::NativeTheme::kColorId_LabelTextSelectionBackgroundFocused); |
| 853 } |
| 602 RecalculateColors(); | 854 RecalculateColors(); |
| 603 } | 855 } |
| 604 | 856 |
| 605 bool Label::ShouldShowDefaultTooltip() const { | 857 bool Label::ShouldShowDefaultTooltip() const { |
| 606 const gfx::Size text_size = GetTextSize(); | 858 const gfx::Size text_size = GetTextSize(); |
| 607 const gfx::Size size = GetContentsBounds().size(); | 859 const gfx::Size size = GetContentsBounds().size(); |
| 608 return !obscured() && (text_size.width() > size.width() || | 860 return !obscured() && (text_size.width() > size.width() || |
| 609 (multi_line() && text_size.height() > size.height())); | 861 (multi_line() && text_size.height() > size.height())); |
| 610 } | 862 } |
| 611 | 863 |
| 864 void Label::ClearRenderTextLines() const { |
| 865 // Persist the selection range if there is an active selection. |
| 866 if (HasSelection()) { |
| 867 stored_selection_range_ = |
| 868 GetRenderTextForSelectionController()->selection(); |
| 869 } |
| 870 lines_.clear(); |
| 871 } |
| 872 |
| 612 } // namespace views | 873 } // namespace views |
| OLD | NEW |