SkScalerContext.cpp revision ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976e
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 "SkRegion.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 117SkScalerContext::~SkScalerContext() { 118 SkDELETE(fNextContext); 119 120 SkSafeUnref(fPathEffect); 121 SkSafeUnref(fMaskFilter); 122 SkSafeUnref(fRasterizer); 123} 124 125static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) { 126 // fonthost will determine the next possible font to search, based 127 // on the current font in fRec. It will return NULL if ctx is our 128 // last font that can be searched (i.e. ultimate fallback font) 129 uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID); 130 if (0 == newFontID) { 131 return NULL; 132 } 133 134 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); 135 SkDescriptor* desc = ad.getDesc(); 136 137 desc->init(); 138 SkScalerContext::Rec* newRec = 139 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, 140 sizeof(rec), &rec); 141 newRec->fFontID = newFontID; 142 desc->computeChecksum(); 143 144 return SkFontHost::CreateScalerContext(desc); 145} 146 147/* Return the next context, creating it if its not already created, but return 148 NULL if the fonthost says there are no more fonts to fallback to. 149 */ 150SkScalerContext* SkScalerContext::getNextContext() { 151 SkScalerContext* next = fNextContext; 152 // if next is null, then either it isn't cached yet, or we're at the 153 // end of our possible chain 154 if (NULL == next) { 155 next = allocNextContext(fRec); 156 if (NULL == next) { 157 return NULL; 158 } 159 // next's base is our base + our local count 160 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); 161 // cache the answer 162 fNextContext = next; 163 } 164 return next; 165} 166 167SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { 168 unsigned glyphID = glyph.getGlyphID(); 169 SkScalerContext* ctx = this; 170 for (;;) { 171 unsigned count = ctx->getGlyphCount(); 172 if (glyphID < count) { 173 break; 174 } 175 glyphID -= count; 176 ctx = ctx->getNextContext(); 177 if (NULL == ctx) { 178 SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); 179 // just return the original context (this) 180 return this; 181 } 182 } 183 return ctx; 184} 185 186/* This loops through all available fallback contexts (if needed) until it 187 finds some context that can handle the unichar. If all fail, returns 0 188 */ 189uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { 190 SkScalerContext* ctx = this; 191 unsigned glyphID; 192 for (;;) { 193 glyphID = ctx->generateCharToGlyph(uni); 194 if (glyphID) { 195 break; // found it 196 } 197 ctx = ctx->getNextContext(); 198 if (NULL == ctx) { 199 return 0; // no more contexts, return missing glyph 200 } 201 } 202 // add the ctx's base, making glyphID unique for chain of contexts 203 glyphID += ctx->fBaseGlyphCount; 204 // check for overflow of 16bits, since our glyphID cannot exceed that 205 if (glyphID > 0xFFFF) { 206 glyphID = 0; 207 } 208 return SkToU16(glyphID); 209} 210 211SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) { 212 SkScalerContext* ctx = this; 213 unsigned rangeEnd = 0; 214 do { 215 unsigned rangeStart = rangeEnd; 216 217 rangeEnd += ctx->getGlyphCount(); 218 if (rangeStart <= glyphID && glyphID < rangeEnd) { 219 return ctx->generateGlyphToChar(glyphID - rangeStart); 220 } 221 ctx = ctx->getNextContext(); 222 } while (NULL != ctx); 223 return 0; 224} 225 226void SkScalerContext::getAdvance(SkGlyph* glyph) { 227 // mark us as just having a valid advance 228 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 229 // we mark the format before making the call, in case the impl 230 // internally ends up calling its generateMetrics, which is OK 231 // albeit slower than strictly necessary 232 this->getGlyphContext(*glyph)->generateAdvance(glyph); 233} 234 235void SkScalerContext::getMetrics(SkGlyph* glyph) { 236 this->getGlyphContext(*glyph)->generateMetrics(glyph); 237 238 // for now we have separate cache entries for devkerning on and off 239 // in the future we might share caches, but make our measure/draw 240 // code make the distinction. Thus we zap the values if the caller 241 // has not asked for them. 242 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 243 // no devkern, so zap the fields 244 glyph->fLsbDelta = glyph->fRsbDelta = 0; 245 } 246 247 // if either dimension is empty, zap the image bounds of the glyph 248 if (0 == glyph->fWidth || 0 == glyph->fHeight) { 249 glyph->fWidth = 0; 250 glyph->fHeight = 0; 251 glyph->fTop = 0; 252 glyph->fLeft = 0; 253 glyph->fMaskFormat = 0; 254 return; 255 } 256 257 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 258 SkPath devPath, fillPath; 259 SkMatrix fillToDevMatrix; 260 261 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 262 263 if (fRasterizer) { 264 SkMask mask; 265 266 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 267 fMaskFilter, &mask, 268 SkMask::kJustComputeBounds_CreateMode)) { 269 glyph->fLeft = mask.fBounds.fLeft; 270 glyph->fTop = mask.fBounds.fTop; 271 glyph->fWidth = SkToU16(mask.fBounds.width()); 272 glyph->fHeight = SkToU16(mask.fBounds.height()); 273 } else { 274 goto SK_ERROR; 275 } 276 } else { 277 // just use devPath 278 SkIRect ir; 279 devPath.getBounds().roundOut(&ir); 280 281 if (ir.isEmpty() || !ir.is16Bit()) { 282 goto SK_ERROR; 283 } 284 glyph->fLeft = ir.fLeft; 285 glyph->fTop = ir.fTop; 286 glyph->fWidth = SkToU16(ir.width()); 287 glyph->fHeight = SkToU16(ir.height()); 288 } 289 } 290 291 if (SkMask::kARGB32_Format != glyph->fMaskFormat) { 292 glyph->fMaskFormat = fRec.fMaskFormat; 293 } 294 295 if (fMaskFilter) { 296 SkMask src, dst; 297 SkMatrix matrix; 298 299 glyph->toMask(&src); 300 fRec.getMatrixFrom2x2(&matrix); 301 302 src.fImage = NULL; // only want the bounds from the filter 303 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 304 SkASSERT(dst.fImage == NULL); 305 glyph->fLeft = dst.fBounds.fLeft; 306 glyph->fTop = dst.fBounds.fTop; 307 glyph->fWidth = SkToU16(dst.fBounds.width()); 308 glyph->fHeight = SkToU16(dst.fBounds.height()); 309 glyph->fMaskFormat = dst.fFormat; 310 } 311 } 312 return; 313 314SK_ERROR: 315 // draw nothing 'cause we failed 316 glyph->fLeft = 0; 317 glyph->fTop = 0; 318 glyph->fWidth = 0; 319 glyph->fHeight = 0; 320 // put a valid value here, in case it was earlier set to 321 // MASK_FORMAT_JUST_ADVANCE 322 glyph->fMaskFormat = fRec.fMaskFormat; 323} 324 325void SkScalerContext::getImage(const SkGlyph& origGlyph) { 326 const SkGlyph* glyph = &origGlyph; 327 SkGlyph tmpGlyph; 328 329 if (fMaskFilter) { // restore the prefilter bounds 330 tmpGlyph.init(origGlyph.fID); 331 332 // need the original bounds, sans our maskfilter 333 SkMaskFilter* mf = fMaskFilter; 334 fMaskFilter = NULL; // temp disable 335 this->getMetrics(&tmpGlyph); 336 fMaskFilter = mf; // restore 337 338 tmpGlyph.fImage = origGlyph.fImage; 339 340 // we need the prefilter bounds to be <= filter bounds 341 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 342 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 343 glyph = &tmpGlyph; 344 } 345 346 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 347 SkPath devPath, fillPath; 348 SkMatrix fillToDevMatrix; 349 350 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 351 352 if (fRasterizer) { 353 SkMask mask; 354 355 glyph->toMask(&mask); 356 mask.fFormat = SkMask::kA8_Format; 357 sk_bzero(glyph->fImage, mask.computeImageSize()); 358 359 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 360 fMaskFilter, &mask, 361 SkMask::kJustRenderImage_CreateMode)) { 362 return; 363 } 364 } else { 365 SkBitmap bm; 366 SkBitmap::Config config; 367 SkMatrix matrix; 368 SkRegion clip; 369 SkPaint paint; 370 SkDraw draw; 371 372 if (SkMask::kA8_Format == fRec.fMaskFormat) { 373 config = SkBitmap::kA8_Config; 374 paint.setAntiAlias(true); 375 } else { 376 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); 377 config = SkBitmap::kA1_Config; 378 paint.setAntiAlias(false); 379 } 380 381 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); 382 matrix.setTranslate(-SkIntToScalar(glyph->fLeft), 383 -SkIntToScalar(glyph->fTop)); 384 bm.setConfig(config, glyph->fWidth, glyph->fHeight, 385 glyph->rowBytes()); 386 bm.setPixels(glyph->fImage); 387 sk_bzero(glyph->fImage, bm.height() * bm.rowBytes()); 388 389 draw.fClip = &clip; 390 draw.fMatrix = &matrix; 391 draw.fBitmap = &bm; 392 draw.fBounder = NULL; 393 draw.drawPath(devPath, paint); 394 } 395 } else { 396 this->getGlyphContext(*glyph)->generateImage(*glyph); 397 } 398 399 if (fMaskFilter) { 400 SkMask srcM, dstM; 401 SkMatrix matrix; 402 403 // the src glyph image shouldn't be 3D 404 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 405 glyph->toMask(&srcM); 406 fRec.getMatrixFrom2x2(&matrix); 407 408 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 409 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 410 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 411 int dstRB = origGlyph.rowBytes(); 412 int srcRB = dstM.fRowBytes; 413 414 const uint8_t* src = (const uint8_t*)dstM.fImage; 415 uint8_t* dst = (uint8_t*)origGlyph.fImage; 416 417 if (SkMask::k3D_Format == dstM.fFormat) { 418 // we have to copy 3 times as much 419 height *= 3; 420 } 421 422 // clean out our glyph, since it may be larger than dstM 423 //sk_bzero(dst, height * dstRB); 424 425 while (--height >= 0) { 426 memcpy(dst, src, width); 427 src += srcRB; 428 dst += dstRB; 429 } 430 SkMask::FreeImage(dstM.fImage); 431 } 432 } 433 434 // check to see if we should filter the alpha channel 435 436 if (NULL == fMaskFilter && 437 fRec.fMaskFormat != SkMask::kBW_Format && 438 fRec.fMaskFormat != SkMask::kLCD16_Format && 439 fRec.fMaskFormat != SkMask::kLCD32_Format && 440 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) 441 { 442 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; 443 if (NULL != table) { 444 uint8_t* dst = (uint8_t*)origGlyph.fImage; 445 unsigned rowBytes = origGlyph.rowBytes(); 446 447 for (int y = origGlyph.fHeight - 1; y >= 0; --y) { 448 for (int x = origGlyph.fWidth - 1; x >= 0; --x) { 449 dst[x] = table[dst[x]]; 450 } 451 dst += rowBytes; 452 } 453 } 454 } 455} 456 457void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) { 458 this->internalGetPath(glyph, NULL, path, NULL); 459} 460 461void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, 462 SkPaint::FontMetrics* my) { 463 this->generateFontMetrics(mx, my); 464} 465 466SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { 467 return 0; 468} 469 470/////////////////////////////////////////////////////////////////////////////// 471 472void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, 473 SkPath* devPath, SkMatrix* fillToDevMatrix) { 474 SkPath path; 475 476 this->getGlyphContext(glyph)->generatePath(glyph, &path); 477 478 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) { 479 // need the path in user-space, with only the point-size applied 480 // so that our stroking and effects will operate the same way they 481 // would if the user had extracted the path themself, and then 482 // called drawPath 483 SkPath localPath; 484 SkMatrix matrix, inverse; 485 486 fRec.getMatrixFrom2x2(&matrix); 487 matrix.invert(&inverse); 488 path.transform(inverse, &localPath); 489 // now localPath is only affected by the paint settings, and not the canvas matrix 490 491 SkScalar width = fRec.fFrameWidth; 492 493 if (fPathEffect) { 494 SkPath effectPath; 495 496 if (fPathEffect->filterPath(&effectPath, localPath, &width)) { 497 localPath.swap(effectPath); 498 } 499 } 500 501 if (width > 0) { 502 SkStroke stroker; 503 SkPath outline; 504 505 stroker.setWidth(width); 506 stroker.setMiterLimit(fRec.fMiterLimit); 507 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin); 508 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 509 stroker.strokePath(localPath, &outline); 510 localPath.swap(outline); 511 } 512 513 // now return stuff to the caller 514 if (fillToDevMatrix) { 515 *fillToDevMatrix = matrix; 516 } 517 if (devPath) { 518 localPath.transform(matrix, devPath); 519 } 520 if (fillPath) { 521 fillPath->swap(localPath); 522 } 523 } else { // nothing tricky to do 524 if (fillToDevMatrix) { 525 fillToDevMatrix->reset(); 526 } 527 if (devPath) { 528 if (fillPath == NULL) { 529 devPath->swap(path); 530 } else { 531 *devPath = path; 532 } 533 } 534 535 if (fillPath) { 536 fillPath->swap(path); 537 } 538 } 539 540 if (devPath) { 541 devPath->updateBoundsCache(); 542 } 543 if (fillPath) { 544 fillPath->updateBoundsCache(); 545 } 546} 547 548 549void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const { 550 dst->reset(); 551 dst->setScaleX(fPost2x2[0][0]); 552 dst->setSkewX( fPost2x2[0][1]); 553 dst->setSkewY( fPost2x2[1][0]); 554 dst->setScaleY(fPost2x2[1][1]); 555} 556 557void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const { 558 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize); 559 if (fPreSkewX) { 560 m->postSkew(fPreSkewX, 0); 561 } 562} 563 564void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const { 565 this->getLocalMatrix(m); 566 567 // now concat the device matrix 568 SkMatrix deviceMatrix; 569 this->getMatrixFrom2x2(&deviceMatrix); 570 m->postConcat(deviceMatrix); 571} 572 573/////////////////////////////////////////////////////////////////////////////// 574 575#include "SkFontHost.h" 576 577class SkScalerContext_Empty : public SkScalerContext { 578public: 579 SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {} 580 581protected: 582 virtual unsigned generateGlyphCount() { 583 return 0; 584 } 585 virtual uint16_t generateCharToGlyph(SkUnichar uni) { 586 return 0; 587 } 588 virtual void generateAdvance(SkGlyph* glyph) { 589 glyph->zeroMetrics(); 590 } 591 virtual void generateMetrics(SkGlyph* glyph) { 592 glyph->zeroMetrics(); 593 } 594 virtual void generateImage(const SkGlyph& glyph) {} 595 virtual void generatePath(const SkGlyph& glyph, SkPath* path) {} 596 virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 597 SkPaint::FontMetrics* my) { 598 if (mx) { 599 sk_bzero(mx, sizeof(*mx)); 600 } 601 if (my) { 602 sk_bzero(my, sizeof(*my)); 603 } 604 } 605}; 606 607extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); 608 609SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) { 610 SkScalerContext* c = NULL; //SkCreateColorScalerContext(desc); 611 if (NULL == c) { 612 c = SkFontHost::CreateScalerContext(desc); 613 } 614 if (NULL == c) { 615 c = SkNEW_ARGS(SkScalerContext_Empty, (desc)); 616 } 617 return c; 618} 619 620