border.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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
  3. // found in the LICENSE file.
  4. #include "ui/views/border.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "cc/paint/paint_flags.h"
  10. #include "ui/color/color_provider.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/gfx/canvas.h"
  13. #include "ui/gfx/geometry/dip_util.h"
  14. #include "ui/gfx/geometry/insets_conversions.h"
  15. #include "ui/gfx/geometry/rect_f.h"
  16. #include "ui/gfx/scoped_canvas.h"
  17. #include "ui/views/painter.h"
  18. #include "ui/views/view.h"
  19. namespace views {
  20. namespace {
  21. // A simple border with different thicknesses on each side and single color.
  22. class SolidSidedBorder : public Border {
  23. public:
  24. SolidSidedBorder(const gfx::Insets& insets, SkColor color);
  25. SolidSidedBorder(const SolidSidedBorder&) = delete;
  26. SolidSidedBorder& operator=(const SolidSidedBorder&) = delete;
  27. // Overridden from Border:
  28. void Paint(const View& view, gfx::Canvas* canvas) override;
  29. gfx::Insets GetInsets() const override;
  30. gfx::Size GetMinimumSize() const override;
  31. private:
  32. const gfx::Insets insets_;
  33. };
  34. SolidSidedBorder::SolidSidedBorder(const gfx::Insets& insets, SkColor color)
  35. : Border(color), insets_(insets) {}
  36. void SolidSidedBorder::Paint(const View& view, gfx::Canvas* canvas) {
  37. // Undo DSF so that we can be sure to draw an integral number of pixels for
  38. // the border. Integral scale factors should be unaffected by this, but for
  39. // fractional scale factors this ensures sharp lines.
  40. gfx::ScopedCanvas scoped(canvas);
  41. float dsf = canvas->UndoDeviceScaleFactor();
  42. gfx::RectF scaled_bounds;
  43. if (view.layer()) {
  44. scaled_bounds = gfx::ConvertRectToPixels(
  45. view.GetLocalBounds(), view.layer()->device_scale_factor());
  46. } else {
  47. scaled_bounds = gfx::RectF(view.GetLocalBounds());
  48. scaled_bounds.Scale(dsf);
  49. }
  50. gfx::InsetsF insets_in_pixels(
  51. gfx::ToFlooredInsets(gfx::ConvertInsetsToPixels(insets_, dsf)));
  52. scaled_bounds.Inset(insets_in_pixels);
  53. canvas->sk_canvas()->clipRect(gfx::RectFToSkRect(scaled_bounds),
  54. SkClipOp::kDifference, true);
  55. canvas->DrawColor(color());
  56. }
  57. gfx::Insets SolidSidedBorder::GetInsets() const {
  58. return insets_;
  59. }
  60. gfx::Size SolidSidedBorder::GetMinimumSize() const {
  61. return gfx::Size(insets_.width(), insets_.height());
  62. }
  63. class ThemedSolidSidedBorder : public SolidSidedBorder {
  64. public:
  65. ThemedSolidSidedBorder(const gfx::Insets& insets, ui::ColorId color_id);
  66. // SolidSidedBorder:
  67. void Paint(const View& view, gfx::Canvas* canvas) override;
  68. void OnViewThemeChanged(View* view) override;
  69. private:
  70. ui::ColorId color_id_;
  71. };
  72. ThemedSolidSidedBorder::ThemedSolidSidedBorder(const gfx::Insets& insets,
  73. ui::ColorId color_id)
  74. : SolidSidedBorder(insets, gfx::kPlaceholderColor), color_id_(color_id) {}
  75. void ThemedSolidSidedBorder::Paint(const View& view, gfx::Canvas* canvas) {
  76. set_color(view.GetColorProvider()->GetColor(color_id_));
  77. SolidSidedBorder::Paint(view, canvas);
  78. }
  79. void ThemedSolidSidedBorder::OnViewThemeChanged(View* view) {
  80. view->SchedulePaint();
  81. }
  82. // A border with a rounded rectangle and single color.
  83. class RoundedRectBorder : public Border {
  84. public:
  85. RoundedRectBorder(int thickness,
  86. float corner_radius,
  87. const gfx::Insets& paint_insets,
  88. SkColor color);
  89. RoundedRectBorder(const RoundedRectBorder&) = delete;
  90. RoundedRectBorder& operator=(const RoundedRectBorder&) = delete;
  91. // Overridden from Border:
  92. void Paint(const View& view, gfx::Canvas* canvas) override;
  93. gfx::Insets GetInsets() const override;
  94. gfx::Size GetMinimumSize() const override;
  95. private:
  96. const int thickness_;
  97. const float corner_radius_;
  98. const gfx::Insets paint_insets_;
  99. };
  100. RoundedRectBorder::RoundedRectBorder(int thickness,
  101. float corner_radius,
  102. const gfx::Insets& paint_insets,
  103. SkColor color)
  104. : Border(color),
  105. thickness_(thickness),
  106. corner_radius_(corner_radius),
  107. paint_insets_(paint_insets) {}
  108. void RoundedRectBorder::Paint(const View& view, gfx::Canvas* canvas) {
  109. cc::PaintFlags flags;
  110. flags.setStrokeWidth(thickness_);
  111. flags.setColor(color());
  112. flags.setStyle(cc::PaintFlags::kStroke_Style);
  113. flags.setAntiAlias(true);
  114. const float half_thickness = thickness_ / 2.0f;
  115. gfx::RectF bounds(view.GetLocalBounds());
  116. bounds.Inset(gfx::InsetsF(paint_insets_));
  117. bounds.Inset(half_thickness);
  118. canvas->DrawRoundRect(bounds, corner_radius_ - half_thickness, flags);
  119. }
  120. gfx::Insets RoundedRectBorder::GetInsets() const {
  121. return gfx::Insets(thickness_) + paint_insets_;
  122. }
  123. gfx::Size RoundedRectBorder::GetMinimumSize() const {
  124. return gfx::Size(thickness_ * 2, thickness_ * 2);
  125. }
  126. class EmptyBorder : public Border {
  127. public:
  128. explicit EmptyBorder(const gfx::Insets& insets);
  129. EmptyBorder(const EmptyBorder&) = delete;
  130. EmptyBorder& operator=(const EmptyBorder&) = delete;
  131. // Overridden from Border:
  132. void Paint(const View& view, gfx::Canvas* canvas) override;
  133. gfx::Insets GetInsets() const override;
  134. gfx::Size GetMinimumSize() const override;
  135. private:
  136. const gfx::Insets insets_;
  137. };
  138. EmptyBorder::EmptyBorder(const gfx::Insets& insets) : insets_(insets) {}
  139. void EmptyBorder::Paint(const View& view, gfx::Canvas* canvas) {}
  140. gfx::Insets EmptyBorder::GetInsets() const {
  141. return insets_;
  142. }
  143. gfx::Size EmptyBorder::GetMinimumSize() const {
  144. return gfx::Size();
  145. }
  146. class ExtraInsetsBorder : public Border {
  147. public:
  148. ExtraInsetsBorder(std::unique_ptr<Border> border, const gfx::Insets& insets);
  149. ExtraInsetsBorder(const ExtraInsetsBorder&) = delete;
  150. ExtraInsetsBorder& operator=(const ExtraInsetsBorder&) = delete;
  151. // Overridden from Border:
  152. void Paint(const View& view, gfx::Canvas* canvas) override;
  153. gfx::Insets GetInsets() const override;
  154. gfx::Size GetMinimumSize() const override;
  155. private:
  156. std::unique_ptr<Border> border_;
  157. const gfx::Insets extra_insets_;
  158. };
  159. ExtraInsetsBorder::ExtraInsetsBorder(std::unique_ptr<Border> border,
  160. const gfx::Insets& insets)
  161. : Border(border->color()),
  162. border_(std::move(border)),
  163. extra_insets_(insets) {}
  164. void ExtraInsetsBorder::Paint(const View& view, gfx::Canvas* canvas) {
  165. border_->Paint(view, canvas);
  166. }
  167. gfx::Insets ExtraInsetsBorder::GetInsets() const {
  168. return border_->GetInsets() + extra_insets_;
  169. }
  170. gfx::Size ExtraInsetsBorder::GetMinimumSize() const {
  171. gfx::Size size = border_->GetMinimumSize();
  172. size.Enlarge(extra_insets_.width(), extra_insets_.height());
  173. return size;
  174. }
  175. class BorderPainter : public Border {
  176. public:
  177. BorderPainter(std::unique_ptr<Painter> painter, const gfx::Insets& insets);
  178. BorderPainter(const BorderPainter&) = delete;
  179. BorderPainter& operator=(const BorderPainter&) = delete;
  180. // Overridden from Border:
  181. void Paint(const View& view, gfx::Canvas* canvas) override;
  182. gfx::Insets GetInsets() const override;
  183. gfx::Size GetMinimumSize() const override;
  184. private:
  185. std::unique_ptr<Painter> painter_;
  186. const gfx::Insets insets_;
  187. };
  188. BorderPainter::BorderPainter(std::unique_ptr<Painter> painter,
  189. const gfx::Insets& insets)
  190. : painter_(std::move(painter)), insets_(insets) {
  191. DCHECK(painter_);
  192. }
  193. void BorderPainter::Paint(const View& view, gfx::Canvas* canvas) {
  194. Painter::PaintPainterAt(canvas, painter_.get(), view.GetLocalBounds());
  195. }
  196. gfx::Insets BorderPainter::GetInsets() const {
  197. return insets_;
  198. }
  199. gfx::Size BorderPainter::GetMinimumSize() const {
  200. return painter_->GetMinimumSize();
  201. }
  202. class ThemedRoundedRectBorder : public RoundedRectBorder {
  203. public:
  204. ThemedRoundedRectBorder(int thickness,
  205. float corner_radius,
  206. const gfx::Insets& paint_insets,
  207. ui::ColorId color_id)
  208. : RoundedRectBorder(thickness,
  209. corner_radius,
  210. paint_insets,
  211. gfx::kPlaceholderColor),
  212. color_id_(color_id) {}
  213. ThemedRoundedRectBorder(const ThemedRoundedRectBorder&) = delete;
  214. ThemedRoundedRectBorder& operator=(const ThemedRoundedRectBorder&) = delete;
  215. void Paint(const View& view, gfx::Canvas* canvas) override {
  216. set_color(view.GetColorProvider()->GetColor(color_id_));
  217. RoundedRectBorder::Paint(view, canvas);
  218. }
  219. void OnViewThemeChanged(View* view) override { view->SchedulePaint(); }
  220. private:
  221. const ui::ColorId color_id_;
  222. };
  223. } // namespace
  224. Border::Border() = default;
  225. Border::Border(SkColor color) : color_(color) {}
  226. Border::~Border() = default;
  227. void Border::OnViewThemeChanged(View* view) {}
  228. std::unique_ptr<Border> NullBorder() {
  229. return nullptr;
  230. }
  231. std::unique_ptr<Border> CreateSolidBorder(int thickness, SkColor color) {
  232. return std::make_unique<SolidSidedBorder>(gfx::Insets(thickness), color);
  233. }
  234. std::unique_ptr<Border> CreateThemedSolidBorder(int thickness,
  235. ui::ColorId color) {
  236. return std::make_unique<ThemedSolidSidedBorder>(gfx::Insets(thickness),
  237. color);
  238. }
  239. std::unique_ptr<Border> CreateEmptyBorder(const gfx::Insets& insets) {
  240. return std::make_unique<EmptyBorder>(insets);
  241. }
  242. std::unique_ptr<Border> CreateEmptyBorder(int thickness) {
  243. return CreateEmptyBorder(gfx::Insets(thickness));
  244. }
  245. std::unique_ptr<Border> CreateRoundedRectBorder(int thickness,
  246. float corner_radius,
  247. SkColor color) {
  248. return CreateRoundedRectBorder(thickness, corner_radius, gfx::Insets(),
  249. color);
  250. }
  251. std::unique_ptr<Border> CreateRoundedRectBorder(int thickness,
  252. float corner_radius,
  253. const gfx::Insets& paint_insets,
  254. SkColor color) {
  255. return std::make_unique<RoundedRectBorder>(thickness, corner_radius,
  256. paint_insets, color);
  257. }
  258. std::unique_ptr<Border> CreateThemedRoundedRectBorder(int thickness,
  259. float corner_radius,
  260. ui::ColorId color_id) {
  261. return CreateThemedRoundedRectBorder(thickness, corner_radius, gfx::Insets(),
  262. color_id);
  263. }
  264. std::unique_ptr<Border> CreateThemedRoundedRectBorder(
  265. int thickness,
  266. float corner_radius,
  267. const gfx::Insets& paint_insets,
  268. ui::ColorId color_id) {
  269. return std::make_unique<ThemedRoundedRectBorder>(thickness, corner_radius,
  270. paint_insets, color_id);
  271. }
  272. std::unique_ptr<Border> CreateSolidSidedBorder(const gfx::Insets& insets,
  273. SkColor color) {
  274. return std::make_unique<SolidSidedBorder>(insets, color);
  275. }
  276. std::unique_ptr<Border> CreatePaddedBorder(std::unique_ptr<Border> border,
  277. const gfx::Insets& insets) {
  278. return std::make_unique<ExtraInsetsBorder>(std::move(border), insets);
  279. }
  280. std::unique_ptr<Border> CreateBorderPainter(std::unique_ptr<Painter> painter,
  281. const gfx::Insets& insets) {
  282. return base::WrapUnique(new BorderPainter(std::move(painter), insets));
  283. }
  284. } // namespace views