blob: 91502b7e8446d8ebe5434db7d573a4a0221ac9cb [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"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019#include "SkXfermode.h"
20#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,
81 SkPaint::kFill_Style)) {
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;
132 draw.fClip = &rectClip.bwRgn();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 // we set the matrixproc in the loop, as the matrix changes each time (potentially)
reed@google.com82065d62011-02-07 15:30:46 +0000134
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000135 SkDeque::F2BIter iter(*fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 SkLayerRasterizer_Rec* rec;
137
halcanary96fcdcc2015-08-27 07:41:13 -0700138 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 drawMatrix = translatedMatrix;
140 drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
141 draw.drawPath(path, rec->fPaint);
142 }
143 }
144 return true;
145}
146
reed60c9b582016-04-03 09:11:13 -0700147sk_sp<SkFlattenable> SkLayerRasterizer::CreateProc(SkReadBuffer& buffer) {
148 return sk_sp<SkFlattenable>(new SkLayerRasterizer(ReadLayers(buffer)));
reed9fa60da2014-08-21 07:59:51 -0700149}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000150
151SkDeque* SkLayerRasterizer::ReadLayers(SkReadBuffer& buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000152 int count = buffer.readInt();
mtklein3f3b3d02014-12-01 11:47:08 -0800153
halcanary385fe4d2015-08-26 13:07:48 -0700154 SkDeque* layers = new SkDeque(sizeof(SkLayerRasterizer_Rec));
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000155 for (int i = 0; i < count; i++) {
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000156 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)layers->push_back();
reed@google.com82065d62011-02-07 15:30:46 +0000157
halcanary385fe4d2015-08-26 13:07:48 -0700158 new (&rec->fPaint) SkPaint;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000159 buffer.readPaint(&rec->fPaint);
160 buffer.readPoint(&rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 }
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000162 return layers;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163}
164
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000165void SkLayerRasterizer::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 this->INHERITED::flatten(buffer);
167
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000168 SkASSERT(fLayers);
169 buffer.writeInt(fLayers->count());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000171 SkDeque::F2BIter iter(*fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 const SkLayerRasterizer_Rec* rec;
173
halcanary96fcdcc2015-08-27 07:41:13 -0700174 while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000175 buffer.writePaint(rec->fPaint);
176 buffer.writePoint(rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 }
178}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000179
halcanary385fe4d2015-08-26 13:07:48 -0700180SkLayerRasterizer::Builder::Builder() : fLayers(new SkDeque(sizeof(SkLayerRasterizer_Rec))) {}
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000181
182SkLayerRasterizer::Builder::~Builder()
183{
halcanary96fcdcc2015-08-27 07:41:13 -0700184 if (fLayers != nullptr) {
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000185 clean_up_layers(fLayers);
186 }
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000187}
188
189void SkLayerRasterizer::Builder::addLayer(const SkPaint& paint, SkScalar dx,
190 SkScalar dy) {
191 SkASSERT(fLayers);
192 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers->push_back();
193
halcanary385fe4d2015-08-26 13:07:48 -0700194 new (&rec->fPaint) SkPaint(paint);
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000195 rec->fOffset.set(dx, dy);
196}
197
reed7b380d02016-03-21 13:25:16 -0700198sk_sp<SkLayerRasterizer> SkLayerRasterizer::Builder::detach() {
scroggo65044bf2014-06-03 13:12:51 -0700199 SkLayerRasterizer* rasterizer;
200 if (0 == fLayers->count()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700201 rasterizer = nullptr;
halcanary385fe4d2015-08-26 13:07:48 -0700202 delete fLayers;
scroggo65044bf2014-06-03 13:12:51 -0700203 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700204 rasterizer = new SkLayerRasterizer(fLayers);
scroggo65044bf2014-06-03 13:12:51 -0700205 }
halcanary96fcdcc2015-08-27 07:41:13 -0700206 fLayers = nullptr;
reed7b380d02016-03-21 13:25:16 -0700207 return sk_sp<SkLayerRasterizer>(rasterizer);
commit-bot@chromium.orgf792a1b2014-02-26 13:27:37 +0000208}
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000209
reed7b380d02016-03-21 13:25:16 -0700210sk_sp<SkLayerRasterizer> SkLayerRasterizer::Builder::snapshot() const {
scroggo65044bf2014-06-03 13:12:51 -0700211 if (0 == fLayers->count()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700212 return nullptr;
scroggo65044bf2014-06-03 13:12:51 -0700213 }
halcanary385fe4d2015-08-26 13:07:48 -0700214 SkDeque* layers = new SkDeque(sizeof(SkLayerRasterizer_Rec), fLayers->count());
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000215 SkDeque::F2BIter iter(*fLayers);
216 const SkLayerRasterizer_Rec* recOrig;
217 SkDEBUGCODE(int count = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -0700218 while ((recOrig = static_cast<SkLayerRasterizer_Rec*>(iter.next())) != nullptr) {
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000219 SkDEBUGCODE(count++);
220 SkLayerRasterizer_Rec* recCopy = static_cast<SkLayerRasterizer_Rec*>(layers->push_back());
halcanary385fe4d2015-08-26 13:07:48 -0700221 new (&recCopy->fPaint) SkPaint(recOrig->fPaint);
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000222 recCopy->fOffset = recOrig->fOffset;
223 }
224 SkASSERT(fLayers->count() == count);
225 SkASSERT(layers->count() == count);
reed7b380d02016-03-21 13:25:16 -0700226 return sk_sp<SkLayerRasterizer>(new SkLayerRasterizer(layers));
commit-bot@chromium.org6573ce72014-04-10 20:42:53 +0000227}