blob: ea5808c2b4e7c80749a49f932e9e5c431bb42fbf [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkLayerRasterizer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkDraw.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkFlattenableBuffers.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
27SkLayerRasterizer::SkLayerRasterizer() : fLayers(sizeof(SkLayerRasterizer_Rec))
28{
29}
30
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000031SkLayerRasterizer::~SkLayerRasterizer() {
reed@google.com4c09d5c2011-02-22 13:16:38 +000032 SkDeque::F2BIter iter(fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +000033 SkLayerRasterizer_Rec* rec;
34
35 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
36 rec->fPaint.~SkPaint();
37}
38
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000039void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx,
40 SkScalar dy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
42
tomhudson@google.com060ef182012-07-24 12:22:40 +000043 SkNEW_PLACEMENT_ARGS(&rec->fPaint, SkPaint, (paint));
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 rec->fOffset.set(dx, dy);
45}
46
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000047static bool compute_bounds(const SkDeque& layers, const SkPath& path,
48 const SkMatrix& matrix,
49 const SkIRect* clipBounds, SkIRect* bounds) {
reed@google.com4c09d5c2011-02-22 13:16:38 +000050 SkDeque::F2BIter iter(layers);
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 SkLayerRasterizer_Rec* rec;
52
53 bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32);
reed@google.com82065d62011-02-07 15:30:46 +000054
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000055 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 const SkPaint& paint = rec->fPaint;
57 SkPath fillPath, devPath;
58 const SkPath* p = &path;
59
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000060 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 paint.getFillPath(path, &fillPath);
62 p = &fillPath;
63 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000064 if (p->isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 continue;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000066 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000067
68 // apply the matrix and offset
69 {
70 SkMatrix m = matrix;
71 m.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
72 p->transform(m, &devPath);
73 }
74
75 SkMask mask;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000076 if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(),
77 &matrix, &mask,
junov@chromium.org2ac4ef52012-04-04 15:16:51 +000078 SkMask::kJustComputeBounds_CreateMode,
79 SkPaint::kFill_Style)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000082
83 bounds->join(mask.fBounds);
84 }
85 return true;
86}
87
88bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
89 const SkIRect* clipBounds,
reed@google.comfdba4042012-12-18 16:57:03 +000090 SkMask* mask, SkMask::CreateMode mode) const {
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000091 if (fLayers.empty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000093 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000094
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000095 if (SkMask::kJustRenderImage_CreateMode != mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds))
97 return false;
98 }
99
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000100 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 mask->fFormat = SkMask::kA8_Format;
reed@android.com49f0ff22009-03-19 21:52:42 +0000102 mask->fRowBytes = mask->fBounds.width();
reed@android.com543ed932009-04-24 12:43:40 +0000103 size_t size = mask->computeImageSize();
104 if (0 == size) {
105 return false; // too big to allocate, abort
106 }
107 mask->fImage = SkMask::AllocImage(size);
108 memset(mask->fImage, 0, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 }
110
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000111 if (SkMask::kJustComputeBounds_CreateMode != mode) {
reed@google.com045e62d2011-10-24 12:19:46 +0000112 SkBitmap device;
113 SkRasterClip rectClip;
114 SkDraw draw;
115 SkMatrix translatedMatrix; // this translates us to our local pixels
116 SkMatrix drawMatrix; // this translates the path by each layer's offset
reed@google.com82065d62011-02-07 15:30:46 +0000117
reed@google.com045e62d2011-10-24 12:19:46 +0000118 rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height()));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
120 translatedMatrix = matrix;
121 translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
122 -SkIntToScalar(mask->fBounds.fTop));
123
124 device.setConfig(SkBitmap::kA8_Config, mask->fBounds.width(), mask->fBounds.height(), mask->fRowBytes);
125 device.setPixels(mask->fImage);
126
127 draw.fBitmap = &device;
128 draw.fMatrix = &drawMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000129 draw.fRC = &rectClip;
130 draw.fClip = &rectClip.bwRgn();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 // we set the matrixproc in the loop, as the matrix changes each time (potentially)
132 draw.fBounder = NULL;
reed@google.com82065d62011-02-07 15:30:46 +0000133
reed@google.com4c09d5c2011-02-22 13:16:38 +0000134 SkDeque::F2BIter iter(fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 SkLayerRasterizer_Rec* rec;
136
137 while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) {
138 drawMatrix = translatedMatrix;
139 drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
140 draw.drawPath(path, rec->fPaint);
141 }
142 }
143 return true;
144}
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146SkLayerRasterizer::SkLayerRasterizer(SkFlattenableReadBuffer& buffer)
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000147 : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec)) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000148 int count = buffer.readInt();
reed@google.com82065d62011-02-07 15:30:46 +0000149
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000150 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
reed@google.com82065d62011-02-07 15:30:46 +0000152
tomhudson@google.com060ef182012-07-24 12:22:40 +0000153 SkNEW_PLACEMENT(&rec->fPaint, SkPaint);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000154 buffer.readPaint(&rec->fPaint);
155 buffer.readPoint(&rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 }
157}
158
djsollen@google.com54924242012-03-29 15:18:04 +0000159void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 this->INHERITED::flatten(buffer);
161
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000162 buffer.writeInt(fLayers.count());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163
reed@google.com4c09d5c2011-02-22 13:16:38 +0000164 SkDeque::F2BIter iter(fLayers);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 const SkLayerRasterizer_Rec* rec;
166
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000167 while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000168 buffer.writePaint(rec->fPaint);
169 buffer.writePoint(rec->fOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 }
171}