record_paint_canvas.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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 "cc/paint/record_paint_canvas.h"
  5. #include <utility>
  6. #include "cc/paint/display_item_list.h"
  7. #include "cc/paint/paint_image_builder.h"
  8. #include "cc/paint/paint_record.h"
  9. #include "cc/paint/paint_recorder.h"
  10. #include "cc/paint/skottie_frame_data.h"
  11. #include "cc/paint/skottie_wrapper.h"
  12. #include "third_party/skia/include/core/SkAnnotation.h"
  13. #include "third_party/skia/include/core/SkTextBlob.h"
  14. #include "third_party/skia/include/utils/SkNWayCanvas.h"
  15. namespace cc {
  16. RecordPaintCanvas::RecordPaintCanvas(DisplayItemList* list,
  17. const SkRect& bounds)
  18. : list_(list), recording_bounds_(bounds) {
  19. DCHECK(list_);
  20. }
  21. RecordPaintCanvas::~RecordPaintCanvas() = default;
  22. SkImageInfo RecordPaintCanvas::imageInfo() const {
  23. return GetCanvas()->imageInfo();
  24. }
  25. template <typename T, typename... Args>
  26. size_t RecordPaintCanvas::push(Args&&... args) {
  27. #if DCHECK_IS_ON()
  28. // The following check fails if client code does not check and handle
  29. // NeedsFlush() before issuing draw calls.
  30. // Note: restore ops are tolerated when flushes are requested since they are
  31. // often necessary in order to bring the canvas to a flushable state.
  32. // SetNodeId ops are also tolerated because they may be inserted just before
  33. // flushing.
  34. DCHECK(disable_flush_check_scope_ || !needs_flush_ ||
  35. (std::is_same<T, RestoreOp>::value) ||
  36. (std::is_same<T, SetNodeIdOp>::value));
  37. #endif
  38. return list_->push<T>(std::forward<Args>(args)...);
  39. }
  40. void* RecordPaintCanvas::accessTopLayerPixels(SkImageInfo* info,
  41. size_t* rowBytes,
  42. SkIPoint* origin) {
  43. // Modifications to the underlying pixels cannot be saved.
  44. return nullptr;
  45. }
  46. void RecordPaintCanvas::flush() {
  47. // RecordPaintCanvas is unable to flush its own recording into the graphics
  48. // pipeline. So instead we make note of the flush request so that it can be
  49. // handled by code that owns the recording.
  50. //
  51. // Note: The value of needs_flush_ never gets reset. That is because
  52. // flushing a recording implies closing this RecordPaintCanvas and starting a
  53. // new one.
  54. needs_flush_ = true;
  55. }
  56. bool RecordPaintCanvas::NeedsFlush() const {
  57. return needs_flush_;
  58. }
  59. int RecordPaintCanvas::save() {
  60. push<SaveOp>();
  61. return GetCanvas()->save();
  62. }
  63. int RecordPaintCanvas::saveLayer(const SkRect* bounds,
  64. const PaintFlags* flags) {
  65. if (flags) {
  66. if (flags->IsSimpleOpacity()) {
  67. // TODO(enne): maybe more callers should know this and call
  68. // saveLayerAlpha instead of needing to check here.
  69. uint8_t alpha = SkColorGetA(flags->getColor());
  70. return saveLayerAlpha(bounds, alpha);
  71. }
  72. // TODO(enne): it appears that image filters affect matrices and color
  73. // matrices affect transparent flags on SkCanvas layers, but it's not clear
  74. // whether those are actually needed and we could just skip ToSkPaint here.
  75. push<SaveLayerOp>(bounds, flags);
  76. SkPaint paint = flags->ToSkPaint();
  77. return GetCanvas()->saveLayer(bounds, &paint);
  78. }
  79. push<SaveLayerOp>(bounds, flags);
  80. return GetCanvas()->saveLayer(bounds, nullptr);
  81. }
  82. int RecordPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) {
  83. push<SaveLayerAlphaOp>(bounds, static_cast<float>(alpha / 255.0f));
  84. return GetCanvas()->saveLayerAlpha(bounds, alpha);
  85. }
  86. void RecordPaintCanvas::restore() {
  87. push<RestoreOp>();
  88. GetCanvas()->restore();
  89. }
  90. int RecordPaintCanvas::getSaveCount() const {
  91. return GetCanvas()->getSaveCount();
  92. }
  93. void RecordPaintCanvas::restoreToCount(int save_count) {
  94. if (!canvas_) {
  95. DCHECK_EQ(save_count, 1);
  96. return;
  97. }
  98. DCHECK_GE(save_count, 1);
  99. int diff = GetCanvas()->getSaveCount() - save_count;
  100. DCHECK_GE(diff, 0);
  101. for (int i = 0; i < diff; ++i)
  102. restore();
  103. }
  104. void RecordPaintCanvas::translate(SkScalar dx, SkScalar dy) {
  105. push<TranslateOp>(dx, dy);
  106. GetCanvas()->translate(dx, dy);
  107. }
  108. void RecordPaintCanvas::scale(SkScalar sx, SkScalar sy) {
  109. push<ScaleOp>(sx, sy);
  110. GetCanvas()->scale(sx, sy);
  111. }
  112. void RecordPaintCanvas::rotate(SkScalar degrees) {
  113. push<RotateOp>(degrees);
  114. GetCanvas()->rotate(degrees);
  115. }
  116. void RecordPaintCanvas::concat(const SkMatrix& matrix) {
  117. SkM44 m = SkM44(matrix);
  118. push<ConcatOp>(m);
  119. GetCanvas()->concat(m);
  120. }
  121. void RecordPaintCanvas::concat(const SkM44& matrix) {
  122. push<ConcatOp>(matrix);
  123. GetCanvas()->concat(matrix);
  124. }
  125. void RecordPaintCanvas::setMatrix(const SkMatrix& matrix) {
  126. SkM44 m = SkM44(matrix);
  127. push<SetMatrixOp>(m);
  128. GetCanvas()->setMatrix(m);
  129. }
  130. void RecordPaintCanvas::setMatrix(const SkM44& matrix) {
  131. push<SetMatrixOp>(matrix);
  132. GetCanvas()->setMatrix(matrix);
  133. }
  134. void RecordPaintCanvas::clipRect(const SkRect& rect,
  135. SkClipOp op,
  136. bool antialias) {
  137. push<ClipRectOp>(rect, op, antialias);
  138. GetCanvas()->clipRect(rect, op, antialias);
  139. }
  140. void RecordPaintCanvas::clipRRect(const SkRRect& rrect,
  141. SkClipOp op,
  142. bool antialias) {
  143. // TODO(enne): does this happen? Should the caller know this?
  144. if (rrect.isRect()) {
  145. clipRect(rrect.getBounds(), op, antialias);
  146. return;
  147. }
  148. push<ClipRRectOp>(rrect, op, antialias);
  149. GetCanvas()->clipRRect(rrect, op, antialias);
  150. }
  151. void RecordPaintCanvas::clipPath(const SkPath& path,
  152. SkClipOp op,
  153. bool antialias,
  154. UsePaintCache use_paint_cache) {
  155. if (!path.isInverseFillType() &&
  156. GetCanvas()->getTotalMatrix().rectStaysRect()) {
  157. // TODO(enne): do these cases happen? should the caller know that this isn't
  158. // a path?
  159. SkRect rect;
  160. if (path.isRect(&rect)) {
  161. clipRect(rect, op, antialias);
  162. return;
  163. }
  164. SkRRect rrect;
  165. if (path.isOval(&rect)) {
  166. rrect.setOval(rect);
  167. clipRRect(rrect, op, antialias);
  168. return;
  169. }
  170. if (path.isRRect(&rrect)) {
  171. clipRRect(rrect, op, antialias);
  172. return;
  173. }
  174. }
  175. push<ClipPathOp>(path, op, antialias, use_paint_cache);
  176. GetCanvas()->clipPath(path, op, antialias);
  177. return;
  178. }
  179. SkRect RecordPaintCanvas::getLocalClipBounds() const {
  180. DCHECK(InitializedWithRecordingBounds());
  181. return GetCanvas()->getLocalClipBounds();
  182. }
  183. bool RecordPaintCanvas::getLocalClipBounds(SkRect* bounds) const {
  184. DCHECK(InitializedWithRecordingBounds());
  185. return GetCanvas()->getLocalClipBounds(bounds);
  186. }
  187. SkIRect RecordPaintCanvas::getDeviceClipBounds() const {
  188. DCHECK(InitializedWithRecordingBounds());
  189. return GetCanvas()->getDeviceClipBounds();
  190. }
  191. bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
  192. DCHECK(InitializedWithRecordingBounds());
  193. return GetCanvas()->getDeviceClipBounds(bounds);
  194. }
  195. void RecordPaintCanvas::drawColor(SkColor4f color, SkBlendMode mode) {
  196. push<DrawColorOp>(color, mode);
  197. }
  198. void RecordPaintCanvas::clear(SkColor4f color) {
  199. push<DrawColorOp>(color, SkBlendMode::kSrc);
  200. }
  201. void RecordPaintCanvas::drawLine(SkScalar x0,
  202. SkScalar y0,
  203. SkScalar x1,
  204. SkScalar y1,
  205. const PaintFlags& flags) {
  206. push<DrawLineOp>(x0, y0, x1, y1, flags);
  207. }
  208. void RecordPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) {
  209. push<DrawRectOp>(rect, flags);
  210. }
  211. void RecordPaintCanvas::drawIRect(const SkIRect& rect,
  212. const PaintFlags& flags) {
  213. push<DrawIRectOp>(rect, flags);
  214. }
  215. void RecordPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) {
  216. push<DrawOvalOp>(oval, flags);
  217. }
  218. void RecordPaintCanvas::drawRRect(const SkRRect& rrect,
  219. const PaintFlags& flags) {
  220. push<DrawRRectOp>(rrect, flags);
  221. }
  222. void RecordPaintCanvas::drawDRRect(const SkRRect& outer,
  223. const SkRRect& inner,
  224. const PaintFlags& flags) {
  225. if (outer.isEmpty())
  226. return;
  227. if (inner.isEmpty()) {
  228. drawRRect(outer, flags);
  229. return;
  230. }
  231. push<DrawDRRectOp>(outer, inner, flags);
  232. }
  233. void RecordPaintCanvas::drawRoundRect(const SkRect& rect,
  234. SkScalar rx,
  235. SkScalar ry,
  236. const PaintFlags& flags) {
  237. // TODO(enne): move this into base class?
  238. if (rx > 0 && ry > 0) {
  239. SkRRect rrect;
  240. rrect.setRectXY(rect, rx, ry);
  241. drawRRect(rrect, flags);
  242. } else {
  243. drawRect(rect, flags);
  244. }
  245. }
  246. void RecordPaintCanvas::drawPath(const SkPath& path,
  247. const PaintFlags& flags,
  248. UsePaintCache use_paint_cache) {
  249. push<DrawPathOp>(path, flags, use_paint_cache);
  250. }
  251. void RecordPaintCanvas::drawImage(const PaintImage& image,
  252. SkScalar left,
  253. SkScalar top,
  254. const SkSamplingOptions& sampling,
  255. const PaintFlags* flags) {
  256. DCHECK(!image.IsPaintWorklet());
  257. push<DrawImageOp>(image, left, top, sampling, flags);
  258. }
  259. void RecordPaintCanvas::drawImageRect(const PaintImage& image,
  260. const SkRect& src,
  261. const SkRect& dst,
  262. const SkSamplingOptions& sampling,
  263. const PaintFlags* flags,
  264. SkCanvas::SrcRectConstraint constraint) {
  265. push<DrawImageRectOp>(image, src, dst, sampling, flags, constraint);
  266. }
  267. void RecordPaintCanvas::drawSkottie(scoped_refptr<SkottieWrapper> skottie,
  268. const SkRect& dst,
  269. float t,
  270. SkottieFrameDataMap images,
  271. const SkottieColorMap& color_map,
  272. SkottieTextPropertyValueMap text_map) {
  273. push<DrawSkottieOp>(std::move(skottie), dst, t, std::move(images), color_map,
  274. std::move(text_map));
  275. }
  276. void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
  277. SkScalar x,
  278. SkScalar y,
  279. const PaintFlags& flags) {
  280. push<DrawTextBlobOp>(std::move(blob), x, y, flags);
  281. }
  282. void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
  283. SkScalar x,
  284. SkScalar y,
  285. NodeId node_id,
  286. const PaintFlags& flags) {
  287. push<DrawTextBlobOp>(std::move(blob), x, y, node_id, flags);
  288. }
  289. void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
  290. // TODO(enne): If this is small, maybe flatten it?
  291. push<DrawRecordOp>(record);
  292. }
  293. bool RecordPaintCanvas::isClipEmpty() const {
  294. DCHECK(InitializedWithRecordingBounds());
  295. return GetCanvas()->isClipEmpty();
  296. }
  297. SkMatrix RecordPaintCanvas::getTotalMatrix() const {
  298. return GetCanvas()->getTotalMatrix();
  299. }
  300. SkM44 RecordPaintCanvas::getLocalToDevice() const {
  301. return GetCanvas()->getLocalToDevice();
  302. }
  303. void RecordPaintCanvas::Annotate(AnnotationType type,
  304. const SkRect& rect,
  305. sk_sp<SkData> data) {
  306. push<AnnotateOp>(type, rect, data);
  307. }
  308. void RecordPaintCanvas::recordCustomData(uint32_t id) {
  309. push<CustomDataOp>(id);
  310. }
  311. void RecordPaintCanvas::setNodeId(int node_id) {
  312. push<SetNodeIdOp>(node_id);
  313. }
  314. const SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() const {
  315. return const_cast<RecordPaintCanvas*>(this)->GetCanvas();
  316. }
  317. SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() {
  318. if (canvas_)
  319. return &*canvas_;
  320. // Size the canvas to be large enough to contain the |recording_bounds|, which
  321. // may not be positioned at the origin.
  322. SkIRect enclosing_rect = recording_bounds_.roundOut();
  323. canvas_.emplace(enclosing_rect.right(), enclosing_rect.bottom());
  324. // This is part of the "recording canvases have a size, but why" dance.
  325. // By creating a canvas of size (right x bottom) and then clipping it,
  326. // It makes getDeviceClipBounds return the original cull rect, which code
  327. // in GraphicsContextCanvas on Mac expects. (Just creating an SkNoDrawCanvas
  328. // with the recording_bounds_ makes a canvas of size (width x height) instead
  329. // which is incorrect. SkRecorder cheats with private resetForNextCanvas.
  330. canvas_->clipRect(recording_bounds_, SkClipOp::kIntersect, false);
  331. return &*canvas_;
  332. }
  333. bool RecordPaintCanvas::InitializedWithRecordingBounds() const {
  334. // If the RecordPaintCanvas is initialized with an empty bounds then
  335. // the various clip related functions are not valid and should not
  336. // be called.
  337. return !recording_bounds_.isEmpty();
  338. }
  339. } // namespace cc