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