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 "SkPaint.h" 9 10 #include "SkColorFilter.h" 11 #include "SkColorSpacePriv.h" 12 #include "SkColorSpaceXformSteps.h" 13 #include "SkData.h" 14 #include "SkDraw.h" 15 #include "SkGraphics.h" 16 #include "SkImageFilter.h" 17 #include "SkMaskFilter.h" 18 #include "SkMaskGamma.h" 19 #include "SkMutex.h" 20 #include "SkOpts.h" 21 #include "SkPaintDefaults.h" 22 #include "SkPaintPriv.h" 23 #include "SkPathEffect.h" 24 #include "SkReadBuffer.h" 25 #include "SkSafeRange.h" 26 #include "SkScalar.h" 27 #include "SkShader.h" 28 #include "SkShaderBase.h" 29 #include "SkStringUtils.h" 30 #include "SkStroke.h" 31 #include "SkStrokeRec.h" 32 #include "SkSurfacePriv.h" 33 #include "SkTLazy.h" 34 #include "SkTo.h" 35 #include "SkTypeface.h" 36 #include "SkWriteBuffer.h" 37 38 // define this to get a printf for out-of-range parameter in setters 39 // e.g. setTextSize(-1) 40 //#define SK_REPORT_API_RANGE_CHECK 41 42 43 SkPaint::SkPaint() 44 : fColor4f{0, 0, 0, 1} // opaque black 45 , fWidth{0} 46 , fMiterLimit{SkPaintDefaults_MiterLimit} 47 , fBitfields{(unsigned)false, // fAntiAlias 48 (unsigned)false, // fDither 49 (unsigned)SkPaint::kDefault_Cap, // fCapType 50 (unsigned)SkPaint::kDefault_Join, // fJoinType 51 (unsigned)SkPaint::kFill_Style, // fStyle 52 (unsigned)kNone_SkFilterQuality, // fFilterQuality 53 (unsigned)SkBlendMode::kSrcOver, // fBlendMode 54 0} // fPadding 55 { 56 static_assert(sizeof(fBitfields) == sizeof(fBitfieldsUInt), ""); 57 } 58 59 SkPaint::SkPaint(const SkPaint& src) = default; 60 61 SkPaint::SkPaint(SkPaint&& src) = default; 62 63 SkPaint::~SkPaint() = default; 64 65 SkPaint& SkPaint::operator=(const SkPaint& src) = default; 66 67 SkPaint& SkPaint::operator=(SkPaint&& src) = default; 68 69 bool operator==(const SkPaint& a, const SkPaint& b) { 70 #define EQUAL(field) (a.field == b.field) 71 return EQUAL(fPathEffect) 72 && EQUAL(fShader) 73 && EQUAL(fMaskFilter) 74 && EQUAL(fColorFilter) 75 && EQUAL(fDrawLooper) 76 && EQUAL(fImageFilter) 77 && EQUAL(fColor4f) 78 && EQUAL(fWidth) 79 && EQUAL(fMiterLimit) 80 && EQUAL(fBitfieldsUInt) 81 ; 82 #undef EQUAL 83 } 84 85 #define DEFINE_REF_FOO(type) sk_sp<Sk##type> SkPaint::ref##type() const { return f##type; } 86 DEFINE_REF_FOO(ColorFilter) 87 DEFINE_REF_FOO(DrawLooper) 88 DEFINE_REF_FOO(ImageFilter) 89 DEFINE_REF_FOO(MaskFilter) 90 DEFINE_REF_FOO(PathEffect) 91 DEFINE_REF_FOO(Shader) 92 #undef DEFINE_REF_FOO 93 94 void SkPaint::reset() { *this = SkPaint(); } 95 96 void SkPaint::setFilterQuality(SkFilterQuality quality) { 97 fBitfields.fFilterQuality = quality; 98 } 99 100 void SkPaint::setStyle(Style style) { 101 if ((unsigned)style < kStyleCount) { 102 fBitfields.fStyle = style; 103 } else { 104 #ifdef SK_REPORT_API_RANGE_CHECK 105 SkDebugf("SkPaint::setStyle(%d) out of range\n", style); 106 #endif 107 } 108 } 109 110 void SkPaint::setColor(SkColor color) { 111 fColor4f = SkColor4f::FromColor(color); 112 } 113 114 void SkPaint::setColor4f(const SkColor4f& color, SkColorSpace* colorSpace) { 115 SkASSERT(fColor4f.fA >= 0 && fColor4f.fA <= 1.0f); 116 117 SkColorSpaceXformSteps steps{colorSpace, kUnpremul_SkAlphaType, 118 sk_srgb_singleton(), kUnpremul_SkAlphaType}; 119 fColor4f = color; 120 steps.apply(fColor4f.vec()); 121 } 122 123 void SkPaint::setAlphaf(float a) { 124 SkASSERT(a >= 0 && a <= 1.0f); 125 fColor4f.fA = a; 126 } 127 128 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { 129 this->setColor(SkColorSetARGB(a, r, g, b)); 130 } 131 132 void SkPaint::setStrokeWidth(SkScalar width) { 133 if (width >= 0) { 134 fWidth = width; 135 } else { 136 #ifdef SK_REPORT_API_RANGE_CHECK 137 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n"); 138 #endif 139 } 140 } 141 142 void SkPaint::setStrokeMiter(SkScalar limit) { 143 if (limit >= 0) { 144 fMiterLimit = limit; 145 } else { 146 #ifdef SK_REPORT_API_RANGE_CHECK 147 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); 148 #endif 149 } 150 } 151 152 void SkPaint::setStrokeCap(Cap ct) { 153 if ((unsigned)ct < kCapCount) { 154 fBitfields.fCapType = SkToU8(ct); 155 } else { 156 #ifdef SK_REPORT_API_RANGE_CHECK 157 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); 158 #endif 159 } 160 } 161 162 void SkPaint::setStrokeJoin(Join jt) { 163 if ((unsigned)jt < kJoinCount) { 164 fBitfields.fJoinType = SkToU8(jt); 165 } else { 166 #ifdef SK_REPORT_API_RANGE_CHECK 167 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); 168 #endif 169 } 170 } 171 172 /////////////////////////////////////////////////////////////////////////////// 173 174 #define MOVE_FIELD(Field) void SkPaint::set##Field(sk_sp<Sk##Field> f) { f##Field = std::move(f); } 175 MOVE_FIELD(ImageFilter) 176 MOVE_FIELD(Shader) 177 MOVE_FIELD(ColorFilter) 178 MOVE_FIELD(PathEffect) 179 MOVE_FIELD(MaskFilter) 180 MOVE_FIELD(DrawLooper) 181 #undef MOVE_FIELD 182 void SkPaint::setLooper(sk_sp<SkDrawLooper> looper) { fDrawLooper = std::move(looper); } 183 184 /////////////////////////////////////////////////////////////////////////////// 185 186 #include "SkStream.h" 187 188 #ifdef SK_DEBUG 189 static void ASSERT_FITS_IN(uint32_t value, int bitCount) { 190 SkASSERT(bitCount > 0 && bitCount <= 32); 191 uint32_t mask = ~0U; 192 mask >>= (32 - bitCount); 193 SkASSERT(0 == (value & ~mask)); 194 } 195 #else 196 #define ASSERT_FITS_IN(value, bitcount) 197 #endif 198 199 enum FlatFlags { 200 kHasTypeface_FlatFlag = 0x1, 201 kHasEffects_FlatFlag = 0x2, 202 203 kFlatFlagMask = 0x3, 204 }; 205 206 enum BitsPerField { 207 kFlags_BPF = 16, 208 kHint_BPF = 2, 209 kFilter_BPF = 2, 210 kFlatFlags_BPF = 3, 211 }; 212 213 static inline int BPF_Mask(int bits) { 214 return (1 << bits) - 1; 215 } 216 217 // SkPaint originally defined flags, some of which now apply to SkFont. These are renames 218 // of those flags, split into categories depending on which objects they (now) apply to. 219 220 enum PaintFlagsForPaint { 221 kAA_PaintFlagForPaint = 0x01, 222 kDither_PaintFlagForPaint = 0x04, 223 }; 224 225 enum PaintFlagsForFont { 226 kFakeBold_PaintFlagForFont = 0x20, 227 kLinear_PaintFlagForFont = 0x40, 228 kSubpixel_PaintFlagForFont = 0x80, 229 kLCD_PaintFlagForFont = 0x200, 230 kEmbeddedBitmap_PaintFlagForFont = 0x400, 231 kAutoHinting_PaintFlagForFont = 0x800, 232 }; 233 234 static FlatFlags unpack_paint_flags(SkPaint* paint, uint32_t packed, SkFont* font) { 235 uint32_t f = packed >> 16; 236 paint->setAntiAlias((f & kAA_PaintFlagForPaint) != 0); 237 paint->setDither((f & kDither_PaintFlagForPaint) != 0); 238 if (font) { 239 font->setEmbolden((f & kFakeBold_PaintFlagForFont) != 0); 240 font->setLinearMetrics((f & kLinear_PaintFlagForFont) != 0); 241 font->setSubpixel((f & kSubpixel_PaintFlagForFont) != 0); 242 font->setEmbeddedBitmaps((f & kEmbeddedBitmap_PaintFlagForFont) != 0); 243 font->setForceAutoHinting((f & kAutoHinting_PaintFlagForFont) != 0); 244 245 font->setHinting((SkFontHinting)((packed >> 14) & BPF_Mask(kHint_BPF))); 246 247 if (f & kAA_PaintFlagForPaint) { 248 if (f & kLCD_PaintFlagForFont) { 249 font->setEdging(SkFont::Edging::kSubpixelAntiAlias); 250 } else { 251 font->setEdging(SkFont::Edging::kAntiAlias); 252 } 253 } else { 254 font->setEdging(SkFont::Edging::kAlias); 255 } 256 } 257 258 paint->setFilterQuality((SkFilterQuality)((packed >> 10) & BPF_Mask(kFilter_BPF))); 259 return (FlatFlags)(packed & kFlatFlagMask); 260 } 261 262 template <typename T> uint32_t shift_bits(T value, unsigned shift, unsigned bits) { 263 SkASSERT(shift + bits <= 32); 264 uint32_t v = static_cast<uint32_t>(value); 265 ASSERT_FITS_IN(v, bits); 266 return v << shift; 267 } 268 269 /* Packing the paint 270 flags : 8 // 2... 271 blend : 8 // 30+ 272 cap : 2 // 3 273 join : 2 // 3 274 style : 2 // 3 275 filter: 2 // 4 276 flat : 8 // 1... 277 total : 32 278 */ 279 static uint32_t pack_v68(const SkPaint& paint, unsigned flatFlags) { 280 uint32_t packed = 0; 281 packed |= shift_bits(((unsigned)paint.isDither() << 1) | 282 (unsigned)paint.isAntiAlias(), 0, 8); 283 packed |= shift_bits(paint.getBlendMode(), 8, 8); 284 packed |= shift_bits(paint.getStrokeCap(), 16, 2); 285 packed |= shift_bits(paint.getStrokeJoin(), 18, 2); 286 packed |= shift_bits(paint.getStyle(), 20, 2); 287 packed |= shift_bits(paint.getFilterQuality(), 22, 2); 288 packed |= shift_bits(flatFlags, 24, 8); 289 return packed; 290 } 291 292 static uint32_t unpack_v68(SkPaint* paint, uint32_t packed, SkSafeRange& safe) { 293 paint->setAntiAlias((packed & 1) != 0); 294 paint->setDither((packed & 2) != 0); 295 packed >>= 8; 296 paint->setBlendMode(safe.checkLE(packed & 0xFF, SkBlendMode::kLastMode)); 297 packed >>= 8; 298 paint->setStrokeCap(safe.checkLE(packed & 0x3, SkPaint::kLast_Cap)); 299 packed >>= 2; 300 paint->setStrokeJoin(safe.checkLE(packed & 0x3, SkPaint::kLast_Join)); 301 packed >>= 2; 302 paint->setStyle(safe.checkLE(packed & 0x3, SkPaint::kStrokeAndFill_Style)); 303 packed >>= 2; 304 paint->setFilterQuality(safe.checkLE(packed & 0x3, kLast_SkFilterQuality)); 305 packed >>= 2; 306 return packed; 307 } 308 309 /* To save space/time, we analyze the paint, and write a truncated version of 310 it if there are not tricky elements like shaders, etc. 311 */ 312 void SkPaintPriv::Flatten(const SkPaint& paint, SkWriteBuffer& buffer) { 313 uint8_t flatFlags = 0; 314 315 if (paint.getPathEffect() || 316 paint.getShader() || 317 paint.getMaskFilter() || 318 paint.getColorFilter() || 319 paint.getLooper() || 320 paint.getImageFilter()) { 321 flatFlags |= kHasEffects_FlatFlag; 322 } 323 324 buffer.writeScalar(paint.getStrokeWidth()); 325 buffer.writeScalar(paint.getStrokeMiter()); 326 buffer.writeColor4f(paint.getColor4f()); 327 328 buffer.write32(pack_v68(paint, flatFlags)); 329 330 if (flatFlags & kHasEffects_FlatFlag) { 331 buffer.writeFlattenable(paint.getPathEffect()); 332 buffer.writeFlattenable(paint.getShader()); 333 buffer.writeFlattenable(paint.getMaskFilter()); 334 buffer.writeFlattenable(paint.getColorFilter()); 335 buffer.writeFlattenable(paint.getLooper()); 336 buffer.writeFlattenable(paint.getImageFilter()); 337 } 338 } 339 340 SkReadPaintResult SkPaintPriv::Unflatten_PreV68(SkPaint* paint, SkReadBuffer& buffer, SkFont* font) { 341 SkSafeRange safe; 342 343 { 344 SkScalar sz = buffer.readScalar(); 345 SkScalar sx = buffer.readScalar(); 346 SkScalar kx = buffer.readScalar(); 347 if (font) { 348 font->setSize(sz); 349 font->setScaleX(sx); 350 font->setSkewX(kx); 351 } 352 } 353 354 paint->setStrokeWidth(buffer.readScalar()); 355 paint->setStrokeMiter(buffer.readScalar()); 356 if (buffer.isVersionLT(SkReadBuffer::kFloat4PaintColor_Version)) { 357 paint->setColor(buffer.readColor()); 358 } else { 359 SkColor4f color; 360 buffer.readColor4f(&color); 361 paint->setColor4f(color, sk_srgb_singleton()); 362 } 363 364 unsigned flatFlags = unpack_paint_flags(paint, buffer.readUInt(), font); 365 366 uint32_t tmp = buffer.readUInt(); 367 paint->setStrokeCap(safe.checkLE((tmp >> 24) & 0xFF, SkPaint::kLast_Cap)); 368 paint->setStrokeJoin(safe.checkLE((tmp >> 16) & 0xFF, SkPaint::kLast_Join)); 369 paint->setStyle(safe.checkLE((tmp >> 12) & 0xF, SkPaint::kStrokeAndFill_Style)); 370 paint->setBlendMode(safe.checkLE(tmp & 0xFF, SkBlendMode::kLastMode)); 371 372 sk_sp<SkTypeface> tf; 373 if (flatFlags & kHasTypeface_FlatFlag) { 374 tf = buffer.readTypeface(); 375 } 376 if (font) { 377 font->setTypeface(tf); 378 } 379 380 if (flatFlags & kHasEffects_FlatFlag) { 381 paint->setPathEffect(buffer.readPathEffect()); 382 paint->setShader(buffer.readShader()); 383 paint->setMaskFilter(buffer.readMaskFilter()); 384 paint->setColorFilter(buffer.readColorFilter()); 385 (void)buffer.read32(); // use to be SkRasterizer 386 paint->setLooper(buffer.readDrawLooper()); 387 paint->setImageFilter(buffer.readImageFilter()); 388 } else { 389 paint->setPathEffect(nullptr); 390 paint->setShader(nullptr); 391 paint->setMaskFilter(nullptr); 392 paint->setColorFilter(nullptr); 393 paint->setLooper(nullptr); 394 paint->setImageFilter(nullptr); 395 } 396 397 if (!buffer.validate(safe)) { 398 paint->reset(); 399 return kFailed_ReadPaint; 400 } 401 return kSuccess_PaintAndFont; 402 } 403 404 SkReadPaintResult SkPaintPriv::Unflatten(SkPaint* paint, SkReadBuffer& buffer, SkFont* font) { 405 if (buffer.isVersionLT(SkReadBuffer::kPaintDoesntSerializeFonts_Version)) { 406 return Unflatten_PreV68(paint, buffer, font); 407 } 408 409 SkSafeRange safe; 410 411 paint->setStrokeWidth(buffer.readScalar()); 412 paint->setStrokeMiter(buffer.readScalar()); 413 { 414 SkColor4f color; 415 buffer.readColor4f(&color); 416 paint->setColor4f(color, sk_srgb_singleton()); 417 } 418 419 unsigned flatFlags = unpack_v68(paint, buffer.readUInt(), safe); 420 421 if (flatFlags & kHasEffects_FlatFlag) { 422 paint->setPathEffect(buffer.readPathEffect()); 423 paint->setShader(buffer.readShader()); 424 paint->setMaskFilter(buffer.readMaskFilter()); 425 paint->setColorFilter(buffer.readColorFilter()); 426 paint->setLooper(buffer.readDrawLooper()); 427 paint->setImageFilter(buffer.readImageFilter()); 428 } else { 429 paint->setPathEffect(nullptr); 430 paint->setShader(nullptr); 431 paint->setMaskFilter(nullptr); 432 paint->setColorFilter(nullptr); 433 paint->setLooper(nullptr); 434 paint->setImageFilter(nullptr); 435 } 436 437 if (!buffer.validate(safe)) { 438 paint->reset(); 439 return kFailed_ReadPaint; 440 } 441 return kSuccess_JustPaint; 442 } 443 444 /////////////////////////////////////////////////////////////////////////////// 445 446 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, 447 SkScalar resScale) const { 448 if (!src.isFinite()) { 449 dst->reset(); 450 return false; 451 } 452 453 SkStrokeRec rec(*this, resScale); 454 455 const SkPath* srcPtr = &src; 456 SkPath tmpPath; 457 458 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) { 459 srcPtr = &tmpPath; 460 } 461 462 if (!rec.applyToPath(dst, *srcPtr)) { 463 if (srcPtr == &tmpPath) { 464 // If path's were copy-on-write, this trick would not be needed. 465 // As it is, we want to save making a deep-copy from tmpPath -> dst 466 // since we know we're just going to delete tmpPath when we return, 467 // so the swap saves that copy. 468 dst->swap(tmpPath); 469 } else { 470 *dst = *srcPtr; 471 } 472 } 473 474 if (!dst->isFinite()) { 475 dst->reset(); 476 return false; 477 } 478 return !rec.isHairlineStyle(); 479 } 480 481 bool SkPaint::canComputeFastBounds() const { 482 if (this->getLooper()) { 483 return this->getLooper()->canComputeFastBounds(*this); 484 } 485 if (this->getImageFilter() && !this->getImageFilter()->canComputeFastBounds()) { 486 return false; 487 } 488 return true; 489 } 490 491 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, 492 SkRect* storage, 493 Style style) const { 494 SkASSERT(storage); 495 496 const SkRect* src = &origSrc; 497 498 if (this->getLooper()) { 499 SkASSERT(this->getLooper()->canComputeFastBounds(*this)); 500 this->getLooper()->computeFastBounds(*this, *src, storage); 501 return *storage; 502 } 503 504 SkRect tmpSrc; 505 if (this->getPathEffect()) { 506 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc); 507 src = &tmpSrc; 508 } 509 510 SkScalar radius = SkStrokeRec::GetInflationRadius(*this, style); 511 *storage = src->makeOutset(radius, radius); 512 513 if (this->getMaskFilter()) { 514 as_MFB(this->getMaskFilter())->computeFastBounds(*storage, storage); 515 } 516 517 if (this->getImageFilter()) { 518 *storage = this->getImageFilter()->computeFastBounds(*storage); 519 } 520 521 return *storage; 522 } 523 524 /////////////////////////////////////////////////////////////////////////////// 525 526 // return true if the filter exists, and may affect alpha 527 static bool affects_alpha(const SkColorFilter* cf) { 528 return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); 529 } 530 531 // return true if the filter exists, and may affect alpha 532 static bool affects_alpha(const SkImageFilter* imf) { 533 // TODO: check if we should allow imagefilters to broadcast that they don't affect alpha 534 // ala colorfilters 535 return imf != nullptr; 536 } 537 538 bool SkPaint::nothingToDraw() const { 539 if (fDrawLooper) { 540 return false; 541 } 542 switch (this->getBlendMode()) { 543 case SkBlendMode::kSrcOver: 544 case SkBlendMode::kSrcATop: 545 case SkBlendMode::kDstOut: 546 case SkBlendMode::kDstOver: 547 case SkBlendMode::kPlus: 548 if (0 == this->getAlpha()) { 549 return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get()); 550 } 551 break; 552 case SkBlendMode::kDst: 553 return true; 554 default: 555 break; 556 } 557 return false; 558 } 559 560 uint32_t SkPaint::getHash() const { 561 // We're going to hash 6 pointers and 6 floats, finishing up with fBitfields, 562 // so fBitfields should be 6 pointers and 6 floats from the start. 563 static_assert(offsetof(SkPaint, fBitfieldsUInt) == 6 * sizeof(void*) + 6 * sizeof(float), 564 "SkPaint_notPackedTightly"); 565 return SkOpts::hash(reinterpret_cast<const uint32_t*>(this), 566 offsetof(SkPaint, fBitfieldsUInt) + sizeof(fBitfieldsUInt)); 567 } 568