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