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