SkLayerRasterizer.cpp revision a0c2bc24381fea063008f9c8823756eb020603b3
1
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
9
10#include "SkLayerRasterizer.h"
11#include "SkDraw.h"
12#include "SkFlattenableBuffers.h"
13#include "SkMask.h"
14#include "SkMaskFilter.h"
15#include "SkPaint.h"
16#include "SkPath.h"
17#include "SkPathEffect.h"
18#include "../core/SkRasterClip.h"
19#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
31SkLayerRasterizer::~SkLayerRasterizer() {
32    SkDeque::F2BIter        iter(fLayers);
33    SkLayerRasterizer_Rec*  rec;
34
35    while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
36        rec->fPaint.~SkPaint();
37}
38
39void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx,
40                                 SkScalar dy) {
41    SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
42
43    SkNEW_PLACEMENT_ARGS(&rec->fPaint, SkPaint, (paint));
44    rec->fOffset.set(dx, dy);
45}
46
47static bool compute_bounds(const SkDeque& layers, const SkPath& path,
48                           const SkMatrix& matrix,
49                           const SkIRect* clipBounds, SkIRect* bounds) {
50    SkDeque::F2BIter        iter(layers);
51    SkLayerRasterizer_Rec*  rec;
52
53    bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32);
54
55    while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) {
56        const SkPaint&  paint = rec->fPaint;
57        SkPath          fillPath, devPath;
58        const SkPath*   p = &path;
59
60        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
61            paint.getFillPath(path, &fillPath);
62            p = &fillPath;
63        }
64        if (p->isEmpty()) {
65            continue;
66        }
67
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;
76        if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(),
77                                &matrix, &mask,
78                                SkMask::kJustComputeBounds_CreateMode,
79                                SkPaint::kFill_Style)) {
80            return false;
81        }
82
83        bounds->join(mask.fBounds);
84    }
85    return true;
86}
87
88bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
89                                    const SkIRect* clipBounds,
90                                    SkMask* mask, SkMask::CreateMode mode) {
91    if (fLayers.empty()) {
92        return false;
93    }
94
95    if (SkMask::kJustRenderImage_CreateMode != mode) {
96        if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds))
97            return false;
98    }
99
100    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
101        mask->fFormat   = SkMask::kA8_Format;
102        mask->fRowBytes = mask->fBounds.width();
103        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);
109    }
110
111    if (SkMask::kJustComputeBounds_CreateMode != mode) {
112        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
117
118        rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height()));
119
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;
129        draw.fRC        = &rectClip;
130        draw.fClip      = &rectClip.bwRgn();
131        // we set the matrixproc in the loop, as the matrix changes each time (potentially)
132        draw.fBounder   = NULL;
133
134        SkDeque::F2BIter        iter(fLayers);
135        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
146SkLayerRasterizer::SkLayerRasterizer(SkFlattenableReadBuffer& buffer)
147    : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec)) {
148    int count = buffer.readInt();
149
150    for (int i = 0; i < count; i++) {
151        SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
152
153        SkNEW_PLACEMENT(&rec->fPaint, SkPaint);
154        buffer.readPaint(&rec->fPaint);
155        buffer.readPoint(&rec->fOffset);
156    }
157}
158
159void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) const {
160    this->INHERITED::flatten(buffer);
161
162    buffer.writeInt(fLayers.count());
163
164    SkDeque::F2BIter                iter(fLayers);
165    const SkLayerRasterizer_Rec*    rec;
166
167    while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) {
168        buffer.writePaint(rec->fPaint);
169        buffer.writePoint(rec->fOffset);
170    }
171}
172