| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "SkBlurMaskFilter.h" | 9 #include "SkBlurMaskFilter.h" |
| 10 #include "SkBlurMask.h" | 10 #include "SkBlurMask.h" |
| 11 #include "SkGpuBlurUtils.h" | 11 #include "SkGpuBlurUtils.h" |
| 12 #include "SkFlattenableBuffers.h" | 12 #include "SkFlattenableBuffers.h" |
| 13 #include "SkMaskFilter.h" | 13 #include "SkMaskFilter.h" |
| 14 #include "SkRRect.h" |
| 14 #include "SkRTConf.h" | 15 #include "SkRTConf.h" |
| 15 #include "SkStringUtils.h" | 16 #include "SkStringUtils.h" |
| 16 #include "SkStrokeRec.h" | 17 #include "SkStrokeRec.h" |
| 17 | 18 |
| 18 #if SK_SUPPORT_GPU | 19 #if SK_SUPPORT_GPU |
| 19 #include "GrContext.h" | 20 #include "GrContext.h" |
| 20 #include "GrTexture.h" | 21 #include "GrTexture.h" |
| 21 #include "effects/GrSimpleTextureEffect.h" | 22 #include "effects/GrSimpleTextureEffect.h" |
| 22 #include "SkGrPixelRef.h" | 23 #include "SkGrPixelRef.h" |
| 23 #endif | 24 #endif |
| (...skipping 21 matching lines...) Expand all Loading... |
| 45 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; | 46 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; |
| 46 | 47 |
| 47 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) | 48 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) |
| 48 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) | 49 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) |
| 49 | 50 |
| 50 protected: | 51 protected: |
| 51 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa
trix&, | 52 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa
trix&, |
| 52 const SkIRect& clipBounds, | 53 const SkIRect& clipBounds, |
| 53 NinePatch*) const SK_OVERRIDE; | 54 NinePatch*) const SK_OVERRIDE; |
| 54 | 55 |
| 56 virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&, |
| 57 const SkIRect& clipBounds, |
| 58 NinePatch*) const SK_OVERRIDE; |
| 59 |
| 55 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix, | 60 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix, |
| 56 SkIPoint* margin, SkMask::CreateMode createMode) const; | 61 SkIPoint* margin, SkMask::CreateMode createMode) const; |
| 57 | 62 |
| 58 private: | 63 private: |
| 59 // To avoid unseemly allocation requests (esp. for finite platforms like | 64 // To avoid unseemly allocation requests (esp. for finite platforms like |
| 60 // handset) we limit the radius so something manageable. (as opposed to | 65 // handset) we limit the radius so something manageable. (as opposed to |
| 61 // a request like 10,000) | 66 // a request like 10,000) |
| 62 static const SkScalar kMAX_BLUR_SIGMA; | 67 static const SkScalar kMAX_BLUR_SIGMA; |
| 63 | 68 |
| 64 SkScalar fSigma; | 69 SkScalar fSigma; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 const SkMatrix& matrix, | 153 const SkMatrix& matrix, |
| 149 SkIPoint* margin, SkMask::CreateMode c
reateMode) const{ | 154 SkIPoint* margin, SkMask::CreateMode c
reateMode) const{ |
| 150 SkScalar sigma = computeXformedSigma(matrix); | 155 SkScalar sigma = computeXformedSigma(matrix); |
| 151 | 156 |
| 152 return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, | 157 return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, |
| 153 margin, createMode); | 158 margin, createMode); |
| 154 } | 159 } |
| 155 | 160 |
| 156 #include "SkCanvas.h" | 161 #include "SkCanvas.h" |
| 157 | 162 |
| 158 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) { | 163 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) { |
| 159 rects[0].roundOut(&mask->fBounds); | 164 SkASSERT(mask != NULL); |
| 165 |
| 166 bounds.roundOut(&mask->fBounds); |
| 160 mask->fRowBytes = SkAlign4(mask->fBounds.width()); | 167 mask->fRowBytes = SkAlign4(mask->fBounds.width()); |
| 161 mask->fFormat = SkMask::kA8_Format; | 168 mask->fFormat = SkMask::kA8_Format; |
| 162 size_t size = mask->computeImageSize(); | 169 const size_t size = mask->computeImageSize(); |
| 163 mask->fImage = SkMask::AllocImage(size); | 170 mask->fImage = SkMask::AllocImage(size); |
| 164 if (NULL == mask->fImage) { | 171 if (NULL == mask->fImage) { |
| 165 return false; | 172 return false; |
| 166 } | 173 } |
| 174 |
| 175 // FIXME: use sk_calloc in AllocImage? |
| 167 sk_bzero(mask->fImage, size); | 176 sk_bzero(mask->fImage, size); |
| 177 return true; |
| 178 } |
| 179 |
| 180 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) { |
| 181 if (!prepare_to_draw_into_mask(rrect.rect(), mask)) { |
| 182 return false; |
| 183 } |
| 184 |
| 185 // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there
a |
| 186 // clean way to share more code? |
| 187 SkBitmap bitmap; |
| 188 bitmap.setConfig(SkBitmap::kA8_Config, |
| 189 mask->fBounds.width(), mask->fBounds.height(), |
| 190 mask->fRowBytes); |
| 191 bitmap.setPixels(mask->fImage); |
| 192 |
| 193 SkCanvas canvas(bitmap); |
| 194 canvas.translate(-SkIntToScalar(mask->fBounds.left()), |
| 195 -SkIntToScalar(mask->fBounds.top())); |
| 196 |
| 197 SkPaint paint; |
| 198 paint.setAntiAlias(true); |
| 199 canvas.drawRRect(rrect, paint); |
| 200 return true; |
| 201 } |
| 202 |
| 203 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask)
{ |
| 204 if (!prepare_to_draw_into_mask(rects[0], mask)) { |
| 205 return false; |
| 206 } |
| 168 | 207 |
| 169 SkBitmap bitmap; | 208 SkBitmap bitmap; |
| 170 bitmap.setConfig(SkBitmap::kA8_Config, | 209 bitmap.setConfig(SkBitmap::kA8_Config, |
| 171 mask->fBounds.width(), mask->fBounds.height(), | 210 mask->fBounds.width(), mask->fBounds.height(), |
| 172 mask->fRowBytes); | 211 mask->fRowBytes); |
| 173 bitmap.setPixels(mask->fImage); | 212 bitmap.setPixels(mask->fImage); |
| 174 | 213 |
| 175 SkCanvas canvas(bitmap); | 214 SkCanvas canvas(bitmap); |
| 176 canvas.translate(-SkIntToScalar(mask->fBounds.left()), | 215 canvas.translate(-SkIntToScalar(mask->fBounds.left()), |
| 177 -SkIntToScalar(mask->fBounds.top())); | 216 -SkIntToScalar(mask->fBounds.top())); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 190 canvas.drawPath(path, paint); | 229 canvas.drawPath(path, paint); |
| 191 } | 230 } |
| 192 return true; | 231 return true; |
| 193 } | 232 } |
| 194 | 233 |
| 195 static bool rect_exceeds(const SkRect& r, SkScalar v) { | 234 static bool rect_exceeds(const SkRect& r, SkScalar v) { |
| 196 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || | 235 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || |
| 197 r.width() > v || r.height() > v; | 236 r.width() > v || r.height() > v; |
| 198 } | 237 } |
| 199 | 238 |
| 239 SkMaskFilter::FilterReturn |
| 240 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
trix, |
| 241 const SkIRect& clipBounds, |
| 242 NinePatch* patch) const { |
| 243 SkASSERT(patch != NULL); |
| 244 switch (rrect.getType()) { |
| 245 case SkRRect::kUnknown_Type: |
| 246 // Unknown should never be returned. |
| 247 SkASSERT(false); |
| 248 // Fall through. |
| 249 case SkRRect::kEmpty_Type: |
| 250 // Nothing to draw. |
| 251 return kFalse_FilterReturn; |
| 252 |
| 253 case SkRRect::kRect_Type: |
| 254 // We should have caught this earlier. |
| 255 SkASSERT(false); |
| 256 // Fall through. |
| 257 case SkRRect::kOval_Type: |
| 258 // The nine patch special case does not handle ovals, and we |
| 259 // already have code for rectangles. |
| 260 return kUnimplemented_FilterReturn; |
| 261 |
| 262 case SkRRect::kSimple_Type: |
| 263 // Fall through. |
| 264 case SkRRect::kComplex_Type: |
| 265 // These can take advantage of this fast path. |
| 266 break; |
| 267 } |
| 268 |
| 269 // TODO: report correct metrics for innerstyle, where we do not grow the |
| 270 // total bounds, but we do need an inset the size of our blur-radius |
| 271 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) { |
| 272 return kUnimplemented_FilterReturn; |
| 273 } |
| 274 |
| 275 // TODO: take clipBounds into account to limit our coordinates up front |
| 276 // for now, just skip too-large src rects (to take the old code path). |
| 277 if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) { |
| 278 return kUnimplemented_FilterReturn; |
| 279 } |
| 280 |
| 281 SkIPoint margin; |
| 282 SkMask srcM, dstM; |
| 283 rrect.rect().roundOut(&srcM.fBounds); |
| 284 srcM.fImage = NULL; |
| 285 srcM.fFormat = SkMask::kA8_Format; |
| 286 srcM.fRowBytes = 0; |
| 287 |
| 288 if (!this->filterMask(&dstM, srcM, matrix, &margin)) { |
| 289 return kFalse_FilterReturn; |
| 290 } |
| 291 |
| 292 // Now figure out the appropriate width and height of the smaller round rect
angle |
| 293 // to stretch. It will take into account the larger radius per side as well
as double |
| 294 // the margin, to account for inner and outer blur. |
| 295 const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner); |
| 296 const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner); |
| 297 const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner); |
| 298 const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner); |
| 299 |
| 300 const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * ma
rgin.fX); |
| 301 const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * m
argin.fX); |
| 302 |
| 303 // Extra space in the middle to ensure an unchanging piece for stretching. U
se 3 to cover |
| 304 // any fractional space on either side plus 1 for the part to stretch. |
| 305 const SkScalar stretchSize = SkIntToScalar(3); |
| 306 |
| 307 const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretc
hSize; |
| 308 if (totalSmallWidth >= rrect.rect().width()) { |
| 309 // There is no valid piece to stretch. |
| 310 return kUnimplemented_FilterReturn; |
| 311 } |
| 312 |
| 313 const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * mar
gin.fY); |
| 314 const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 *
margin.fY); |
| 315 |
| 316 const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stret
chSize; |
| 317 if (totalSmallHeight >= rrect.rect().height()) { |
| 318 // There is no valid piece to stretch. |
| 319 return kUnimplemented_FilterReturn; |
| 320 } |
| 321 |
| 322 SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight); |
| 323 |
| 324 SkRRect smallRR; |
| 325 SkVector radii[4]; |
| 326 radii[SkRRect::kUpperLeft_Corner] = UL; |
| 327 radii[SkRRect::kUpperRight_Corner] = UR; |
| 328 radii[SkRRect::kLowerRight_Corner] = LR; |
| 329 radii[SkRRect::kLowerLeft_Corner] = LL; |
| 330 smallRR.setRectRadii(smallR, radii); |
| 331 |
| 332 if (!draw_rrect_into_mask(smallRR, &srcM)) { |
| 333 return kFalse_FilterReturn; |
| 334 } |
| 335 |
| 336 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) { |
| 337 return kFalse_FilterReturn; |
| 338 } |
| 339 |
| 340 patch->fMask.fBounds.offsetTo(0, 0); |
| 341 patch->fOuterRect = dstM.fBounds; |
| 342 patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1; |
| 343 patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1; |
| 344 return kTrue_FilterReturn; |
| 345 } |
| 346 |
| 200 #ifdef SK_IGNORE_FAST_RECT_BLUR | 347 #ifdef SK_IGNORE_FAST_RECT_BLUR |
| 201 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch",
false, "Use the faster analytic blur approach for ninepatch rects" ); | 348 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch",
false, "Use the faster analytic blur approach for ninepatch rects" ); |
| 202 #else | 349 #else |
| 203 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch",
true, "Use the faster analytic blur approach for ninepatch rects" ); | 350 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch",
true, "Use the faster analytic blur approach for ninepatch rects" ); |
| 204 #endif | 351 #endif |
| 205 | 352 |
| 206 SkMaskFilter::FilterReturn | 353 SkMaskFilter::FilterReturn |
| 207 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, | 354 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, |
| 208 const SkMatrix& matrix, | 355 const SkMatrix& matrix, |
| 209 const SkIRect& clipBounds, | 356 const SkIRect& clipBounds, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 if (smallR[0].width() < 2 || smallR[0].height() < 2) { | 442 if (smallR[0].width() < 2 || smallR[0].height() < 2) { |
| 296 return kUnimplemented_FilterReturn; | 443 return kUnimplemented_FilterReturn; |
| 297 } | 444 } |
| 298 if (2 == count) { | 445 if (2 == count) { |
| 299 smallR[1].set(rects[1].left(), rects[1].top(), | 446 smallR[1].set(rects[1].left(), rects[1].top(), |
| 300 rects[1].right() - dx, rects[1].bottom() - dy); | 447 rects[1].right() - dx, rects[1].bottom() - dy); |
| 301 SkASSERT(!smallR[1].isEmpty()); | 448 SkASSERT(!smallR[1].isEmpty()); |
| 302 } | 449 } |
| 303 | 450 |
| 304 if (count > 1 || !c_analyticBlurNinepatch) { | 451 if (count > 1 || !c_analyticBlurNinepatch) { |
| 305 if (!drawRectsIntoMask(smallR, count, &srcM)) { | 452 if (!draw_rects_into_mask(smallR, count, &srcM)) { |
| 306 return kFalse_FilterReturn; | 453 return kFalse_FilterReturn; |
| 307 } | 454 } |
| 308 | 455 |
| 309 SkAutoMaskFreeImage amf(srcM.fImage); | 456 SkAutoMaskFreeImage amf(srcM.fImage); |
| 310 | 457 |
| 311 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) { | 458 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) { |
| 312 return kFalse_FilterReturn; | 459 return kFalse_FilterReturn; |
| 313 } | 460 } |
| 314 } else { | 461 } else { |
| 315 if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin, | 462 if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin, |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 } else { | 620 } else { |
| 474 str->append("None"); | 621 str->append("None"); |
| 475 } | 622 } |
| 476 str->append("))"); | 623 str->append("))"); |
| 477 } | 624 } |
| 478 #endif | 625 #endif |
| 479 | 626 |
| 480 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) | 627 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) |
| 481 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) | 628 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) |
| 482 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 629 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
| OLD | NEW |