uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { unsigned glyphID = this->generateCharToGlyph(uni); if (0 == glyphID) { // try auxcontext SkScalerContext* ctx = this->loadAuxContext(); if (NULL != ctx) { glyphID = ctx->generateCharToGlyph(uni); if (0 != glyphID) { // only fiddle with it if its not missing glyphID += this->getGlyphCount(); if (glyphID > 0xFFFF) { glyphID = 0; } } } } #ifdef TRACK_MISSING_CHARS if (0 == glyphID) { bool announce = false; if (uni > 0xFFFF) { // we don't record these announce = true; } else { unsigned index = uni >> 3; unsigned mask = 1 << (uni & 7); SkASSERT(index < SK_ARRAY_COUNT(gMissingChars)); if ((gMissingChars[index] & mask) == 0) { gMissingChars[index] |= mask; announce = true; } } if (announce) { printf(">>> MISSING CHAR <<< 0x%04X\n", uni); } }
void SkGScalerContext::generateMetrics(SkGlyph* glyph) { fProxy->getMetrics(glyph); SkVector advance; fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFloat(advance.fX); glyph->fAdvanceY = SkScalarToFloat(advance.fY); SkPath path; fProxy->getPath(*glyph, &path); path.transform(fMatrix); SkRect storage; const SkPaint& paint = fFace->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); glyph->fMaskFormat = SkMask::kARGB32_Format; }
SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni, unsigned& glyphID) { SkScalerContext* ctx = this; for (;;) { glyphID = ctx->generateCharToGlyph(uni); if (glyphID) { break; // found it } ctx = ctx->getNextContext(); if (NULL == ctx) { return NULL; } } return ctx; }
SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) { SkScalerContext* ctx = this; unsigned rangeEnd = 0; do { unsigned rangeStart = rangeEnd; rangeEnd += ctx->getGlyphCount(); if (rangeStart <= glyphID && glyphID < rangeEnd) { return ctx->generateGlyphToChar(glyphID - rangeStart); } ctx = ctx->getNextContext(); } while (NULL != ctx); return 0; }
/* Return the next context, creating it if its not already created, but return NULL if the fonthost says there are no more fonts to fallback to. */ SkScalerContext* SkScalerContext::getNextContext() { SkScalerContext* next = fNextContext; // if next is null, then either it isn't cached yet, or we're at the // end of our possible chain if (NULL == next) { next = allocNextContext(fRec); if (NULL == next) { return NULL; } // next's base is our base + our local count next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); // cache the answer fNextContext = next; } return next; }
/* This loops through all available fallback contexts (if needed) until it finds some context that can handle the unichar and return it. As this is somewhat expensive operation, it should only be done on the first char of a run. */ unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) { SkScalerContext* ctx = this; unsigned glyphID; for (;;) { glyphID = ctx->generateCharToGlyph(uni); if (glyphID) { break; // found it } ctx = ctx->getNextContext(); if (NULL == ctx) { SkDebugf("--- no context for char %x\n", uni); // just return the original context (this) return this->fBaseGlyphCount; } } return ctx->fBaseGlyphCount; }
void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) { fProxy->getAdvance(glyph); SkVector advance; fMatrix.mapXY(SkFixedToScalar(glyph->fAdvanceX), SkFixedToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFixed(advance.fX); glyph->fAdvanceY = SkScalarToFixed(advance.fY); SkPath path; fProxy->getPath(*glyph, &path); path.transform(fMatrix); SkRect storage; const SkPaint& paint = fFace->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); // Here we will change the mask format of the glyph // NOTE this is being overridden by the base class SkMask::Format format; switch (glyph->getGlyphID() % 6) { case 0: format = SkMask::kLCD16_Format; break; case 1: format = SkMask::kA8_Format; break; case 2: format = SkMask::kARGB32_Format; break; default: // we will fiddle with these in generate image format = (SkMask::Format)MASK_FORMAT_UNKNOWN; } glyph->fMaskFormat = format; }
SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { unsigned glyphID = glyph.getGlyphID(); SkScalerContext* ctx = this; for (;;) { unsigned count = ctx->getGlyphCount(); if (glyphID < count) { break; } glyphID -= count; ctx = ctx->getNextContext(); if (NULL == ctx) { SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); // just return the original context (this) return this; } } return ctx; }
SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni, uint16_t* glyphID) { SkScalerContext* ctx = this; for (;;) { const uint16_t glyph = ctx->generateCharToGlyph(uni); if (glyph) { if (NULL != glyphID) { *glyphID = glyph; } break; // found it } ctx = ctx->getNextContext(); if (NULL == ctx) { return NULL; } } return ctx; }
void SkGScalerContext::generateAdvance(SkGlyph* glyph) { fProxy->getAdvance(glyph); SkVector advance; fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFloat(advance.fX); glyph->fAdvanceY = SkScalarToFloat(advance.fY); }
void SkGScalerContext::generateImage(const SkGlyph& glyph) { if (SkMask::kARGB32_Format == glyph.fMaskFormat) { SkPath path; fProxy->getPath(glyph, &path); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), glyph.fImage, glyph.rowBytes()); bm.eraseColor(0); SkCanvas canvas(bm); canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); canvas.concat(fMatrix); canvas.drawPath(path, fFace->paint()); } else { fProxy->getImage(glyph); } }
void SkRandomScalerContext::generateImage(const SkGlyph& glyph) { SkMask::Format format = (SkMask::Format)glyph.fMaskFormat; switch (glyph.getGlyphID() % 4) { case 0: format = SkMask::kLCD16_Format; break; case 1: format = SkMask::kA8_Format; break; case 2: format = SkMask::kARGB32_Format; break; case 3: format = SkMask::kBW_Format; break; } const_cast<SkGlyph&>(glyph).fMaskFormat = format; // if the format is ARGB, we just draw the glyph from path ourselves. Otherwise, we force // our proxy context to generate the image from paths. if (!fFakeIt) { if (SkMask::kARGB32_Format == glyph.fMaskFormat) { SkPath path; fProxy->getPath(glyph, &path); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight), glyph.fImage, glyph.rowBytes()); bm.eraseColor(0); SkCanvas canvas(bm); canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); canvas.drawPath(path, fFace->paint()); } else { fProxy->forceGenerateImageFromPath(); fProxy->getImage(glyph); fProxy->forceOffGenerateImageFromPath(); } } else { sk_bzero(glyph.fImage, glyph.computeImageSize()); } }
/* This loops through all available fallback contexts (if needed) until it finds some context that can handle the unichar. If all fail, returns 0 */ uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { SkScalerContext* ctx = this; unsigned glyphID; for (;;) { glyphID = ctx->generateCharToGlyph(uni); if (glyphID) { break; // found it } ctx = ctx->getNextContext(); if (NULL == ctx) { return 0; // no more contexts, return missing glyph } } // add the ctx's base, making glyphID unique for chain of contexts glyphID += ctx->fBaseGlyphCount; // check for overflow of 16bits, since our glyphID cannot exceed that if (glyphID > 0xFFFF) { glyphID = 0; } return SkToU16(glyphID); }
void SkGScalerContext::generateFontMetrics(SkPaint::FontMetrics* metrics) { fProxy->getFontMetrics(metrics); if (metrics) { SkScalar scale = fMatrix.getScaleY(); metrics->fTop = SkScalarMul(metrics->fTop, scale); metrics->fAscent = SkScalarMul(metrics->fAscent, scale); metrics->fDescent = SkScalarMul(metrics->fDescent, scale); metrics->fBottom = SkScalarMul(metrics->fBottom, scale); metrics->fLeading = SkScalarMul(metrics->fLeading, scale); metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale); metrics->fXMin = SkScalarMul(metrics->fXMin, scale); metrics->fXMax = SkScalarMul(metrics->fXMax, scale); metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale); } }
void SkRandomScalerContext::generateFontMetrics(SkPaint::FontMetrics* metrics) { fProxy->getFontMetrics(metrics); }
void SkGScalerContext::generatePath(const SkGlyph& glyph, SkPath* path) { fProxy->getPath(glyph, path); path->transform(fMatrix); }
void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) { // Here we will change the mask format of the glyph // NOTE this is being overridden by the base class SkMask::Format format = SkMask::kARGB32_Format; // init to handle defective compilers switch (glyph->getGlyphID() % 4) { case 0: format = SkMask::kLCD16_Format; break; case 1: format = SkMask::kA8_Format; break; case 2: format = SkMask::kARGB32_Format; break; case 3: format = SkMask::kBW_Format; break; } fProxy->getMetrics(glyph); glyph->fMaskFormat = format; if (fFakeIt) { return; } if (SkMask::kARGB32_Format == format) { SkPath path; fProxy->getPath(*glyph, &path); SkRect storage; const SkPaint& paint = fFace->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); } else { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); // just use devPath const SkIRect ir = devPath.getBounds().roundOut(); if (ir.isEmpty() || !ir.is16Bit()) { glyph->fLeft = 0; glyph->fTop = 0; glyph->fWidth = 0; glyph->fHeight = 0; return; } glyph->fLeft = ir.fLeft; glyph->fTop = ir.fTop; glyph->fWidth = SkToU16(ir.width()); glyph->fHeight = SkToU16(ir.height()); if (glyph->fWidth > 0) { switch (glyph->fMaskFormat) { case SkMask::kLCD16_Format: glyph->fWidth += 2; glyph->fLeft -= 1; break; default: break; } } } }
void SkRandomScalerContext::generateAdvance(SkGlyph* glyph) { fProxy->getAdvance(glyph); }
uint16_t SkRandomScalerContext::generateCharToGlyph(SkUnichar uni) { return fProxy->charToGlyphID(uni); }
unsigned SkRandomScalerContext::generateGlyphCount() { return fProxy->getGlyphCount(); }
void SkRandomScalerContext::generatePath(const SkGlyph& glyph, SkPath* path) { fProxy->getPath(glyph, path); }