SkMaskFilter.cpp revision e16efc1882ab34a0bb3ae361a2d37f840044cf87
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 "SkMaskFilter.h" 11#include "SkBlitter.h" 12#include "SkBounder.h" 13#include "SkDraw.h" 14#include "SkRasterClip.h" 15 16 17SK_DEFINE_INST_COUNT(SkMaskFilter) 18 19bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, 20 SkIPoint*) const { 21 return false; 22} 23 24static void extractMaskSubset(const SkMask& src, SkMask* dst) { 25 SkASSERT(src.fBounds.contains(dst->fBounds)); 26 27 const int dx = dst->fBounds.left() - src.fBounds.left(); 28 const int dy = dst->fBounds.top() - src.fBounds.top(); 29 dst->fImage = src.fImage + dy * src.fRowBytes + dx; 30 dst->fRowBytes = src.fRowBytes; 31 dst->fFormat = src.fFormat; 32} 33 34static void blitClippedMask(SkBlitter* blitter, const SkMask& mask, 35 const SkIRect& bounds, const SkIRect& clipR) { 36 SkIRect r; 37 if (r.intersect(bounds, clipR)) { 38 blitter->blitMask(mask, r); 39 } 40} 41 42static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) { 43 SkIRect r; 44 if (r.intersect(rect, clipR)) { 45 blitter->blitRect(r.left(), r.top(), r.width(), r.height()); 46 } 47} 48 49#if 0 50static void dump(const SkMask& mask) { 51 for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) { 52 for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) { 53 SkDebugf("%02X", *mask.getAddr8(x, y)); 54 } 55 SkDebugf("\n"); 56 } 57 SkDebugf("\n"); 58} 59#endif 60 61static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR, 62 const SkIPoint& center, bool fillCenter, 63 const SkIRect& clipR, SkBlitter* blitter) { 64 int cx = center.x(); 65 int cy = center.y(); 66 SkMask m; 67 68 // top-left 69 m.fBounds = mask.fBounds; 70 m.fBounds.fRight = cx; 71 m.fBounds.fBottom = cy; 72 extractMaskSubset(mask, &m); 73 m.fBounds.offsetTo(outerR.left(), outerR.top()); 74 blitClippedMask(blitter, m, m.fBounds, clipR); 75 76 // top-right 77 m.fBounds = mask.fBounds; 78 m.fBounds.fLeft = cx + 1; 79 m.fBounds.fBottom = cy; 80 extractMaskSubset(mask, &m); 81 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top()); 82 blitClippedMask(blitter, m, m.fBounds, clipR); 83 84 // bottom-left 85 m.fBounds = mask.fBounds; 86 m.fBounds.fRight = cx; 87 m.fBounds.fTop = cy + 1; 88 extractMaskSubset(mask, &m); 89 m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height()); 90 blitClippedMask(blitter, m, m.fBounds, clipR); 91 92 // bottom-right 93 m.fBounds = mask.fBounds; 94 m.fBounds.fLeft = cx + 1; 95 m.fBounds.fTop = cy + 1; 96 extractMaskSubset(mask, &m); 97 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), 98 outerR.bottom() - m.fBounds.height()); 99 blitClippedMask(blitter, m, m.fBounds, clipR); 100 101 SkIRect innerR; 102 innerR.set(outerR.left() + cx - mask.fBounds.left(), 103 outerR.top() + cy - mask.fBounds.top(), 104 outerR.right() + (cx + 1 - mask.fBounds.right()), 105 outerR.bottom() + (cy + 1 - mask.fBounds.bottom())); 106 if (fillCenter) { 107 blitClippedRect(blitter, innerR, clipR); 108 } 109 110 const int innerW = innerR.width(); 111 size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t)); 112 SkAutoSMalloc<4*1024> storage(storageSize); 113 int16_t* runs = (int16_t*)storage.get(); 114 uint8_t* alpha = (uint8_t*)(runs + innerW + 1); 115 116 SkIRect r; 117 // top 118 r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top()); 119 if (r.intersect(clipR)) { 120 int startY = SkMax32(0, r.top() - outerR.top()); 121 int stopY = startY + r.height(); 122 int width = r.width(); 123 for (int y = startY; y < stopY; ++y) { 124 runs[0] = width; 125 runs[width] = 0; 126 alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y); 127 blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs); 128 } 129 } 130 // bottom 131 r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom()); 132 if (r.intersect(clipR)) { 133 int startY = outerR.bottom() - r.bottom(); 134 int stopY = startY + r.height(); 135 int width = r.width(); 136 for (int y = startY; y < stopY; ++y) { 137 runs[0] = width; 138 runs[width] = 0; 139 alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1); 140 blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs); 141 } 142 } 143 // left 144 r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom()); 145 if (r.intersect(clipR)) { 146 int startX = r.left() - outerR.left(); 147 int stopX = startX + r.width(); 148 int height = r.height(); 149 for (int x = startX; x < stopX; ++x) { 150 blitter->blitV(outerR.left() + x, r.top(), height, 151 *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy)); 152 } 153 } 154 // right 155 r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom()); 156 if (r.intersect(clipR)) { 157 int startX = outerR.right() - r.right(); 158 int stopX = startX + r.width(); 159 int height = r.height(); 160 for (int x = startX; x < stopX; ++x) { 161 blitter->blitV(outerR.right() - x - 1, r.top(), height, 162 *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy)); 163 } 164 } 165} 166 167static void draw_nine(const SkMask& mask, const SkIRect& outerR, 168 const SkIPoint& center, bool fillCenter, 169 const SkRasterClip& clip, SkBounder* bounder, 170 SkBlitter* blitter) { 171 // if we get here, we need to (possibly) resolve the clip and blitter 172 SkAAClipBlitterWrapper wrapper(clip, blitter); 173 blitter = wrapper.getBlitter(); 174 175 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR); 176 177 if (!clipper.done() && (!bounder || bounder->doIRect(outerR))) { 178 const SkIRect& cr = clipper.rect(); 179 do { 180 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter); 181 clipper.next(); 182 } while (!clipper.done()); 183 } 184} 185 186static int countNestedRects(const SkPath& path, SkRect rects[2]) { 187 if (path.isNestedRects(rects)) { 188 return 2; 189 } 190 return path.isRect(&rects[0]); 191} 192 193bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, 194 const SkRasterClip& clip, SkBounder* bounder, 195 SkBlitter* blitter, SkPaint::Style style) const { 196 SkRect rects[2]; 197 int rectCount = 0; 198 if (SkPaint::kFill_Style == style) { 199 rectCount = countNestedRects(devPath, rects); 200 } 201 if (rectCount > 0) { 202 NinePatch patch; 203 204 patch.fMask.fImage = NULL; 205 switch (this->filterRectsToNine(rects, rectCount, matrix, 206 clip.getBounds(), &patch)) { 207 case kFalse_FilterReturn: 208 SkASSERT(NULL == patch.fMask.fImage); 209 return false; 210 211 case kTrue_FilterReturn: 212 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 213 1 == rectCount, clip, bounder, blitter); 214 SkMask::FreeImage(patch.fMask.fImage); 215 return true; 216 217 case kUnimplemented_FilterReturn: 218 SkASSERT(NULL == patch.fMask.fImage); 219 // fall through 220 break; 221 } 222 } 223 224 SkMask srcM, dstM; 225 226 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM, 227 SkMask::kComputeBoundsAndRenderImage_CreateMode, 228 style)) { 229 return false; 230 } 231 SkAutoMaskFreeImage autoSrc(srcM.fImage); 232 233 if (!this->filterMask(&dstM, srcM, matrix, NULL)) { 234 return false; 235 } 236 SkAutoMaskFreeImage autoDst(dstM.fImage); 237 238 // if we get here, we need to (possibly) resolve the clip and blitter 239 SkAAClipBlitterWrapper wrapper(clip, blitter); 240 blitter = wrapper.getBlitter(); 241 242 SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds); 243 244 if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) { 245 const SkIRect& cr = clipper.rect(); 246 do { 247 blitter->blitMask(dstM, cr); 248 clipper.next(); 249 } while (!clipper.done()); 250 } 251 252 return true; 253} 254 255SkMaskFilter::FilterReturn 256SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&, 257 const SkIRect& clipBounds, NinePatch*) const { 258 return kUnimplemented_FilterReturn; 259} 260 261SkMaskFilter::BlurType SkMaskFilter::asABlur(BlurInfo*) const { 262 return kNone_BlurType; 263} 264 265void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 266 SkMask srcM, dstM; 267 268 srcM.fImage = NULL; 269 src.roundOut(&srcM.fBounds); 270 srcM.fRowBytes = 0; 271 srcM.fFormat = SkMask::kA8_Format; 272 273 SkIPoint margin; // ignored 274 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) { 275 dst->set(dstM.fBounds); 276 } else { 277 dst->set(srcM.fBounds); 278 } 279} 280