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