inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph, const SkPoint& pos, FallbackBlobBuilder* fallback) { // Stick the glyphs we can't draw into the fallback text blob. if (SkMask::kARGB32_Format == glyph.fMaskFormat) { if (!fallback->isInitialized()) { fallback->init(fFont, fTextRatio); } fallback->appendGlyph(glyph.getGlyphID(), pos); } else { fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y()); } }
bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, IDWriteColorGlyphRunEnumerator** colorGlyph) { FLOAT advance = 0; UINT16 glyphId = glyph.getGlyphID(); DWRITE_GLYPH_OFFSET offset; offset.advanceOffset = 0.0f; offset.ascenderOffset = 0.0f; DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; run.fontFace = fTypeface->fDWriteFontFace.get(); run.fontEmSize = SkScalarToFloat(fTextSizeRender); run.bidiLevel = 0; run.glyphIndices = &glyphId; run.isSideways = FALSE; run.glyphOffsets = &offset; HRESULT hr = fFactory2->TranslateColorGlyphRun( 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); if (hr == DWRITE_E_NOCOLOR) { return false; } HRBM(hr, "Failed to translate color glyph run"); return true; }
void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) { SkASSERT(fScaledFont != nullptr); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags); if (err != 0) { memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); return; } prepareGlyph(face->glyph); bool useLcdFilter = face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && isLCD(glyph) && gSetLcdFilter; if (useLcdFilter) { gSetLcdFilter(face->glyph->library, fLcdFilter); } generateGlyphImage(face, glyph); if (useLcdFilter) { gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE); } }
void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* fontCache, GrBatchTextStrike** strike, const SkGlyph& skGlyph, int vx, int vy, GrColor color, GrFontScaler* scaler) { if (!*strike) { *strike = fontCache->getStrike(scaler); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle); GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler); if (!glyph) { return; } int x = vx + glyph->fBounds.fLeft; int y = vy + glyph->fBounds.fTop; // keep them as ints until we've done the clip-test int width = glyph->fBounds.width(); int height = glyph->fBounds.height(); SkRect r; r.fLeft = SkIntToScalar(x); r.fTop = SkIntToScalar(y); r.fRight = r.fLeft + SkIntToScalar(width); r.fBottom = r.fTop + SkIntToScalar(height); blob->appendGlyph(runIndex, r, color, *strike, glyph, scaler, skGlyph, SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false); }
inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { // Stick the glyphs we can't draw into the fallback arrays. if (SkMask::kARGB32_Format == glyph.fMaskFormat) { fFallbackIndices.push_back(glyph.getGlyphID()); fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); } else { // TODO: infer the reserve count from the text length. if (!fDraw) { fDraw = GrPathRangeDraw::Create(fGlyphs, GrPathRendering::kTranslate_PathTransformType, 64); } float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y() }; fDraw->append(glyph.getGlyphID(), translate); } }
inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); this->flush(); } // Stick the glyphs we can't draw at the end of the buffer, growing backwards. int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ? --fFallbackGlyphsIdx : fQueuedGlyphCount++; fGlyphIndices[index] = glyph.getGlyphID(); fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); }
void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) { SkASSERT(fScaledFont != NULL); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags); if (err != 0) { memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); return; } generateGlyphImage(face, 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()); } }
void SkScalerContext_Ascender::generateImage(const SkGlyph& glyph) { aca_GlyphImageRec rec; aca_Vector topLeft; aca_Rasterize(glyph.getGlyphID(), fHandle, &rec, &topLeft); const uint8_t* src = (const uint8_t*)rec.buffer; uint8_t* dst = (uint8_t*)glyph.fImage; int height = glyph.fHeight; src += rec.y0 * rec.pitch + rec.x0; while (--height >= 0) { memcpy(dst, src, glyph.fWidth); src += rec.pitch; dst += glyph.fRowBytes; } }
bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* cache, GrBatchTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, GrColor color, GrFontScaler* scaler, SkScalar textRatio, const SkMatrix& viewMatrix) { if (!*strike) { *strike = cache->getStrike(scaler); } GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), skGlyph.getSubXFixed(), skGlyph.getSubYFixed(), GrGlyph::kDistance_MaskStyle); GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler); if (!glyph) { return true; } // fallback to color glyph support if (kA8_GrMaskFormat != glyph->fMaskFormat) { return false; } SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset); SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset); SkScalar scale = textRatio; dx *= scale; dy *= scale; width *= scale; height *= scale; sx += dx; sy += dy; SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, scaler, skGlyph, sx - dx, sy - dy, scale, true); return true; }
void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) { SkASSERT(fScaledFont != NULL); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); SkASSERT(&glyph && path); uint32_t flags = fLoadGlyphFlags; flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), flags); if (err != 0) { path->reset(); return; } generateGlyphPath(face, path); }
void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); SkASSERT(fDDC); const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; if ((SkMask::kLCD16_Format == fRec.fMaskFormat) || isBW) { HDC dc = CreateCompatibleDC(0); void* bits = 0; int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth; MyBitmapInfo info; sk_bzero(&info, sizeof(info)); if (isBW) { RGBQUAD blackQuad = { 0, 0, 0, 0 }; RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; info.bmiColors[0] = blackQuad; info.bmiColors[1] = whiteQuad; } info.bmiHeader.biSize = sizeof(info.bmiHeader); info.bmiHeader.biWidth = biWidth; info.bmiHeader.biHeight = glyph.fHeight; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = isBW ? 1 : 32; info.bmiHeader.biCompression = BI_RGB; if (isBW) { info.bmiHeader.biClrUsed = 2; } HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0); SelectObject(dc, bm); // erase to white size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2); size_t size = glyph.fHeight * srcRB; memset(bits, isBW ? 0 : 0xFF, size); SetGraphicsMode(dc, GM_ADVANCED); SetBkMode(dc, TRANSPARENT); SetTextAlign(dc, TA_LEFT | TA_BASELINE); XFORM xform = fXform; xform.eDx = (float)-glyph.fLeft; xform.eDy = (float)-glyph.fTop; SetWorldTransform(dc, &xform); HGDIOBJ prevFont = SelectObject(dc, fFont); COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0); SkASSERT(color != CLR_INVALID); uint16_t glyphID = glyph.getGlyphID(); #if defined(UNICODE) ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); #else ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); #endif GdiFlush(); // downsample from rgba to rgb565 int width = glyph.fWidth; size_t dstRB = glyph.rowBytes(); if (isBW) { const uint8_t* src = (const uint8_t*)bits; // gdi's bitmap is upside-down, so we reverse dst walking in Y uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); for (int y = 0; y < glyph.fHeight; y++) { memcpy(dst, src, dstRB); src += srcRB; dst -= dstRB; } } else { // LCD16 const uint32_t* src = (const uint32_t*)bits; // gdi's bitmap is upside-down, so we reverse dst walking in Y uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); for (int y = 0; y < glyph.fHeight; y++) { for (int i = 0; i < width; i++) { dst[i] = rgb_to_lcd16(src[i]); } src = (const uint32_t*)((const char*)src + srcRB); dst = (uint16_t*)((char*)dst - dstRB); } } DeleteDC(dc); DeleteObject(bm); return; }
void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); SkASSERT(fDDC); if (SkMask::kLCD16_Format == fRec.fMaskFormat) { HDC dc = CreateCompatibleDC(0); void* bits = 0; BITMAPINFO info; sk_bzero(&info, sizeof(info)); info.bmiHeader.biSize = sizeof(info.bmiHeader); info.bmiHeader.biWidth = glyph.fWidth; info.bmiHeader.biHeight = glyph.fHeight; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 32; info.bmiHeader.biCompression = BI_RGB; HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0); SelectObject(dc, bm); // erase to white size_t srcRB = glyph.fWidth << 2; size_t size = glyph.fHeight * srcRB; memset(bits, 0xFF, size); SetBkMode(dc, TRANSPARENT); SetTextAlign(dc, TA_LEFT | TA_BASELINE); SetGraphicsMode(dc, GM_ADVANCED); XFORM xform = fXform; xform.eDx = (float)-glyph.fLeft; xform.eDy = (float)-glyph.fTop; SetWorldTransform(dc, &xform); HGDIOBJ prevFont = SelectObject(dc, fFont); COLORREF color = SetTextColor(dc, 0); // black SkASSERT(color != CLR_INVALID); uint16_t glyphID = glyph.getGlyphID(); ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); GdiFlush(); // downsample from rgba to rgb565 int width = glyph.fWidth; size_t dstRB = glyph.rowBytes(); const uint32_t* src = (const uint32_t*)bits; // gdi's bitmap is upside-down, so we reverse dst walking in Y uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); for (int y = 0; y < glyph.fHeight; y++) { for (int i = 0; i < width; i++) { dst[i] = rgb_to_lcd16(src[i]); } src = (const uint32_t*)((const char*)src + srcRB); dst = (uint16_t*)((char*)dst - dstRB); } DeleteDC(dc); DeleteObject(bm); return; } GLYPHMETRICS gm; memset(&gm, 0, sizeof(gm)); uint32_t bytecount = 0; uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); if (GDI_ERROR != total_size && total_size > 0) { uint8_t *pBuff = new uint8_t[total_size]; if (NULL != pBuff) { total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22); SkASSERT(total_size != GDI_ERROR); SkASSERT(glyph.fWidth == gm.gmBlackBoxX); SkASSERT(glyph.fHeight == gm.gmBlackBoxY); uint8_t* dst = (uint8_t*)glyph.fImage; uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3; if (pitch != glyph.rowBytes()) { SkASSERT(false); // glyph.fImage has different rowsize!? } for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) { uint8_t* src = pBuff + pitch * y; for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) { if (*src > 63) { *dst = 0xFF; } else { *dst = *src << 2; // scale to 0-255 } dst++; src++; bytecount++; } memset(dst, 0, glyph.rowBytes() - glyph.fWidth); dst += glyph.rowBytes() - glyph.fWidth; } delete[] pBuff; } } SkASSERT(GDI_ERROR != total_size && total_size >= 0); }