| epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 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 |  | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 9 |  | 
 | 10 | #include "SkLayerRasterizer.h" | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 11 | #include "SkDraw.h" | 
| djsollen@google.com | c73dd5c | 2012-08-07 15:54:32 +0000 | [diff] [blame] | 12 | #include "SkFlattenableBuffers.h" | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 13 | #include "SkMask.h" | 
 | 14 | #include "SkMaskFilter.h" | 
 | 15 | #include "SkPaint.h" | 
 | 16 | #include "SkPath.h" | 
| reed@google.com | 75a0972 | 2012-05-10 12:56:16 +0000 | [diff] [blame] | 17 | #include "SkPathEffect.h" | 
| reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 18 | #include "../core/SkRasterClip.h" | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 19 | #include "SkXfermode.h" | 
 | 20 | #include <new> | 
 | 21 |  | 
 | 22 | struct SkLayerRasterizer_Rec { | 
 | 23 |     SkPaint     fPaint; | 
 | 24 |     SkVector    fOffset; | 
 | 25 | }; | 
 | 26 |  | 
 | 27 | SkLayerRasterizer::SkLayerRasterizer() : fLayers(sizeof(SkLayerRasterizer_Rec)) | 
 | 28 | { | 
 | 29 | } | 
 | 30 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 31 | SkLayerRasterizer::~SkLayerRasterizer() { | 
| reed@google.com | 4c09d5c | 2011-02-22 13:16:38 +0000 | [diff] [blame] | 32 |     SkDeque::F2BIter        iter(fLayers); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 33 |     SkLayerRasterizer_Rec*  rec; | 
 | 34 |  | 
 | 35 |     while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) | 
 | 36 |         rec->fPaint.~SkPaint(); | 
 | 37 | } | 
 | 38 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 39 | void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, | 
 | 40 |                                  SkScalar dy) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 41 |     SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back(); | 
 | 42 |  | 
| tomhudson@google.com | 060ef18 | 2012-07-24 12:22:40 +0000 | [diff] [blame] | 43 |     SkNEW_PLACEMENT_ARGS(&rec->fPaint, SkPaint, (paint)); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 44 |     rec->fOffset.set(dx, dy); | 
 | 45 | } | 
 | 46 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 47 | static bool compute_bounds(const SkDeque& layers, const SkPath& path, | 
 | 48 |                            const SkMatrix& matrix, | 
 | 49 |                            const SkIRect* clipBounds, SkIRect* bounds) { | 
| reed@google.com | 4c09d5c | 2011-02-22 13:16:38 +0000 | [diff] [blame] | 50 |     SkDeque::F2BIter        iter(layers); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 51 |     SkLayerRasterizer_Rec*  rec; | 
 | 52 |  | 
 | 53 |     bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32); | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 54 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 55 |     while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 56 |         const SkPaint&  paint = rec->fPaint; | 
 | 57 |         SkPath          fillPath, devPath; | 
 | 58 |         const SkPath*   p = &path; | 
 | 59 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 60 |         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 61 |             paint.getFillPath(path, &fillPath); | 
 | 62 |             p = &fillPath; | 
 | 63 |         } | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 64 |         if (p->isEmpty()) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 65 |             continue; | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 66 |         } | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 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; | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 76 |         if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(), | 
 | 77 |                                 &matrix, &mask, | 
| junov@chromium.org | 2ac4ef5 | 2012-04-04 15:16:51 +0000 | [diff] [blame] | 78 |                                 SkMask::kJustComputeBounds_CreateMode, | 
 | 79 |                                 SkPaint::kFill_Style)) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 80 |             return false; | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 81 |         } | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 82 |  | 
 | 83 |         bounds->join(mask.fBounds); | 
 | 84 |     } | 
 | 85 |     return true; | 
 | 86 | } | 
 | 87 |  | 
 | 88 | bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix, | 
 | 89 |                                     const SkIRect* clipBounds, | 
| reed@google.com | fdba404 | 2012-12-18 16:57:03 +0000 | [diff] [blame] | 90 |                                     SkMask* mask, SkMask::CreateMode mode) const { | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 91 |     if (fLayers.empty()) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 92 |         return false; | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 93 |     } | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 94 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 95 |     if (SkMask::kJustRenderImage_CreateMode != mode) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 96 |         if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds)) | 
 | 97 |             return false; | 
 | 98 |     } | 
 | 99 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 100 |     if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 101 |         mask->fFormat   = SkMask::kA8_Format; | 
| reed@android.com | 49f0ff2 | 2009-03-19 21:52:42 +0000 | [diff] [blame] | 102 |         mask->fRowBytes = mask->fBounds.width(); | 
| reed@android.com | 543ed93 | 2009-04-24 12:43:40 +0000 | [diff] [blame] | 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); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 109 |     } | 
 | 110 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 111 |     if (SkMask::kJustComputeBounds_CreateMode != mode) { | 
| reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 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 | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 117 |  | 
| reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 118 |         rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height())); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 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; | 
| reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 129 |         draw.fRC        = &rectClip; | 
 | 130 |         draw.fClip      = &rectClip.bwRgn(); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 131 |         // we set the matrixproc in the loop, as the matrix changes each time (potentially) | 
 | 132 |         draw.fBounder   = NULL; | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 133 |  | 
| reed@google.com | 4c09d5c | 2011-02-22 13:16:38 +0000 | [diff] [blame] | 134 |         SkDeque::F2BIter        iter(fLayers); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 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 |  | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 146 | SkLayerRasterizer::SkLayerRasterizer(SkFlattenableReadBuffer& buffer) | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 147 |     : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec)) { | 
| djsollen@google.com | c73dd5c | 2012-08-07 15:54:32 +0000 | [diff] [blame] | 148 |     int count = buffer.readInt(); | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 149 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 150 |     for (int i = 0; i < count; i++) { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 151 |         SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back(); | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 152 |  | 
| tomhudson@google.com | 060ef18 | 2012-07-24 12:22:40 +0000 | [diff] [blame] | 153 |         SkNEW_PLACEMENT(&rec->fPaint, SkPaint); | 
| djsollen@google.com | c73dd5c | 2012-08-07 15:54:32 +0000 | [diff] [blame] | 154 |         buffer.readPaint(&rec->fPaint); | 
 | 155 |         buffer.readPoint(&rec->fOffset); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 156 |     } | 
 | 157 | } | 
 | 158 |  | 
| djsollen@google.com | 5492424 | 2012-03-29 15:18:04 +0000 | [diff] [blame] | 159 | void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) const { | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 160 |     this->INHERITED::flatten(buffer); | 
 | 161 |  | 
| djsollen@google.com | c73dd5c | 2012-08-07 15:54:32 +0000 | [diff] [blame] | 162 |     buffer.writeInt(fLayers.count()); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 163 |  | 
| reed@google.com | 4c09d5c | 2011-02-22 13:16:38 +0000 | [diff] [blame] | 164 |     SkDeque::F2BIter                iter(fLayers); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 165 |     const SkLayerRasterizer_Rec*    rec; | 
 | 166 |  | 
| mike@reedtribe.org | 3334c3a | 2011-04-20 11:39:28 +0000 | [diff] [blame] | 167 |     while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) { | 
| djsollen@google.com | c73dd5c | 2012-08-07 15:54:32 +0000 | [diff] [blame] | 168 |         buffer.writePaint(rec->fPaint); | 
 | 169 |         buffer.writePoint(rec->fOffset); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 170 |     } | 
 | 171 | } |