SkScalerContext.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
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 = 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 55#ifdef SK_DEBUG 56 #define DUMP_RECx 57#endif 58 59static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) { 60 SkFlattenable* obj = NULL; 61 uint32_t len; 62 const void* data = desc->findEntry(tag, &len); 63 64 if (data) { 65 SkFlattenableReadBuffer buffer(data, len); 66 obj = buffer.readFlattenable(); 67 SkASSERT(buffer.offset() == buffer.size()); 68 } 69 return obj; 70} 71 72SkScalerContext::SkScalerContext(const SkDescriptor* desc) 73 : fPathEffect(NULL), fMaskFilter(NULL) 74{ 75 static bool gHaveGammaTables; 76 if (!gHaveGammaTables) { 77 const uint8_t* tables[2]; 78 SkFontHost::GetGammaTables(tables); 79 gBlackGammaTable = tables[0]; 80 gWhiteGammaTable = tables[1]; 81 gHaveGammaTables = true; 82 } 83 84 fBaseGlyphCount = 0; 85 fAuxScalerContext = NULL; 86 87 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL); 88 SkASSERT(rec); 89 90 fRec = *rec; 91 92#ifdef DUMP_REC 93 desc->assertChecksum(); 94 SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecksum(), desc->getCount(), desc->getLength()); 95 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", 96 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], 97 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); 98 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", 99 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, 100 rec->fMaskFormat, rec->fStrokeJoin); 101 SkDebugf(" pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDescriptorTag, NULL), 102 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); 103#endif 104 105 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag); 106 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag); 107 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag); 108} 109 110SkScalerContext::~SkScalerContext() { 111 fPathEffect->safeUnref(); 112 fMaskFilter->safeUnref(); 113 fRasterizer->safeUnref(); 114 115 SkDELETE(fAuxScalerContext); 116} 117 118SkScalerContext* SkScalerContext::loadAuxContext() const { 119 if (NULL == fAuxScalerContext) { 120 fAuxScalerContext = SkFontHost::CreateFallbackScalerContext(fRec); 121 if (NULL != fAuxScalerContext) { 122 fAuxScalerContext->setBaseGlyphCount(this->getGlyphCount()); 123 } 124 } 125 return fAuxScalerContext; 126} 127 128#ifdef TRACK_MISSING_CHARS 129 static uint8_t gMissingChars[1 << 13]; 130#endif 131 132uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { 133 unsigned glyphID = this->generateCharToGlyph(uni); 134 135 if (0 == glyphID) { // try auxcontext 136 SkScalerContext* ctx = this->loadAuxContext(); 137 if (NULL != ctx) { 138 glyphID = ctx->generateCharToGlyph(uni); 139 if (0 != glyphID) { // only fiddle with it if its not missing 140 glyphID += this->getGlyphCount(); 141 if (glyphID > 0xFFFF) { 142 glyphID = 0; 143 } 144 } 145 } 146 } 147#ifdef TRACK_MISSING_CHARS 148 if (0 == glyphID) { 149 bool announce = false; 150 if (uni > 0xFFFF) { // we don't record these 151 announce = true; 152 } else { 153 unsigned index = uni >> 3; 154 unsigned mask = 1 << (uni & 7); 155 SkASSERT(index < SK_ARRAY_COUNT(gMissingChars)); 156 if ((gMissingChars[index] & mask) == 0) { 157 gMissingChars[index] |= mask; 158 announce = true; 159 } 160 } 161 if (announce) { 162 printf(">>> MISSING CHAR <<< 0x%04X\n", uni); 163 } 164 } 165#endif 166 return SkToU16(glyphID); 167} 168 169/* Internal routine to resolve auxContextID into a real context. 170 Only makes sense to call once the glyph has been given a 171 valid auxGlyphID. 172*/ 173SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const { 174 SkScalerContext* ctx = const_cast<SkScalerContext*>(this); 175 176 if (glyph.getGlyphID() >= this->getGlyphCount()) { 177 ctx = this->loadAuxContext(); 178 if (NULL == ctx) { // if no aux, just return us 179 ctx = const_cast<SkScalerContext*>(this); 180 } 181 } 182 return ctx; 183} 184 185static int plus_minus_pin(int value, int max) { 186 SkASSERT(max >= 0); 187 188 if (value > max) { 189 value = max; 190 } else if (value < -max) { 191 value = -max; 192 } 193 return value; 194} 195 196void SkScalerContext::getAdvance(SkGlyph* glyph) { 197 // mark us as just having a valid advance 198 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 199 // we mark the format before making the call, in case the impl 200 // internally ends up calling its generateMetrics, which is OK 201 // albeit slower than strictly necessary 202 this->getGlyphContext(*glyph)->generateAdvance(glyph); 203} 204 205void SkScalerContext::getMetrics(SkGlyph* glyph) { 206 this->getGlyphContext(*glyph)->generateMetrics(glyph); 207 208 // for now we have separate cache entries for devkerning on and off 209 // in the future we might share caches, but make our measure/draw 210 // code make the distinction. Thus we zap the values if the caller 211 // has not asked for them. 212 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 213 // no devkern, so zap the fields 214 glyph->fLsbDelta = glyph->fRsbDelta = 0; 215 } 216 217 // if either dimension is empty, zap the image bounds of the glyph 218 if (0 == glyph->fWidth || 0 == glyph->fHeight) { 219 glyph->fWidth = 0; 220 glyph->fHeight = 0; 221 glyph->fTop = 0; 222 glyph->fLeft = 0; 223 glyph->fMaskFormat = 0; 224 return; 225 } 226 227 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 228 SkPath devPath, fillPath; 229 SkMatrix fillToDevMatrix; 230 231 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 232 233 if (fRasterizer) { 234 SkMask mask; 235 236 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 237 fMaskFilter, &mask, 238 SkMask::kJustComputeBounds_CreateMode)) { 239 glyph->fLeft = mask.fBounds.fLeft; 240 glyph->fTop = mask.fBounds.fTop; 241 glyph->fWidth = SkToU16(mask.fBounds.width()); 242 glyph->fHeight = SkToU16(mask.fBounds.height()); 243 } else { 244 // draw nothing 'cause we failed 245 glyph->fLeft = 0; 246 glyph->fTop = 0; 247 glyph->fWidth = 0; 248 glyph->fHeight = 0; 249 return; 250 } 251 } else { 252 // just use devPath 253 SkRect r; 254 SkIRect ir; 255 256 devPath.computeBounds(&r, SkPath::kExact_BoundsType); 257 r.roundOut(&ir); 258 259 glyph->fLeft = ir.fLeft; 260 glyph->fTop = ir.fTop; 261 glyph->fWidth = SkToU16(ir.width()); 262 glyph->fHeight = SkToU16(ir.height()); 263 } 264 } 265 266 glyph->fMaskFormat = fRec.fMaskFormat; 267 268 if (fMaskFilter) { 269 SkMask src, dst; 270 SkMatrix matrix; 271 272 glyph->toMask(&src); 273 fRec.getMatrixFrom2x2(&matrix); 274 275 src.fImage = NULL; // only want the bounds from the filter 276 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 277 SkASSERT(dst.fImage == NULL); 278 glyph->fLeft = dst.fBounds.fLeft; 279 glyph->fTop = dst.fBounds.fTop; 280 glyph->fWidth = SkToU16(dst.fBounds.width()); 281 glyph->fHeight = SkToU16(dst.fBounds.height()); 282 glyph->fMaskFormat = dst.fFormat; 283 } 284 } 285} 286 287void SkScalerContext::getImage(const SkGlyph& origGlyph) { 288 const SkGlyph* glyph = &origGlyph; 289 SkGlyph tmpGlyph; 290 291 if (fMaskFilter) { // restore the prefilter bounds 292 tmpGlyph.fID = origGlyph.fID; 293 294 // need the original bounds, sans our maskfilter 295 SkMaskFilter* mf = fMaskFilter; 296 fMaskFilter = NULL; // temp disable 297 this->getMetrics(&tmpGlyph); 298 fMaskFilter = mf; // restore 299 300 tmpGlyph.fImage = origGlyph.fImage; 301 302 // we need the prefilter bounds to be <= filter bounds 303 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 304 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 305 glyph = &tmpGlyph; 306 } 307 308 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { 309 SkPath devPath, fillPath; 310 SkMatrix fillToDevMatrix; 311 312 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 313 314 if (fRasterizer) { 315 SkMask mask; 316 317 glyph->toMask(&mask); 318 mask.fFormat = SkMask::kA8_Format; 319 bzero(glyph->fImage, mask.computeImageSize()); 320 321 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 322 fMaskFilter, &mask, 323 SkMask::kJustRenderImage_CreateMode)) { 324 return; 325 } 326 } else { 327 SkBitmap bm; 328 SkBitmap::Config config; 329 SkMatrix matrix; 330 SkRegion clip; 331 SkPaint paint; 332 SkDraw draw; 333 334 if (SkMask::kA8_Format == fRec.fMaskFormat) { 335 config = SkBitmap::kA8_Config; 336 paint.setAntiAlias(true); 337 } else { 338 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); 339 config = SkBitmap::kA1_Config; 340 paint.setAntiAlias(false); 341 } 342 343 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); 344 matrix.setTranslate(-SkIntToScalar(glyph->fLeft), 345 -SkIntToScalar(glyph->fTop)); 346 bm.setConfig(config, glyph->fWidth, glyph->fHeight, 347 glyph->rowBytes()); 348 bm.setPixels(glyph->fImage); 349 bzero(glyph->fImage, bm.height() * bm.rowBytes()); 350 351 draw.fClip = &clip; 352 draw.fMatrix = &matrix; 353 draw.fBitmap = &bm; 354 draw.fBounder = NULL; 355 draw.drawPath(devPath, paint); 356 } 357 } else { 358 this->getGlyphContext(*glyph)->generateImage(*glyph); 359 } 360 361 if (fMaskFilter) { 362 SkMask srcM, dstM; 363 SkMatrix matrix; 364 365 // the src glyph image shouldn't be 3D 366 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 367 glyph->toMask(&srcM); 368 fRec.getMatrixFrom2x2(&matrix); 369 370 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 371 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 372 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 373 int dstRB = origGlyph.rowBytes(); 374 int srcRB = dstM.fRowBytes; 375 376 const uint8_t* src = (const uint8_t*)dstM.fImage; 377 uint8_t* dst = (uint8_t*)origGlyph.fImage; 378 379 if (SkMask::k3D_Format == dstM.fFormat) { 380 // we have to copy 3 times as much 381 height *= 3; 382 } 383 384 // clean out our glyph, since it may be larger than dstM 385 //bzero(dst, height * dstRB); 386 387 while (--height >= 0) { 388 memcpy(dst, src, width); 389 src += srcRB; 390 dst += dstRB; 391 } 392 SkMask::FreeImage(dstM.fImage); 393 } 394 } 395 396 // check to see if we should filter the alpha channel 397 398 if (NULL == fMaskFilter && 399 fRec.fMaskFormat != SkMask::kBW_Format && 400 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) 401 { 402 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; 403 if (NULL != table) 404 { 405 uint8_t* dst = (uint8_t*)origGlyph.fImage; 406 unsigned rowBytes = origGlyph.rowBytes(); 407 408 for (int y = origGlyph.fHeight - 1; y >= 0; --y) 409 { 410 for (int x = origGlyph.fWidth - 1; x >= 0; --x) 411 dst[x] = table[dst[x]]; 412 dst += rowBytes; 413 } 414 } 415 } 416} 417 418void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) 419{ 420 this->internalGetPath(glyph, NULL, path, NULL); 421} 422 423void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) 424{ 425 this->generateFontMetrics(mx, my); 426} 427 428/////////////////////////////////////////////////////////////////////// 429 430void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix) 431{ 432 SkPath path; 433 434 this->getGlyphContext(glyph)->generatePath(glyph, &path); 435 436 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) 437 { 438 // need the path in user-space, with only the point-size applied 439 // so that our stroking and effects will operate the same way they 440 // would if the user had extracted the path themself, and then 441 // called drawPath 442 SkPath localPath; 443 SkMatrix matrix, inverse; 444 445 fRec.getMatrixFrom2x2(&matrix); 446 matrix.invert(&inverse); 447 path.transform(inverse, &localPath); 448 // now localPath is only affected by the paint settings, and not the canvas matrix 449 450 SkScalar width = fRec.fFrameWidth; 451 452 if (fPathEffect) 453 { 454 SkPath effectPath; 455 456 if (fPathEffect->filterPath(&effectPath, localPath, &width)) 457 localPath.swap(effectPath); 458 } 459 460 if (width > 0) 461 { 462 SkStroke stroker; 463 SkPath outline; 464 465 stroker.setWidth(width); 466 stroker.setMiterLimit(fRec.fMiterLimit); 467 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin); 468 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 469 stroker.strokePath(localPath, &outline); 470 localPath.swap(outline); 471 } 472 473 // now return stuff to the caller 474 if (fillToDevMatrix) 475 *fillToDevMatrix = matrix; 476 477 if (devPath) 478 localPath.transform(matrix, devPath); 479 480 if (fillPath) 481 fillPath->swap(localPath); 482 } 483 else // nothing tricky to do 484 { 485 if (fillToDevMatrix) 486 fillToDevMatrix->reset(); 487 488 if (devPath) 489 { 490 if (fillPath == NULL) 491 devPath->swap(path); 492 else 493 *devPath = path; 494 } 495 496 if (fillPath) 497 fillPath->swap(path); 498 } 499 500 if (devPath) 501 devPath->updateBoundsCache(); 502 if (fillPath) 503 fillPath->updateBoundsCache(); 504} 505 506 507void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const 508{ 509 dst->reset(); 510 dst->setScaleX(fPost2x2[0][0]); 511 dst->setSkewX( fPost2x2[0][1]); 512 dst->setSkewY( fPost2x2[1][0]); 513 dst->setScaleY(fPost2x2[1][1]); 514} 515 516void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const 517{ 518 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize); 519 if (fPreSkewX) 520 m->postSkew(fPreSkewX, 0); 521} 522 523void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const 524{ 525 this->getLocalMatrix(m); 526 527 // now concat the device matrix 528 { 529 SkMatrix deviceMatrix; 530 this->getMatrixFrom2x2(&deviceMatrix); 531 m->postConcat(deviceMatrix); 532 } 533} 534 535#include "SkFontHost.h" 536 537SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) 538{ 539 return SkFontHost::CreateScalerContext(desc); 540} 541 542