SkScalerContext.cpp revision a8c52de60de1d2471206b3c81e9243e2c76f2edb
1/* libs/graphics/sgl/SkScalerContext.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include "SkScalerContext.h" 19#include "SkDescriptor.h" 20#include "SkDraw.h" 21#include "SkFontHost.h" 22#include "SkMaskFilter.h" 23#include "SkPathEffect.h" 24#include "SkRasterizer.h" 25#include "SkRegion.h" 26#include "SkStroke.h" 27#include "SkThread.h" 28 29#ifdef SK_DEBUG 30// #define TRACK_MISSING_CHARS 31#endif 32 33#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) 34 35static const uint8_t* gBlackGammaTable; 36static const uint8_t* gWhiteGammaTable; 37 38void SkGlyph::toMask(SkMask* mask) const { 39 SkASSERT(mask); 40 41 mask->fImage = (uint8_t*)fImage; 42 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); 43 mask->fRowBytes = this->rowBytes(); 44 mask->fFormat = static_cast<SkMask::Format>(fMaskFormat); 45} 46 47size_t SkGlyph::computeImageSize() const { 48 size_t size = this->rowBytes() * fHeight; 49 if (fMaskFormat == SkMask::k3D_Format) { 50 size *= 3; 51 } 52 return size; 53} 54 55void SkGlyph::zeroMetrics() { 56 fAdvanceX = 0; 57 fAdvanceY = 0; 58 fWidth = 0; 59 fHeight = 0; 60 fTop = 0; 61 fLeft = 0; 62 fRsbDelta = 0; 63 fLsbDelta = 0; 64} 65 66/////////////////////////////////////////////////////////////////////////////// 67 68#ifdef SK_DEBUG 69 #define DUMP_RECx 70#endif 71 72static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) { 73 SkFlattenable* obj = NULL; 74 uint32_t len; 75 const void* data = desc->findEntry(tag, &len); 76 77 if (data) { 78 SkFlattenableReadBuffer buffer(data, len); 79 obj = buffer.readFlattenable(); 80 SkASSERT(buffer.offset() == buffer.size()); 81 } 82 return obj; 83} 84 85SkScalerContext::SkScalerContext(const SkDescriptor* desc) 86 : fPathEffect(NULL), fMaskFilter(NULL) 87{ 88 static bool gHaveGammaTables; 89 if (!gHaveGammaTables) { 90 const uint8_t* tables[2]; 91 SkFontHost::GetGammaTables(tables); 92 gBlackGammaTable = tables[0]; 93 gWhiteGammaTable = tables[1]; 94 gHaveGammaTables = true; 95 } 96 97 fBaseGlyphCount = 0; 98 fNextContext = NULL; 99 100 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL); 101 SkASSERT(rec); 102 103 fRec = *rec; 104 105#ifdef DUMP_REC 106 desc->assertChecksum(); 107 SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecksum(), desc->getCount(), desc->getLength()); 108 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", 109 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], 110 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); 111 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", 112 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, 113 rec->fMaskFormat, rec->fStrokeJoin); 114 SkDebugf(" pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDescriptorTag, NULL), 115 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); 116#endif 117 118 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag); 119 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag); 120 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag); 121} 122 123SkScalerContext::~SkScalerContext() { 124 SkDELETE(fNextContext); 125 126 fPathEffect->safeUnref(); 127 fMaskFilter->safeUnref(); 128 fRasterizer->safeUnref(); 129} 130 131static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) { 132 // fonthost will determine the next possible font to search, based 133 // on the current font in fRec. It will return NULL if ctx is our 134 // last font that can be searched (i.e. ultimate fallback font) 135 uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID); 136 if (0 == newFontID) { 137 return NULL; 138 } 139 140 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); 141 SkDescriptor* desc = ad.getDesc(); 142 143 desc->init(); 144 SkScalerContext::Rec* newRec = 145 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, 146 sizeof(rec), &rec); 147 newRec->fFontID = newFontID; 148 desc->computeChecksum(); 149 150 return SkFontHost::CreateScalerContext(desc); 151} 152 153/* Return the next context, creating it if its not already created, but return 154 NULL if the fonthost says there are no more fonts to fallback to. 155 */ 156SkScalerContext* SkScalerContext::getNextContext() { 157 SkScalerContext* next = fNextContext; 158 // if next is null, then either it isn't cached yet, or we're at the 159 // end of our possible chain 160 if (NULL == next) { 161 next = allocNextContext(fRec); 162 if (NULL == next) { 163 return NULL; 164 } 165 // next's base is our base + our local count 166 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); 167 // cache the answer 168 fNextContext = next; 169 } 170 return next; 171} 172 173SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { 174 unsigned glyphID = glyph.getGlyphID(); 175 SkScalerContext* ctx = this; 176 for (;;) { 177 unsigned count = ctx->getGlyphCount(); 178 if (glyphID < count) { 179 break; 180 } 181 glyphID -= count; 182 ctx = ctx->getNextContext(); 183 if (NULL == ctx) { 184 SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); 185 // just return the original context (this) 186 return this; 187 } 188 } 189 return ctx; 190} 191 192/* This loops through all available fallback contexts (if needed) until it 193 finds some context that can handle the unichar. If all fail, returns 0 194 */ 195uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { 196 SkScalerContext* ctx = this; 197 unsigned glyphID; 198 for (;;) { 199 glyphID = ctx->generateCharToGlyph(uni); 200 if (glyphID) { 201 break; // found it 202 } 203 ctx = ctx->getNextContext(); 204 if (NULL == ctx) { 205 return 0; // no more contexts, return missing glyph 206 } 207 } 208 // add the ctx's base, making glyphID unique for chain of contexts 209 glyphID += ctx->fBaseGlyphCount; 210 // check for overflow of 16bits, since our glyphID cannot exceed that 211 if (glyphID > 0xFFFF) { 212 glyphID = 0; 213 } 214 return SkToU16(glyphID); 215} 216 217void SkScalerContext::getAdvance(SkGlyph* glyph) { 218 // mark us as just having a valid advance 219 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 220 // we mark the format before making the call, in case the impl 221 // internally ends up calling its generateMetrics, which is OK 222 // albeit slower than strictly necessary 223 this->getGlyphContext(*glyph)->generateAdvance(glyph); 224} 225 226void SkScalerContext::getMetrics(SkGlyph* glyph) { 227 this->getGlyphContext(*glyph)->generateMetrics(glyph); 228 229 // for now we have separate cache entries for devkerning on and off 230 // in the future we might share caches, but make our measure/draw 231 // code make the distinction. Thus we zap the values if the caller 232 // has not asked for them. 233 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 234 // no devkern, so zap the fields 235 glyph->fLsbDelta = glyph->fRsbDelta = 0; 236 } 237 238 // if either dimension is empty, zap the image bounds of the glyph 239 if (0 == glyph->fWidth || 0 == glyph->fHeight) { 240 glyph->fWidth = 0; 241 glyph->fHeight = 0; 242 glyph->fTop = 0; 243 glyph->fLeft = 0; 244 glyph->fMaskFormat = 0; 245 return; 246 } 247 248 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 249 SkPath devPath, fillPath; 250 SkMatrix fillToDevMatrix; 251 252 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 253 254 if (fRasterizer) { 255 SkMask mask; 256 257 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 258 fMaskFilter, &mask, 259 SkMask::kJustComputeBounds_CreateMode)) { 260 glyph->fLeft = mask.fBounds.fLeft; 261 glyph->fTop = mask.fBounds.fTop; 262 glyph->fWidth = SkToU16(mask.fBounds.width()); 263 glyph->fHeight = SkToU16(mask.fBounds.height()); 264 } else { 265 // draw nothing 'cause we failed 266 glyph->fLeft = 0; 267 glyph->fTop = 0; 268 glyph->fWidth = 0; 269 glyph->fHeight = 0; 270 return; 271 } 272 } else { 273 // just use devPath 274 SkIRect ir; 275 devPath.getBounds().roundOut(&ir); 276 277 glyph->fLeft = ir.fLeft; 278 glyph->fTop = ir.fTop; 279 glyph->fWidth = SkToU16(ir.width()); 280 glyph->fHeight = SkToU16(ir.height()); 281 } 282 } 283 284 glyph->fMaskFormat = fRec.fMaskFormat; 285 286 if (fMaskFilter) { 287 SkMask src, dst; 288 SkMatrix matrix; 289 290 glyph->toMask(&src); 291 fRec.getMatrixFrom2x2(&matrix); 292 293 src.fImage = NULL; // only want the bounds from the filter 294 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 295 SkASSERT(dst.fImage == NULL); 296 glyph->fLeft = dst.fBounds.fLeft; 297 glyph->fTop = dst.fBounds.fTop; 298 glyph->fWidth = SkToU16(dst.fBounds.width()); 299 glyph->fHeight = SkToU16(dst.fBounds.height()); 300 glyph->fMaskFormat = dst.fFormat; 301 } 302 } 303} 304 305void SkScalerContext::getImage(const SkGlyph& origGlyph) { 306 const SkGlyph* glyph = &origGlyph; 307 SkGlyph tmpGlyph; 308 309 if (fMaskFilter) { // restore the prefilter bounds 310 tmpGlyph.fID = origGlyph.fID; 311 312 // need the original bounds, sans our maskfilter 313 SkMaskFilter* mf = fMaskFilter; 314 fMaskFilter = NULL; // temp disable 315 this->getMetrics(&tmpGlyph); 316 fMaskFilter = mf; // restore 317 318 tmpGlyph.fImage = origGlyph.fImage; 319 320 // we need the prefilter bounds to be <= filter bounds 321 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 322 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 323 glyph = &tmpGlyph; 324 } 325 326 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 327 SkPath devPath, fillPath; 328 SkMatrix fillToDevMatrix; 329 330 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 331 332 if (fRasterizer) { 333 SkMask mask; 334 335 glyph->toMask(&mask); 336 mask.fFormat = SkMask::kA8_Format; 337 sk_bzero(glyph->fImage, mask.computeImageSize()); 338 339 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 340 fMaskFilter, &mask, 341 SkMask::kJustRenderImage_CreateMode)) { 342 return; 343 } 344 } else { 345 SkBitmap bm; 346 SkBitmap::Config config; 347 SkMatrix matrix; 348 SkRegion clip; 349 SkPaint paint; 350 SkDraw draw; 351 352 if (SkMask::kA8_Format == fRec.fMaskFormat) { 353 config = SkBitmap::kA8_Config; 354 paint.setAntiAlias(true); 355 } else { 356 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); 357 config = SkBitmap::kA1_Config; 358 paint.setAntiAlias(false); 359 } 360 361 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); 362 matrix.setTranslate(-SkIntToScalar(glyph->fLeft), 363 -SkIntToScalar(glyph->fTop)); 364 bm.setConfig(config, glyph->fWidth, glyph->fHeight, 365 glyph->rowBytes()); 366 bm.setPixels(glyph->fImage); 367 sk_bzero(glyph->fImage, bm.height() * bm.rowBytes()); 368 369 draw.fClip = &clip; 370 draw.fMatrix = &matrix; 371 draw.fBitmap = &bm; 372 draw.fBounder = NULL; 373 draw.drawPath(devPath, paint); 374 } 375 } else { 376 this->getGlyphContext(*glyph)->generateImage(*glyph); 377 } 378 379 if (fMaskFilter) { 380 SkMask srcM, dstM; 381 SkMatrix matrix; 382 383 // the src glyph image shouldn't be 3D 384 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 385 glyph->toMask(&srcM); 386 fRec.getMatrixFrom2x2(&matrix); 387 388 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 389 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 390 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 391 int dstRB = origGlyph.rowBytes(); 392 int srcRB = dstM.fRowBytes; 393 394 const uint8_t* src = (const uint8_t*)dstM.fImage; 395 uint8_t* dst = (uint8_t*)origGlyph.fImage; 396 397 if (SkMask::k3D_Format == dstM.fFormat) { 398 // we have to copy 3 times as much 399 height *= 3; 400 } 401 402 // clean out our glyph, since it may be larger than dstM 403 //sk_bzero(dst, height * dstRB); 404 405 while (--height >= 0) { 406 memcpy(dst, src, width); 407 src += srcRB; 408 dst += dstRB; 409 } 410 SkMask::FreeImage(dstM.fImage); 411 } 412 } 413 414 // check to see if we should filter the alpha channel 415 416 if (NULL == fMaskFilter && 417 fRec.fMaskFormat != SkMask::kBW_Format && 418 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) 419 { 420 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; 421 if (NULL != table) 422 { 423 uint8_t* dst = (uint8_t*)origGlyph.fImage; 424 unsigned rowBytes = origGlyph.rowBytes(); 425 426 for (int y = origGlyph.fHeight - 1; y >= 0; --y) 427 { 428 for (int x = origGlyph.fWidth - 1; x >= 0; --x) 429 dst[x] = table[dst[x]]; 430 dst += rowBytes; 431 } 432 } 433 } 434} 435 436void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) 437{ 438 this->internalGetPath(glyph, NULL, path, NULL); 439} 440 441void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) 442{ 443 this->generateFontMetrics(mx, my); 444} 445 446/////////////////////////////////////////////////////////////////////// 447 448void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix) 449{ 450 SkPath path; 451 452 this->getGlyphContext(glyph)->generatePath(glyph, &path); 453 454 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) 455 { 456 // need the path in user-space, with only the point-size applied 457 // so that our stroking and effects will operate the same way they 458 // would if the user had extracted the path themself, and then 459 // called drawPath 460 SkPath localPath; 461 SkMatrix matrix, inverse; 462 463 fRec.getMatrixFrom2x2(&matrix); 464 matrix.invert(&inverse); 465 path.transform(inverse, &localPath); 466 // now localPath is only affected by the paint settings, and not the canvas matrix 467 468 SkScalar width = fRec.fFrameWidth; 469 470 if (fPathEffect) 471 { 472 SkPath effectPath; 473 474 if (fPathEffect->filterPath(&effectPath, localPath, &width)) 475 localPath.swap(effectPath); 476 } 477 478 if (width > 0) 479 { 480 SkStroke stroker; 481 SkPath outline; 482 483 stroker.setWidth(width); 484 stroker.setMiterLimit(fRec.fMiterLimit); 485 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin); 486 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 487 stroker.strokePath(localPath, &outline); 488 localPath.swap(outline); 489 } 490 491 // now return stuff to the caller 492 if (fillToDevMatrix) 493 *fillToDevMatrix = matrix; 494 495 if (devPath) 496 localPath.transform(matrix, devPath); 497 498 if (fillPath) 499 fillPath->swap(localPath); 500 } 501 else // nothing tricky to do 502 { 503 if (fillToDevMatrix) 504 fillToDevMatrix->reset(); 505 506 if (devPath) 507 { 508 if (fillPath == NULL) 509 devPath->swap(path); 510 else 511 *devPath = path; 512 } 513 514 if (fillPath) 515 fillPath->swap(path); 516 } 517 518 if (devPath) 519 devPath->updateBoundsCache(); 520 if (fillPath) 521 fillPath->updateBoundsCache(); 522} 523 524 525void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const 526{ 527 dst->reset(); 528 dst->setScaleX(fPost2x2[0][0]); 529 dst->setSkewX( fPost2x2[0][1]); 530 dst->setSkewY( fPost2x2[1][0]); 531 dst->setScaleY(fPost2x2[1][1]); 532} 533 534void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const 535{ 536 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize); 537 if (fPreSkewX) 538 m->postSkew(fPreSkewX, 0); 539} 540 541void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const 542{ 543 this->getLocalMatrix(m); 544 545 // now concat the device matrix 546 { 547 SkMatrix deviceMatrix; 548 this->getMatrixFrom2x2(&deviceMatrix); 549 m->postConcat(deviceMatrix); 550 } 551} 552 553/////////////////////////////////////////////////////////////////////////////// 554 555#include "SkFontHost.h" 556 557class SkScalerContext_Empty : public SkScalerContext { 558public: 559 SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {} 560 561protected: 562 virtual unsigned generateGlyphCount() const { 563 return 0; 564 } 565 virtual uint16_t generateCharToGlyph(SkUnichar uni) { 566 return 0; 567 } 568 virtual void generateAdvance(SkGlyph* glyph) { 569 glyph->zeroMetrics(); 570 } 571 virtual void generateMetrics(SkGlyph* glyph) { 572 glyph->zeroMetrics(); 573 } 574 virtual void generateImage(const SkGlyph& glyph) {} 575 virtual void generatePath(const SkGlyph& glyph, SkPath* path) {} 576 virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 577 SkPaint::FontMetrics* my) { 578 if (mx) { 579 sk_bzero(mx, sizeof(*mx)); 580 } 581 if (my) { 582 sk_bzero(my, sizeof(*my)); 583 } 584 } 585}; 586 587SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) 588{ 589 SkScalerContext* c = SkFontHost::CreateScalerContext(desc); 590 if (NULL == c) { 591 c = SkNEW_ARGS(SkScalerContext_Empty, (desc)); 592 } 593 return c; 594} 595 596