blob: b3e84593bd6ee6de5b9af9bea561d8a2f85ed057 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed9f014712014-06-18 15:51:20 -07008
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkLayerRasterizer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkDraw.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkMask.h"
14#include "SkMaskFilter.h"
15#include "SkPaint.h"
16#include "SkPath.h"
reed@google.com75a09722012-05-10 12:56:16 +000017#include "SkPathEffect.h"
reed@google.com045e62d2011-10-24 12:19:46 +000018#include "../core/SkRasterClip.h"
bsalomon055e1922016-05-06 07:22:58 -070019#include "../core/SkStrokeRec.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include <new>
21
22struct SkLayerRasterizer_Rec {
23 SkPaint fPaint;
24 SkVector fOffset;
25};
26
halcanary385fe4d2015-08-26 13:07:48 -070027SkLayerRasterizer::SkLayerRasterizer() : fLayers(new SkDeque(sizeof(SkLayerRasterizer_Rec))) {}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +000028
29SkLayerRasterizer::SkLayerRasterizer(SkDeque* layers) : fLayers(layers)
reed@android.com8a1c16f2008-12-17 15:59:43 +000030{
31}
32
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +000033// Helper function to call destructors on SkPaints held by layers and delete layers.
34static void clean_up_layers(SkDeque* layers) {
35 SkDeque::F2BIter iter(*layers);
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 SkLayerRasterizer_Rec* rec;
37
halcanary96fcdcc2015-08-27 07:41:13 -070038 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 rec->fPaint.~SkPaint();
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +000040
halcanary385fe4d2015-08-26 13:07:48 -070041 delete layers;
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +000042}
43
44SkLayerRasterizer::~SkLayerRasterizer() {
45 SkASSERT(fLayers);
46 clean_up_layers(const_cast<SkDeque*>(fLayers));
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
48
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000049static bool compute_bounds(const SkDeque& layers, const SkPath& path,
50 const SkMatrix& matrix,
51 const SkIRect* clipBounds, SkIRect* bounds) {
reed@google.com4c09d5c2011-02-22 13:16:38 +000052 SkDeque::F2BIter iter(layers);
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 SkLayerRasterizer_Rec* rec;
54
55 bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32);
reed@google.com82065d62011-02-07 15:30:46 +000056
halcanary96fcdcc2015-08-27 07:41:13 -070057 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 const SkPaint& paint = rec->fPaint;
59 SkPath fillPath, devPath;
60 const SkPath* p = &path;
61
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000062 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 paint.getFillPath(path, &fillPath);
64 p = &fillPath;
65 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000066 if (p->isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 continue;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000068 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
70 // apply the matrix and offset
71 {
72 SkMatrix m = matrix;
73 m.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
74 p->transform(m, &devPath);
75 }
76
77 SkMask mask;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000078 if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(),
79 &matrix, &mask,
junov@chromium.org2ac4ef52012-04-04 15:16:51 +000080 SkMask::kJustComputeBounds_CreateMode,
bsalomon055e1922016-05-06 07:22:58 -070081 SkStrokeRec::kFill_InitStyle)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000084
85 bounds->join(mask.fBounds);
86 }
87 return true;
88}
89
90bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
91 const SkIRect* clipBounds,
reed@google.comfdba4042012-12-18 16:57:03 +000092 SkMask* mask, SkMask::CreateMode mode) const {
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +000093 SkASSERT(fLayers);
94 if (fLayers->empty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000096 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000098 if (SkMask::kJustRenderImage_CreateMode != mode) {
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +000099 if (!compute_bounds(*fLayers, path, matrix, clipBounds, &mask->fBounds))
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 return false;
101 }
102
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000103 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 mask->fFormat = SkMask::kA8_Format;
reed@android.com49f0ff22009-03-19 21:52:42 +0000105 mask->fRowBytes = mask->fBounds.width();
reed@android.com543ed932009-04-24 12:43:40 +0000106 size_t size = mask->computeImageSize();
107 if (0 == size) {
108 return false; // too big to allocate, abort
109 }
110 mask->fImage = SkMask::AllocImage(size);
111 memset(mask->fImage, 0, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 }
113
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000114 if (SkMask::kJustComputeBounds_CreateMode != mode) {
reedb3f0ec92015-06-08 19:58:07 -0700115 SkDraw draw;
reed41e010c2015-06-09 12:16:53 -0700116 if (!draw.fDst.reset(*mask)) {
117 return false;
118 }
119
120 SkRasterClip rectClip;
reed@google.com045e62d2011-10-24 12:19:46 +0000121 SkMatrix translatedMatrix; // this translates us to our local pixels
122 SkMatrix drawMatrix; // this translates the path by each layer's offset
reed@google.com82065d62011-02-07 15:30:46 +0000123
reed@google.com045e62d2011-10-24 12:19:46 +0000124 rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height()));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125
126 translatedMatrix = matrix;
127 translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
128 -SkIntToScalar(mask->fBounds.fTop));
129
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 draw.fMatrix = &drawMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000131 draw.fRC = &rectClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 // we set the matrixproc in the loop, as the matrix changes each time (potentially)
reed@google.com82065d62011-02-07 15:30:46 +0000133
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000134 SkDeque::F2BIter iter(*fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 SkLayerRasterizer_Rec* rec;
136
halcanary96fcdcc2015-08-27 07:41:13 -0700137 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 drawMatrix = translatedMatrix;
139 drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
140 draw.drawPath(path, rec->fPaint);
141 }
142 }
143 return true;
144}
145
reed60c9b582016-04-03 09:11:13 -0700146sk_sp<SkFlattenable> SkLayerRasterizer::CreateProc(SkReadBuffer& buffer) {
147 return sk_sp<SkFlattenable>(new SkLayerRasterizer(ReadLayers(buffer)));
reed9fa60da2014-08-21 07:59:51 -0700148}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000149
150SkDeque* SkLayerRasterizer::ReadLayers(SkReadBuffer& buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000151 int count = buffer.readInt();
mtklein3f3b3d02014-12-01 11:47:08 -0800152
halcanary385fe4d2015-08-26 13:07:48 -0700153 SkDeque* layers = new SkDeque(sizeof(SkLayerRasterizer_Rec));
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000154 for (int i = 0; i < count; i++) {
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000155 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)layers->push_back();
reed@google.com82065d62011-02-07 15:30:46 +0000156
halcanary385fe4d2015-08-26 13:07:48 -0700157 new (&rec->fPaint) SkPaint;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000158 buffer.readPaint(&rec->fPaint);
159 buffer.readPoint(&rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 }
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000161 return layers;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000164void SkLayerRasterizer::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 this->INHERITED::flatten(buffer);
166
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000167 SkASSERT(fLayers);
168 buffer.writeInt(fLayers->count());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000170 SkDeque::F2BIter iter(*fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 const SkLayerRasterizer_Rec* rec;
172
halcanary96fcdcc2015-08-27 07:41:13 -0700173 while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000174 buffer.writePaint(rec->fPaint);
175 buffer.writePoint(rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 }
177}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000178
halcanary385fe4d2015-08-26 13:07:48 -0700179SkLayerRasterizer::Builder::Builder() : fLayers(new SkDeque(sizeof(SkLayerRasterizer_Rec))) {}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000180
181SkLayerRasterizer::Builder::~Builder()
182{
halcanary96fcdcc2015-08-27 07:41:13 -0700183 if (fLayers != nullptr) {
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000184 clean_up_layers(fLayers);
185 }
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000186}
187
188void SkLayerRasterizer::Builder::addLayer(const SkPaint& paint, SkScalar dx,
189 SkScalar dy) {
190 SkASSERT(fLayers);
191 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers->push_back();
192
halcanary385fe4d2015-08-26 13:07:48 -0700193 new (&rec->fPaint) SkPaint(paint);
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000194 rec->fOffset.set(dx, dy);
195}
196
reed7b380d02016-03-21 13:25:16 -0700197sk_sp<SkLayerRasterizer> SkLayerRasterizer::Builder::detach() {
scroggo65044bf2014-06-03 13:12:51 -0700198 SkLayerRasterizer* rasterizer;
199 if (0 == fLayers->count()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700200 rasterizer = nullptr;
halcanary385fe4d2015-08-26 13:07:48 -0700201 delete fLayers;
scroggo65044bf2014-06-03 13:12:51 -0700202 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700203 rasterizer = new SkLayerRasterizer(fLayers);
scroggo65044bf2014-06-03 13:12:51 -0700204 }
halcanary96fcdcc2015-08-27 07:41:13 -0700205 fLayers = nullptr;
reed7b380d02016-03-21 13:25:16 -0700206 return sk_sp<SkLayerRasterizer>(rasterizer);
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000207}
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000208
reed7b380d02016-03-21 13:25:16 -0700209sk_sp<SkLayerRasterizer> SkLayerRasterizer::Builder::snapshot() const {
scroggo65044bf2014-06-03 13:12:51 -0700210 if (0 == fLayers->count()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700211 return nullptr;
scroggo65044bf2014-06-03 13:12:51 -0700212 }
halcanary385fe4d2015-08-26 13:07:48 -0700213 SkDeque* layers = new SkDeque(sizeof(SkLayerRasterizer_Rec), fLayers->count());
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000214 SkDeque::F2BIter iter(*fLayers);
215 const SkLayerRasterizer_Rec* recOrig;
216 SkDEBUGCODE(int count = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -0700217 while ((recOrig = static_cast<SkLayerRasterizer_Rec*>(iter.next())) != nullptr) {
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000218 SkDEBUGCODE(count++);
219 SkLayerRasterizer_Rec* recCopy = static_cast<SkLayerRasterizer_Rec*>(layers->push_back());
halcanary385fe4d2015-08-26 13:07:48 -0700220 new (&recCopy->fPaint) SkPaint(recOrig->fPaint);
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000221 recCopy->fOffset = recOrig->fOffset;
222 }
223 SkASSERT(fLayers->count() == count);
224 SkASSERT(layers->count() == count);
reed7b380d02016-03-21 13:25:16 -0700225 return sk_sp<SkLayerRasterizer>(new SkLayerRasterizer(layers));
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000226}