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 #include "SkTypes.h" 16 17 #if SK_SUPPORT_GPU 18 #include "GrTexture.h" 19 #include "SkGr.h" 20 #include "SkGrPixelRef.h" 21 #endif 22 23 SK_DEFINE_INST_COUNT(SkMaskFilter) 24 25 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, 26 SkIPoint*) const { 27 return false; 28 } 29 30 static void extractMaskSubset(const SkMask& src, SkMask* dst) { 31 SkASSERT(src.fBounds.contains(dst->fBounds)); 32 33 const int dx = dst->fBounds.left() - src.fBounds.left(); 34 const int dy = dst->fBounds.top() - src.fBounds.top(); 35 dst->fImage = src.fImage + dy * src.fRowBytes + dx; 36 dst->fRowBytes = src.fRowBytes; 37 dst->fFormat = src.fFormat; 38 } 39 40 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask, 41 const SkIRect& bounds, const SkIRect& clipR) { 42 SkIRect r; 43 if (r.intersect(bounds, clipR)) { 44 blitter->blitMask(mask, r); 45 } 46 } 47 48 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) { 49 SkIRect r; 50 if (r.intersect(rect, clipR)) { 51 blitter->blitRect(r.left(), r.top(), r.width(), r.height()); 52 } 53 } 54 55 #if 0 56 static void dump(const SkMask& mask) { 57 for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) { 58 for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) { 59 SkDebugf("%02X", *mask.getAddr8(x, y)); 60 } 61 SkDebugf("\n"); 62 } 63 SkDebugf("\n"); 64 } 65 #endif 66 67 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR, 68 const SkIPoint& center, bool fillCenter, 69 const SkIRect& clipR, SkBlitter* blitter) { 70 int cx = center.x(); 71 int cy = center.y(); 72 SkMask m; 73 74 // top-left 75 m.fBounds = mask.fBounds; 76 m.fBounds.fRight = cx; 77 m.fBounds.fBottom = cy; 78 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) { 79 extractMaskSubset(mask, &m); 80 m.fBounds.offsetTo(outerR.left(), outerR.top()); 81 blitClippedMask(blitter, m, m.fBounds, clipR); 82 } 83 84 // top-right 85 m.fBounds = mask.fBounds; 86 m.fBounds.fLeft = cx + 1; 87 m.fBounds.fBottom = cy; 88 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) { 89 extractMaskSubset(mask, &m); 90 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top()); 91 blitClippedMask(blitter, m, m.fBounds, clipR); 92 } 93 94 // bottom-left 95 m.fBounds = mask.fBounds; 96 m.fBounds.fRight = cx; 97 m.fBounds.fTop = cy + 1; 98 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) { 99 extractMaskSubset(mask, &m); 100 m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height()); 101 blitClippedMask(blitter, m, m.fBounds, clipR); 102 } 103 104 // bottom-right 105 m.fBounds = mask.fBounds; 106 m.fBounds.fLeft = cx + 1; 107 m.fBounds.fTop = cy + 1; 108 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) { 109 extractMaskSubset(mask, &m); 110 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), 111 outerR.bottom() - m.fBounds.height()); 112 blitClippedMask(blitter, m, m.fBounds, clipR); 113 } 114 115 SkIRect innerR; 116 innerR.set(outerR.left() + cx - mask.fBounds.left(), 117 outerR.top() + cy - mask.fBounds.top(), 118 outerR.right() + (cx + 1 - mask.fBounds.right()), 119 outerR.bottom() + (cy + 1 - mask.fBounds.bottom())); 120 if (fillCenter) { 121 blitClippedRect(blitter, innerR, clipR); 122 } 123 124 const int innerW = innerR.width(); 125 size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t)); 126 SkAutoSMalloc<4*1024> storage(storageSize); 127 int16_t* runs = (int16_t*)storage.get(); 128 uint8_t* alpha = (uint8_t*)(runs + innerW + 1); 129 130 SkIRect r; 131 // top 132 r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top()); 133 if (r.intersect(clipR)) { 134 int startY = SkMax32(0, r.top() - outerR.top()); 135 int stopY = startY + r.height(); 136 int width = r.width(); 137 for (int y = startY; y < stopY; ++y) { 138 runs[0] = width; 139 runs[width] = 0; 140 alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y); 141 blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs); 142 } 143 } 144 // bottom 145 r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom()); 146 if (r.intersect(clipR)) { 147 int startY = outerR.bottom() - r.bottom(); 148 int stopY = startY + r.height(); 149 int width = r.width(); 150 for (int y = startY; y < stopY; ++y) { 151 runs[0] = width; 152 runs[width] = 0; 153 alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1); 154 blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs); 155 } 156 } 157 // left 158 r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom()); 159 if (r.intersect(clipR)) { 160 int startX = r.left() - outerR.left(); 161 int stopX = startX + r.width(); 162 int height = r.height(); 163 for (int x = startX; x < stopX; ++x) { 164 blitter->blitV(outerR.left() + x, r.top(), height, 165 *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy)); 166 } 167 } 168 // right 169 r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom()); 170 if (r.intersect(clipR)) { 171 int startX = outerR.right() - r.right(); 172 int stopX = startX + r.width(); 173 int height = r.height(); 174 for (int x = startX; x < stopX; ++x) { 175 blitter->blitV(outerR.right() - x - 1, r.top(), height, 176 *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy)); 177 } 178 } 179 } 180 181 static void draw_nine(const SkMask& mask, const SkIRect& outerR, 182 const SkIPoint& center, bool fillCenter, 183 const SkRasterClip& clip, SkBounder* bounder, 184 SkBlitter* blitter) { 185 // if we get here, we need to (possibly) resolve the clip and blitter 186 SkAAClipBlitterWrapper wrapper(clip, blitter); 187 blitter = wrapper.getBlitter(); 188 189 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR); 190 191 if (!clipper.done() && (!bounder || bounder->doIRect(outerR))) { 192 const SkIRect& cr = clipper.rect(); 193 do { 194 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter); 195 clipper.next(); 196 } while (!clipper.done()); 197 } 198 } 199 200 static int countNestedRects(const SkPath& path, SkRect rects[2]) { 201 if (path.isNestedRects(rects)) { 202 return 2; 203 } 204 return path.isRect(&rects[0]); 205 } 206 207 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, 208 const SkRasterClip& clip, SkBounder* bounder, 209 SkBlitter* blitter, SkPaint::Style style) const { 210 SkRect rects[2]; 211 int rectCount = 0; 212 if (SkPaint::kFill_Style == style) { 213 rectCount = countNestedRects(devPath, rects); 214 } 215 if (rectCount > 0) { 216 NinePatch patch; 217 218 patch.fMask.fImage = NULL; 219 switch (this->filterRectsToNine(rects, rectCount, matrix, 220 clip.getBounds(), &patch)) { 221 case kFalse_FilterReturn: 222 SkASSERT(NULL == patch.fMask.fImage); 223 return false; 224 225 case kTrue_FilterReturn: 226 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 227 1 == rectCount, clip, bounder, blitter); 228 SkMask::FreeImage(patch.fMask.fImage); 229 return true; 230 231 case kUnimplemented_FilterReturn: 232 SkASSERT(NULL == patch.fMask.fImage); 233 // fall through 234 break; 235 } 236 } 237 238 SkMask srcM, dstM; 239 240 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM, 241 SkMask::kComputeBoundsAndRenderImage_CreateMode, 242 style)) { 243 return false; 244 } 245 SkAutoMaskFreeImage autoSrc(srcM.fImage); 246 247 if (!this->filterMask(&dstM, srcM, matrix, NULL)) { 248 return false; 249 } 250 SkAutoMaskFreeImage autoDst(dstM.fImage); 251 252 // if we get here, we need to (possibly) resolve the clip and blitter 253 SkAAClipBlitterWrapper wrapper(clip, blitter); 254 blitter = wrapper.getBlitter(); 255 256 SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds); 257 258 if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) { 259 const SkIRect& cr = clipper.rect(); 260 do { 261 blitter->blitMask(dstM, cr); 262 clipper.next(); 263 } while (!clipper.done()); 264 } 265 266 return true; 267 } 268 269 SkMaskFilter::FilterReturn 270 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&, 271 const SkIRect& clipBounds, NinePatch*) const { 272 return kUnimplemented_FilterReturn; 273 } 274 275 #if SK_SUPPORT_GPU 276 bool SkMaskFilter::asNewEffect(GrEffectRef** effect, GrTexture*) const { 277 return false; 278 } 279 280 bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds, 281 const SkIRect& clipBounds, 282 const SkMatrix& ctm, 283 SkRect* maskRect) const { 284 return false; 285 } 286 287 bool SkMaskFilter::filterMaskGPU(GrContext* context, 288 const SkBitmap& srcBM, 289 const SkRect& maskRect, 290 SkBitmap* resultBM) const { 291 SkAutoTUnref<GrTexture> src; 292 bool canOverwriteSrc = false; 293 if (NULL == srcBM.getTexture()) { 294 GrTextureDesc desc; 295 // Needs to be a render target to be overwritten in filterMaskGPU 296 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 297 desc.fConfig = SkBitmapConfig2GrPixelConfig(srcBM.config()); 298 desc.fWidth = srcBM.width(); 299 desc.fHeight = srcBM.height(); 300 301 // TODO: right now this is exact to guard against out of bounds reads 302 // by the filter code. More thought needs to be devoted to the 303 // "filterMaskGPU" contract and then enforced (i.e., clamp the code 304 // in "filterMaskGPU" so it never samples beyond maskRect) 305 GrAutoScratchTexture ast(context, desc, GrContext::kExact_ScratchTexMatch); 306 if (NULL == ast.texture()) { 307 return false; 308 } 309 310 SkAutoLockPixels alp(srcBM); 311 ast.texture()->writePixels(0, 0, srcBM.width(), srcBM.height(), 312 desc.fConfig, 313 srcBM.getPixels(), srcBM.rowBytes()); 314 315 src.reset(ast.detach()); 316 canOverwriteSrc = true; 317 } else { 318 src.reset((GrTexture*) srcBM.getTexture()); 319 src.get()->ref(); 320 } 321 GrTexture* dst; 322 323 bool result = this->filterMaskGPU(src, maskRect, &dst, canOverwriteSrc); 324 if (!result) { 325 return false; 326 } 327 328 resultBM->setConfig(srcBM.config(), dst->width(), dst->height()); 329 resultBM->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (dst)))->unref(); 330 dst->unref(); 331 return true; 332 } 333 334 bool SkMaskFilter::filterMaskGPU(GrTexture* src, 335 const SkRect& maskRect, 336 GrTexture** result, 337 bool canOverwriteSrc) const { 338 return false; 339 } 340 #endif 341 342 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 343 SkMask srcM, dstM; 344 345 srcM.fImage = NULL; 346 src.roundOut(&srcM.fBounds); 347 srcM.fRowBytes = 0; 348 srcM.fFormat = SkMask::kA8_Format; 349 350 SkIPoint margin; // ignored 351 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) { 352 dst->set(dstM.fBounds); 353 } else { 354 dst->set(srcM.fBounds); 355 } 356 } 357