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