canvas.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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/gfx/canvas.h"
  5. #include <cmath>
  6. #include <limits>
  7. #include "base/i18n/rtl.h"
  8. #include "base/logging.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "cc/paint/paint_flags.h"
  11. #include "cc/paint/paint_shader.h"
  12. #include "cc/paint/skottie_wrapper.h"
  13. #include "third_party/skia/include/core/SkBitmap.h"
  14. #include "third_party/skia/include/core/SkPath.h"
  15. #include "third_party/skia/include/core/SkRefCnt.h"
  16. #include "third_party/skia/include/effects/SkDashPathEffect.h"
  17. #include "third_party/skia/include/effects/SkGradientShader.h"
  18. #include "ui/gfx/font_list.h"
  19. #include "ui/gfx/geometry/insets_f.h"
  20. #include "ui/gfx/geometry/rect.h"
  21. #include "ui/gfx/geometry/rect_conversions.h"
  22. #include "ui/gfx/geometry/rect_f.h"
  23. #include "ui/gfx/geometry/size_conversions.h"
  24. #include "ui/gfx/geometry/skia_conversions.h"
  25. #include "ui/gfx/geometry/transform.h"
  26. #include "ui/gfx/image/image_skia_rep.h"
  27. #include "ui/gfx/scoped_canvas.h"
  28. #include "ui/gfx/skia_paint_util.h"
  29. #include "ui/gfx/switches.h"
  30. namespace gfx {
  31. Canvas::Canvas(const Size& size, float image_scale, bool is_opaque)
  32. : image_scale_(image_scale) {
  33. Size pixel_size = ScaleToCeiledSize(size, image_scale);
  34. canvas_ = CreateOwnedCanvas(pixel_size, is_opaque);
  35. SkScalar scale_scalar = SkFloatToScalar(image_scale);
  36. canvas_->scale(scale_scalar, scale_scalar);
  37. }
  38. Canvas::Canvas()
  39. : image_scale_(1.f), canvas_(CreateOwnedCanvas({0, 0}, false)) {}
  40. Canvas::Canvas(cc::PaintCanvas* canvas, float image_scale)
  41. : image_scale_(image_scale), canvas_(canvas) {
  42. DCHECK(canvas_);
  43. }
  44. Canvas::~Canvas() {
  45. }
  46. void Canvas::RecreateBackingCanvas(const Size& size,
  47. float image_scale,
  48. bool is_opaque) {
  49. image_scale_ = image_scale;
  50. Size pixel_size = ScaleToFlooredSize(size, image_scale);
  51. canvas_ = CreateOwnedCanvas(pixel_size, is_opaque);
  52. SkScalar scale_scalar = SkFloatToScalar(image_scale);
  53. canvas_->scale(scale_scalar, scale_scalar);
  54. }
  55. // static
  56. void Canvas::SizeStringInt(const std::u16string& text,
  57. const FontList& font_list,
  58. int* width,
  59. int* height,
  60. int line_height,
  61. int flags) {
  62. float fractional_width = static_cast<float>(*width);
  63. float factional_height = static_cast<float>(*height);
  64. SizeStringFloat(text, font_list, &fractional_width, &factional_height,
  65. line_height, flags);
  66. *width = base::ClampCeil(fractional_width);
  67. *height = base::ClampCeil(factional_height);
  68. }
  69. // static
  70. int Canvas::GetStringWidth(const std::u16string& text,
  71. const FontList& font_list) {
  72. int width = 0, height = 0;
  73. SizeStringInt(text, font_list, &width, &height, 0, NO_ELLIPSIS);
  74. return width;
  75. }
  76. // static
  77. float Canvas::GetStringWidthF(const std::u16string& text,
  78. const FontList& font_list) {
  79. float width = 0, height = 0;
  80. SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS);
  81. return width;
  82. }
  83. // static
  84. int Canvas::DefaultCanvasTextAlignment() {
  85. return base::i18n::IsRTL() ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
  86. }
  87. float Canvas::UndoDeviceScaleFactor() {
  88. SkScalar scale_factor = 1.0f / image_scale_;
  89. canvas_->scale(scale_factor, scale_factor);
  90. return image_scale_;
  91. }
  92. void Canvas::Save() {
  93. canvas_->save();
  94. }
  95. void Canvas::SaveLayerAlpha(uint8_t alpha) {
  96. canvas_->saveLayerAlpha(NULL, alpha);
  97. }
  98. void Canvas::SaveLayerAlpha(uint8_t alpha, const Rect& layer_bounds) {
  99. SkRect bounds(RectToSkRect(layer_bounds));
  100. canvas_->saveLayerAlpha(&bounds, alpha);
  101. }
  102. void Canvas::SaveLayerWithFlags(const cc::PaintFlags& flags) {
  103. canvas_->saveLayer(nullptr /* bounds */, &flags);
  104. }
  105. void Canvas::Restore() {
  106. canvas_->restore();
  107. }
  108. void Canvas::ClipRect(const Rect& rect, SkClipOp op) {
  109. canvas_->clipRect(RectToSkRect(rect), op);
  110. }
  111. void Canvas::ClipRect(const RectF& rect, SkClipOp op) {
  112. canvas_->clipRect(RectFToSkRect(rect), op);
  113. }
  114. void Canvas::ClipPath(const SkPath& path, bool do_anti_alias) {
  115. canvas_->clipPath(path, SkClipOp::kIntersect, do_anti_alias);
  116. }
  117. bool Canvas::GetClipBounds(Rect* bounds) {
  118. SkRect out;
  119. if (canvas_->getLocalClipBounds(&out)) {
  120. *bounds = ToEnclosingRect(SkRectToRectF(out));
  121. return true;
  122. }
  123. *bounds = gfx::Rect();
  124. return false;
  125. }
  126. void Canvas::Translate(const Vector2d& offset) {
  127. canvas_->translate(SkIntToScalar(offset.x()), SkIntToScalar(offset.y()));
  128. }
  129. void Canvas::Scale(float x_scale, float y_scale) {
  130. canvas_->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale));
  131. }
  132. void Canvas::DrawColor(SkColor color) {
  133. DrawColor(color, SkBlendMode::kSrcOver);
  134. }
  135. void Canvas::DrawColor(SkColor color, SkBlendMode mode) {
  136. canvas_->drawColor(SkColor4f::FromColor(color), mode);
  137. }
  138. void Canvas::FillRect(const Rect& rect, SkColor color) {
  139. FillRect(rect, color, SkBlendMode::kSrcOver);
  140. }
  141. void Canvas::FillRect(const Rect& rect, SkColor color, SkBlendMode mode) {
  142. cc::PaintFlags flags;
  143. flags.setColor(color);
  144. flags.setStyle(cc::PaintFlags::kFill_Style);
  145. flags.setBlendMode(mode);
  146. DrawRect(rect, flags);
  147. }
  148. void Canvas::DrawRect(const RectF& rect, SkColor color) {
  149. DrawRect(rect, color, SkBlendMode::kSrcOver);
  150. }
  151. void Canvas::DrawRect(const RectF& rect, SkColor color, SkBlendMode mode) {
  152. cc::PaintFlags flags;
  153. flags.setColor(color);
  154. flags.setStyle(cc::PaintFlags::kStroke_Style);
  155. // Set a stroke width of 0, which will put us down the stroke rect path. If
  156. // we set a stroke width of 1, for example, this will internally create a
  157. // path and fill it, which causes problems near the edge of the canvas.
  158. flags.setStrokeWidth(SkIntToScalar(0));
  159. flags.setBlendMode(mode);
  160. DrawRect(rect, flags);
  161. }
  162. void Canvas::DrawRect(const Rect& rect, const cc::PaintFlags& flags) {
  163. DrawRect(RectF(rect), flags);
  164. }
  165. void Canvas::DrawRect(const RectF& rect, const cc::PaintFlags& flags) {
  166. canvas_->drawRect(RectFToSkRect(rect), flags);
  167. }
  168. void Canvas::DrawLine(const Point& p1, const Point& p2, SkColor color) {
  169. DrawLine(PointF(p1), PointF(p2), color);
  170. }
  171. void Canvas::DrawLine(const PointF& p1, const PointF& p2, SkColor color) {
  172. cc::PaintFlags flags;
  173. flags.setColor(color);
  174. flags.setStrokeWidth(SkIntToScalar(1));
  175. DrawLine(p1, p2, flags);
  176. }
  177. void Canvas::DrawLine(const Point& p1,
  178. const Point& p2,
  179. const cc::PaintFlags& flags) {
  180. DrawLine(PointF(p1), PointF(p2), flags);
  181. }
  182. void Canvas::DrawLine(const PointF& p1,
  183. const PointF& p2,
  184. const cc::PaintFlags& flags) {
  185. canvas_->drawLine(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
  186. SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()), flags);
  187. }
  188. void Canvas::DrawSharpLine(PointF p1, PointF p2, SkColor color) {
  189. ScopedCanvas scoped(this);
  190. float dsf = UndoDeviceScaleFactor();
  191. p1.Scale(dsf);
  192. p2.Scale(dsf);
  193. cc::PaintFlags flags;
  194. flags.setColor(color);
  195. flags.setStrokeWidth(SkFloatToScalar(std::floor(dsf)));
  196. DrawLine(p1, p2, flags);
  197. }
  198. void Canvas::Draw1pxLine(PointF p1, PointF p2, SkColor color) {
  199. ScopedCanvas scoped(this);
  200. float dsf = UndoDeviceScaleFactor();
  201. p1.Scale(dsf);
  202. p2.Scale(dsf);
  203. DrawLine(p1, p2, color);
  204. }
  205. void Canvas::DrawCircle(const Point& center_point,
  206. int radius,
  207. const cc::PaintFlags& flags) {
  208. canvas_->drawOval(
  209. SkRect::MakeLTRB(center_point.x() - radius, center_point.y() - radius,
  210. center_point.x() + radius, center_point.y() + radius),
  211. flags);
  212. }
  213. void Canvas::DrawCircle(const PointF& center_point,
  214. float radius,
  215. const cc::PaintFlags& flags) {
  216. canvas_->drawOval(
  217. SkRect::MakeLTRB(center_point.x() - radius, center_point.y() - radius,
  218. center_point.x() + radius, center_point.y() + radius),
  219. flags);
  220. }
  221. void Canvas::DrawRoundRect(const Rect& rect,
  222. int radius,
  223. const cc::PaintFlags& flags) {
  224. DrawRoundRect(RectF(rect), radius, flags);
  225. }
  226. void Canvas::DrawRoundRect(const RectF& rect,
  227. float radius,
  228. const cc::PaintFlags& flags) {
  229. canvas_->drawRoundRect(RectFToSkRect(rect), SkFloatToScalar(radius),
  230. SkFloatToScalar(radius), flags);
  231. }
  232. void Canvas::DrawPath(const SkPath& path, const cc::PaintFlags& flags) {
  233. canvas_->drawPath(path, flags);
  234. }
  235. void Canvas::DrawSolidFocusRect(RectF rect, SkColor color, int thickness) {
  236. cc::PaintFlags flags;
  237. flags.setColor(color);
  238. const float adjusted_thickness =
  239. std::floor(thickness * image_scale_) / image_scale_;
  240. flags.setStrokeWidth(SkFloatToScalar(adjusted_thickness));
  241. flags.setStyle(cc::PaintFlags::kStroke_Style);
  242. rect.Inset(gfx::InsetsF(adjusted_thickness / 2));
  243. DrawRect(rect, flags);
  244. }
  245. void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) {
  246. cc::PaintFlags flags;
  247. DrawImageInt(image, x, y, flags);
  248. }
  249. void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8_t a) {
  250. cc::PaintFlags flags;
  251. flags.setAlpha(a);
  252. DrawImageInt(image, x, y, flags);
  253. }
  254. void Canvas::DrawImageInt(const ImageSkia& image,
  255. int x,
  256. int y,
  257. const cc::PaintFlags& flags) {
  258. const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
  259. if (image_rep.is_null())
  260. return;
  261. float bitmap_scale = image_rep.scale();
  262. ScopedCanvas scoper(this);
  263. canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale),
  264. SkFloatToScalar(1.0f / bitmap_scale));
  265. canvas_->translate(SkFloatToScalar(std::round(x * bitmap_scale)),
  266. SkFloatToScalar(std::round(y * bitmap_scale)));
  267. canvas_->saveLayer(nullptr, &flags);
  268. canvas_->drawPicture(image_rep.GetPaintRecord());
  269. canvas_->restore();
  270. }
  271. void Canvas::DrawImageInt(const ImageSkia& image,
  272. int src_x,
  273. int src_y,
  274. int src_w,
  275. int src_h,
  276. int dest_x,
  277. int dest_y,
  278. int dest_w,
  279. int dest_h,
  280. bool filter) {
  281. cc::PaintFlags flags;
  282. DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
  283. dest_h, filter, flags);
  284. }
  285. void Canvas::DrawImageInt(const ImageSkia& image,
  286. int src_x,
  287. int src_y,
  288. int src_w,
  289. int src_h,
  290. int dest_x,
  291. int dest_y,
  292. int dest_w,
  293. int dest_h,
  294. bool filter,
  295. const cc::PaintFlags& flags) {
  296. const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
  297. if (image_rep.is_null())
  298. return;
  299. bool remove_image_scale = true;
  300. DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y,
  301. dest_w, dest_h, filter, flags, remove_image_scale);
  302. }
  303. void Canvas::DrawImageIntInPixel(const ImageSkiaRep& image_rep,
  304. int dest_x,
  305. int dest_y,
  306. int dest_w,
  307. int dest_h,
  308. bool filter,
  309. const cc::PaintFlags& flags) {
  310. int src_x = 0;
  311. int src_y = 0;
  312. int src_w = image_rep.pixel_width();
  313. int src_h = image_rep.pixel_height();
  314. // Don't remove image scale here, this function is used to draw the
  315. // (already scaled) |image_rep| at a 1:1 scale with the canvas.
  316. bool remove_image_scale = false;
  317. DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y,
  318. dest_w, dest_h, filter, flags, remove_image_scale);
  319. }
  320. void Canvas::DrawImageInPath(const ImageSkia& image,
  321. int x,
  322. int y,
  323. const SkPath& path,
  324. const cc::PaintFlags& original_flags) {
  325. const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
  326. if (image_rep.is_null())
  327. return;
  328. SkMatrix matrix;
  329. matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
  330. cc::PaintFlags flags(original_flags);
  331. flags.setShader(CreateImageRepShader(image_rep, SkTileMode::kRepeat,
  332. SkTileMode::kRepeat, matrix));
  333. canvas_->drawPath(path, flags);
  334. }
  335. void Canvas::DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie,
  336. const Rect& dst,
  337. float t,
  338. cc::SkottieFrameDataMap images,
  339. const cc::SkottieColorMap& color_map,
  340. cc::SkottieTextPropertyValueMap text_map) {
  341. canvas_->drawSkottie(std::move(skottie), RectToSkRect(dst), t,
  342. std::move(images), color_map, std::move(text_map));
  343. }
  344. void Canvas::DrawStringRect(const std::u16string& text,
  345. const FontList& font_list,
  346. SkColor color,
  347. const Rect& display_rect) {
  348. DrawStringRectWithFlags(text, font_list, color, display_rect,
  349. DefaultCanvasTextAlignment());
  350. }
  351. void Canvas::TileImageInt(const ImageSkia& image,
  352. int x,
  353. int y,
  354. int w,
  355. int h) {
  356. TileImageInt(image, 0, 0, x, y, w, h);
  357. }
  358. void Canvas::TileImageInt(const ImageSkia& image,
  359. int src_x,
  360. int src_y,
  361. int dest_x,
  362. int dest_y,
  363. int w,
  364. int h,
  365. float tile_scale,
  366. SkTileMode tile_mode_x,
  367. SkTileMode tile_mode_y,
  368. cc::PaintFlags* flags) {
  369. SkRect dest_rect = { SkIntToScalar(dest_x),
  370. SkIntToScalar(dest_y),
  371. SkIntToScalar(dest_x + w),
  372. SkIntToScalar(dest_y + h) };
  373. if (!IntersectsClipRect(dest_rect))
  374. return;
  375. cc::PaintFlags paint_flags;
  376. if (!flags)
  377. flags = &paint_flags;
  378. if (InitPaintFlagsForTiling(image, src_x, src_y, tile_scale, tile_scale,
  379. dest_x, dest_y, tile_mode_x, tile_mode_y, flags))
  380. canvas_->drawRect(dest_rect, *flags);
  381. }
  382. bool Canvas::InitPaintFlagsForTiling(const ImageSkia& image,
  383. int src_x,
  384. int src_y,
  385. float tile_scale_x,
  386. float tile_scale_y,
  387. int dest_x,
  388. int dest_y,
  389. SkTileMode tile_mode_x,
  390. SkTileMode tile_mode_y,
  391. cc::PaintFlags* flags) {
  392. const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
  393. if (image_rep.is_null())
  394. return false;
  395. SkMatrix shader_scale;
  396. shader_scale.setScale(SkFloatToScalar(tile_scale_x),
  397. SkFloatToScalar(tile_scale_y));
  398. shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
  399. shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
  400. flags->setShader(CreateImageRepShader(image_rep, tile_mode_x, tile_mode_y,
  401. shader_scale));
  402. return true;
  403. }
  404. void Canvas::Transform(const gfx::Transform& transform) {
  405. canvas_->concat(transform.matrix().asM33());
  406. }
  407. SkBitmap Canvas::GetBitmap() const {
  408. DCHECK(bitmap_);
  409. return bitmap_.value();
  410. }
  411. bool Canvas::IntersectsClipRect(const SkRect& rect) {
  412. SkRect clip;
  413. return canvas_->getLocalClipBounds(&clip) && clip.intersects(rect);
  414. }
  415. void Canvas::DrawImageIntHelper(const ImageSkiaRep& image_rep,
  416. int src_x,
  417. int src_y,
  418. int src_w,
  419. int src_h,
  420. int dest_x,
  421. int dest_y,
  422. int dest_w,
  423. int dest_h,
  424. bool filter,
  425. const cc::PaintFlags& original_flags,
  426. bool remove_image_scale) {
  427. DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
  428. src_y + src_h < std::numeric_limits<int16_t>::max());
  429. if (src_w <= 0 || src_h <= 0) {
  430. NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
  431. return;
  432. }
  433. SkRect dest_rect = { SkIntToScalar(dest_x),
  434. SkIntToScalar(dest_y),
  435. SkIntToScalar(dest_x + dest_w),
  436. SkIntToScalar(dest_y + dest_h) };
  437. if (!IntersectsClipRect(dest_rect))
  438. return;
  439. float user_scale_x = static_cast<float>(dest_w) / src_w;
  440. float user_scale_y = static_cast<float>(dest_h) / src_h;
  441. // Make a bitmap shader that contains the bitmap we want to draw. This is
  442. // basically what SkCanvas.drawBitmap does internally, but it gives us
  443. // more control over quality and will use the mipmap in the source image if
  444. // it has one, whereas drawBitmap won't.
  445. SkMatrix shader_scale;
  446. shader_scale.setScale(SkFloatToScalar(user_scale_x),
  447. SkFloatToScalar(user_scale_y));
  448. shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
  449. shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
  450. cc::PaintFlags flags(original_flags);
  451. flags.setFilterQuality(filter ? cc::PaintFlags::FilterQuality::kLow
  452. : cc::PaintFlags::FilterQuality::kNone);
  453. flags.setShader(CreateImageRepShaderForScale(
  454. image_rep, SkTileMode::kRepeat, SkTileMode::kRepeat, shader_scale,
  455. remove_image_scale ? image_rep.scale() : 1.f));
  456. // The rect will be filled by the bitmap.
  457. canvas_->drawRect(dest_rect, flags);
  458. }
  459. cc::PaintCanvas* Canvas::CreateOwnedCanvas(const Size& size, bool is_opaque) {
  460. // SkBitmap cannot be zero-sized, but clients of Canvas sometimes request
  461. // that (and then later resize).
  462. int width = std::max(size.width(), 1);
  463. int height = std::max(size.height(), 1);
  464. SkAlphaType alpha = is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
  465. SkImageInfo info = SkImageInfo::MakeN32(width, height, alpha);
  466. bitmap_.emplace();
  467. bitmap_->allocPixels(info);
  468. // Ensure that the bitmap is zeroed, since the code expects that.
  469. memset(bitmap_->getPixels(), 0, bitmap_->computeByteSize());
  470. owned_canvas_.emplace(bitmap_.value());
  471. return &owned_canvas_.value();
  472. }
  473. } // namespace gfx