paint_info.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/views/paint_info.h"
  5. #include "base/feature_list.h"
  6. #include "ui/views/views_features.h"
  7. namespace views {
  8. namespace {
  9. gfx::Rect GetSnappedRecordingBoundsInternal(
  10. const gfx::Rect& paint_recording_bounds,
  11. float device_scale_factor,
  12. const gfx::Size& parent_size,
  13. const gfx::Rect& child_bounds) {
  14. const gfx::Vector2d& child_origin = child_bounds.OffsetFromOrigin();
  15. int right = child_origin.x() + child_bounds.width();
  16. int bottom = child_origin.y() + child_bounds.height();
  17. int new_x = std::round(child_origin.x() * device_scale_factor);
  18. int new_y = std::round(child_origin.y() * device_scale_factor);
  19. int new_right;
  20. int new_bottom;
  21. bool empty = paint_recording_bounds.IsEmpty();
  22. if (right == parent_size.width() && !empty)
  23. new_right = paint_recording_bounds.width();
  24. else
  25. new_right = std::round(right * device_scale_factor);
  26. if (bottom == parent_size.height() && !empty)
  27. new_bottom = paint_recording_bounds.height();
  28. else
  29. new_bottom = std::round(bottom * device_scale_factor);
  30. return gfx::Rect(new_x + paint_recording_bounds.x(),
  31. new_y + paint_recording_bounds.y(), new_right - new_x,
  32. new_bottom - new_y);
  33. }
  34. // Layer's paint info should use the corner scaling logic to compute
  35. // the recording which is what Views uses to compte the view's
  36. // paint_recording_bounds_, with exception that a view touches the right/bottom
  37. // edges of the parent, and its layer has to be able to paint to these
  38. // edges. Such cases should be handled case by case basis.
  39. gfx::Rect GetViewsLayerRecordingBounds(const ui::PaintContext& context,
  40. const gfx::Rect& child_bounds) {
  41. if (!context.is_pixel_canvas())
  42. return gfx::Rect(child_bounds.size());
  43. return gfx::Rect(GetSnappedRecordingBoundsInternal(
  44. gfx::Rect(), context.device_scale_factor(),
  45. gfx::Size() /* not used */, child_bounds)
  46. .size());
  47. }
  48. } // namespace
  49. // static
  50. PaintInfo PaintInfo::CreateRootPaintInfo(const ui::PaintContext& root_context,
  51. const gfx::Size& size) {
  52. return PaintInfo(root_context, size);
  53. }
  54. // static
  55. PaintInfo PaintInfo::CreateChildPaintInfo(const PaintInfo& parent_paint_info,
  56. const gfx::Rect& bounds,
  57. const gfx::Size& parent_size,
  58. ScaleType scale_type,
  59. bool is_layer,
  60. bool needs_paint) {
  61. return PaintInfo(parent_paint_info, bounds, parent_size, scale_type, is_layer,
  62. needs_paint);
  63. }
  64. PaintInfo::~PaintInfo() = default;
  65. bool PaintInfo::IsPixelCanvas() const {
  66. return context().is_pixel_canvas();
  67. }
  68. bool PaintInfo::ShouldPaint() const {
  69. if (base::FeatureList::IsEnabled(features::kEnableViewPaintOptimization))
  70. return needs_paint_;
  71. return context().IsRectInvalid(gfx::Rect(paint_recording_size()));
  72. }
  73. PaintInfo::PaintInfo(const PaintInfo& other)
  74. : paint_recording_scale_x_(other.paint_recording_scale_x_),
  75. paint_recording_scale_y_(other.paint_recording_scale_y_),
  76. paint_recording_bounds_(other.paint_recording_bounds_),
  77. offset_from_parent_(other.offset_from_parent_),
  78. context_(other.context(), gfx::Vector2d()),
  79. root_context_(nullptr) {}
  80. // The root layer should use the ScaleToEnclosingRect, the same logic that
  81. // cc(chrome compositor) is using.
  82. PaintInfo::PaintInfo(const ui::PaintContext& root_context,
  83. const gfx::Size& size)
  84. : paint_recording_scale_x_(root_context.is_pixel_canvas()
  85. ? root_context.device_scale_factor()
  86. : 1.f),
  87. paint_recording_scale_y_(paint_recording_scale_x_),
  88. paint_recording_bounds_(
  89. gfx::ScaleToEnclosingRect(gfx::Rect(size), paint_recording_scale_x_)),
  90. context_(root_context, gfx::Vector2d()),
  91. root_context_(&root_context) {}
  92. PaintInfo::PaintInfo(const PaintInfo& parent_paint_info,
  93. const gfx::Rect& bounds,
  94. const gfx::Size& parent_size,
  95. ScaleType scale_type,
  96. bool is_layer,
  97. bool needs_paint)
  98. : paint_recording_scale_x_(1.f),
  99. paint_recording_scale_y_(1.f),
  100. paint_recording_bounds_(
  101. is_layer ? GetViewsLayerRecordingBounds(parent_paint_info.context(),
  102. bounds)
  103. : parent_paint_info.GetSnappedRecordingBounds(parent_size,
  104. bounds)),
  105. offset_from_parent_(
  106. paint_recording_bounds_.OffsetFromOrigin() -
  107. parent_paint_info.paint_recording_bounds_.OffsetFromOrigin()),
  108. context_(parent_paint_info.context(), offset_from_parent_),
  109. root_context_(nullptr),
  110. needs_paint_(needs_paint) {
  111. if (IsPixelCanvas()) {
  112. if (scale_type == ScaleType::kUniformScaling) {
  113. paint_recording_scale_x_ = paint_recording_scale_y_ =
  114. context().device_scale_factor();
  115. } else if (scale_type == ScaleType::kScaleWithEdgeSnapping) {
  116. if (bounds.size().width() > 0) {
  117. paint_recording_scale_x_ =
  118. static_cast<float>(paint_recording_bounds_.width()) /
  119. static_cast<float>(bounds.size().width());
  120. }
  121. if (bounds.size().height() > 0) {
  122. paint_recording_scale_y_ =
  123. static_cast<float>(paint_recording_bounds_.height()) /
  124. static_cast<float>(bounds.size().height());
  125. }
  126. }
  127. }
  128. }
  129. gfx::Rect PaintInfo::GetSnappedRecordingBounds(
  130. const gfx::Size& parent_size,
  131. const gfx::Rect& child_bounds) const {
  132. if (!IsPixelCanvas())
  133. return (child_bounds + paint_recording_bounds_.OffsetFromOrigin());
  134. return GetSnappedRecordingBoundsInternal(paint_recording_bounds_,
  135. context().device_scale_factor(),
  136. parent_size, child_bounds);
  137. }
  138. } // namespace views