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