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 #include "SkPaint.h" 10 #include "SkAnnotation.h" 11 #include "SkColorFilter.h" 12 #include "SkDeviceProperties.h" 13 #include "SkFontHost.h" 14 #include "SkImageFilter.h" 15 #include "SkMaskFilter.h" 16 #include "SkMaskGamma.h" 17 #include "SkPathEffect.h" 18 #include "SkRasterizer.h" 19 #include "SkShader.h" 20 #include "SkScalar.h" 21 #include "SkScalerContext.h" 22 #include "SkStroke.h" 23 #include "SkTextFormatParams.h" 24 #include "SkTextToPathIter.h" 25 #include "SkTypeface.h" 26 #include "SkXfermode.h" 27 #include "SkAutoKern.h" 28 #include "SkGlyphCache.h" 29 #include "SkPaintDefaults.h" 30 #include "SkOrderedReadBuffer.h" 31 #include "SkOrderedWriteBuffer.h" 32 33 // define this to get a printf for out-of-range parameter in setters 34 // e.g. setTextSize(-1) 35 //#define SK_REPORT_API_RANGE_CHECK 36 37 #ifdef SK_BUILD_FOR_ANDROID 38 #include "SkLanguage.h" 39 #define GEN_ID_INC fGenerationID++ 40 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; } 41 #else 42 #define GEN_ID_INC 43 #define GEN_ID_INC_EVAL(expression) 44 #endif 45 46 SkPaint::SkPaint() { 47 // since we may have padding, we zero everything so that our memcmp() call 48 // in operator== will work correctly. 49 // with this, we can skip 0 and null individual initializations 50 sk_bzero(this, sizeof(*this)); 51 52 #if 0 // not needed with the bzero call above 53 fTypeface = NULL; 54 fTextSkewX = 0; 55 fPathEffect = NULL; 56 fShader = NULL; 57 fXfermode = NULL; 58 fMaskFilter = NULL; 59 fColorFilter = NULL; 60 fRasterizer = NULL; 61 fLooper = NULL; 62 fImageFilter = NULL; 63 fAnnotation = NULL; 64 fWidth = 0; 65 #endif 66 67 fTextSize = SkPaintDefaults_TextSize; 68 fTextScaleX = SK_Scalar1; 69 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 70 fHintingScaleFactor = SK_Scalar1; 71 #endif 72 fColor = SK_ColorBLACK; 73 fMiterLimit = SkPaintDefaults_MiterLimit; 74 fFlags = SkPaintDefaults_Flags; 75 fCapType = kDefault_Cap; 76 fJoinType = kDefault_Join; 77 fTextAlign = kLeft_Align; 78 fStyle = kFill_Style; 79 fTextEncoding = kUTF8_TextEncoding; 80 fHinting = SkPaintDefaults_Hinting; 81 fPrivFlags = 0; 82 #ifdef SK_BUILD_FOR_ANDROID 83 fLanguage = SkLanguage(); 84 fFontVariant = kDefault_Variant; 85 fGenerationID = 0; 86 #endif 87 } 88 89 SkPaint::SkPaint(const SkPaint& src) { 90 memcpy(this, &src, sizeof(src)); 91 92 SkSafeRef(fTypeface); 93 SkSafeRef(fPathEffect); 94 SkSafeRef(fShader); 95 SkSafeRef(fXfermode); 96 SkSafeRef(fMaskFilter); 97 SkSafeRef(fColorFilter); 98 SkSafeRef(fRasterizer); 99 SkSafeRef(fLooper); 100 SkSafeRef(fImageFilter); 101 SkSafeRef(fAnnotation); 102 } 103 104 SkPaint::~SkPaint() { 105 SkSafeUnref(fTypeface); 106 SkSafeUnref(fPathEffect); 107 SkSafeUnref(fShader); 108 SkSafeUnref(fXfermode); 109 SkSafeUnref(fMaskFilter); 110 SkSafeUnref(fColorFilter); 111 SkSafeUnref(fRasterizer); 112 SkSafeUnref(fLooper); 113 SkSafeUnref(fImageFilter); 114 SkSafeUnref(fAnnotation); 115 } 116 117 SkPaint& SkPaint::operator=(const SkPaint& src) { 118 SkASSERT(&src); 119 120 SkSafeRef(src.fTypeface); 121 SkSafeRef(src.fPathEffect); 122 SkSafeRef(src.fShader); 123 SkSafeRef(src.fXfermode); 124 SkSafeRef(src.fMaskFilter); 125 SkSafeRef(src.fColorFilter); 126 SkSafeRef(src.fRasterizer); 127 SkSafeRef(src.fLooper); 128 SkSafeRef(src.fImageFilter); 129 SkSafeRef(src.fAnnotation); 130 131 SkSafeUnref(fTypeface); 132 SkSafeUnref(fPathEffect); 133 SkSafeUnref(fShader); 134 SkSafeUnref(fXfermode); 135 SkSafeUnref(fMaskFilter); 136 SkSafeUnref(fColorFilter); 137 SkSafeUnref(fRasterizer); 138 SkSafeUnref(fLooper); 139 SkSafeUnref(fImageFilter); 140 SkSafeUnref(fAnnotation); 141 142 #ifdef SK_BUILD_FOR_ANDROID 143 uint32_t oldGenerationID = fGenerationID; 144 #endif 145 memcpy(this, &src, sizeof(src)); 146 #ifdef SK_BUILD_FOR_ANDROID 147 fGenerationID = oldGenerationID + 1; 148 #endif 149 150 return *this; 151 } 152 153 bool operator==(const SkPaint& a, const SkPaint& b) { 154 #ifdef SK_BUILD_FOR_ANDROID 155 //assumes that fGenerationID is the last field in the struct 156 return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID)); 157 #else 158 return !memcmp(&a, &b, sizeof(a)); 159 #endif 160 } 161 162 void SkPaint::reset() { 163 SkPaint init; 164 165 #ifdef SK_BUILD_FOR_ANDROID 166 uint32_t oldGenerationID = fGenerationID; 167 #endif 168 *this = init; 169 #ifdef SK_BUILD_FOR_ANDROID 170 fGenerationID = oldGenerationID + 1; 171 #endif 172 } 173 174 #ifdef SK_BUILD_FOR_ANDROID 175 uint32_t SkPaint::getGenerationID() const { 176 return fGenerationID; 177 } 178 179 void SkPaint::setGenerationID(uint32_t generationID) { 180 fGenerationID = generationID; 181 } 182 #endif 183 184 #ifdef SK_BUILD_FOR_ANDROID 185 unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const { 186 SkAutoGlyphCache autoCache(*this, NULL, NULL); 187 SkGlyphCache* cache = autoCache.getCache(); 188 return cache->getBaseGlyphCount(text); 189 } 190 #endif 191 192 void SkPaint::setHinting(Hinting hintingLevel) { 193 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting); 194 fHinting = hintingLevel; 195 } 196 197 void SkPaint::setFlags(uint32_t flags) { 198 GEN_ID_INC_EVAL(fFlags != flags); 199 fFlags = flags; 200 } 201 202 void SkPaint::setAntiAlias(bool doAA) { 203 GEN_ID_INC_EVAL(doAA != isAntiAlias()); 204 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); 205 } 206 207 void SkPaint::setDither(bool doDither) { 208 GEN_ID_INC_EVAL(doDither != isDither()); 209 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); 210 } 211 212 void SkPaint::setSubpixelText(bool doSubpixel) { 213 GEN_ID_INC_EVAL(doSubpixel != isSubpixelText()); 214 this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag)); 215 } 216 217 void SkPaint::setLCDRenderText(bool doLCDRender) { 218 GEN_ID_INC_EVAL(doLCDRender != isLCDRenderText()); 219 this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag)); 220 } 221 222 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) { 223 GEN_ID_INC_EVAL(doEmbeddedBitmapText != isEmbeddedBitmapText()); 224 this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); 225 } 226 227 void SkPaint::setAutohinted(bool useAutohinter) { 228 GEN_ID_INC_EVAL(useAutohinter != isAutohinted()); 229 this->setFlags(SkSetClearMask(fFlags, useAutohinter, kAutoHinting_Flag)); 230 } 231 232 void SkPaint::setLinearText(bool doLinearText) { 233 GEN_ID_INC_EVAL(doLinearText != isLinearText()); 234 this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag)); 235 } 236 237 void SkPaint::setVerticalText(bool doVertical) { 238 GEN_ID_INC_EVAL(doVertical != isVerticalText()); 239 this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag)); 240 } 241 242 void SkPaint::setUnderlineText(bool doUnderline) { 243 GEN_ID_INC_EVAL(doUnderline != isUnderlineText()); 244 this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag)); 245 } 246 247 void SkPaint::setStrikeThruText(bool doStrikeThru) { 248 GEN_ID_INC_EVAL(doStrikeThru != isStrikeThruText()); 249 this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag)); 250 } 251 252 void SkPaint::setFakeBoldText(bool doFakeBold) { 253 GEN_ID_INC_EVAL(doFakeBold != isFakeBoldText()); 254 this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag)); 255 } 256 257 void SkPaint::setDevKernText(bool doDevKern) { 258 GEN_ID_INC_EVAL(doDevKern != isDevKernText()); 259 this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag)); 260 } 261 262 void SkPaint::setFilterBitmap(bool doFilter) { 263 GEN_ID_INC_EVAL(doFilter != isFilterBitmap()); 264 this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag)); 265 } 266 267 void SkPaint::setStyle(Style style) { 268 if ((unsigned)style < kStyleCount) { 269 GEN_ID_INC_EVAL((unsigned)style != fStyle); 270 fStyle = style; 271 } else { 272 #ifdef SK_REPORT_API_RANGE_CHECK 273 SkDebugf("SkPaint::setStyle(%d) out of range\n", style); 274 #endif 275 } 276 } 277 278 void SkPaint::setColor(SkColor color) { 279 GEN_ID_INC_EVAL(color != fColor); 280 fColor = color; 281 } 282 283 void SkPaint::setAlpha(U8CPU a) { 284 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor), 285 SkColorGetG(fColor), SkColorGetB(fColor))); 286 } 287 288 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { 289 this->setColor(SkColorSetARGB(a, r, g, b)); 290 } 291 292 void SkPaint::setStrokeWidth(SkScalar width) { 293 if (width >= 0) { 294 GEN_ID_INC_EVAL(width != fWidth); 295 fWidth = width; 296 } else { 297 #ifdef SK_REPORT_API_RANGE_CHECK 298 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n"); 299 #endif 300 } 301 } 302 303 void SkPaint::setStrokeMiter(SkScalar limit) { 304 if (limit >= 0) { 305 GEN_ID_INC_EVAL(limit != fMiterLimit); 306 fMiterLimit = limit; 307 } else { 308 #ifdef SK_REPORT_API_RANGE_CHECK 309 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); 310 #endif 311 } 312 } 313 314 void SkPaint::setStrokeCap(Cap ct) { 315 if ((unsigned)ct < kCapCount) { 316 GEN_ID_INC_EVAL((unsigned)ct != fCapType); 317 fCapType = SkToU8(ct); 318 } else { 319 #ifdef SK_REPORT_API_RANGE_CHECK 320 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); 321 #endif 322 } 323 } 324 325 void SkPaint::setStrokeJoin(Join jt) { 326 if ((unsigned)jt < kJoinCount) { 327 GEN_ID_INC_EVAL((unsigned)jt != fJoinType); 328 fJoinType = SkToU8(jt); 329 } else { 330 #ifdef SK_REPORT_API_RANGE_CHECK 331 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); 332 #endif 333 } 334 } 335 336 /////////////////////////////////////////////////////////////////////////////// 337 338 void SkPaint::setTextAlign(Align align) { 339 if ((unsigned)align < kAlignCount) { 340 GEN_ID_INC_EVAL((unsigned)align != fTextAlign); 341 fTextAlign = SkToU8(align); 342 } else { 343 #ifdef SK_REPORT_API_RANGE_CHECK 344 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); 345 #endif 346 } 347 } 348 349 void SkPaint::setTextSize(SkScalar ts) { 350 if (ts >= 0) { 351 GEN_ID_INC_EVAL(ts != fTextSize); 352 fTextSize = ts; 353 } else { 354 #ifdef SK_REPORT_API_RANGE_CHECK 355 SkDebugf("SkPaint::setTextSize() called with negative value\n"); 356 #endif 357 } 358 } 359 360 void SkPaint::setTextScaleX(SkScalar scaleX) { 361 GEN_ID_INC_EVAL(scaleX != fTextScaleX); 362 fTextScaleX = scaleX; 363 } 364 365 void SkPaint::setTextSkewX(SkScalar skewX) { 366 GEN_ID_INC_EVAL(skewX != fTextSkewX); 367 fTextSkewX = skewX; 368 } 369 370 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 371 void SkPaint::setHintingScaleFactor(SkScalar hintingScaleFactor) { 372 GEN_ID_INC_EVAL(hintingScaleFactor != fHintingScaleFactor); 373 fHintingScaleFactor = hintingScaleFactor; 374 } 375 #endif 376 377 void SkPaint::setTextEncoding(TextEncoding encoding) { 378 if ((unsigned)encoding <= kGlyphID_TextEncoding) { 379 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding); 380 fTextEncoding = encoding; 381 } else { 382 #ifdef SK_REPORT_API_RANGE_CHECK 383 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); 384 #endif 385 } 386 } 387 388 #ifdef SK_BUILD_FOR_ANDROID 389 void SkPaint::setLanguage(const SkLanguage& language) { 390 if(fLanguage != language) { 391 fLanguage = language; 392 GEN_ID_INC; 393 } 394 } 395 396 void SkPaint::setFontVariant(FontVariant fontVariant) { 397 if ((unsigned)fontVariant <= kLast_Variant) { 398 GEN_ID_INC_EVAL((unsigned)fontVariant != fFontVariant); 399 fFontVariant = fontVariant; 400 } else { 401 #ifdef SK_REPORT_API_RANGE_CHECK 402 SkDebugf("SkPaint::setFontVariant(%d) out of range\n", fontVariant); 403 #endif 404 } 405 } 406 407 #endif 408 409 /////////////////////////////////////////////////////////////////////////////// 410 411 SkTypeface* SkPaint::setTypeface(SkTypeface* font) { 412 SkRefCnt_SafeAssign(fTypeface, font); 413 GEN_ID_INC; 414 return font; 415 } 416 417 SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) { 418 SkRefCnt_SafeAssign(fRasterizer, r); 419 GEN_ID_INC; 420 return r; 421 } 422 423 SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) { 424 SkRefCnt_SafeAssign(fLooper, looper); 425 GEN_ID_INC; 426 return looper; 427 } 428 429 SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) { 430 SkRefCnt_SafeAssign(fImageFilter, imageFilter); 431 GEN_ID_INC; 432 return imageFilter; 433 } 434 435 SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) { 436 SkRefCnt_SafeAssign(fAnnotation, annotation); 437 GEN_ID_INC; 438 439 bool isNoDraw = annotation && annotation->isNoDraw(); 440 fPrivFlags = SkSetClearMask(fPrivFlags, isNoDraw, kNoDrawAnnotation_PrivFlag); 441 442 return annotation; 443 } 444 445 /////////////////////////////////////////////////////////////////////////////// 446 447 #include "SkGlyphCache.h" 448 #include "SkUtils.h" 449 450 static void DetachDescProc(const SkDescriptor* desc, void* context) { 451 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc); 452 } 453 454 #ifdef SK_BUILD_FOR_ANDROID 455 const SkGlyph& SkPaint::getUnicharMetrics(SkUnichar text, const SkMatrix* deviceMatrix) { 456 SkGlyphCache* cache; 457 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true); 458 459 const SkGlyph& glyph = cache->getUnicharMetrics(text); 460 461 SkGlyphCache::AttachCache(cache); 462 return glyph; 463 } 464 465 const SkGlyph& SkPaint::getGlyphMetrics(uint16_t glyphId, const SkMatrix* deviceMatrix) { 466 SkGlyphCache* cache; 467 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true); 468 469 const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphId); 470 471 SkGlyphCache::AttachCache(cache); 472 return glyph; 473 } 474 475 const void* SkPaint::findImage(const SkGlyph& glyph, const SkMatrix* deviceMatrix) { 476 // See ::detachCache() 477 SkGlyphCache* cache; 478 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true); 479 480 const void* image = cache->findImage(glyph); 481 482 SkGlyphCache::AttachCache(cache); 483 return image; 484 } 485 #endif 486 487 int SkPaint::textToGlyphs(const void* textData, size_t byteLength, 488 uint16_t glyphs[]) const { 489 if (byteLength == 0) { 490 return 0; 491 } 492 493 SkASSERT(textData != NULL); 494 495 if (NULL == glyphs) { 496 switch (this->getTextEncoding()) { 497 case kUTF8_TextEncoding: 498 return SkUTF8_CountUnichars((const char*)textData, byteLength); 499 case kUTF16_TextEncoding: 500 return SkUTF16_CountUnichars((const uint16_t*)textData, 501 byteLength >> 1); 502 case kUTF32_TextEncoding: 503 return byteLength >> 2; 504 case kGlyphID_TextEncoding: 505 return byteLength >> 1; 506 default: 507 SkDEBUGFAIL("unknown text encoding"); 508 } 509 return 0; 510 } 511 512 // if we get here, we have a valid glyphs[] array, so time to fill it in 513 514 // handle this encoding before the setup for the glyphcache 515 if (this->getTextEncoding() == kGlyphID_TextEncoding) { 516 // we want to ignore the low bit of byteLength 517 memcpy(glyphs, textData, byteLength >> 1 << 1); 518 return byteLength >> 1; 519 } 520 521 SkAutoGlyphCache autoCache(*this, NULL, NULL); 522 SkGlyphCache* cache = autoCache.getCache(); 523 524 const char* text = (const char*)textData; 525 const char* stop = text + byteLength; 526 uint16_t* gptr = glyphs; 527 528 switch (this->getTextEncoding()) { 529 case SkPaint::kUTF8_TextEncoding: 530 while (text < stop) { 531 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); 532 } 533 break; 534 case SkPaint::kUTF16_TextEncoding: { 535 const uint16_t* text16 = (const uint16_t*)text; 536 const uint16_t* stop16 = (const uint16_t*)stop; 537 while (text16 < stop16) { 538 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16)); 539 } 540 break; 541 } 542 case kUTF32_TextEncoding: { 543 const int32_t* text32 = (const int32_t*)text; 544 const int32_t* stop32 = (const int32_t*)stop; 545 while (text32 < stop32) { 546 *gptr++ = cache->unicharToGlyph(*text32++); 547 } 548 break; 549 } 550 default: 551 SkDEBUGFAIL("unknown text encoding"); 552 } 553 return gptr - glyphs; 554 } 555 556 bool SkPaint::containsText(const void* textData, size_t byteLength) const { 557 if (0 == byteLength) { 558 return true; 559 } 560 561 SkASSERT(textData != NULL); 562 563 // handle this encoding before the setup for the glyphcache 564 if (this->getTextEncoding() == kGlyphID_TextEncoding) { 565 const uint16_t* glyphID = static_cast<const uint16_t*>(textData); 566 size_t count = byteLength >> 1; 567 for (size_t i = 0; i < count; i++) { 568 if (0 == glyphID[i]) { 569 return false; 570 } 571 } 572 return true; 573 } 574 575 SkAutoGlyphCache autoCache(*this, NULL, NULL); 576 SkGlyphCache* cache = autoCache.getCache(); 577 578 switch (this->getTextEncoding()) { 579 case SkPaint::kUTF8_TextEncoding: { 580 const char* text = static_cast<const char*>(textData); 581 const char* stop = text + byteLength; 582 while (text < stop) { 583 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) { 584 return false; 585 } 586 } 587 break; 588 } 589 case SkPaint::kUTF16_TextEncoding: { 590 const uint16_t* text = static_cast<const uint16_t*>(textData); 591 const uint16_t* stop = text + (byteLength >> 1); 592 while (text < stop) { 593 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) { 594 return false; 595 } 596 } 597 break; 598 } 599 case SkPaint::kUTF32_TextEncoding: { 600 const int32_t* text = static_cast<const int32_t*>(textData); 601 const int32_t* stop = text + (byteLength >> 2); 602 while (text < stop) { 603 if (0 == cache->unicharToGlyph(*text++)) { 604 return false; 605 } 606 } 607 break; 608 } 609 default: 610 SkDEBUGFAIL("unknown text encoding"); 611 return false; 612 } 613 return true; 614 } 615 616 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count, 617 SkUnichar textData[]) const { 618 if (count <= 0) { 619 return; 620 } 621 622 SkASSERT(glyphs != NULL); 623 SkASSERT(textData != NULL); 624 625 SkAutoGlyphCache autoCache(*this, NULL, NULL); 626 SkGlyphCache* cache = autoCache.getCache(); 627 628 for (int index = 0; index < count; index++) { 629 textData[index] = cache->glyphToUnichar(glyphs[index]); 630 } 631 } 632 633 /////////////////////////////////////////////////////////////////////////////// 634 635 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache, 636 const char** text) { 637 SkASSERT(cache != NULL); 638 SkASSERT(text != NULL); 639 640 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); 641 } 642 643 static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache, 644 const char** text) { 645 SkASSERT(cache != NULL); 646 SkASSERT(text != NULL); 647 648 return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text)); 649 } 650 651 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache, 652 const char** text) { 653 SkASSERT(cache != NULL); 654 SkASSERT(text != NULL); 655 656 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); 657 } 658 659 static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache, 660 const char** text) { 661 SkASSERT(cache != NULL); 662 SkASSERT(text != NULL); 663 664 return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text)); 665 } 666 667 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache, 668 const char** text) { 669 SkASSERT(cache != NULL); 670 SkASSERT(text != NULL); 671 672 const int32_t* ptr = *(const int32_t**)text; 673 SkUnichar uni = *ptr++; 674 *text = (const char*)ptr; 675 return cache->getUnicharMetrics(uni); 676 } 677 678 static const SkGlyph& sk_getMetrics_utf32_prev(SkGlyphCache* cache, 679 const char** text) { 680 SkASSERT(cache != NULL); 681 SkASSERT(text != NULL); 682 683 const int32_t* ptr = *(const int32_t**)text; 684 SkUnichar uni = *--ptr; 685 *text = (const char*)ptr; 686 return cache->getUnicharMetrics(uni); 687 } 688 689 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache, 690 const char** text) { 691 SkASSERT(cache != NULL); 692 SkASSERT(text != NULL); 693 694 const uint16_t* ptr = *(const uint16_t**)text; 695 unsigned glyphID = *ptr; 696 ptr += 1; 697 *text = (const char*)ptr; 698 return cache->getGlyphIDMetrics(glyphID); 699 } 700 701 static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache, 702 const char** text) { 703 SkASSERT(cache != NULL); 704 SkASSERT(text != NULL); 705 706 const uint16_t* ptr = *(const uint16_t**)text; 707 ptr -= 1; 708 unsigned glyphID = *ptr; 709 *text = (const char*)ptr; 710 return cache->getGlyphIDMetrics(glyphID); 711 } 712 713 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache, 714 const char** text) { 715 SkASSERT(cache != NULL); 716 SkASSERT(text != NULL); 717 718 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text)); 719 } 720 721 static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache, 722 const char** text) { 723 SkASSERT(cache != NULL); 724 SkASSERT(text != NULL); 725 726 return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text)); 727 } 728 729 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache, 730 const char** text) { 731 SkASSERT(cache != NULL); 732 SkASSERT(text != NULL); 733 734 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text)); 735 } 736 737 static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache, 738 const char** text) { 739 SkASSERT(cache != NULL); 740 SkASSERT(text != NULL); 741 742 return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text)); 743 } 744 745 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache, 746 const char** text) { 747 SkASSERT(cache != NULL); 748 SkASSERT(text != NULL); 749 750 const int32_t* ptr = *(const int32_t**)text; 751 SkUnichar uni = *ptr++; 752 *text = (const char*)ptr; 753 return cache->getUnicharAdvance(uni); 754 } 755 756 static const SkGlyph& sk_getAdvance_utf32_prev(SkGlyphCache* cache, 757 const char** text) { 758 SkASSERT(cache != NULL); 759 SkASSERT(text != NULL); 760 761 const int32_t* ptr = *(const int32_t**)text; 762 SkUnichar uni = *--ptr; 763 *text = (const char*)ptr; 764 return cache->getUnicharAdvance(uni); 765 } 766 767 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache, 768 const char** text) { 769 SkASSERT(cache != NULL); 770 SkASSERT(text != NULL); 771 772 const uint16_t* ptr = *(const uint16_t**)text; 773 unsigned glyphID = *ptr; 774 ptr += 1; 775 *text = (const char*)ptr; 776 return cache->getGlyphIDAdvance(glyphID); 777 } 778 779 static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache, 780 const char** text) { 781 SkASSERT(cache != NULL); 782 SkASSERT(text != NULL); 783 784 const uint16_t* ptr = *(const uint16_t**)text; 785 ptr -= 1; 786 unsigned glyphID = *ptr; 787 *text = (const char*)ptr; 788 return cache->getGlyphIDAdvance(glyphID); 789 } 790 791 SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd, 792 bool needFullMetrics) const { 793 static const SkMeasureCacheProc gMeasureCacheProcs[] = { 794 sk_getMetrics_utf8_next, 795 sk_getMetrics_utf16_next, 796 sk_getMetrics_utf32_next, 797 sk_getMetrics_glyph_next, 798 799 sk_getMetrics_utf8_prev, 800 sk_getMetrics_utf16_prev, 801 sk_getMetrics_utf32_prev, 802 sk_getMetrics_glyph_prev, 803 804 sk_getAdvance_utf8_next, 805 sk_getAdvance_utf16_next, 806 sk_getAdvance_utf32_next, 807 sk_getAdvance_glyph_next, 808 809 sk_getAdvance_utf8_prev, 810 sk_getAdvance_utf16_prev, 811 sk_getAdvance_utf32_prev, 812 sk_getAdvance_glyph_prev 813 }; 814 815 unsigned index = this->getTextEncoding(); 816 817 if (kBackward_TextBufferDirection == tbd) { 818 index += 4; 819 } 820 if (!needFullMetrics && !this->isDevKernText()) { 821 index += 8; 822 } 823 824 SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs)); 825 return gMeasureCacheProcs[index]; 826 } 827 828 /////////////////////////////////////////////////////////////////////////////// 829 830 static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache, 831 const char** text, SkFixed, SkFixed) { 832 SkASSERT(cache != NULL); 833 SkASSERT(text != NULL); 834 835 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); 836 } 837 838 static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache, 839 const char** text, SkFixed x, SkFixed y) { 840 SkASSERT(cache != NULL); 841 SkASSERT(text != NULL); 842 843 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y); 844 } 845 846 static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache, 847 const char** text, SkFixed, SkFixed) { 848 SkASSERT(cache != NULL); 849 SkASSERT(text != NULL); 850 851 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); 852 } 853 854 static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache, 855 const char** text, SkFixed x, SkFixed y) { 856 SkASSERT(cache != NULL); 857 SkASSERT(text != NULL); 858 859 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text), 860 x, y); 861 } 862 863 static const SkGlyph& sk_getMetrics_utf32_00(SkGlyphCache* cache, 864 const char** text, SkFixed, SkFixed) { 865 SkASSERT(cache != NULL); 866 SkASSERT(text != NULL); 867 868 const int32_t* ptr = *(const int32_t**)text; 869 SkUnichar uni = *ptr++; 870 *text = (const char*)ptr; 871 return cache->getUnicharMetrics(uni); 872 } 873 874 static const SkGlyph& sk_getMetrics_utf32_xy(SkGlyphCache* cache, 875 const char** text, SkFixed x, SkFixed y) { 876 SkASSERT(cache != NULL); 877 SkASSERT(text != NULL); 878 879 const int32_t* ptr = *(const int32_t**)text; 880 SkUnichar uni = *--ptr; 881 *text = (const char*)ptr; 882 return cache->getUnicharMetrics(uni); 883 } 884 885 static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache, 886 const char** text, SkFixed, SkFixed) { 887 SkASSERT(cache != NULL); 888 SkASSERT(text != NULL); 889 890 const uint16_t* ptr = *(const uint16_t**)text; 891 unsigned glyphID = *ptr; 892 ptr += 1; 893 *text = (const char*)ptr; 894 return cache->getGlyphIDMetrics(glyphID); 895 } 896 897 static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache, 898 const char** text, SkFixed x, SkFixed y) { 899 SkASSERT(cache != NULL); 900 SkASSERT(text != NULL); 901 902 const uint16_t* ptr = *(const uint16_t**)text; 903 unsigned glyphID = *ptr; 904 ptr += 1; 905 *text = (const char*)ptr; 906 return cache->getGlyphIDMetrics(glyphID, x, y); 907 } 908 909 SkDrawCacheProc SkPaint::getDrawCacheProc() const { 910 static const SkDrawCacheProc gDrawCacheProcs[] = { 911 sk_getMetrics_utf8_00, 912 sk_getMetrics_utf16_00, 913 sk_getMetrics_utf32_00, 914 sk_getMetrics_glyph_00, 915 916 sk_getMetrics_utf8_xy, 917 sk_getMetrics_utf16_xy, 918 sk_getMetrics_utf32_xy, 919 sk_getMetrics_glyph_xy 920 }; 921 922 unsigned index = this->getTextEncoding(); 923 if (fFlags & kSubpixelText_Flag) { 924 index += 4; 925 } 926 927 SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs)); 928 return gDrawCacheProcs[index]; 929 } 930 931 /////////////////////////////////////////////////////////////////////////////// 932 933 class SkAutoRestorePaintTextSizeAndFrame { 934 public: 935 SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint) 936 : fPaint((SkPaint*)paint) { 937 #ifdef SK_BUILD_FOR_ANDROID 938 fGenerationID = fPaint->getGenerationID(); 939 #endif 940 fTextSize = paint->getTextSize(); 941 fStyle = paint->getStyle(); 942 fPaint->setStyle(SkPaint::kFill_Style); 943 } 944 945 ~SkAutoRestorePaintTextSizeAndFrame() { 946 fPaint->setStyle(fStyle); 947 fPaint->setTextSize(fTextSize); 948 #ifdef SK_BUILD_FOR_ANDROID 949 fPaint->setGenerationID(fGenerationID); 950 #endif 951 } 952 953 private: 954 SkPaint* fPaint; 955 SkScalar fTextSize; 956 SkPaint::Style fStyle; 957 #ifdef SK_BUILD_FOR_ANDROID 958 uint32_t fGenerationID; 959 #endif 960 }; 961 962 static void set_bounds(const SkGlyph& g, SkRect* bounds) { 963 bounds->set(SkIntToScalar(g.fLeft), 964 SkIntToScalar(g.fTop), 965 SkIntToScalar(g.fLeft + g.fWidth), 966 SkIntToScalar(g.fTop + g.fHeight)); 967 } 968 969 // 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so 970 // we don't overflow along the way 971 typedef int64_t Sk48Dot16; 972 973 #ifdef SK_SCALAR_IS_FLOAT 974 static inline float Sk48Dot16ToScalar(Sk48Dot16 x) { 975 return (float) (x * 1.5258789e-5); // x * (1 / 65536.0f) 976 } 977 #else 978 static inline SkFixed Sk48Dot16ToScalar(Sk48Dot16 x) { 979 // just return the low 32bits 980 return static_cast<SkFixed>(x); 981 } 982 #endif 983 984 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) { 985 SkScalar sx = Sk48Dot16ToScalar(dx); 986 bounds->join(SkIntToScalar(g.fLeft) + sx, 987 SkIntToScalar(g.fTop), 988 SkIntToScalar(g.fLeft + g.fWidth) + sx, 989 SkIntToScalar(g.fTop + g.fHeight)); 990 } 991 992 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) { 993 SkScalar sy = Sk48Dot16ToScalar(dy); 994 bounds->join(SkIntToScalar(g.fLeft), 995 SkIntToScalar(g.fTop) + sy, 996 SkIntToScalar(g.fLeft + g.fWidth), 997 SkIntToScalar(g.fTop + g.fHeight) + sy); 998 } 999 1000 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16); 1001 1002 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY 1003 static SkFixed advance(const SkGlyph& glyph, int xyIndex) { 1004 SkASSERT(0 == xyIndex || 1 == xyIndex); 1005 return (&glyph.fAdvanceX)[xyIndex]; 1006 } 1007 1008 SkScalar SkPaint::measure_text(SkGlyphCache* cache, 1009 const char* text, size_t byteLength, 1010 int* count, SkRect* bounds) const { 1011 SkASSERT(count); 1012 if (byteLength == 0) { 1013 *count = 0; 1014 if (bounds) { 1015 bounds->setEmpty(); 1016 } 1017 return 0; 1018 } 1019 1020 SkMeasureCacheProc glyphCacheProc; 1021 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, 1022 NULL != bounds); 1023 1024 int xyIndex; 1025 JoinBoundsProc joinBoundsProc; 1026 if (this->isVerticalText()) { 1027 xyIndex = 1; 1028 joinBoundsProc = join_bounds_y; 1029 } else { 1030 xyIndex = 0; 1031 joinBoundsProc = join_bounds_x; 1032 } 1033 1034 int n = 1; 1035 const char* stop = (const char*)text + byteLength; 1036 const SkGlyph* g = &glyphCacheProc(cache, &text); 1037 // our accumulated fixed-point advances might overflow 16.16, so we use 1038 // a 48.16 (64bit) accumulator, and then convert that to scalar at the 1039 // very end. 1040 Sk48Dot16 x = advance(*g, xyIndex); 1041 1042 SkAutoKern autokern; 1043 1044 if (NULL == bounds) { 1045 if (this->isDevKernText()) { 1046 int rsb; 1047 for (; text < stop; n++) { 1048 rsb = g->fRsbDelta; 1049 g = &glyphCacheProc(cache, &text); 1050 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex); 1051 } 1052 } else { 1053 for (; text < stop; n++) { 1054 x += advance(glyphCacheProc(cache, &text), xyIndex); 1055 } 1056 } 1057 } else { 1058 set_bounds(*g, bounds); 1059 if (this->isDevKernText()) { 1060 int rsb; 1061 for (; text < stop; n++) { 1062 rsb = g->fRsbDelta; 1063 g = &glyphCacheProc(cache, &text); 1064 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta); 1065 joinBoundsProc(*g, bounds, x); 1066 x += advance(*g, xyIndex); 1067 } 1068 } else { 1069 for (; text < stop; n++) { 1070 g = &glyphCacheProc(cache, &text); 1071 joinBoundsProc(*g, bounds, x); 1072 x += advance(*g, xyIndex); 1073 } 1074 } 1075 } 1076 SkASSERT(text == stop); 1077 1078 *count = n; 1079 return Sk48Dot16ToScalar(x); 1080 } 1081 1082 SkScalar SkPaint::measureText(const void* textData, size_t length, 1083 SkRect* bounds, SkScalar zoom) const { 1084 const char* text = (const char*)textData; 1085 SkASSERT(text != NULL || length == 0); 1086 1087 SkScalar scale = 0; 1088 SkAutoRestorePaintTextSizeAndFrame restore(this); 1089 1090 if (this->isLinearText()) { 1091 scale = fTextSize / kCanonicalTextSizeForPaths; 1092 // this gets restored by restore 1093 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); 1094 } 1095 1096 SkMatrix zoomMatrix, *zoomPtr = NULL; 1097 if (zoom) { 1098 zoomMatrix.setScale(zoom, zoom); 1099 zoomPtr = &zoomMatrix; 1100 } 1101 1102 SkAutoGlyphCache autoCache(*this, NULL, zoomPtr); 1103 SkGlyphCache* cache = autoCache.getCache(); 1104 1105 SkScalar width = 0; 1106 1107 if (length > 0) { 1108 int tempCount; 1109 1110 width = this->measure_text(cache, text, length, &tempCount, bounds); 1111 if (scale) { 1112 width = SkScalarMul(width, scale); 1113 if (bounds) { 1114 bounds->fLeft = SkScalarMul(bounds->fLeft, scale); 1115 bounds->fTop = SkScalarMul(bounds->fTop, scale); 1116 bounds->fRight = SkScalarMul(bounds->fRight, scale); 1117 bounds->fBottom = SkScalarMul(bounds->fBottom, scale); 1118 } 1119 } 1120 } 1121 return width; 1122 } 1123 1124 typedef bool (*SkTextBufferPred)(const char* text, const char* stop); 1125 1126 static bool forward_textBufferPred(const char* text, const char* stop) { 1127 return text < stop; 1128 } 1129 1130 static bool backward_textBufferPred(const char* text, const char* stop) { 1131 return text > stop; 1132 } 1133 1134 static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd, 1135 const char** text, size_t length, 1136 const char** stop) { 1137 if (SkPaint::kForward_TextBufferDirection == tbd) { 1138 *stop = *text + length; 1139 return forward_textBufferPred; 1140 } else { 1141 // text should point to the end of the buffer, and stop to the beginning 1142 *stop = *text; 1143 *text += length; 1144 return backward_textBufferPred; 1145 } 1146 } 1147 1148 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, 1149 SkScalar* measuredWidth, 1150 TextBufferDirection tbd) const { 1151 if (0 == length || 0 >= maxWidth) { 1152 if (measuredWidth) { 1153 *measuredWidth = 0; 1154 } 1155 return 0; 1156 } 1157 1158 if (0 == fTextSize) { 1159 if (measuredWidth) { 1160 *measuredWidth = 0; 1161 } 1162 return length; 1163 } 1164 1165 SkASSERT(textD != NULL); 1166 const char* text = (const char*)textD; 1167 1168 SkScalar scale = 0; 1169 SkAutoRestorePaintTextSizeAndFrame restore(this); 1170 1171 if (this->isLinearText()) { 1172 scale = fTextSize / kCanonicalTextSizeForPaths; 1173 maxWidth = SkScalarMulDiv(maxWidth, kCanonicalTextSizeForPaths, fTextSize); 1174 // this gets restored by restore 1175 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); 1176 } 1177 1178 SkAutoGlyphCache autoCache(*this, NULL, NULL); 1179 SkGlyphCache* cache = autoCache.getCache(); 1180 1181 SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false); 1182 const char* stop; 1183 SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop); 1184 const int xyIndex = this->isVerticalText() ? 1 : 0; 1185 // use 64bits for our accumulator, to avoid overflowing 16.16 1186 Sk48Dot16 max = SkScalarToFixed(maxWidth); 1187 Sk48Dot16 width = 0; 1188 1189 SkAutoKern autokern; 1190 1191 if (this->isDevKernText()) { 1192 int rsb = 0; 1193 while (pred(text, stop)) { 1194 const char* curr = text; 1195 const SkGlyph& g = glyphCacheProc(cache, &text); 1196 SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex); 1197 if ((width += x) > max) { 1198 width -= x; 1199 text = curr; 1200 break; 1201 } 1202 rsb = g.fRsbDelta; 1203 } 1204 } else { 1205 while (pred(text, stop)) { 1206 const char* curr = text; 1207 SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex); 1208 if ((width += x) > max) { 1209 width -= x; 1210 text = curr; 1211 break; 1212 } 1213 } 1214 } 1215 1216 if (measuredWidth) { 1217 SkScalar scalarWidth = Sk48Dot16ToScalar(width); 1218 if (scale) { 1219 scalarWidth = SkScalarMul(scalarWidth, scale); 1220 } 1221 *measuredWidth = scalarWidth; 1222 } 1223 1224 // return the number of bytes measured 1225 return (kForward_TextBufferDirection == tbd) ? 1226 text - stop + length : stop - text + length; 1227 } 1228 1229 /////////////////////////////////////////////////////////////////////////////// 1230 1231 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) { 1232 *(SkPaint::FontMetrics*)context = cache->getFontMetricsY(); 1233 return false; // don't detach the cache 1234 } 1235 1236 static void FontMetricsDescProc(const SkDescriptor* desc, void* context) { 1237 SkGlyphCache::VisitCache(desc, FontMetricsCacheProc, context); 1238 } 1239 1240 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { 1241 SkScalar scale = 0; 1242 SkAutoRestorePaintTextSizeAndFrame restore(this); 1243 1244 if (this->isLinearText()) { 1245 scale = fTextSize / kCanonicalTextSizeForPaths; 1246 // this gets restored by restore 1247 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); 1248 } 1249 1250 SkMatrix zoomMatrix, *zoomPtr = NULL; 1251 if (zoom) { 1252 zoomMatrix.setScale(zoom, zoom); 1253 zoomPtr = &zoomMatrix; 1254 } 1255 1256 #if 0 1257 SkAutoGlyphCache autoCache(*this, zoomPtr); 1258 SkGlyphCache* cache = autoCache.getCache(); 1259 const FontMetrics& my = cache->getFontMetricsY(); 1260 #endif 1261 FontMetrics storage; 1262 if (NULL == metrics) { 1263 metrics = &storage; 1264 } 1265 1266 this->descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true); 1267 1268 if (scale) { 1269 metrics->fTop = SkScalarMul(metrics->fTop, scale); 1270 metrics->fAscent = SkScalarMul(metrics->fAscent, scale); 1271 metrics->fDescent = SkScalarMul(metrics->fDescent, scale); 1272 metrics->fBottom = SkScalarMul(metrics->fBottom, scale); 1273 metrics->fLeading = SkScalarMul(metrics->fLeading, scale); 1274 } 1275 return metrics->fDescent - metrics->fAscent + metrics->fLeading; 1276 } 1277 1278 /////////////////////////////////////////////////////////////////////////////// 1279 1280 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) { 1281 bounds->set(g.fLeft * scale, 1282 g.fTop * scale, 1283 (g.fLeft + g.fWidth) * scale, 1284 (g.fTop + g.fHeight) * scale); 1285 } 1286 1287 int SkPaint::getTextWidths(const void* textData, size_t byteLength, 1288 SkScalar widths[], SkRect bounds[]) const { 1289 if (0 == byteLength) { 1290 return 0; 1291 } 1292 1293 SkASSERT(NULL != textData); 1294 1295 if (NULL == widths && NULL == bounds) { 1296 return this->countText(textData, byteLength); 1297 } 1298 1299 SkAutoRestorePaintTextSizeAndFrame restore(this); 1300 SkScalar scale = 0; 1301 1302 if (this->isLinearText()) { 1303 scale = fTextSize / kCanonicalTextSizeForPaths; 1304 // this gets restored by restore 1305 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); 1306 } 1307 1308 SkAutoGlyphCache autoCache(*this, NULL, NULL); 1309 SkGlyphCache* cache = autoCache.getCache(); 1310 SkMeasureCacheProc glyphCacheProc; 1311 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, 1312 NULL != bounds); 1313 1314 const char* text = (const char*)textData; 1315 const char* stop = text + byteLength; 1316 int count = 0; 1317 const int xyIndex = this->isVerticalText() ? 1 : 0; 1318 1319 if (this->isDevKernText()) { 1320 // we adjust the widths returned here through auto-kerning 1321 SkAutoKern autokern; 1322 SkFixed prevWidth = 0; 1323 1324 if (scale) { 1325 while (text < stop) { 1326 const SkGlyph& g = glyphCacheProc(cache, &text); 1327 if (widths) { 1328 SkFixed adjust = autokern.adjust(g); 1329 1330 if (count > 0) { 1331 SkScalar w = SkFixedToScalar(prevWidth + adjust); 1332 *widths++ = SkScalarMul(w, scale); 1333 } 1334 prevWidth = advance(g, xyIndex); 1335 } 1336 if (bounds) { 1337 set_bounds(g, bounds++, scale); 1338 } 1339 ++count; 1340 } 1341 if (count > 0 && widths) { 1342 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale); 1343 } 1344 } else { 1345 while (text < stop) { 1346 const SkGlyph& g = glyphCacheProc(cache, &text); 1347 if (widths) { 1348 SkFixed adjust = autokern.adjust(g); 1349 1350 if (count > 0) { 1351 *widths++ = SkFixedToScalar(prevWidth + adjust); 1352 } 1353 prevWidth = advance(g, xyIndex); 1354 } 1355 if (bounds) { 1356 set_bounds(g, bounds++); 1357 } 1358 ++count; 1359 } 1360 if (count > 0 && widths) { 1361 *widths = SkFixedToScalar(prevWidth); 1362 } 1363 } 1364 } else { // no devkern 1365 if (scale) { 1366 while (text < stop) { 1367 const SkGlyph& g = glyphCacheProc(cache, &text); 1368 if (widths) { 1369 *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)), 1370 scale); 1371 } 1372 if (bounds) { 1373 set_bounds(g, bounds++, scale); 1374 } 1375 ++count; 1376 } 1377 } else { 1378 while (text < stop) { 1379 const SkGlyph& g = glyphCacheProc(cache, &text); 1380 if (widths) { 1381 *widths++ = SkFixedToScalar(advance(g, xyIndex)); 1382 } 1383 if (bounds) { 1384 set_bounds(g, bounds++); 1385 } 1386 ++count; 1387 } 1388 } 1389 } 1390 1391 SkASSERT(text == stop); 1392 return count; 1393 } 1394 1395 /////////////////////////////////////////////////////////////////////////////// 1396 1397 #include "SkDraw.h" 1398 1399 void SkPaint::getTextPath(const void* textData, size_t length, 1400 SkScalar x, SkScalar y, SkPath* path) const { 1401 SkASSERT(length == 0 || textData != NULL); 1402 1403 const char* text = (const char*)textData; 1404 if (text == NULL || length == 0 || path == NULL) { 1405 return; 1406 } 1407 1408 SkTextToPathIter iter(text, length, *this, false); 1409 SkMatrix matrix; 1410 SkScalar prevXPos = 0; 1411 1412 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1413 matrix.postTranslate(x, y); 1414 path->reset(); 1415 1416 SkScalar xpos; 1417 const SkPath* iterPath; 1418 while (iter.next(&iterPath, &xpos)) { 1419 matrix.postTranslate(xpos - prevXPos, 0); 1420 if (iterPath) { 1421 path->addPath(*iterPath, matrix); 1422 } 1423 prevXPos = xpos; 1424 } 1425 } 1426 1427 void SkPaint::getPosTextPath(const void* textData, size_t length, 1428 const SkPoint pos[], SkPath* path) const { 1429 SkASSERT(length == 0 || textData != NULL); 1430 1431 const char* text = (const char*)textData; 1432 if (text == NULL || length == 0 || path == NULL) { 1433 return; 1434 } 1435 1436 SkTextToPathIter iter(text, length, *this, false); 1437 SkMatrix matrix; 1438 SkPoint prevPos; 1439 prevPos.set(0, 0); 1440 1441 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1442 path->reset(); 1443 1444 unsigned int i = 0; 1445 const SkPath* iterPath; 1446 while (iter.next(&iterPath, NULL)) { 1447 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY); 1448 if (iterPath) { 1449 path->addPath(*iterPath, matrix); 1450 } 1451 prevPos = pos[i]; 1452 i++; 1453 } 1454 } 1455 1456 static void add_flattenable(SkDescriptor* desc, uint32_t tag, 1457 SkOrderedWriteBuffer* buffer) { 1458 buffer->writeToMemory(desc->addEntry(tag, buffer->size(), NULL)); 1459 } 1460 1461 // SkFontHost can override this choice in FilterRec() 1462 static SkMask::Format computeMaskFormat(const SkPaint& paint) { 1463 uint32_t flags = paint.getFlags(); 1464 1465 // Antialiasing being disabled trumps all other settings. 1466 if (!(flags & SkPaint::kAntiAlias_Flag)) { 1467 return SkMask::kBW_Format; 1468 } 1469 1470 if (flags & SkPaint::kLCDRenderText_Flag) { 1471 return SkMask::kLCD16_Format; 1472 } 1473 1474 return SkMask::kA8_Format; 1475 } 1476 1477 // if linear-text is on, then we force hinting to be off (since that's sort of 1478 // the point of linear-text. 1479 static SkPaint::Hinting computeHinting(const SkPaint& paint) { 1480 SkPaint::Hinting h = paint.getHinting(); 1481 if (paint.isLinearText()) { 1482 h = SkPaint::kNo_Hinting; 1483 } 1484 return h; 1485 } 1486 1487 // return true if the paint is just a single color (i.e. not a shader). If its 1488 // a shader, then we can't compute a const luminance for it :( 1489 static bool justAColor(const SkPaint& paint, SkColor* color) { 1490 if (paint.getShader()) { 1491 return false; 1492 } 1493 SkColor c = paint.getColor(); 1494 if (paint.getColorFilter()) { 1495 c = paint.getColorFilter()->filterColor(c); 1496 } 1497 if (color) { 1498 *color = c; 1499 } 1500 return true; 1501 } 1502 1503 static SkColor computeLuminanceColor(const SkPaint& paint) { 1504 SkColor c; 1505 if (!justAColor(paint, &c)) { 1506 c = SkColorSetRGB(0x7F, 0x80, 0x7F); 1507 } 1508 return c; 1509 } 1510 1511 #define assert_byte(x) SkASSERT(0 == ((x) >> 8)) 1512 1513 // Beyond this size, LCD doesn't appreciably improve quality, but it always 1514 // cost more RAM and draws slower, so we set a cap. 1515 #ifndef SK_MAX_SIZE_FOR_LCDTEXT 1516 #define SK_MAX_SIZE_FOR_LCDTEXT 48 1517 #endif 1518 1519 static bool tooBigForLCD(const SkScalerContext::Rec& rec) { 1520 SkScalar area = SkScalarMul(rec.fPost2x2[0][0], rec.fPost2x2[1][1]) - 1521 SkScalarMul(rec.fPost2x2[1][0], rec.fPost2x2[0][1]); 1522 SkScalar size = SkScalarMul(area, rec.fTextSize); 1523 return SkScalarAbs(size) > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT); 1524 } 1525 1526 /* 1527 * Return the scalar with only limited fractional precision. Used to consolidate matrices 1528 * that vary only slightly when we create our key into the font cache, since the font scaler 1529 * typically returns the same looking resuts for tiny changes in the matrix. 1530 */ 1531 static SkScalar sk_relax(SkScalar x) { 1532 #ifdef SK_SCALAR_IS_FLOAT 1533 int n = sk_float_round2int(x * 1024); 1534 return n / 1024.0f; 1535 #else 1536 // round to the nearest 10 fractional bits 1537 return (x + (1 << 5)) & ~(1024 - 1); 1538 #endif 1539 } 1540 1541 void SkScalerContext::MakeRec(const SkPaint& paint, 1542 const SkDeviceProperties* deviceProperties, 1543 const SkMatrix* deviceMatrix, 1544 Rec* rec) { 1545 SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective()); 1546 1547 SkTypeface* typeface = paint.getTypeface(); 1548 if (NULL == typeface) { 1549 typeface = SkTypeface::GetDefaultTypeface(); 1550 } 1551 rec->fOrigFontID = typeface->uniqueID(); 1552 rec->fFontID = rec->fOrigFontID; 1553 rec->fTextSize = paint.getTextSize(); 1554 rec->fPreScaleX = paint.getTextScaleX(); 1555 rec->fPreSkewX = paint.getTextSkewX(); 1556 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 1557 rec->fHintingScaleFactor = paint.getHintingScaleFactor(); 1558 #endif 1559 1560 if (deviceMatrix) { 1561 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX()); 1562 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX()); 1563 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY()); 1564 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY()); 1565 } else { 1566 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; 1567 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; 1568 } 1569 1570 SkPaint::Style style = paint.getStyle(); 1571 SkScalar strokeWidth = paint.getStrokeWidth(); 1572 1573 unsigned flags = 0; 1574 1575 #ifdef SK_USE_FREETYPE_EMBOLDEN 1576 // It is possible that the SkTypeface used to draw glyphs has 1577 // different properties than the SkTypeface set in the SkPaint. 1578 // If we are asked to render bold text with a bold font, and are 1579 // forced to fall back to a font with normal weight for some 1580 // glyphs, we need to use fake bold to render those glyphs. In 1581 // order to do that, we set SkScalerContext's "embolden" flag 1582 // here if we are trying to draw bold text via any means, and 1583 // ignore it at the glyph outline generation stage if the font 1584 // actually being used is already bold. 1585 if (paint.isFakeBoldText() || (typeface && typeface->isBold())) { 1586 flags |= SkScalerContext::kEmbolden_Flag; 1587 } 1588 #else 1589 if (paint.isFakeBoldText()) { 1590 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), 1591 kStdFakeBoldInterpKeys, 1592 kStdFakeBoldInterpValues, 1593 kStdFakeBoldInterpLength); 1594 SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale); 1595 1596 if (style == SkPaint::kFill_Style) { 1597 style = SkPaint::kStrokeAndFill_Style; 1598 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" 1599 } else { 1600 strokeWidth += extra; 1601 } 1602 } 1603 #endif 1604 1605 if (paint.isDevKernText()) { 1606 flags |= SkScalerContext::kDevKernText_Flag; 1607 } 1608 1609 if (style != SkPaint::kFill_Style && strokeWidth > 0) { 1610 rec->fFrameWidth = strokeWidth; 1611 rec->fMiterLimit = paint.getStrokeMiter(); 1612 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); 1613 1614 if (style == SkPaint::kStrokeAndFill_Style) { 1615 flags |= SkScalerContext::kFrameAndFill_Flag; 1616 } 1617 } else { 1618 rec->fFrameWidth = 0; 1619 rec->fMiterLimit = 0; 1620 rec->fStrokeJoin = 0; 1621 } 1622 1623 rec->fMaskFormat = SkToU8(computeMaskFormat(paint)); 1624 1625 SkDeviceProperties::Geometry geometry = deviceProperties 1626 ? deviceProperties->fGeometry 1627 : SkDeviceProperties::Geometry::MakeDefault(); 1628 if (SkMask::kLCD16_Format == rec->fMaskFormat || SkMask::kLCD32_Format == rec->fMaskFormat) { 1629 if (!geometry.isOrientationKnown() || !geometry.isLayoutKnown() || tooBigForLCD(*rec)) { 1630 // eeek, can't support LCD 1631 rec->fMaskFormat = SkMask::kA8_Format; 1632 } else { 1633 if (SkDeviceProperties::Geometry::kVertical_Orientation == geometry.getOrientation()) { 1634 flags |= SkScalerContext::kLCD_Vertical_Flag; 1635 } 1636 if (SkDeviceProperties::Geometry::kBGR_Layout == geometry.getLayout()) { 1637 flags |= SkScalerContext::kLCD_BGROrder_Flag; 1638 } 1639 } 1640 } 1641 1642 if (paint.isEmbeddedBitmapText()) { 1643 flags |= SkScalerContext::kEmbeddedBitmapText_Flag; 1644 } 1645 if (paint.isSubpixelText()) { 1646 flags |= SkScalerContext::kSubpixelPositioning_Flag; 1647 } 1648 if (paint.isAutohinted()) { 1649 flags |= SkScalerContext::kAutohinting_Flag; 1650 } 1651 if (paint.isVerticalText()) { 1652 flags |= SkScalerContext::kVertical_Flag; 1653 } 1654 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { 1655 flags |= SkScalerContext::kGenA8FromLCD_Flag; 1656 } 1657 rec->fFlags = SkToU16(flags); 1658 1659 // these modify fFlags, so do them after assigning fFlags 1660 rec->setHinting(computeHinting(paint)); 1661 1662 rec->setLuminanceColor(computeLuminanceColor(paint)); 1663 1664 if (NULL == deviceProperties) { 1665 rec->setDeviceGamma(SK_GAMMA_EXPONENT); 1666 rec->setPaintGamma(SK_GAMMA_EXPONENT); 1667 } else { 1668 rec->setDeviceGamma(deviceProperties->fGamma); 1669 1670 //For now always set the paint gamma equal to the device gamma. 1671 //The math in SkMaskGamma can handle them being different, 1672 //but it requires superluminous masks when 1673 //Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. 1674 rec->setPaintGamma(deviceProperties->fGamma); 1675 } 1676 1677 #ifdef SK_GAMMA_CONTRAST 1678 rec->setContrast(SK_GAMMA_CONTRAST); 1679 #else 1680 /** 1681 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. 1682 * With lower values small text appears washed out (though correctly so). 1683 * With higher values lcd fringing is worse and the smoothing effect of 1684 * partial coverage is diminished. 1685 */ 1686 rec->setContrast(SkFloatToScalar(0.5f)); 1687 #endif 1688 1689 rec->fReservedAlign = 0; 1690 1691 #ifdef SK_BUILD_FOR_ANDROID 1692 rec->fLanguage = paint.getLanguage(); 1693 rec->fFontVariant = paint.getFontVariant(); 1694 #endif //SK_BUILD_FOR_ANDROID 1695 1696 /* Allow the fonthost to modify our rec before we use it as a key into the 1697 cache. This way if we're asking for something that they will ignore, 1698 they can modify our rec up front, so we don't create duplicate cache 1699 entries. 1700 */ 1701 SkFontHost::FilterRec(rec, typeface); 1702 1703 // be sure to call PostMakeRec(rec) before you actually use it! 1704 } 1705 1706 /** 1707 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or 1708 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue 1709 * to hold it until the returned pointer is refed or forgotten. 1710 */ 1711 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex); 1712 1713 static SkMaskGamma* gLinearMaskGamma = NULL; 1714 static SkMaskGamma* gMaskGamma = NULL; 1715 static SkScalar gContrast = SK_ScalarMin; 1716 static SkScalar gPaintGamma = SK_ScalarMin; 1717 static SkScalar gDeviceGamma = SK_ScalarMin; 1718 /** 1719 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until 1720 * the returned SkMaskGamma pointer is refed or forgotten. 1721 */ 1722 static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) { 1723 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) { 1724 if (NULL == gLinearMaskGamma) { 1725 gLinearMaskGamma = SkNEW(SkMaskGamma); 1726 } 1727 return *gLinearMaskGamma; 1728 } 1729 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) { 1730 SkSafeUnref(gMaskGamma); 1731 gMaskGamma = SkNEW_ARGS(SkMaskGamma, (contrast, paintGamma, deviceGamma)); 1732 gContrast = contrast; 1733 gPaintGamma = paintGamma; 1734 gDeviceGamma = deviceGamma; 1735 } 1736 return *gMaskGamma; 1737 } 1738 1739 /*static*/ void SkPaint::Term() { 1740 SkAutoMutexAcquire ama(gMaskGammaCacheMutex); 1741 1742 SkSafeUnref(gLinearMaskGamma); 1743 gLinearMaskGamma = NULL; 1744 SkSafeUnref(gMaskGamma); 1745 gMaskGamma = NULL; 1746 SkDEBUGCODE(gContrast = SK_ScalarMin;) 1747 SkDEBUGCODE(gPaintGamma = SK_ScalarMin;) 1748 SkDEBUGCODE(gDeviceGamma = SK_ScalarMin;) 1749 } 1750 1751 /** 1752 * We ensure that the rec is self-consistent and efficient (where possible) 1753 */ 1754 void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* rec) { 1755 /** 1756 * If we're asking for A8, we force the colorlum to be gray, since that 1757 * limits the number of unique entries, and the scaler will only look at 1758 * the lum of one of them. 1759 */ 1760 switch (rec->fMaskFormat) { 1761 case SkMask::kLCD16_Format: 1762 case SkMask::kLCD32_Format: { 1763 // filter down the luminance color to a finite number of bits 1764 SkColor color = rec->getLuminanceColor(); 1765 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); 1766 break; 1767 } 1768 case SkMask::kA8_Format: { 1769 // filter down the luminance to a single component, since A8 can't 1770 // use per-component information 1771 1772 SkColor color = rec->getLuminanceColor(); 1773 U8CPU lum = SkColorSpaceLuminance::computeLuminance(rec->getPaintGamma(), color); 1774 //If we are asked to look like LCD, look like LCD. 1775 if (!(rec->fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { 1776 // HACK: Prevents green from being pre-blended as white. 1777 lum -= ((255 - lum) * lum) / 255; 1778 } 1779 1780 // reduce to our finite number of bits 1781 color = SkColorSetRGB(lum, lum, lum); 1782 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); 1783 break; 1784 } 1785 case SkMask::kBW_Format: 1786 // No need to differentiate gamma if we're BW 1787 rec->ignorePreBlend(); 1788 break; 1789 } 1790 } 1791 1792 #define MIN_SIZE_FOR_EFFECT_BUFFER 1024 1793 1794 #ifdef SK_DEBUG 1795 #define TEST_DESC 1796 #endif 1797 1798 /* 1799 * ignoreGamma tells us that the caller just wants metrics that are unaffected 1800 * by gamma correction, so we jam the luminance field to 0 (most common value 1801 * for black text) in hopes that we get a cache hit easier. A better solution 1802 * would be for the fontcache lookup to know to ignore the luminance field 1803 * entirely, but not sure how to do that and keep it fast. 1804 */ 1805 void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, 1806 const SkMatrix* deviceMatrix, 1807 void (*proc)(const SkDescriptor*, void*), 1808 void* context, bool ignoreGamma) const { 1809 SkScalerContext::Rec rec; 1810 1811 SkScalerContext::MakeRec(*this, deviceProperties, deviceMatrix, &rec); 1812 if (ignoreGamma) { 1813 rec.setLuminanceColor(0); 1814 } 1815 1816 size_t descSize = sizeof(rec); 1817 int entryCount = 1; 1818 SkPathEffect* pe = this->getPathEffect(); 1819 SkMaskFilter* mf = this->getMaskFilter(); 1820 SkRasterizer* ra = this->getRasterizer(); 1821 1822 SkOrderedWriteBuffer peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); 1823 SkOrderedWriteBuffer mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); 1824 SkOrderedWriteBuffer raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); 1825 1826 if (pe) { 1827 peBuffer.writeFlattenable(pe); 1828 descSize += peBuffer.size(); 1829 entryCount += 1; 1830 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion 1831 // seems like we could support kLCD as well at this point... 1832 } 1833 if (mf) { 1834 mfBuffer.writeFlattenable(mf); 1835 descSize += mfBuffer.size(); 1836 entryCount += 1; 1837 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters 1838 /* Pre-blend is not currently applied to filtered text. 1839 The primary filter is blur, for which contrast makes no sense, 1840 and for which the destination guess error is more visible. 1841 Also, all existing users of blur have calibrated for linear. */ 1842 rec.ignorePreBlend(); 1843 } 1844 if (ra) { 1845 raBuffer.writeFlattenable(ra); 1846 descSize += raBuffer.size(); 1847 entryCount += 1; 1848 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion 1849 } 1850 1851 /////////////////////////////////////////////////////////////////////////// 1852 // Now that we're done tweaking the rec, call the PostMakeRec cleanup 1853 SkScalerContext::PostMakeRec(*this, &rec); 1854 1855 descSize += SkDescriptor::ComputeOverhead(entryCount); 1856 1857 SkAutoDescriptor ad(descSize); 1858 SkDescriptor* desc = ad.getDesc(); 1859 1860 desc->init(); 1861 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1862 1863 if (pe) { 1864 add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer); 1865 } 1866 if (mf) { 1867 add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer); 1868 } 1869 if (ra) { 1870 add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer); 1871 } 1872 1873 SkASSERT(descSize == desc->getLength()); 1874 desc->computeChecksum(); 1875 1876 #ifdef TEST_DESC 1877 { 1878 // Check that we completely write the bytes in desc (our key), and that 1879 // there are no uninitialized bytes. If there were, then we would get 1880 // false-misses (or worse, false-hits) in our fontcache. 1881 // 1882 // We do this buy filling 2 others, one with 0s and the other with 1s 1883 // and create those, and then check that all 3 are identical. 1884 SkAutoDescriptor ad1(descSize); 1885 SkAutoDescriptor ad2(descSize); 1886 SkDescriptor* desc1 = ad1.getDesc(); 1887 SkDescriptor* desc2 = ad2.getDesc(); 1888 1889 memset(desc1, 0x00, descSize); 1890 memset(desc2, 0xFF, descSize); 1891 1892 desc1->init(); 1893 desc2->init(); 1894 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1895 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1896 1897 if (pe) { 1898 add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer); 1899 add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer); 1900 } 1901 if (mf) { 1902 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer); 1903 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer); 1904 } 1905 if (ra) { 1906 add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer); 1907 add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer); 1908 } 1909 1910 SkASSERT(descSize == desc1->getLength()); 1911 SkASSERT(descSize == desc2->getLength()); 1912 desc1->computeChecksum(); 1913 desc2->computeChecksum(); 1914 SkASSERT(!memcmp(desc, desc1, descSize)); 1915 SkASSERT(!memcmp(desc, desc2, descSize)); 1916 } 1917 #endif 1918 1919 proc(desc, context); 1920 } 1921 1922 SkGlyphCache* SkPaint::detachCache(const SkDeviceProperties* deviceProperties, 1923 const SkMatrix* deviceMatrix) const { 1924 SkGlyphCache* cache; 1925 this->descriptorProc(deviceProperties, deviceMatrix, DetachDescProc, &cache, false); 1926 return cache; 1927 } 1928 1929 /** 1930 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend. 1931 */ 1932 //static 1933 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) { 1934 SkAutoMutexAcquire ama(gMaskGammaCacheMutex); 1935 const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(), 1936 rec.getPaintGamma(), 1937 rec.getDeviceGamma()); 1938 return maskGamma.preBlend(rec.getLuminanceColor()); 1939 } 1940 1941 /////////////////////////////////////////////////////////////////////////////// 1942 1943 #include "SkStream.h" 1944 1945 static uintptr_t asint(const void* p) { 1946 return reinterpret_cast<uintptr_t>(p); 1947 } 1948 1949 union Scalar32 { 1950 SkScalar fScalar; 1951 uint32_t f32; 1952 }; 1953 1954 static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) { 1955 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); 1956 Scalar32 tmp; 1957 tmp.fScalar = value; 1958 *ptr = tmp.f32; 1959 return ptr + 1; 1960 } 1961 1962 static SkScalar read_scalar(const uint32_t*& ptr) { 1963 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); 1964 Scalar32 tmp; 1965 tmp.f32 = *ptr++; 1966 return tmp.fScalar; 1967 } 1968 1969 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) { 1970 SkASSERT(a == (uint8_t)a); 1971 SkASSERT(b == (uint8_t)b); 1972 SkASSERT(c == (uint8_t)c); 1973 SkASSERT(d == (uint8_t)d); 1974 return (a << 24) | (b << 16) | (c << 8) | d; 1975 } 1976 1977 enum FlatFlags { 1978 kHasTypeface_FlatFlag = 0x01, 1979 kHasEffects_FlatFlag = 0x02, 1980 }; 1981 1982 // The size of a flat paint's POD fields 1983 // Include an SkScalar for hinting scale factor whether it is 1984 // supported or not so that an SKP is valid whether it was 1985 // created with support or not. 1986 1987 static const uint32_t kPODPaintSize = 6 * sizeof(SkScalar) + 1988 1 * sizeof(SkColor) + 1989 1 * sizeof(uint16_t) + 1990 6 * sizeof(uint8_t); 1991 1992 /* To save space/time, we analyze the paint, and write a truncated version of 1993 it if there are not tricky elements like shaders, etc. 1994 */ 1995 void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const { 1996 uint8_t flatFlags = 0; 1997 if (this->getTypeface()) { 1998 flatFlags |= kHasTypeface_FlatFlag; 1999 } 2000 if (asint(this->getPathEffect()) | 2001 asint(this->getShader()) | 2002 asint(this->getXfermode()) | 2003 asint(this->getMaskFilter()) | 2004 asint(this->getColorFilter()) | 2005 asint(this->getRasterizer()) | 2006 asint(this->getLooper()) | 2007 asint(this->getAnnotation()) | 2008 asint(this->getImageFilter())) { 2009 flatFlags |= kHasEffects_FlatFlag; 2010 } 2011 2012 2013 if (buffer.isOrderedBinaryBuffer()) { 2014 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); 2015 uint32_t* ptr = buffer.getOrderedBinaryBuffer()->reserve(kPODPaintSize); 2016 2017 ptr = write_scalar(ptr, this->getTextSize()); 2018 ptr = write_scalar(ptr, this->getTextScaleX()); 2019 ptr = write_scalar(ptr, this->getTextSkewX()); 2020 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 2021 ptr = write_scalar(ptr, this->getHintingScaleFactor()); 2022 #else 2023 // Dummy value. 2024 ptr = write_scalar(ptr, SK_Scalar1); 2025 #endif 2026 ptr = write_scalar(ptr, this->getStrokeWidth()); 2027 ptr = write_scalar(ptr, this->getStrokeMiter()); 2028 *ptr++ = this->getColor(); 2029 // previously flags:16, textAlign:8, flatFlags:8 2030 // now flags:16, hinting:4, textAlign:4, flatFlags:8 2031 *ptr++ = (this->getFlags() << 16) | 2032 // hinting added later. 0 in this nibble means use the default. 2033 ((this->getHinting()+1) << 12) | 2034 (this->getTextAlign() << 8) | 2035 flatFlags; 2036 *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(), 2037 this->getStyle(), this->getTextEncoding()); 2038 } else { 2039 buffer.writeScalar(fTextSize); 2040 buffer.writeScalar(fTextScaleX); 2041 buffer.writeScalar(fTextSkewX); 2042 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 2043 buffer.writeScalar(fHintingScaleFactor); 2044 #else 2045 // Dummy value. 2046 buffer.writeScalar(SK_Scalar1); 2047 #endif 2048 buffer.writeScalar(fWidth); 2049 buffer.writeScalar(fMiterLimit); 2050 buffer.writeColor(fColor); 2051 buffer.writeUInt(fFlags); 2052 buffer.writeUInt(fHinting); 2053 buffer.writeUInt(fTextAlign); 2054 buffer.writeUInt(flatFlags); 2055 2056 buffer.writeUInt(fCapType); 2057 buffer.writeUInt(fJoinType); 2058 buffer.writeUInt(fStyle); 2059 buffer.writeUInt(fTextEncoding); 2060 } 2061 2062 // now we're done with ptr and the (pre)reserved space. If we need to write 2063 // additional fields, use the buffer directly 2064 if (flatFlags & kHasTypeface_FlatFlag) { 2065 buffer.writeTypeface(this->getTypeface()); 2066 } 2067 if (flatFlags & kHasEffects_FlatFlag) { 2068 buffer.writeFlattenable(this->getPathEffect()); 2069 buffer.writeFlattenable(this->getShader()); 2070 buffer.writeFlattenable(this->getXfermode()); 2071 buffer.writeFlattenable(this->getMaskFilter()); 2072 buffer.writeFlattenable(this->getColorFilter()); 2073 buffer.writeFlattenable(this->getRasterizer()); 2074 buffer.writeFlattenable(this->getLooper()); 2075 buffer.writeFlattenable(this->getImageFilter()); 2076 buffer.writeFlattenable(this->getAnnotation()); 2077 } 2078 } 2079 2080 void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) { 2081 fPrivFlags = 0; 2082 2083 uint8_t flatFlags = 0; 2084 if (buffer.isOrderedBinaryBuffer()) { 2085 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); 2086 const void* podData = buffer.getOrderedBinaryBuffer()->skip(kPODPaintSize); 2087 const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData); 2088 2089 // the order we read must match the order we wrote in flatten() 2090 this->setTextSize(read_scalar(pod)); 2091 this->setTextScaleX(read_scalar(pod)); 2092 this->setTextSkewX(read_scalar(pod)); 2093 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 2094 this->setHintingScaleFactor(read_scalar(pod)); 2095 #else 2096 // Skip the hinting scalar factor, which is not supported. 2097 read_scalar(pod); 2098 #endif 2099 this->setStrokeWidth(read_scalar(pod)); 2100 this->setStrokeMiter(read_scalar(pod)); 2101 this->setColor(*pod++); 2102 2103 // previously flags:16, textAlign:8, flatFlags:8 2104 // now flags:16, hinting:4, textAlign:4, flatFlags:8 2105 uint32_t tmp = *pod++; 2106 this->setFlags(tmp >> 16); 2107 2108 // hinting added later. 0 in this nibble means use the default. 2109 uint32_t hinting = (tmp >> 12) & 0xF; 2110 this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1)); 2111 2112 this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF)); 2113 2114 flatFlags = tmp & 0xFF; 2115 2116 tmp = *pod++; 2117 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF)); 2118 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF)); 2119 this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF)); 2120 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF)); 2121 } else { 2122 this->setTextSize(buffer.readScalar()); 2123 this->setTextScaleX(buffer.readScalar()); 2124 this->setTextSkewX(buffer.readScalar()); 2125 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR 2126 this->setHintingScaleFactor(buffer.readScalar()); 2127 #else 2128 // Skip the hinting scalar factor, which is not supported. 2129 buffer.readScalar(); 2130 #endif 2131 this->setStrokeWidth(buffer.readScalar()); 2132 this->setStrokeMiter(buffer.readScalar()); 2133 this->setColor(buffer.readColor()); 2134 this->setFlags(buffer.readUInt()); 2135 this->setHinting(static_cast<SkPaint::Hinting>(buffer.readUInt())); 2136 this->setTextAlign(static_cast<SkPaint::Align>(buffer.readUInt())); 2137 flatFlags = buffer.readUInt(); 2138 2139 this->setStrokeCap(static_cast<SkPaint::Cap>(buffer.readUInt())); 2140 this->setStrokeJoin(static_cast<SkPaint::Join>(buffer.readUInt())); 2141 this->setStyle(static_cast<SkPaint::Style>(buffer.readUInt())); 2142 this->setTextEncoding(static_cast<SkPaint::TextEncoding>(buffer.readUInt())); 2143 } 2144 2145 if (flatFlags & kHasTypeface_FlatFlag) { 2146 this->setTypeface(buffer.readTypeface()); 2147 } else { 2148 this->setTypeface(NULL); 2149 } 2150 2151 if (flatFlags & kHasEffects_FlatFlag) { 2152 SkSafeUnref(this->setPathEffect(buffer.readFlattenableT<SkPathEffect>())); 2153 SkSafeUnref(this->setShader(buffer.readFlattenableT<SkShader>())); 2154 SkSafeUnref(this->setXfermode(buffer.readFlattenableT<SkXfermode>())); 2155 SkSafeUnref(this->setMaskFilter(buffer.readFlattenableT<SkMaskFilter>())); 2156 SkSafeUnref(this->setColorFilter(buffer.readFlattenableT<SkColorFilter>())); 2157 SkSafeUnref(this->setRasterizer(buffer.readFlattenableT<SkRasterizer>())); 2158 SkSafeUnref(this->setLooper(buffer.readFlattenableT<SkDrawLooper>())); 2159 SkSafeUnref(this->setImageFilter(buffer.readFlattenableT<SkImageFilter>())); 2160 SkSafeUnref(this->setAnnotation(buffer.readFlattenableT<SkAnnotation>())); 2161 } else { 2162 this->setPathEffect(NULL); 2163 this->setShader(NULL); 2164 this->setXfermode(NULL); 2165 this->setMaskFilter(NULL); 2166 this->setColorFilter(NULL); 2167 this->setRasterizer(NULL); 2168 this->setLooper(NULL); 2169 this->setImageFilter(NULL); 2170 } 2171 } 2172 2173 /////////////////////////////////////////////////////////////////////////////// 2174 2175 SkShader* SkPaint::setShader(SkShader* shader) { 2176 GEN_ID_INC_EVAL(shader != fShader); 2177 SkRefCnt_SafeAssign(fShader, shader); 2178 return shader; 2179 } 2180 2181 SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) { 2182 GEN_ID_INC_EVAL(filter != fColorFilter); 2183 SkRefCnt_SafeAssign(fColorFilter, filter); 2184 return filter; 2185 } 2186 2187 SkXfermode* SkPaint::setXfermode(SkXfermode* mode) { 2188 GEN_ID_INC_EVAL(mode != fXfermode); 2189 SkRefCnt_SafeAssign(fXfermode, mode); 2190 return mode; 2191 } 2192 2193 SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) { 2194 SkSafeUnref(fXfermode); 2195 fXfermode = SkXfermode::Create(mode); 2196 GEN_ID_INC; 2197 return fXfermode; 2198 } 2199 2200 SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) { 2201 GEN_ID_INC_EVAL(effect != fPathEffect); 2202 SkRefCnt_SafeAssign(fPathEffect, effect); 2203 return effect; 2204 } 2205 2206 SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) { 2207 GEN_ID_INC_EVAL(filter != fMaskFilter); 2208 SkRefCnt_SafeAssign(fMaskFilter, filter); 2209 return filter; 2210 } 2211 2212 /////////////////////////////////////////////////////////////////////////////// 2213 2214 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, 2215 const SkRect* cullRect) const { 2216 SkStrokeRec rec(*this); 2217 2218 const SkPath* srcPtr = &src; 2219 SkPath tmpPath; 2220 2221 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) { 2222 srcPtr = &tmpPath; 2223 } 2224 2225 if (!rec.applyToPath(dst, *srcPtr)) { 2226 if (srcPtr == &tmpPath) { 2227 // If path's were copy-on-write, this trick would not be needed. 2228 // As it is, we want to save making a deep-copy from tmpPath -> dst 2229 // since we know we're just going to delete tmpPath when we return, 2230 // so the swap saves that copy. 2231 dst->swap(tmpPath); 2232 } else { 2233 *dst = *srcPtr; 2234 } 2235 } 2236 return !rec.isHairlineStyle(); 2237 } 2238 2239 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, 2240 SkRect* storage, 2241 Style style) const { 2242 SkASSERT(storage); 2243 2244 const SkRect* src = &origSrc; 2245 2246 if (this->getLooper()) { 2247 SkASSERT(this->getLooper()->canComputeFastBounds(*this)); 2248 this->getLooper()->computeFastBounds(*this, *src, storage); 2249 return *storage; 2250 } 2251 2252 SkRect tmpSrc; 2253 if (this->getPathEffect()) { 2254 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc); 2255 src = &tmpSrc; 2256 } 2257 2258 if (kFill_Style != style) { 2259 // since we're stroked, outset the rect by the radius (and join type) 2260 SkScalar radius = SkScalarHalf(this->getStrokeWidth()); 2261 if (0 == radius) { // hairline 2262 radius = SK_Scalar1; 2263 } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) { 2264 SkScalar scale = this->getStrokeMiter(); 2265 if (scale > SK_Scalar1) { 2266 radius = SkScalarMul(radius, scale); 2267 } 2268 } 2269 storage->set(src->fLeft - radius, src->fTop - radius, 2270 src->fRight + radius, src->fBottom + radius); 2271 } else { 2272 *storage = *src; 2273 } 2274 2275 if (this->getMaskFilter()) { 2276 this->getMaskFilter()->computeFastBounds(*storage, storage); 2277 } 2278 2279 return *storage; 2280 } 2281 2282 /////////////////////////////////////////////////////////////////////////////// 2283 2284 static bool has_thick_frame(const SkPaint& paint) { 2285 return paint.getStrokeWidth() > 0 && 2286 paint.getStyle() != SkPaint::kFill_Style; 2287 } 2288 2289 SkTextToPathIter::SkTextToPathIter( const char text[], size_t length, 2290 const SkPaint& paint, 2291 bool applyStrokeAndPathEffects) 2292 : fPaint(paint) { 2293 fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection, 2294 true); 2295 2296 fPaint.setLinearText(true); 2297 fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup 2298 2299 if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) { 2300 applyStrokeAndPathEffects = false; 2301 } 2302 2303 // can't use our canonical size if we need to apply patheffects 2304 if (fPaint.getPathEffect() == NULL) { 2305 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)); 2306 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; 2307 if (has_thick_frame(fPaint)) { 2308 fPaint.setStrokeWidth(SkScalarDiv(fPaint.getStrokeWidth(), fScale)); 2309 } 2310 } else { 2311 fScale = SK_Scalar1; 2312 } 2313 2314 if (!applyStrokeAndPathEffects) { 2315 fPaint.setStyle(SkPaint::kFill_Style); 2316 fPaint.setPathEffect(NULL); 2317 } 2318 2319 fCache = fPaint.detachCache(NULL, NULL); 2320 2321 SkPaint::Style style = SkPaint::kFill_Style; 2322 SkPathEffect* pe = NULL; 2323 2324 if (!applyStrokeAndPathEffects) { 2325 style = paint.getStyle(); // restore 2326 pe = paint.getPathEffect(); // restore 2327 } 2328 fPaint.setStyle(style); 2329 fPaint.setPathEffect(pe); 2330 fPaint.setMaskFilter(paint.getMaskFilter()); // restore 2331 2332 // now compute fXOffset if needed 2333 2334 SkScalar xOffset = 0; 2335 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first 2336 int count; 2337 SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length, 2338 &count, NULL), fScale); 2339 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2340 width = SkScalarHalf(width); 2341 } 2342 xOffset = -width; 2343 } 2344 fXPos = xOffset; 2345 fPrevAdvance = 0; 2346 2347 fText = text; 2348 fStop = text + length; 2349 2350 fXYIndex = paint.isVerticalText() ? 1 : 0; 2351 } 2352 2353 SkTextToPathIter::~SkTextToPathIter() { 2354 SkGlyphCache::AttachCache(fCache); 2355 } 2356 2357 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { 2358 if (fText < fStop) { 2359 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); 2360 2361 fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale); 2362 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); 2363 2364 if (glyph.fWidth) { 2365 if (path) { 2366 *path = fCache->findPath(glyph); 2367 } 2368 } else { 2369 if (path) { 2370 *path = NULL; 2371 } 2372 } 2373 if (xpos) { 2374 *xpos = fXPos; 2375 } 2376 return true; 2377 } 2378 return false; 2379 } 2380 2381 /////////////////////////////////////////////////////////////////////////////// 2382 2383 bool SkPaint::nothingToDraw() const { 2384 if (fLooper) { 2385 return false; 2386 } 2387 SkXfermode::Mode mode; 2388 if (SkXfermode::AsMode(fXfermode, &mode)) { 2389 switch (mode) { 2390 case SkXfermode::kSrcOver_Mode: 2391 case SkXfermode::kSrcATop_Mode: 2392 case SkXfermode::kDstOut_Mode: 2393 case SkXfermode::kDstOver_Mode: 2394 case SkXfermode::kPlus_Mode: 2395 return 0 == this->getAlpha(); 2396 case SkXfermode::kDst_Mode: 2397 return true; 2398 default: 2399 break; 2400 } 2401 } 2402 return false; 2403 } 2404 2405 2406 //////////// Move these to their own file soon. 2407 2408 SK_DEFINE_INST_COUNT(SkDrawLooper) 2409 2410 bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) { 2411 SkCanvas canvas; 2412 2413 this->init(&canvas); 2414 for (;;) { 2415 SkPaint p(paint); 2416 if (this->next(&canvas, &p)) { 2417 p.setLooper(NULL); 2418 if (!p.canComputeFastBounds()) { 2419 return false; 2420 } 2421 } else { 2422 break; 2423 } 2424 } 2425 return true; 2426 } 2427 2428 void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src, 2429 SkRect* dst) { 2430 SkCanvas canvas; 2431 2432 this->init(&canvas); 2433 for (bool firstTime = true;; firstTime = false) { 2434 SkPaint p(paint); 2435 if (this->next(&canvas, &p)) { 2436 SkRect r(src); 2437 2438 p.setLooper(NULL); 2439 p.computeFastBounds(r, &r); 2440 canvas.getTotalMatrix().mapRect(&r); 2441 2442 if (firstTime) { 2443 *dst = r; 2444 } else { 2445 dst->join(r); 2446 } 2447 } else { 2448 break; 2449 } 2450 } 2451 } 2452