SkScalerContext.cpp revision 045e62d715f5ee9b03deb5af3c750f8318096179
1 2/* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkScalerContext.h" 11#include "SkColorPriv.h" 12#include "SkDescriptor.h" 13#include "SkDraw.h" 14#include "SkFontHost.h" 15#include "SkMaskFilter.h" 16#include "SkPathEffect.h" 17#include "SkRasterizer.h" 18#include "SkRasterClip.h" 19#include "SkStroke.h" 20#include "SkThread.h" 21 22#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) 23 24static const uint8_t* gBlackGammaTable; 25static const uint8_t* gWhiteGammaTable; 26 27void SkGlyph::toMask(SkMask* mask) const { 28 SkASSERT(mask); 29 30 mask->fImage = (uint8_t*)fImage; 31 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); 32 mask->fRowBytes = this->rowBytes(); 33 mask->fFormat = static_cast<SkMask::Format>(fMaskFormat); 34} 35 36size_t SkGlyph::computeImageSize() const { 37 const size_t size = this->rowBytes() * fHeight; 38 39 switch (fMaskFormat) { 40 case SkMask::k3D_Format: 41 return 3 * size; 42 default: 43 return size; 44 } 45} 46 47void SkGlyph::zeroMetrics() { 48 fAdvanceX = 0; 49 fAdvanceY = 0; 50 fWidth = 0; 51 fHeight = 0; 52 fTop = 0; 53 fLeft = 0; 54 fRsbDelta = 0; 55 fLsbDelta = 0; 56} 57 58/////////////////////////////////////////////////////////////////////////////// 59 60#ifdef SK_DEBUG 61 #define DUMP_RECx 62#endif 63 64static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) { 65 SkFlattenable* obj = NULL; 66 uint32_t len; 67 const void* data = desc->findEntry(tag, &len); 68 69 if (data) { 70 SkFlattenableReadBuffer buffer(data, len); 71 obj = buffer.readFlattenable(); 72 SkASSERT(buffer.offset() == buffer.size()); 73 } 74 return obj; 75} 76 77SkScalerContext::SkScalerContext(const SkDescriptor* desc) 78 : fPathEffect(NULL), fMaskFilter(NULL) 79{ 80 static bool gHaveGammaTables; 81 if (!gHaveGammaTables) { 82 const uint8_t* tables[2]; 83 SkFontHost::GetGammaTables(tables); 84 gBlackGammaTable = tables[0]; 85 gWhiteGammaTable = tables[1]; 86 gHaveGammaTables = true; 87 } 88 89 fBaseGlyphCount = 0; 90 fNextContext = NULL; 91 92 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL); 93 SkASSERT(rec); 94 95 fRec = *rec; 96 97#ifdef DUMP_REC 98 desc->assertChecksum(); 99 SkDebugf("SkScalarContext checksum %x count %d length %d\n", 100 desc->getChecksum(), desc->getCount(), desc->getLength()); 101 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", 102 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], 103 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); 104 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", 105 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, 106 rec->fMaskFormat, rec->fStrokeJoin); 107 SkDebugf(" pathEffect %x maskFilter %x\n", 108 desc->findEntry(kPathEffect_SkDescriptorTag, NULL), 109 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); 110#endif 111 112 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag); 113 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag); 114 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag); 115 116 // initialize based on our settings. subclasses can also force this 117 fGenerateImageFromPath = fRec.fFrameWidth > 0 || fPathEffect != NULL || 118 fRasterizer != NULL; 119} 120 121SkScalerContext::~SkScalerContext() { 122 SkDELETE(fNextContext); 123 124 SkSafeUnref(fPathEffect); 125 SkSafeUnref(fMaskFilter); 126 SkSafeUnref(fRasterizer); 127} 128 129static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) { 130 // fonthost will determine the next possible font to search, based 131 // on the current font in fRec. It will return NULL if ctx is our 132 // last font that can be searched (i.e. ultimate fallback font) 133 uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID); 134 if (0 == newFontID) { 135 return NULL; 136 } 137 138 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); 139 SkDescriptor* desc = ad.getDesc(); 140 141 desc->init(); 142 SkScalerContext::Rec* newRec = 143 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, 144 sizeof(rec), &rec); 145 newRec->fFontID = newFontID; 146 desc->computeChecksum(); 147 148 return SkFontHost::CreateScalerContext(desc); 149} 150 151/* Return the next context, creating it if its not already created, but return 152 NULL if the fonthost says there are no more fonts to fallback to. 153 */ 154SkScalerContext* SkScalerContext::getNextContext() { 155 SkScalerContext* next = fNextContext; 156 // if next is null, then either it isn't cached yet, or we're at the 157 // end of our possible chain 158 if (NULL == next) { 159 next = allocNextContext(fRec); 160 if (NULL == next) { 161 return NULL; 162 } 163 // next's base is our base + our local count 164 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); 165 // cache the answer 166 fNextContext = next; 167 } 168 return next; 169} 170 171SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { 172 unsigned glyphID = glyph.getGlyphID(); 173 SkScalerContext* ctx = this; 174 for (;;) { 175 unsigned count = ctx->getGlyphCount(); 176 if (glyphID < count) { 177 break; 178 } 179 glyphID -= count; 180 ctx = ctx->getNextContext(); 181 if (NULL == ctx) { 182 SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); 183 // just return the original context (this) 184 return this; 185 } 186 } 187 return ctx; 188} 189 190/* This loops through all available fallback contexts (if needed) until it 191 finds some context that can handle the unichar. If all fail, returns 0 192 */ 193uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { 194 SkScalerContext* ctx = this; 195 unsigned glyphID; 196 for (;;) { 197 glyphID = ctx->generateCharToGlyph(uni); 198 if (glyphID) { 199 break; // found it 200 } 201 ctx = ctx->getNextContext(); 202 if (NULL == ctx) { 203 return 0; // no more contexts, return missing glyph 204 } 205 } 206 // add the ctx's base, making glyphID unique for chain of contexts 207 glyphID += ctx->fBaseGlyphCount; 208 // check for overflow of 16bits, since our glyphID cannot exceed that 209 if (glyphID > 0xFFFF) { 210 glyphID = 0; 211 } 212 return SkToU16(glyphID); 213} 214 215SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) { 216 SkScalerContext* ctx = this; 217 unsigned rangeEnd = 0; 218 do { 219 unsigned rangeStart = rangeEnd; 220 221 rangeEnd += ctx->getGlyphCount(); 222 if (rangeStart <= glyphID && glyphID < rangeEnd) { 223 return ctx->generateGlyphToChar(glyphID - rangeStart); 224 } 225 ctx = ctx->getNextContext(); 226 } while (NULL != ctx); 227 return 0; 228} 229 230void SkScalerContext::getAdvance(SkGlyph* glyph) { 231 // mark us as just having a valid advance 232 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 233 // we mark the format before making the call, in case the impl 234 // internally ends up calling its generateMetrics, which is OK 235 // albeit slower than strictly necessary 236 this->getGlyphContext(*glyph)->generateAdvance(glyph); 237} 238 239void SkScalerContext::getMetrics(SkGlyph* glyph) { 240 this->getGlyphContext(*glyph)->generateMetrics(glyph); 241 242 // for now we have separate cache entries for devkerning on and off 243 // in the future we might share caches, but make our measure/draw 244 // code make the distinction. Thus we zap the values if the caller 245 // has not asked for them. 246 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 247 // no devkern, so zap the fields 248 glyph->fLsbDelta = glyph->fRsbDelta = 0; 249 } 250 251 // if either dimension is empty, zap the image bounds of the glyph 252 if (0 == glyph->fWidth || 0 == glyph->fHeight) { 253 glyph->fWidth = 0; 254 glyph->fHeight = 0; 255 glyph->fTop = 0; 256 glyph->fLeft = 0; 257 glyph->fMaskFormat = 0; 258 return; 259 } 260 261 if (fGenerateImageFromPath) { 262 SkPath devPath, fillPath; 263 SkMatrix fillToDevMatrix; 264 265 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 266 267 if (fRasterizer) { 268 SkMask mask; 269 270 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 271 fMaskFilter, &mask, 272 SkMask::kJustComputeBounds_CreateMode)) { 273 glyph->fLeft = mask.fBounds.fLeft; 274 glyph->fTop = mask.fBounds.fTop; 275 glyph->fWidth = SkToU16(mask.fBounds.width()); 276 glyph->fHeight = SkToU16(mask.fBounds.height()); 277 } else { 278 goto SK_ERROR; 279 } 280 } else { 281 // just use devPath 282 SkIRect ir; 283 devPath.getBounds().roundOut(&ir); 284 285 if (ir.isEmpty() || !ir.is16Bit()) { 286 goto SK_ERROR; 287 } 288 glyph->fLeft = ir.fLeft; 289 glyph->fTop = ir.fTop; 290 glyph->fWidth = SkToU16(ir.width()); 291 glyph->fHeight = SkToU16(ir.height()); 292 } 293 } 294 295 if (SkMask::kARGB32_Format != glyph->fMaskFormat) { 296 glyph->fMaskFormat = fRec.fMaskFormat; 297 } 298 299 if (fMaskFilter) { 300 SkMask src, dst; 301 SkMatrix matrix; 302 303 glyph->toMask(&src); 304 fRec.getMatrixFrom2x2(&matrix); 305 306 src.fImage = NULL; // only want the bounds from the filter 307 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 308 SkASSERT(dst.fImage == NULL); 309 glyph->fLeft = dst.fBounds.fLeft; 310 glyph->fTop = dst.fBounds.fTop; 311 glyph->fWidth = SkToU16(dst.fBounds.width()); 312 glyph->fHeight = SkToU16(dst.fBounds.height()); 313 glyph->fMaskFormat = dst.fFormat; 314 } 315 } 316 return; 317 318SK_ERROR: 319 // draw nothing 'cause we failed 320 glyph->fLeft = 0; 321 glyph->fTop = 0; 322 glyph->fWidth = 0; 323 glyph->fHeight = 0; 324 // put a valid value here, in case it was earlier set to 325 // MASK_FORMAT_JUST_ADVANCE 326 glyph->fMaskFormat = fRec.fMaskFormat; 327} 328 329static bool isLCD(const SkScalerContext::Rec& rec) { 330 return SkMask::kLCD16_Format == rec.fMaskFormat || 331 SkMask::kLCD32_Format == rec.fMaskFormat; 332} 333 334static uint16_t a8_to_rgb565(unsigned a8) { 335 return SkPackRGB16(a8 >> 3, a8 >> 2, a8 >> 3); 336} 337 338static void copyToLCD16(const SkBitmap& src, const SkMask& dst) { 339 SkASSERT(SkBitmap::kA8_Config == src.config()); 340 SkASSERT(SkMask::kLCD16_Format == dst.fFormat); 341 342 const int width = dst.fBounds.width(); 343 const int height = dst.fBounds.height(); 344 const uint8_t* srcP = src.getAddr8(0, 0); 345 size_t srcRB = src.rowBytes(); 346 uint16_t* dstP = (uint16_t*)dst.fImage; 347 size_t dstRB = dst.fRowBytes; 348 for (int y = 0; y < height; ++y) { 349 for (int x = 0; x < width; ++x) { 350 dstP[x] = a8_to_rgb565(srcP[x]); 351 } 352 srcP += srcRB; 353 dstP = (uint16_t*)((char*)dstP + dstRB); 354 } 355} 356 357#define SK_FREETYPE_LCD_LERP 160 358 359static int lerp(int start, int end) { 360 SkASSERT((unsigned)SK_FREETYPE_LCD_LERP <= 256); 361 return start + ((end - start) * (SK_FREETYPE_LCD_LERP) >> 8); 362} 363 364static uint16_t packLCD16(unsigned r, unsigned g, unsigned b) { 365 if (SK_FREETYPE_LCD_LERP) { 366 // want (a+b+c)/3, but we approx to avoid the divide 367 unsigned ave = (5 * (r + g + b) + g) >> 4; 368 r = lerp(r, ave); 369 g = lerp(g, ave); 370 b = lerp(b, ave); 371 } 372 return SkPackRGB16(r >> 3, g >> 2, b >> 3); 373} 374 375static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst) { 376 SkASSERT(SkBitmap::kA8_Config == src.config()); 377 SkASSERT(SkMask::kLCD16_Format == dst.fFormat); 378 379 const int width = dst.fBounds.width(); 380 const int height = dst.fBounds.height(); 381 uint16_t* dstP = (uint16_t*)dst.fImage; 382 size_t dstRB = dst.fRowBytes; 383 for (int y = 0; y < height; ++y) { 384 const uint8_t* srcP = src.getAddr8(0, y); 385 for (int x = 0; x < width; ++x) { 386 unsigned r = *srcP++; 387 unsigned g = *srcP++; 388 unsigned b = *srcP++; 389 dstP[x] = packLCD16(r, g, b); 390 } 391 dstP = (uint16_t*)((char*)dstP + dstRB); 392 } 393} 394 395static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst) { 396 SkASSERT(SkBitmap::kA8_Config == src.config()); 397 SkASSERT(SkMask::kLCD32_Format == dst.fFormat); 398 399 const int width = dst.fBounds.width(); 400 const int height = dst.fBounds.height(); 401 SkPMColor* dstP = (SkPMColor*)dst.fImage; 402 size_t dstRB = dst.fRowBytes; 403 for (int y = 0; y < height; ++y) { 404 const uint8_t* srcP = src.getAddr8(0, y); 405 for (int x = 0; x < width; ++x) { 406 unsigned r = *srcP++; 407 unsigned g = *srcP++; 408 unsigned b = *srcP++; 409 unsigned a = SkMax32(SkMax32(r, g), b); 410 dstP[x] = SkPackARGB32(a, r, g, b); 411 } 412 dstP = (SkPMColor*)((char*)dstP + dstRB); 413 } 414} 415 416static void generateMask(const SkMask& mask, const SkPath& path) { 417 SkBitmap::Config config; 418 SkPaint paint; 419 420 int srcW = mask.fBounds.width(); 421 int srcH = mask.fBounds.height(); 422 int dstW = srcW; 423 int dstH = srcH; 424 int dstRB = mask.fRowBytes; 425 426 SkMatrix matrix; 427 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 428 -SkIntToScalar(mask.fBounds.fTop)); 429 430 if (SkMask::kBW_Format == mask.fFormat) { 431 config = SkBitmap::kA1_Config; 432 paint.setAntiAlias(false); 433 } else { 434 config = SkBitmap::kA8_Config; 435 paint.setAntiAlias(true); 436 switch (mask.fFormat) { 437 case SkMask::kA8_Format: 438 break; 439 case SkMask::kLCD16_Format: 440 case SkMask::kLCD32_Format: 441 // TODO: trigger off LCD orientation 442 dstW *= 3; 443 matrix.postScale(SkIntToScalar(3), SK_Scalar1); 444 dstRB = 0; // signals we need a copy 445 break; 446 default: 447 SkASSERT(!"unexpected mask format"); 448 } 449 } 450 451 SkRasterClip clip; 452 clip.setRect(SkIRect::MakeWH(dstW, dstH)); 453 454 SkBitmap bm; 455 bm.setConfig(config, dstW, dstH, dstRB); 456 457 if (0 == dstRB) { 458 bm.allocPixels(); 459 bm.lockPixels(); 460 } else { 461 bm.setPixels(mask.fImage); 462 } 463 sk_bzero(bm.getPixels(), bm.getSafeSize()); 464 465 SkDraw draw; 466 sk_bzero(&draw, sizeof(draw)); 467 draw.fRC = &clip; 468 draw.fClip = &clip.bwRgn(); 469 draw.fMatrix = &matrix; 470 draw.fBitmap = &bm; 471 draw.drawPath(path, paint); 472 473 if (0 == dstRB) { 474 switch (mask.fFormat) { 475 case SkMask::kLCD16_Format: 476 pack3xHToLCD16(bm, mask); 477 break; 478 case SkMask::kLCD32_Format: 479 pack3xHToLCD32(bm, mask); 480 break; 481 default: 482 SkASSERT(!"bad format for copyback"); 483 } 484 } 485} 486 487void SkScalerContext::getImage(const SkGlyph& origGlyph) { 488 const SkGlyph* glyph = &origGlyph; 489 SkGlyph tmpGlyph; 490 491 if (fMaskFilter) { // restore the prefilter bounds 492 tmpGlyph.init(origGlyph.fID); 493 494 // need the original bounds, sans our maskfilter 495 SkMaskFilter* mf = fMaskFilter; 496 fMaskFilter = NULL; // temp disable 497 this->getMetrics(&tmpGlyph); 498 fMaskFilter = mf; // restore 499 500 tmpGlyph.fImage = origGlyph.fImage; 501 502 // we need the prefilter bounds to be <= filter bounds 503 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 504 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 505 glyph = &tmpGlyph; 506 } 507 508 if (fGenerateImageFromPath) { 509 SkPath devPath, fillPath; 510 SkMatrix fillToDevMatrix; 511 SkMask mask; 512 513 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 514 glyph->toMask(&mask); 515 516 if (fRasterizer) { 517 mask.fFormat = SkMask::kA8_Format; 518 sk_bzero(glyph->fImage, mask.computeImageSize()); 519 520 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 521 fMaskFilter, &mask, 522 SkMask::kJustRenderImage_CreateMode)) { 523 return; 524 } 525 } else { 526 generateMask(mask, devPath); 527 } 528 } else { 529 this->getGlyphContext(*glyph)->generateImage(*glyph); 530 } 531 532 if (fMaskFilter) { 533 SkMask srcM, dstM; 534 SkMatrix matrix; 535 536 // the src glyph image shouldn't be 3D 537 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 538 glyph->toMask(&srcM); 539 fRec.getMatrixFrom2x2(&matrix); 540 541 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 542 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 543 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 544 int dstRB = origGlyph.rowBytes(); 545 int srcRB = dstM.fRowBytes; 546 547 const uint8_t* src = (const uint8_t*)dstM.fImage; 548 uint8_t* dst = (uint8_t*)origGlyph.fImage; 549 550 if (SkMask::k3D_Format == dstM.fFormat) { 551 // we have to copy 3 times as much 552 height *= 3; 553 } 554 555 // clean out our glyph, since it may be larger than dstM 556 //sk_bzero(dst, height * dstRB); 557 558 while (--height >= 0) { 559 memcpy(dst, src, width); 560 src += srcRB; 561 dst += dstRB; 562 } 563 SkMask::FreeImage(dstM.fImage); 564 } 565 } 566 567 // check to see if we should filter the alpha channel 568 569 if (NULL == fMaskFilter && 570 fRec.fMaskFormat != SkMask::kBW_Format && 571 fRec.fMaskFormat != SkMask::kLCD16_Format && 572 fRec.fMaskFormat != SkMask::kLCD32_Format && 573 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) 574 { 575 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; 576 if (NULL != table) { 577 uint8_t* dst = (uint8_t*)origGlyph.fImage; 578 unsigned rowBytes = origGlyph.rowBytes(); 579 580 for (int y = origGlyph.fHeight - 1; y >= 0; --y) { 581 for (int x = origGlyph.fWidth - 1; x >= 0; --x) { 582 dst[x] = table[dst[x]]; 583 } 584 dst += rowBytes; 585 } 586 } 587 } 588} 589 590void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) { 591 this->internalGetPath(glyph, NULL, path, NULL); 592} 593 594void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, 595 SkPaint::FontMetrics* my) { 596 this->generateFontMetrics(mx, my); 597} 598 599SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { 600 return 0; 601} 602 603/////////////////////////////////////////////////////////////////////////////// 604 605void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, 606 SkPath* devPath, SkMatrix* fillToDevMatrix) { 607 SkPath path; 608 609 this->getGlyphContext(glyph)->generatePath(glyph, &path); 610 611 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 612 SkFixed dx = glyph.getSubXFixed(); 613 SkFixed dy = glyph.getSubYFixed(); 614 if (dx | dy) { 615 path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); 616 } 617 } 618 619 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) { 620 // need the path in user-space, with only the point-size applied 621 // so that our stroking and effects will operate the same way they 622 // would if the user had extracted the path themself, and then 623 // called drawPath 624 SkPath localPath; 625 SkMatrix matrix, inverse; 626 627 fRec.getMatrixFrom2x2(&matrix); 628 matrix.invert(&inverse); 629 path.transform(inverse, &localPath); 630 // now localPath is only affected by the paint settings, and not the canvas matrix 631 632 SkScalar width = fRec.fFrameWidth; 633 634 if (fPathEffect) { 635 SkPath effectPath; 636 637 if (fPathEffect->filterPath(&effectPath, localPath, &width)) { 638 localPath.swap(effectPath); 639 } 640 } 641 642 if (width > 0) { 643 SkStroke stroker; 644 SkPath outline; 645 646 stroker.setWidth(width); 647 stroker.setMiterLimit(fRec.fMiterLimit); 648 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin); 649 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 650 stroker.strokePath(localPath, &outline); 651 localPath.swap(outline); 652 } 653 654 // now return stuff to the caller 655 if (fillToDevMatrix) { 656 *fillToDevMatrix = matrix; 657 } 658 if (devPath) { 659 localPath.transform(matrix, devPath); 660 } 661 if (fillPath) { 662 fillPath->swap(localPath); 663 } 664 } else { // nothing tricky to do 665 if (fillToDevMatrix) { 666 fillToDevMatrix->reset(); 667 } 668 if (devPath) { 669 if (fillPath == NULL) { 670 devPath->swap(path); 671 } else { 672 *devPath = path; 673 } 674 } 675 676 if (fillPath) { 677 fillPath->swap(path); 678 } 679 } 680 681 if (devPath) { 682 devPath->updateBoundsCache(); 683 } 684 if (fillPath) { 685 fillPath->updateBoundsCache(); 686 } 687} 688 689 690void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const { 691 dst->reset(); 692 dst->setScaleX(fPost2x2[0][0]); 693 dst->setSkewX( fPost2x2[0][1]); 694 dst->setSkewY( fPost2x2[1][0]); 695 dst->setScaleY(fPost2x2[1][1]); 696} 697 698void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const { 699 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize); 700 if (fPreSkewX) { 701 m->postSkew(fPreSkewX, 0); 702 } 703} 704 705void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const { 706 this->getLocalMatrix(m); 707 708 // now concat the device matrix 709 SkMatrix deviceMatrix; 710 this->getMatrixFrom2x2(&deviceMatrix); 711 m->postConcat(deviceMatrix); 712} 713 714SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) { 715 SkASSERT(!matrix.hasPerspective()); 716 717 if (0 == matrix[SkMatrix::kMSkewY]) { 718 return kX_SkAxisAlignment; 719 } 720 if (0 == matrix[SkMatrix::kMScaleX]) { 721 return kY_SkAxisAlignment; 722 } 723 return kNone_SkAxisAlignment; 724} 725 726/////////////////////////////////////////////////////////////////////////////// 727 728#include "SkFontHost.h" 729 730class SkScalerContext_Empty : public SkScalerContext { 731public: 732 SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {} 733 734protected: 735 virtual unsigned generateGlyphCount() { 736 return 0; 737 } 738 virtual uint16_t generateCharToGlyph(SkUnichar uni) { 739 return 0; 740 } 741 virtual void generateAdvance(SkGlyph* glyph) { 742 glyph->zeroMetrics(); 743 } 744 virtual void generateMetrics(SkGlyph* glyph) { 745 glyph->zeroMetrics(); 746 } 747 virtual void generateImage(const SkGlyph& glyph) {} 748 virtual void generatePath(const SkGlyph& glyph, SkPath* path) {} 749 virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 750 SkPaint::FontMetrics* my) { 751 if (mx) { 752 sk_bzero(mx, sizeof(*mx)); 753 } 754 if (my) { 755 sk_bzero(my, sizeof(*my)); 756 } 757 } 758}; 759 760extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); 761 762SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) { 763 SkScalerContext* c = NULL; //SkCreateColorScalerContext(desc); 764 if (NULL == c) { 765 c = SkFontHost::CreateScalerContext(desc); 766 } 767 if (NULL == c) { 768 c = SkNEW_ARGS(SkScalerContext_Empty, (desc)); 769 } 770 return c; 771} 772 773