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