SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { SkGlyph* glyph; int hi = 0; int count = fGlyphArray.count(); if (count) { SkGlyph** gptr = fGlyphArray.begin(); int lo = 0; hi = count - 1; while (lo < hi) { int mid = (hi + lo) >> 1; if (gptr[mid]->fID < id) { lo = mid + 1; } else { hi = mid; } } glyph = gptr[hi]; if (glyph->fID == id) { if (kFull_MetricsType == mtype && glyph->isJustAdvance()) { fScalerContext->getMetrics(glyph); } return glyph; } // check if we need to bump hi before falling though to the allocator if (glyph->fID < id) { hi += 1; } } // not found, but hi tells us where to inser the new glyph fMemoryUsed += sizeof(SkGlyph); glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph), SkChunkAlloc::kThrow_AllocFailType); glyph->init(id); *fGlyphArray.insert(hi) = glyph; if (kJustAdvance_MetricsType == mtype) { fScalerContext->getAdvance(glyph); } else { SkASSERT(kFull_MetricsType == mtype); fScalerContext->getMetrics(glyph); } return glyph; }
void SkScalerContext::getImage(const SkGlyph& origGlyph) { const SkGlyph* glyph = &origGlyph; SkGlyph tmpGlyph; if (fMaskFilter) { // restore the prefilter bounds tmpGlyph.init(origGlyph.fID); // need the original bounds, sans our maskfilter SkMaskFilter* mf = fMaskFilter; fMaskFilter = NULL; // temp disable this->getMetrics(&tmpGlyph); fMaskFilter = mf; // restore tmpGlyph.fImage = origGlyph.fImage; // we need the prefilter bounds to be <= filter bounds SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); glyph = &tmpGlyph; } if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); if (fRasterizer) { SkMask mask; glyph->toMask(&mask); mask.fFormat = SkMask::kA8_Format; sk_bzero(glyph->fImage, mask.computeImageSize()); if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, fMaskFilter, &mask, SkMask::kJustRenderImage_CreateMode)) { return; } } else { SkBitmap bm; SkBitmap::Config config; SkMatrix matrix; SkRegion clip; SkPaint paint; SkDraw draw; if (SkMask::kA8_Format == fRec.fMaskFormat) { config = SkBitmap::kA8_Config; paint.setAntiAlias(true); } else { SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); config = SkBitmap::kA1_Config; paint.setAntiAlias(false); } clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); matrix.setTranslate(-SkIntToScalar(glyph->fLeft), -SkIntToScalar(glyph->fTop)); bm.setConfig(config, glyph->fWidth, glyph->fHeight, glyph->rowBytes()); bm.setPixels(glyph->fImage); sk_bzero(glyph->fImage, bm.height() * bm.rowBytes()); draw.fClip = &clip; draw.fMatrix = &matrix; draw.fBitmap = &bm; draw.fBounder = NULL; draw.drawPath(devPath, paint); } } else { this->getGlyphContext(*glyph)->generateImage(*glyph); } if (fMaskFilter) { SkMask srcM, dstM; SkMatrix matrix; // the src glyph image shouldn't be 3D SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); glyph->toMask(&srcM); fRec.getMatrixFrom2x2(&matrix); if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); int dstRB = origGlyph.rowBytes(); int srcRB = dstM.fRowBytes; const uint8_t* src = (const uint8_t*)dstM.fImage; uint8_t* dst = (uint8_t*)origGlyph.fImage; if (SkMask::k3D_Format == dstM.fFormat) { // we have to copy 3 times as much height *= 3; } // clean out our glyph, since it may be larger than dstM //sk_bzero(dst, height * dstRB); while (--height >= 0) { memcpy(dst, src, width); src += srcRB; dst += dstRB; } SkMask::FreeImage(dstM.fImage); } } // check to see if we should filter the alpha channel if (NULL == fMaskFilter && fRec.fMaskFormat != SkMask::kBW_Format && fRec.fMaskFormat != SkMask::kLCD16_Format && fRec.fMaskFormat != SkMask::kLCD32_Format && (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) { const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; if (NULL != table) { uint8_t* dst = (uint8_t*)origGlyph.fImage; unsigned rowBytes = origGlyph.rowBytes(); for (int y = origGlyph.fHeight - 1; y >= 0; --y) { for (int x = origGlyph.fWidth - 1; x >= 0; --x) { dst[x] = table[dst[x]]; } dst += rowBytes; } } } }
void SkScalerContext::getImage(const SkGlyph& origGlyph) { const SkGlyph* glyph = &origGlyph; SkGlyph tmpGlyph; if (fMaskFilter) { // restore the prefilter bounds tmpGlyph.init(origGlyph.fID); // need the original bounds, sans our maskfilter SkMaskFilter* mf = fMaskFilter; fMaskFilter = NULL; // temp disable this->getMetrics(&tmpGlyph); fMaskFilter = mf; // restore tmpGlyph.fImage = origGlyph.fImage; // we need the prefilter bounds to be <= filter bounds SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); glyph = &tmpGlyph; } if (fGenerateImageFromPath) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; SkMask mask; this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); glyph->toMask(&mask); if (fRasterizer) { mask.fFormat = SkMask::kA8_Format; sk_bzero(glyph->fImage, mask.computeImageSize()); if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, fMaskFilter, &mask, SkMask::kJustRenderImage_CreateMode)) { return; } } else { generateMask(mask, devPath); } } else { this->getGlyphContext(*glyph)->generateImage(*glyph); } if (fMaskFilter) { SkMask srcM, dstM; SkMatrix matrix; // the src glyph image shouldn't be 3D SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); glyph->toMask(&srcM); fRec.getMatrixFrom2x2(&matrix); if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); int dstRB = origGlyph.rowBytes(); int srcRB = dstM.fRowBytes; const uint8_t* src = (const uint8_t*)dstM.fImage; uint8_t* dst = (uint8_t*)origGlyph.fImage; if (SkMask::k3D_Format == dstM.fFormat) { // we have to copy 3 times as much height *= 3; } // clean out our glyph, since it may be larger than dstM //sk_bzero(dst, height * dstRB); while (--height >= 0) { memcpy(dst, src, width); src += srcRB; dst += dstRB; } SkMask::FreeImage(dstM.fImage); } } }
void SkScalerContext::getImage(const SkGlyph& origGlyph) { const SkGlyph* glyph = &origGlyph; SkGlyph tmpGlyph; // in case we need to call generateImage on a mask-format that is different // (i.e. larger) than what our caller allocated by looking at origGlyph. SkAutoMalloc tmpGlyphImageStorage; // If we are going to draw-from-path, then we cannot generate color, since // the path only makes a mask. This case should have been caught up in // generateMetrics(). SkASSERT(!fGenerateImageFromPath || SkMask::kARGB32_Format != origGlyph.fMaskFormat); if (fMaskFilter) { // restore the prefilter bounds tmpGlyph.init(origGlyph.fID); // need the original bounds, sans our maskfilter SkMaskFilter* mf = fMaskFilter; fMaskFilter = NULL; // temp disable this->getMetrics(&tmpGlyph); fMaskFilter = mf; // restore // we need the prefilter bounds to be <= filter bounds SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) { tmpGlyph.fImage = origGlyph.fImage; } else { tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize()); tmpGlyph.fImage = tmpGlyphImageStorage.get(); } glyph = &tmpGlyph; } if (fGenerateImageFromPath) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; SkMask mask; this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); glyph->toMask(&mask); if (fRasterizer) { mask.fFormat = SkMask::kA8_Format; sk_bzero(glyph->fImage, mask.computeImageSize()); if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, fMaskFilter, &mask, SkMask::kJustRenderImage_CreateMode)) { return; } if (fPreBlend.isApplicable()) { applyLUTToA8Mask(mask, fPreBlend.fG); } } else { SkASSERT(SkMask::kARGB32_Format != mask.fFormat); generateMask(mask, devPath, fPreBlend); } } else { generateImage(*glyph); } if (fMaskFilter) { SkMask srcM, dstM; SkMatrix matrix; // the src glyph image shouldn't be 3D SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); SkAutoSMalloc<32*32> a8storage; glyph->toMask(&srcM); if (SkMask::kARGB32_Format == srcM.fFormat) { // now we need to extract the alpha-channel from the glyph's image // and copy it into a temp buffer, and then point srcM at that temp. srcM.fFormat = SkMask::kA8_Format; srcM.fRowBytes = SkAlign4(srcM.fBounds.width()); size_t size = srcM.computeImageSize(); a8storage.reset(size); srcM.fImage = (uint8_t*)a8storage.get(); extract_alpha(srcM, (const SkPMColor*)glyph->fImage, glyph->rowBytes()); } fRec.getMatrixFrom2x2(&matrix); if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); int dstRB = origGlyph.rowBytes(); int srcRB = dstM.fRowBytes; const uint8_t* src = (const uint8_t*)dstM.fImage; uint8_t* dst = (uint8_t*)origGlyph.fImage; if (SkMask::k3D_Format == dstM.fFormat) { // we have to copy 3 times as much height *= 3; } // clean out our glyph, since it may be larger than dstM //sk_bzero(dst, height * dstRB); while (--height >= 0) { memcpy(dst, src, width); src += srcRB; dst += dstRB; } SkMask::FreeImage(dstM.fImage); if (fPreBlendForFilter.isApplicable()) { applyLUTToA8Mask(srcM, fPreBlendForFilter.fG); } } } }