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 "SkGlyphCache.h" 9 #include "SkPaint.h" 10 #include "SkScalerContext.h" 11 12 #include "SkAutoMalloc.h" 13 #include "SkAutoPixmapStorage.h" 14 #include "SkColorData.h" 15 #include "SkDescriptor.h" 16 #include "SkDraw.h" 17 #include "SkGlyph.h" 18 #include "SkMakeUnique.h" 19 #include "SkMaskFilter.h" 20 #include "SkMaskGamma.h" 21 #include "SkMatrix22.h" 22 #include "SkPaintPriv.h" 23 #include "SkPathEffect.h" 24 #include "SkRasterClip.h" 25 #include "SkReadBuffer.h" 26 #include "SkStroke.h" 27 #include "SkStrokeRec.h" 28 #include "SkSurfacePriv.h" 29 #include "SkTextFormatParams.h" 30 #include "SkWriteBuffer.h" 31 32 void SkGlyph::toMask(SkMask* mask) const { 33 SkASSERT(mask); 34 35 mask->fImage = (uint8_t*)fImage; 36 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); 37 mask->fRowBytes = this->rowBytes(); 38 mask->fFormat = static_cast<SkMask::Format>(fMaskFormat); 39 } 40 41 size_t SkGlyph::computeImageSize() const { 42 const size_t size = this->rowBytes() * fHeight; 43 44 switch (fMaskFormat) { 45 case SkMask::k3D_Format: 46 return 3 * size; 47 default: 48 return size; 49 } 50 } 51 52 void SkGlyph::zeroMetrics() { 53 fAdvanceX = 0; 54 fAdvanceY = 0; 55 fWidth = 0; 56 fHeight = 0; 57 fTop = 0; 58 fLeft = 0; 59 fRsbDelta = 0; 60 fLsbDelta = 0; 61 } 62 63 /////////////////////////////////////////////////////////////////////////////// 64 65 #ifdef SK_DEBUG 66 #define DUMP_RECx 67 #endif 68 69 SkScalerContext::SkScalerContext(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, 70 const SkDescriptor* desc) 71 : fRec(*static_cast<const SkScalerContextRec*>(desc->findEntry(kRec_SkDescriptorTag, nullptr))) 72 73 , fTypeface(std::move(typeface)) 74 , fPathEffect(sk_ref_sp(effects.fPathEffect)) 75 , fMaskFilter(sk_ref_sp(effects.fMaskFilter)) 76 // Initialize based on our settings. Subclasses can also force this. 77 , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != nullptr) 78 79 , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec)) 80 , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec) 81 : SkMaskGamma::PreBlend()) 82 { 83 #ifdef DUMP_REC 84 SkDebugf("SkScalerContext checksum %x count %d length %d\n", 85 desc->getChecksum(), desc->getCount(), desc->getLength()); 86 SkDebugf("%s", fRec.dump().c_str()); 87 SkDebugf(" pathEffect %x maskFilter %x\n", 88 desc->findEntry(kPathEffect_SkDescriptorTag, nullptr), 89 desc->findEntry(kMaskFilter_SkDescriptorTag, nullptr)); 90 #endif 91 } 92 93 SkScalerContext::~SkScalerContext() {} 94 95 void SkScalerContext::getAdvance(SkGlyph* glyph) { 96 // mark us as just having a valid advance 97 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 98 // we mark the format before making the call, in case the impl 99 // internally ends up calling its generateMetrics, which is OK 100 // albeit slower than strictly necessary 101 generateAdvance(glyph); 102 } 103 104 void SkScalerContext::getMetrics(SkGlyph* glyph) { 105 generateMetrics(glyph); 106 107 // for now we have separate cache entries for devkerning on and off 108 // in the future we might share caches, but make our measure/draw 109 // code make the distinction. Thus we zap the values if the caller 110 // has not asked for them. 111 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 112 // no devkern, so zap the fields 113 glyph->fLsbDelta = glyph->fRsbDelta = 0; 114 } 115 116 // if either dimension is empty, zap the image bounds of the glyph 117 if (0 == glyph->fWidth || 0 == glyph->fHeight) { 118 glyph->fWidth = 0; 119 glyph->fHeight = 0; 120 glyph->fTop = 0; 121 glyph->fLeft = 0; 122 glyph->fMaskFormat = 0; 123 return; 124 } 125 126 bool generatingImageFromPath = fGenerateImageFromPath; 127 if (fGenerateImageFromPath) { 128 SkPath devPath, fillPath; 129 SkMatrix fillToDevMatrix; 130 131 this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix); 132 if (fillPath.isEmpty()) { 133 generatingImageFromPath = false; 134 } else { 135 // just use devPath 136 const SkIRect ir = devPath.getBounds().roundOut(); 137 138 if (ir.isEmpty() || !ir.is16Bit()) { 139 goto SK_ERROR; 140 } 141 glyph->fLeft = ir.fLeft; 142 glyph->fTop = ir.fTop; 143 glyph->fWidth = SkToU16(ir.width()); 144 glyph->fHeight = SkToU16(ir.height()); 145 146 if (glyph->fWidth > 0) { 147 switch (fRec.fMaskFormat) { 148 case SkMask::kLCD16_Format: 149 glyph->fWidth += 2; 150 glyph->fLeft -= 1; 151 break; 152 default: 153 break; 154 } 155 } 156 } 157 } 158 159 if (SkMask::kARGB32_Format != glyph->fMaskFormat) { 160 glyph->fMaskFormat = fRec.fMaskFormat; 161 } 162 163 // If we are going to create the mask, then we cannot keep the color 164 if ((generatingImageFromPath || fMaskFilter) && SkMask::kARGB32_Format == glyph->fMaskFormat) { 165 glyph->fMaskFormat = SkMask::kA8_Format; 166 } 167 168 if (fMaskFilter) { 169 SkMask src, dst; 170 SkMatrix matrix; 171 172 glyph->toMask(&src); 173 fRec.getMatrixFrom2x2(&matrix); 174 175 src.fImage = nullptr; // only want the bounds from the filter 176 if (as_MFB(fMaskFilter)->filterMask(&dst, src, matrix, nullptr)) { 177 if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) { 178 goto SK_ERROR; 179 } 180 SkASSERT(dst.fImage == nullptr); 181 glyph->fLeft = dst.fBounds.fLeft; 182 glyph->fTop = dst.fBounds.fTop; 183 glyph->fWidth = SkToU16(dst.fBounds.width()); 184 glyph->fHeight = SkToU16(dst.fBounds.height()); 185 glyph->fMaskFormat = dst.fFormat; 186 } 187 } 188 return; 189 190 SK_ERROR: 191 // draw nothing 'cause we failed 192 glyph->fLeft = 0; 193 glyph->fTop = 0; 194 glyph->fWidth = 0; 195 glyph->fHeight = 0; 196 // put a valid value here, in case it was earlier set to 197 // MASK_FORMAT_JUST_ADVANCE 198 glyph->fMaskFormat = fRec.fMaskFormat; 199 } 200 201 #define SK_SHOW_TEXT_BLIT_COVERAGE 0 202 203 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { 204 uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; 205 unsigned rowBytes = mask.fRowBytes; 206 207 for (int y = mask.fBounds.height() - 1; y >= 0; --y) { 208 for (int x = mask.fBounds.width() - 1; x >= 0; --x) { 209 dst[x] = lut[dst[x]]; 210 } 211 dst += rowBytes; 212 } 213 } 214 215 template<bool APPLY_PREBLEND> 216 static void pack4xHToLCD16(const SkPixmap& src, const SkMask& dst, 217 const SkMaskGamma::PreBlend& maskPreBlend) { 218 #define SAMPLES_PER_PIXEL 4 219 #define LCD_PER_PIXEL 3 220 SkASSERT(kAlpha_8_SkColorType == src.colorType()); 221 SkASSERT(SkMask::kLCD16_Format == dst.fFormat); 222 223 const int sample_width = src.width(); 224 const int height = src.height(); 225 226 uint16_t* dstP = (uint16_t*)dst.fImage; 227 size_t dstRB = dst.fRowBytes; 228 // An N tap FIR is defined by 229 // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] 230 // or 231 // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) 232 233 // The strategy is to use one FIR (different coefficients) for each of r, g, and b. 234 // This means using every 4th FIR output value of each FIR and discarding the rest. 235 // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'. 236 // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.) 237 238 // These are in some fixed point repesentation. 239 // Adding up to more than one simulates ink spread. 240 // For implementation reasons, these should never add up to more than two. 241 242 // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast'). 243 // Calculated using tools/generate_fir_coeff.py 244 // With this one almost no fringing is ever seen, but it is imperceptibly blurry. 245 // The lcd smoothed text is almost imperceptibly different from gray, 246 // but is still sharper on small stems and small rounded corners than gray. 247 // This also seems to be about as wide as one can get and only have a three pixel kernel. 248 // TODO: caculate these at runtime so parameters can be adjusted (esp contrast). 249 static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = { 250 //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted. 251 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, }, 252 //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric 253 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, }, 254 //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted. 255 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, }, 256 }; 257 258 for (int y = 0; y < height; ++y) { 259 const uint8_t* srcP = src.addr8(0, y); 260 261 // TODO: this fir filter implementation is straight forward, but slow. 262 // It should be possible to make it much faster. 263 for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) { 264 int fir[LCD_PER_PIXEL] = { 0 }; 265 for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4) 266 ; sample_index < SkMin32(sample_x + 8, sample_width) 267 ; ++sample_index, ++coeff_index) 268 { 269 int sample_value = srcP[sample_index]; 270 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 271 fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value; 272 } 273 } 274 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 275 fir[subpxl_index] /= 0x100; 276 fir[subpxl_index] = SkMin32(fir[subpxl_index], 255); 277 } 278 279 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR); 280 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG); 281 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB); 282 #if SK_SHOW_TEXT_BLIT_COVERAGE 283 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); 284 #endif 285 dstP[pixel_x] = SkPack888ToRGB16(r, g, b); 286 } 287 dstP = (uint16_t*)((char*)dstP + dstRB); 288 } 289 } 290 291 static inline int convert_8_to_1(unsigned byte) { 292 SkASSERT(byte <= 0xFF); 293 return byte >> 7; 294 } 295 296 static uint8_t pack_8_to_1(const uint8_t alpha[8]) { 297 unsigned bits = 0; 298 for (int i = 0; i < 8; ++i) { 299 bits <<= 1; 300 bits |= convert_8_to_1(alpha[i]); 301 } 302 return SkToU8(bits); 303 } 304 305 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { 306 const int height = mask.fBounds.height(); 307 const int width = mask.fBounds.width(); 308 const int octs = width >> 3; 309 const int leftOverBits = width & 7; 310 311 uint8_t* dst = mask.fImage; 312 const int dstPad = mask.fRowBytes - SkAlign8(width)/8; 313 SkASSERT(dstPad >= 0); 314 315 SkASSERT(width >= 0); 316 SkASSERT(srcRB >= (size_t)width); 317 const size_t srcPad = srcRB - width; 318 319 for (int y = 0; y < height; ++y) { 320 for (int i = 0; i < octs; ++i) { 321 *dst++ = pack_8_to_1(src); 322 src += 8; 323 } 324 if (leftOverBits > 0) { 325 unsigned bits = 0; 326 int shift = 7; 327 for (int i = 0; i < leftOverBits; ++i, --shift) { 328 bits |= convert_8_to_1(*src++) << shift; 329 } 330 *dst++ = bits; 331 } 332 src += srcPad; 333 dst += dstPad; 334 } 335 } 336 337 static void generateMask(const SkMask& mask, const SkPath& path, 338 const SkMaskGamma::PreBlend& maskPreBlend) { 339 SkPaint paint; 340 341 int srcW = mask.fBounds.width(); 342 int srcH = mask.fBounds.height(); 343 int dstW = srcW; 344 int dstH = srcH; 345 int dstRB = mask.fRowBytes; 346 347 SkMatrix matrix; 348 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 349 -SkIntToScalar(mask.fBounds.fTop)); 350 351 paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat); 352 switch (mask.fFormat) { 353 case SkMask::kBW_Format: 354 dstRB = 0; // signals we need a copy 355 break; 356 case SkMask::kA8_Format: 357 break; 358 case SkMask::kLCD16_Format: 359 // TODO: trigger off LCD orientation 360 dstW = 4*dstW - 8; 361 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), 362 -SkIntToScalar(mask.fBounds.fTop)); 363 matrix.postScale(SkIntToScalar(4), SK_Scalar1); 364 dstRB = 0; // signals we need a copy 365 break; 366 default: 367 SkDEBUGFAIL("unexpected mask format"); 368 } 369 370 SkRasterClip clip; 371 clip.setRect(SkIRect::MakeWH(dstW, dstH)); 372 373 const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH); 374 SkAutoPixmapStorage dst; 375 376 if (0 == dstRB) { 377 if (!dst.tryAlloc(info)) { 378 // can't allocate offscreen, so empty the mask and return 379 sk_bzero(mask.fImage, mask.computeImageSize()); 380 return; 381 } 382 } else { 383 dst.reset(info, mask.fImage, dstRB); 384 } 385 sk_bzero(dst.writable_addr(), dst.computeByteSize()); 386 387 SkDraw draw; 388 draw.fDst = dst; 389 draw.fRC = &clip; 390 draw.fMatrix = &matrix; 391 draw.drawPath(path, paint); 392 393 switch (mask.fFormat) { 394 case SkMask::kBW_Format: 395 packA8ToA1(mask, dst.addr8(0, 0), dst.rowBytes()); 396 break; 397 case SkMask::kA8_Format: 398 if (maskPreBlend.isApplicable()) { 399 applyLUTToA8Mask(mask, maskPreBlend.fG); 400 } 401 break; 402 case SkMask::kLCD16_Format: 403 if (maskPreBlend.isApplicable()) { 404 pack4xHToLCD16<true>(dst, mask, maskPreBlend); 405 } else { 406 pack4xHToLCD16<false>(dst, mask, maskPreBlend); 407 } 408 break; 409 default: 410 break; 411 } 412 } 413 414 static void extract_alpha(const SkMask& dst, 415 const SkPMColor* srcRow, size_t srcRB) { 416 int width = dst.fBounds.width(); 417 int height = dst.fBounds.height(); 418 int dstRB = dst.fRowBytes; 419 uint8_t* dstRow = dst.fImage; 420 421 for (int y = 0; y < height; ++y) { 422 for (int x = 0; x < width; ++x) { 423 dstRow[x] = SkGetPackedA32(srcRow[x]); 424 } 425 // zero any padding on each row 426 for (int x = width; x < dstRB; ++x) { 427 dstRow[x] = 0; 428 } 429 dstRow += dstRB; 430 srcRow = (const SkPMColor*)((const char*)srcRow + srcRB); 431 } 432 } 433 434 void SkScalerContext::getImage(const SkGlyph& origGlyph) { 435 const SkGlyph* glyph = &origGlyph; 436 SkGlyph tmpGlyph; 437 438 // in case we need to call generateImage on a mask-format that is different 439 // (i.e. larger) than what our caller allocated by looking at origGlyph. 440 SkAutoMalloc tmpGlyphImageStorage; 441 442 if (fMaskFilter) { // restore the prefilter bounds 443 tmpGlyph.initWithGlyphID(origGlyph.getPackedID()); 444 445 // need the original bounds, sans our maskfilter 446 SkMaskFilter* mf = fMaskFilter.release(); // temp disable 447 this->getMetrics(&tmpGlyph); 448 fMaskFilter = sk_sp<SkMaskFilter>(mf); // restore 449 450 // we need the prefilter bounds to be <= filter bounds 451 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 452 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 453 454 if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) { 455 tmpGlyph.fImage = origGlyph.fImage; 456 } else { 457 tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize()); 458 tmpGlyph.fImage = tmpGlyphImageStorage.get(); 459 } 460 glyph = &tmpGlyph; 461 } 462 463 if (fGenerateImageFromPath) { 464 SkPath devPath, fillPath; 465 SkMatrix fillToDevMatrix; 466 SkMask mask; 467 468 this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix); 469 glyph->toMask(&mask); 470 471 if (fillPath.isEmpty()) { 472 generateImage(*glyph); 473 } else { 474 SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat); 475 SkASSERT(SkMask::kARGB32_Format != mask.fFormat); 476 generateMask(mask, devPath, fPreBlend); 477 } 478 } else { 479 generateImage(*glyph); 480 } 481 482 if (fMaskFilter) { 483 SkMask srcM, dstM; 484 SkMatrix matrix; 485 486 // the src glyph image shouldn't be 3D 487 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 488 489 SkAutoSMalloc<32*32> a8storage; 490 glyph->toMask(&srcM); 491 if (SkMask::kARGB32_Format == srcM.fFormat) { 492 // now we need to extract the alpha-channel from the glyph's image 493 // and copy it into a temp buffer, and then point srcM at that temp. 494 srcM.fFormat = SkMask::kA8_Format; 495 srcM.fRowBytes = SkAlign4(srcM.fBounds.width()); 496 size_t size = srcM.computeImageSize(); 497 a8storage.reset(size); 498 srcM.fImage = (uint8_t*)a8storage.get(); 499 extract_alpha(srcM, 500 (const SkPMColor*)glyph->fImage, glyph->rowBytes()); 501 } 502 503 fRec.getMatrixFrom2x2(&matrix); 504 505 if (as_MFB(fMaskFilter)->filterMask(&dstM, srcM, matrix, nullptr)) { 506 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 507 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 508 int dstRB = origGlyph.rowBytes(); 509 int srcRB = dstM.fRowBytes; 510 511 const uint8_t* src = (const uint8_t*)dstM.fImage; 512 uint8_t* dst = (uint8_t*)origGlyph.fImage; 513 514 if (SkMask::k3D_Format == dstM.fFormat) { 515 // we have to copy 3 times as much 516 height *= 3; 517 } 518 519 // clean out our glyph, since it may be larger than dstM 520 //sk_bzero(dst, height * dstRB); 521 522 while (--height >= 0) { 523 memcpy(dst, src, width); 524 src += srcRB; 525 dst += dstRB; 526 } 527 SkMask::FreeImage(dstM.fImage); 528 529 if (fPreBlendForFilter.isApplicable()) { 530 applyLUTToA8Mask(srcM, fPreBlendForFilter.fG); 531 } 532 } 533 } 534 } 535 536 void SkScalerContext::getPath(SkPackedGlyphID glyphID, SkPath* path) { 537 this->internalGetPath(glyphID, nullptr, path, nullptr); 538 } 539 540 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) { 541 SkASSERT(fm); 542 this->generateFontMetrics(fm); 543 } 544 545 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { 546 return 0; 547 } 548 549 /////////////////////////////////////////////////////////////////////////////// 550 551 void SkScalerContext::internalGetPath(SkPackedGlyphID glyphID, SkPath* fillPath, 552 SkPath* devPath, SkMatrix* fillToDevMatrix) { 553 SkPath path; 554 generatePath(glyphID.code(), &path); 555 556 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 557 SkFixed dx = glyphID.getSubXFixed(); 558 SkFixed dy = glyphID.getSubYFixed(); 559 if (dx | dy) { 560 path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); 561 } 562 } 563 564 if (fRec.fFrameWidth > 0 || fPathEffect != nullptr) { 565 // need the path in user-space, with only the point-size applied 566 // so that our stroking and effects will operate the same way they 567 // would if the user had extracted the path themself, and then 568 // called drawPath 569 SkPath localPath; 570 SkMatrix matrix, inverse; 571 572 fRec.getMatrixFrom2x2(&matrix); 573 if (!matrix.invert(&inverse)) { 574 // assume fillPath and devPath are already empty. 575 return; 576 } 577 path.transform(inverse, &localPath); 578 // now localPath is only affected by the paint settings, and not the canvas matrix 579 580 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); 581 582 if (fRec.fFrameWidth > 0) { 583 rec.setStrokeStyle(fRec.fFrameWidth, 584 SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 585 // glyphs are always closed contours, so cap type is ignored, 586 // so we just pass something. 587 rec.setStrokeParams((SkPaint::Cap)fRec.fStrokeCap, 588 (SkPaint::Join)fRec.fStrokeJoin, 589 fRec.fMiterLimit); 590 } 591 592 if (fPathEffect) { 593 SkPath effectPath; 594 if (fPathEffect->filterPath(&effectPath, localPath, &rec, nullptr)) { 595 localPath.swap(effectPath); 596 } 597 } 598 599 if (rec.needToApply()) { 600 SkPath strokePath; 601 if (rec.applyToPath(&strokePath, localPath)) { 602 localPath.swap(strokePath); 603 } 604 } 605 606 // now return stuff to the caller 607 if (fillToDevMatrix) { 608 *fillToDevMatrix = matrix; 609 } 610 if (devPath) { 611 localPath.transform(matrix, devPath); 612 } 613 if (fillPath) { 614 fillPath->swap(localPath); 615 } 616 } else { // nothing tricky to do 617 if (fillToDevMatrix) { 618 fillToDevMatrix->reset(); 619 } 620 if (devPath) { 621 if (fillPath == nullptr) { 622 devPath->swap(path); 623 } else { 624 *devPath = path; 625 } 626 } 627 628 if (fillPath) { 629 fillPath->swap(path); 630 } 631 } 632 633 if (devPath) { 634 devPath->updateBoundsCache(); 635 } 636 if (fillPath) { 637 fillPath->updateBoundsCache(); 638 } 639 } 640 641 642 void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const { 643 dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0, 644 fPost2x2[1][0], fPost2x2[1][1], 0, 645 0, 0, 1); 646 } 647 648 void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const { 649 SkPaintPriv::MakeTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX); 650 } 651 652 void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const { 653 this->getLocalMatrix(m); 654 655 // now concat the device matrix 656 SkMatrix deviceMatrix; 657 this->getMatrixFrom2x2(&deviceMatrix); 658 m->postConcat(deviceMatrix); 659 } 660 661 bool SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector* s, SkMatrix* sA, 662 SkMatrix* GsA, SkMatrix* G_inv, SkMatrix* A_out) 663 { 664 // A is the 'total' matrix. 665 SkMatrix A; 666 this->getSingleMatrix(&A); 667 668 // The caller may find the 'total' matrix useful when dealing directly with EM sizes. 669 if (A_out) { 670 *A_out = A; 671 } 672 673 // GA is the matrix A with rotation removed. 674 SkMatrix GA; 675 bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0; 676 if (skewedOrFlipped) { 677 // QR by Givens rotations. G is Q^T and GA is R. G is rotational (no reflections). 678 // h is where A maps the horizontal baseline. 679 SkPoint h = SkPoint::Make(SK_Scalar1, 0); 680 A.mapPoints(&h, 1); 681 682 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0). 683 SkMatrix G; 684 SkComputeGivensRotation(h, &G); 685 686 GA = G; 687 GA.preConcat(A); 688 689 // The 'remainingRotation' is G inverse, which is fairly simple since G is 2x2 rotational. 690 if (G_inv) { 691 G_inv->setAll( 692 G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), 693 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), 694 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); 695 } 696 } else { 697 GA = A; 698 if (G_inv) { 699 G_inv->reset(); 700 } 701 } 702 703 // If the 'total' matrix is singular, set the 'scale' to something finite and zero the matrices. 704 // All underlying ports have issues with zero text size, so use the matricies to zero. 705 // If one of the scale factors is less than 1/256 then an EM filling square will 706 // never affect any pixels. 707 if (SkScalarAbs(GA.get(SkMatrix::kMScaleX)) <= SK_ScalarNearlyZero || 708 SkScalarAbs(GA.get(SkMatrix::kMScaleY)) <= SK_ScalarNearlyZero) 709 { 710 s->fX = SK_Scalar1; 711 s->fY = SK_Scalar1; 712 sA->setScale(0, 0); 713 if (GsA) { 714 GsA->setScale(0, 0); 715 } 716 if (G_inv) { 717 G_inv->reset(); 718 } 719 return false; 720 } 721 722 // At this point, given GA, create s. 723 switch (preMatrixScale) { 724 case kFull_PreMatrixScale: 725 s->fX = SkScalarAbs(GA.get(SkMatrix::kMScaleX)); 726 s->fY = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 727 break; 728 case kVertical_PreMatrixScale: { 729 SkScalar yScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 730 s->fX = yScale; 731 s->fY = yScale; 732 break; 733 } 734 case kVerticalInteger_PreMatrixScale: { 735 SkScalar realYScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 736 SkScalar intYScale = SkScalarRoundToScalar(realYScale); 737 if (intYScale == 0) { 738 intYScale = SK_Scalar1; 739 } 740 s->fX = intYScale; 741 s->fY = intYScale; 742 break; 743 } 744 } 745 746 // The 'remaining' matrix sA is the total matrix A without the scale. 747 if (!skewedOrFlipped && ( 748 (kFull_PreMatrixScale == preMatrixScale) || 749 (kVertical_PreMatrixScale == preMatrixScale && A.getScaleX() == A.getScaleY()))) 750 { 751 // If GA == A and kFull_PreMatrixScale, sA is identity. 752 // If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity. 753 sA->reset(); 754 } else if (!skewedOrFlipped && kVertical_PreMatrixScale == preMatrixScale) { 755 // If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1. 756 sA->reset(); 757 sA->setScaleX(A.getScaleX() / s->fY); 758 } else { 759 // TODO: like kVertical_PreMatrixScale, kVerticalInteger_PreMatrixScale with int scales. 760 *sA = A; 761 sA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); 762 } 763 764 // The 'remainingWithoutRotation' matrix GsA is the non-rotational part of A without the scale. 765 if (GsA) { 766 *GsA = GA; 767 // G is rotational so reorders with the scale. 768 GsA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); 769 } 770 771 return true; 772 } 773 774 SkAxisAlignment SkScalerContext::computeAxisAlignmentForHText() { 775 // Why fPost2x2 can be used here. 776 // getSingleMatrix multiplies in getLocalMatrix, which consists of 777 // * fTextSize (a scale, which has no effect) 778 // * fPreScaleX (a scale in x, which has no effect) 779 // * fPreSkewX (has no effect, but would on vertical text alignment). 780 // In other words, making the text bigger, stretching it along the 781 // horizontal axis, or fake italicizing it does not move the baseline. 782 783 if (0 == fRec.fPost2x2[1][0]) { 784 // The x axis is mapped onto the x axis. 785 return kX_SkAxisAlignment; 786 } 787 if (0 == fRec.fPost2x2[0][0]) { 788 // The x axis is mapped onto the y axis. 789 return kY_SkAxisAlignment; 790 } 791 return kNone_SkAxisAlignment; 792 } 793 794 /////////////////////////////////////////////////////////////////////////////// 795 796 class SkScalerContext_Empty : public SkScalerContext { 797 public: 798 SkScalerContext_Empty(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, 799 const SkDescriptor* desc) 800 : SkScalerContext(std::move(typeface), effects, desc) {} 801 802 protected: 803 unsigned generateGlyphCount() override { 804 return 0; 805 } 806 uint16_t generateCharToGlyph(SkUnichar uni) override { 807 return 0; 808 } 809 void generateAdvance(SkGlyph* glyph) override { 810 glyph->zeroMetrics(); 811 } 812 void generateMetrics(SkGlyph* glyph) override { 813 glyph->zeroMetrics(); 814 } 815 void generateImage(const SkGlyph& glyph) override {} 816 void generatePath(SkGlyphID glyph, SkPath* path) override {} 817 void generateFontMetrics(SkPaint::FontMetrics* metrics) override { 818 if (metrics) { 819 sk_bzero(metrics, sizeof(*metrics)); 820 } 821 } 822 }; 823 824 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); 825 826 std::unique_ptr<SkScalerContext> SkTypeface::createScalerContext( 827 const SkScalerContextEffects& effects, const SkDescriptor* desc, bool allowFailure) const 828 { 829 std::unique_ptr<SkScalerContext> c(this->onCreateScalerContext(effects, desc)); 830 if (!c && !allowFailure) { 831 c = skstd::make_unique<SkScalerContext_Empty>(sk_ref_sp(const_cast<SkTypeface*>(this)), 832 effects, desc); 833 } 834 return c; 835 } 836 837 /* 838 * Return the scalar with only limited fractional precision. Used to consolidate matrices 839 * that vary only slightly when we create our key into the font cache, since the font scaler 840 * typically returns the same looking resuts for tiny changes in the matrix. 841 */ 842 static SkScalar sk_relax(SkScalar x) { 843 SkScalar n = SkScalarRoundToScalar(x * 1024); 844 return n / 1024.0f; 845 } 846 847 static SkMask::Format compute_mask_format(const SkPaint& paint) { 848 uint32_t flags = paint.getFlags(); 849 850 // Antialiasing being disabled trumps all other settings. 851 if (!(flags & SkPaint::kAntiAlias_Flag)) { 852 return SkMask::kBW_Format; 853 } 854 855 if (flags & SkPaint::kLCDRenderText_Flag) { 856 return SkMask::kLCD16_Format; 857 } 858 859 return SkMask::kA8_Format; 860 } 861 862 // Beyond this size, LCD doesn't appreciably improve quality, but it always 863 // cost more RAM and draws slower, so we set a cap. 864 #ifndef SK_MAX_SIZE_FOR_LCDTEXT 865 #define SK_MAX_SIZE_FOR_LCDTEXT 48 866 #endif 867 868 const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT; 869 870 static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) { 871 if (checkPost2x2) { 872 SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] - 873 rec.fPost2x2[1][0] * rec.fPost2x2[0][1]; 874 area *= rec.fTextSize * rec.fTextSize; 875 return area > gMaxSize2ForLCDText; 876 } else { 877 return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT; 878 } 879 } 880 881 // if linear-text is on, then we force hinting to be off (since that's sort of 882 // the point of linear-text. 883 static SkPaint::Hinting computeHinting(const SkPaint& paint) { 884 SkPaint::Hinting h = paint.getHinting(); 885 if (paint.isLinearText()) { 886 h = SkPaint::kNo_Hinting; 887 } 888 return h; 889 } 890 891 // The only reason this is not file static is because it needs the context of SkScalerContext to 892 // access SkPaint::computeLuminanceColor. 893 void SkScalerContext::MakeRecAndEffects(const SkPaint& paint, 894 const SkSurfaceProps* surfaceProps, 895 const SkMatrix* deviceMatrix, 896 SkScalerContextFlags scalerContextFlags, 897 SkScalerContextRec* rec, 898 SkScalerContextEffects* effects) { 899 SkASSERT(deviceMatrix == nullptr || !deviceMatrix->hasPerspective()); 900 901 SkTypeface* typeface = paint.getTypeface(); 902 if (nullptr == typeface) { 903 typeface = SkTypeface::GetDefaultTypeface(); 904 } 905 rec->fFontID = typeface->uniqueID(); 906 rec->fTextSize = paint.getTextSize(); 907 rec->fPreScaleX = paint.getTextScaleX(); 908 rec->fPreSkewX = paint.getTextSkewX(); 909 910 bool checkPost2x2 = false; 911 912 if (deviceMatrix) { 913 const SkMatrix::TypeMask mask = deviceMatrix->getType(); 914 if (mask & SkMatrix::kScale_Mask) { 915 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX()); 916 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY()); 917 checkPost2x2 = true; 918 } else { 919 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; 920 } 921 if (mask & SkMatrix::kAffine_Mask) { 922 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX()); 923 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY()); 924 checkPost2x2 = true; 925 } else { 926 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; 927 } 928 } else { 929 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; 930 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; 931 } 932 933 SkPaint::Style style = paint.getStyle(); 934 SkScalar strokeWidth = paint.getStrokeWidth(); 935 936 unsigned flags = 0; 937 938 if (paint.isFakeBoldText()) { 939 #ifdef SK_USE_FREETYPE_EMBOLDEN 940 flags |= SkScalerContext::kEmbolden_Flag; 941 #else 942 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), 943 kStdFakeBoldInterpKeys, 944 kStdFakeBoldInterpValues, 945 kStdFakeBoldInterpLength); 946 SkScalar extra = paint.getTextSize() * fakeBoldScale; 947 948 if (style == SkPaint::kFill_Style) { 949 style = SkPaint::kStrokeAndFill_Style; 950 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" 951 } else { 952 strokeWidth += extra; 953 } 954 #endif 955 } 956 957 if (paint.isDevKernText()) { 958 flags |= SkScalerContext::kDevKernText_Flag; 959 } 960 961 if (style != SkPaint::kFill_Style && strokeWidth > 0) { 962 rec->fFrameWidth = strokeWidth; 963 rec->fMiterLimit = paint.getStrokeMiter(); 964 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); 965 rec->fStrokeCap = SkToU8(paint.getStrokeCap()); 966 967 if (style == SkPaint::kStrokeAndFill_Style) { 968 flags |= SkScalerContext::kFrameAndFill_Flag; 969 } 970 } else { 971 rec->fFrameWidth = 0; 972 rec->fMiterLimit = 0; 973 rec->fStrokeJoin = 0; 974 rec->fStrokeCap = 0; 975 } 976 977 rec->fMaskFormat = SkToU8(compute_mask_format(paint)); 978 979 if (SkMask::kLCD16_Format == rec->fMaskFormat) { 980 if (too_big_for_lcd(*rec, checkPost2x2)) { 981 rec->fMaskFormat = SkMask::kA8_Format; 982 flags |= SkScalerContext::kGenA8FromLCD_Flag; 983 } else { 984 SkPixelGeometry geometry = surfaceProps 985 ? surfaceProps->pixelGeometry() 986 : SkSurfacePropsDefaultPixelGeometry(); 987 switch (geometry) { 988 case kUnknown_SkPixelGeometry: 989 // eeek, can't support LCD 990 rec->fMaskFormat = SkMask::kA8_Format; 991 flags |= SkScalerContext::kGenA8FromLCD_Flag; 992 break; 993 case kRGB_H_SkPixelGeometry: 994 // our default, do nothing. 995 break; 996 case kBGR_H_SkPixelGeometry: 997 flags |= SkScalerContext::kLCD_BGROrder_Flag; 998 break; 999 case kRGB_V_SkPixelGeometry: 1000 flags |= SkScalerContext::kLCD_Vertical_Flag; 1001 break; 1002 case kBGR_V_SkPixelGeometry: 1003 flags |= SkScalerContext::kLCD_Vertical_Flag; 1004 flags |= SkScalerContext::kLCD_BGROrder_Flag; 1005 break; 1006 } 1007 } 1008 } 1009 1010 if (paint.isEmbeddedBitmapText()) { 1011 flags |= SkScalerContext::kEmbeddedBitmapText_Flag; 1012 } 1013 if (paint.isSubpixelText()) { 1014 flags |= SkScalerContext::kSubpixelPositioning_Flag; 1015 } 1016 if (paint.isAutohinted()) { 1017 flags |= SkScalerContext::kForceAutohinting_Flag; 1018 } 1019 if (paint.isVerticalText()) { 1020 flags |= SkScalerContext::kVertical_Flag; 1021 } 1022 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { 1023 flags |= SkScalerContext::kGenA8FromLCD_Flag; 1024 } 1025 rec->fFlags = SkToU16(flags); 1026 1027 // these modify fFlags, so do them after assigning fFlags 1028 rec->setHinting(computeHinting(paint)); 1029 1030 rec->setLuminanceColor(paint.computeLuminanceColor()); 1031 1032 // For now always set the paint gamma equal to the device gamma. 1033 // The math in SkMaskGamma can handle them being different, 1034 // but it requires superluminous masks when 1035 // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. 1036 rec->setDeviceGamma(SK_GAMMA_EXPONENT); 1037 rec->setPaintGamma(SK_GAMMA_EXPONENT); 1038 1039 #ifdef SK_GAMMA_CONTRAST 1040 rec->setContrast(SK_GAMMA_CONTRAST); 1041 #else 1042 // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. 1043 // With lower values small text appears washed out (though correctly so). 1044 // With higher values lcd fringing is worse and the smoothing effect of 1045 // partial coverage is diminished. 1046 rec->setContrast(0.5f); 1047 #endif 1048 1049 // Allow the fonthost to modify our rec before we use it as a key into the 1050 // cache. This way if we're asking for something that they will ignore, 1051 // they can modify our rec up front, so we don't create duplicate cache 1052 // entries. 1053 typeface->onFilterRec(rec); 1054 1055 if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) { 1056 rec->ignoreGamma(); 1057 } 1058 if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) { 1059 rec->setContrast(0); 1060 } 1061 1062 new (effects) SkScalerContextEffects{paint}; 1063 if (effects->fPathEffect) { 1064 rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion 1065 // seems like we could support kLCD as well at this point... 1066 } 1067 if (effects->fMaskFilter) { 1068 // force antialiasing with maskfilters 1069 rec->fMaskFormat = SkMask::kA8_Format; 1070 // Pre-blend is not currently applied to filtered text. 1071 // The primary filter is blur, for which contrast makes no sense, 1072 // and for which the destination guess error is more visible. 1073 // Also, all existing users of blur have calibrated for linear. 1074 rec->ignorePreBlend(); 1075 } 1076 1077 // If we're asking for A8, we force the colorlum to be gray, since that 1078 // limits the number of unique entries, and the scaler will only look at 1079 // the lum of one of them. 1080 switch (rec->fMaskFormat) { 1081 case SkMask::kLCD16_Format: { 1082 // filter down the luminance color to a finite number of bits 1083 SkColor color = rec->getLuminanceColor(); 1084 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); 1085 break; 1086 } 1087 case SkMask::kA8_Format: { 1088 // filter down the luminance to a single component, since A8 can't 1089 // use per-component information 1090 SkColor color = rec->getLuminanceColor(); 1091 U8CPU lum = SkComputeLuminance(SkColorGetR(color), 1092 SkColorGetG(color), 1093 SkColorGetB(color)); 1094 // reduce to our finite number of bits 1095 color = SkColorSetRGB(lum, lum, lum); 1096 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); 1097 break; 1098 } 1099 case SkMask::kBW_Format: 1100 // No need to differentiate gamma or apply contrast if we're BW 1101 rec->ignorePreBlend(); 1102 break; 1103 } 1104 } 1105 1106 SkDescriptor* SkScalerContext::MakeDescriptorForPaths(SkFontID typefaceID, 1107 SkAutoDescriptor* ad) { 1108 SkScalerContextRec rec; 1109 memset(&rec, 0, sizeof(rec)); 1110 rec.fFontID = typefaceID; 1111 rec.fTextSize = SkPaint::kCanonicalTextSizeForPaths; 1112 rec.fPreScaleX = rec.fPost2x2[0][0] = rec.fPost2x2[1][1] = SK_Scalar1; 1113 return AutoDescriptorGivenRecAndEffects(rec, SkScalerContextEffects(), ad); 1114 } 1115 1116 SkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint( 1117 const SkPaint& paint, const SkSurfaceProps* surfaceProps, 1118 SkScalerContextFlags scalerContextFlags, 1119 const SkMatrix* deviceMatrix, SkAutoDescriptor* ad, 1120 SkScalerContextEffects* effects) { 1121 1122 SkScalerContextRec rec; 1123 MakeRecAndEffects(paint, surfaceProps, deviceMatrix, scalerContextFlags, &rec, effects); 1124 return AutoDescriptorGivenRecAndEffects(rec, *effects, ad); 1125 } 1126 1127 static size_t calculate_size_and_flatten( 1128 const SkScalerContextRec& rec, 1129 const SkScalerContextEffects& effects, 1130 SkBinaryWriteBuffer* pathEffectBuffer, 1131 SkBinaryWriteBuffer* maskFilterBuffer) 1132 { 1133 size_t descSize = sizeof(rec); 1134 int entryCount = 1; 1135 1136 if (effects.fPathEffect) { 1137 effects.fPathEffect->flatten(*pathEffectBuffer); 1138 descSize += pathEffectBuffer->bytesWritten(); 1139 entryCount += 1; 1140 } 1141 if (effects.fMaskFilter) { 1142 effects.fMaskFilter->flatten(*maskFilterBuffer); 1143 descSize += maskFilterBuffer->bytesWritten(); 1144 entryCount += 1; 1145 } 1146 1147 descSize += SkDescriptor::ComputeOverhead(entryCount); 1148 return descSize; 1149 } 1150 1151 #ifdef SK_DEBUG 1152 #define TEST_DESC 1153 #endif 1154 1155 #ifdef TEST_DESC 1156 static void test_desc(const SkScalerContextRec& rec, 1157 const SkScalerContextEffects& effects, 1158 SkBinaryWriteBuffer* peBuffer, 1159 SkBinaryWriteBuffer* mfBuffer, 1160 const SkDescriptor* desc) { 1161 // Check that we completely write the bytes in desc (our key), and that 1162 // there are no uninitialized bytes. If there were, then we would get 1163 // false-misses (or worse, false-hits) in our fontcache. 1164 // 1165 // We do this buy filling 2 others, one with 0s and the other with 1s 1166 // and create those, and then check that all 3 are identical. 1167 SkAutoDescriptor ad1(desc->getLength()); 1168 SkAutoDescriptor ad2(desc->getLength()); 1169 SkDescriptor* desc1 = ad1.getDesc(); 1170 SkDescriptor* desc2 = ad2.getDesc(); 1171 1172 memset(desc1, 0x00, desc->getLength()); 1173 memset(desc2, 0xFF, desc->getLength()); 1174 1175 desc1->init(); 1176 desc2->init(); 1177 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1178 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1179 1180 auto add_flattenable = [](SkDescriptor* desc, uint32_t tag, 1181 SkBinaryWriteBuffer* buffer) { 1182 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); 1183 }; 1184 1185 if (effects.fPathEffect) { 1186 add_flattenable(desc1, kPathEffect_SkDescriptorTag, peBuffer); 1187 add_flattenable(desc2, kPathEffect_SkDescriptorTag, peBuffer); 1188 } 1189 if (effects.fMaskFilter) { 1190 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, mfBuffer); 1191 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, mfBuffer); 1192 } 1193 1194 SkASSERT(desc->getLength() == desc1->getLength()); 1195 SkASSERT(desc->getLength() == desc2->getLength()); 1196 desc1->computeChecksum(); 1197 desc2->computeChecksum(); 1198 SkASSERT(!memcmp(desc, desc1, desc->getLength())); 1199 SkASSERT(!memcmp(desc, desc2, desc->getLength())); 1200 } 1201 #endif 1202 1203 void generate_descriptor( 1204 const SkScalerContextRec& rec, 1205 const SkScalerContextEffects& effects, 1206 SkBinaryWriteBuffer* pathEffectBuffer, 1207 SkBinaryWriteBuffer* maskFilterBuffer, 1208 SkDescriptor* desc) 1209 { 1210 desc->init(); 1211 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1212 1213 auto add = [&desc](uint32_t tag, SkBinaryWriteBuffer* buffer) { 1214 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); 1215 }; 1216 1217 if (effects.fPathEffect) { 1218 add(kPathEffect_SkDescriptorTag, pathEffectBuffer); 1219 } 1220 if (effects.fMaskFilter) { 1221 add(kMaskFilter_SkDescriptorTag, maskFilterBuffer); 1222 } 1223 1224 desc->computeChecksum(); 1225 #ifdef TEST_DESC 1226 test_desc(rec, effects, pathEffectBuffer, maskFilterBuffer, desc); 1227 #endif 1228 } 1229 1230 SkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects( 1231 const SkScalerContextRec& rec, 1232 const SkScalerContextEffects& effects, 1233 SkAutoDescriptor* ad) 1234 { 1235 SkBinaryWriteBuffer peBuffer, mfBuffer; 1236 1237 ad->reset(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer)); 1238 1239 generate_descriptor(rec, effects, &peBuffer, &mfBuffer, ad->getDesc()); 1240 1241 return ad->getDesc(); 1242 } 1243 1244 std::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects( 1245 const SkScalerContextRec& rec, 1246 const SkScalerContextEffects& effects) 1247 { 1248 SkBinaryWriteBuffer peBuffer, mfBuffer; 1249 1250 auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer)); 1251 1252 generate_descriptor(rec, effects, &peBuffer, &mfBuffer, desc.get()); 1253 1254 return desc; 1255 } 1256 1257 void SkScalerContext::DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer) { 1258 SkScalerContextEffects noEffects; 1259 SkBinaryWriteBuffer peBuffer, mfBuffer; 1260 generate_descriptor(rec, noEffects, &peBuffer, &mfBuffer, (SkDescriptor*)buffer); 1261 } 1262 1263 bool SkScalerContext::CheckBufferSizeForRec(const SkScalerContextRec& rec, 1264 const SkScalerContextEffects& effects, 1265 size_t size) { 1266 SkBinaryWriteBuffer peBuffer, mfBuffer; 1267 1268 return size >= calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer); 1269 } 1270 1271 1272 1273 1274