static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags) { SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkAutoMalloc storage(numGlyphs * (sizeof(SkScalar) + sizeof(uint16_t))); SkScalar* scalarWidths = reinterpret_cast<SkScalar*>(storage.get()); uint16_t* glyphs16 = reinterpret_cast<uint16_t*>(scalarWidths + numGlyphs); // convert HB 32bit glyphs to skia's 16bit for (hb_uint32 i = 0; i < numGlyphs; ++i) { glyphs16[i] = SkToU16(glyphs[i]); } paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarWidths); for (hb_uint32 i = 0; i < numGlyphs; ++i) { advances[i] = SkScalarToHarfbuzzFixed(scalarWidths[i]); } }
static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkScalar width; SkRect bounds; paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft); metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop); metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width()); metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height()); metrics->xOffset = SkiaScalarToHarfbuzzFixed(width); // We can't actually get the |y| correct because Skia doesn't export // the vertical advance. However, nor we do ever render vertical text at // the moment so it's unimportant. metrics->yOffset = 0; }
int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { SkPaint paint; int count = run.length(); SkAutoSTMalloc<64, SkScalar> storage(count); SkScalar* widths = storage.get(); primaryFont()->platformData().setupPaint(&paint); count = paint.getTextWidths(run.characters(), count << 1, widths); if (count > 0) { SkScalar pos = 0; for (int i = 0; i < count; i++) { if (x < SkScalarRound(pos + SkScalarHalf(widths[i]))) return i; pos += widths[i]; } } return count; }
TextBench(void* param, const char text[], int ps, SkColor color, FontQuality fq, bool doPos = false) : INHERITED(param) { fFQ = fq; fDoPos = doPos; fText.set(text); fPaint.setAntiAlias(kBW != fq); fPaint.setLCDRenderText(kLCD == fq); fPaint.setTextSize(SkIntToScalar(ps)); fPaint.setColor(color); if (doPos) { size_t len = strlen(text); SkScalar* adv = new SkScalar[len]; fPaint.getTextWidths(text, len, adv); fPos = new SkPoint[len]; SkScalar x = 0; for (size_t i = 0; i < len; ++i) { fPos[i].set(x, SkIntToScalar(50)); x += adv[i]; } delete[] adv; } }
virtual void onDraw(SkCanvas* canvas) { // explicitly add spaces, to test a prev. bug const char* text = "Ham bur ge fons"; int len = SkToInt(strlen(text)); SkPath path; SkPaint paint; paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); paint.setTextSize(SkIntToScalar(48)); canvas->translate(SkIntToScalar(10), SkIntToScalar(64)); canvas->drawText(text, len, 0, 0, paint); paint.getTextPath(text, len, 0, 0, &path); strokePath(canvas, path); path.reset(); SkAutoTArray<SkPoint> pos(len); SkAutoTArray<SkScalar> widths(len); paint.getTextWidths(text, len, &widths[0]); SkRandom rand; SkScalar x = SkIntToScalar(20); SkScalar y = SkIntToScalar(100); for (int i = 0; i < len; ++i) { pos[i].set(x, y + rand.nextSScalar1() * 24); x += widths[i]; } canvas->translate(0, SkIntToScalar(64)); canvas->drawPosText(text, len, &pos[0], paint); paint.getPosTextPath(text, len, &pos[0], &path); strokePath(canvas, path); }
virtual void onDraw(SkCanvas* inputCanvas) override { #ifdef SK_BUILD_FOR_ANDROID SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f }; #else SkScalar textSizes[] = { 11.0f, 11.0f*2.0f, 11.0f*5.0f, 11.0f*2.0f*5.0f }; #endif SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f }; // set up offscreen rendering with distance field text #if SK_SUPPORT_GPU GrContext* ctx = inputCanvas->getGrContext(); SkImageInfo info = SkImageInfo::MakeN32Premul(onISize()); SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, SkSurfaceProps::kLegacyFontHost_InitType); SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info, 0, &props)); SkCanvas* canvas = surface.get() ? surface->getCanvas() : inputCanvas; // init our new canvas with the old canvas's matrix canvas->setMatrix(inputCanvas->getTotalMatrix()); #else SkCanvas* canvas = inputCanvas; #endif // apply global scale to test glyph positioning canvas->scale(1.05f, 1.05f); canvas->clear(0xffffffff); SkPaint paint; paint.setAntiAlias(true); paint.setSubpixelText(true); sk_tool_utils::set_portable_typeface(&paint, "Times New Roman", SkTypeface::kNormal); const char* text = "Hamburgefons"; const size_t textLen = strlen(text); // check scaling up SkScalar x = SkIntToScalar(0); SkScalar y = SkIntToScalar(78); for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) { SkAutoCanvasRestore acr(canvas, true); canvas->translate(x, y); canvas->scale(scales[i], scales[i]); paint.setTextSize(textSizes[i]); canvas->drawText(text, textLen, 0, 0, paint); y += paint.getFontMetrics(NULL)*scales[i]; } // check rotation for (size_t i = 0; i < 5; ++i) { SkScalar rotX = SkIntToScalar(10); SkScalar rotY = y; SkAutoCanvasRestore acr(canvas, true); canvas->translate(SkIntToScalar(10 + i * 200), -80); rotate_about(canvas, SkIntToScalar(i * 5), rotX, rotY); for (int ps = 6; ps <= 32; ps += 3) { paint.setTextSize(SkIntToScalar(ps)); canvas->drawText(text, textLen, rotX, rotY, paint); rotY += paint.getFontMetrics(NULL); } } // check scaling down paint.setLCDRenderText(true); x = SkIntToScalar(680); y = SkIntToScalar(20); size_t arraySize = SK_ARRAY_COUNT(textSizes); for (size_t i = 0; i < arraySize; ++i) { SkAutoCanvasRestore acr(canvas, true); canvas->translate(x, y); SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]); canvas->scale(scaleFactor, scaleFactor); paint.setTextSize(textSizes[i]); canvas->drawText(text, textLen, 0, 0, paint); y += paint.getFontMetrics(NULL)*scaleFactor; } // check pos text { SkAutoCanvasRestore acr(canvas, true); canvas->scale(2.0f, 2.0f); SkAutoTArray<SkPoint> pos(SkToInt(textLen)); SkAutoTArray<SkScalar> widths(SkToInt(textLen)); paint.setTextSize(textSizes[0]); paint.getTextWidths(text, textLen, &widths[0]); SkScalar x = SkIntToScalar(340); SkScalar y = SkIntToScalar(75); for (unsigned int i = 0; i < textLen; ++i) { pos[i].set(x, y); x += widths[i]; } canvas->drawPosText(text, textLen, &pos[0], paint); } // check gamma-corrected blending const SkColor fg[] = { 0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFF000000, }; paint.setColor(0xFFF1F1F1); SkRect r = SkRect::MakeLTRB(670, 250, 820, 460); canvas->drawRect(r, paint); x = SkIntToScalar(680); y = SkIntToScalar(270); #ifdef SK_BUILD_FOR_ANDROID paint.setTextSize(SkIntToScalar(19)); #else paint.setTextSize(SkIntToScalar(22)); #endif for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { paint.setColor(fg[i]); canvas->drawText(text, textLen, x, y, paint); y += paint.getFontMetrics(NULL); } paint.setColor(0xFF1F1F1F); r = SkRect::MakeLTRB(820, 250, 970, 460); canvas->drawRect(r, paint); x = SkIntToScalar(830); y = SkIntToScalar(270); #ifdef SK_BUILD_FOR_ANDROID paint.setTextSize(SkIntToScalar(19)); #else paint.setTextSize(SkIntToScalar(22)); #endif for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { paint.setColor(fg[i]); canvas->drawText(text, textLen, x, y, paint); y += paint.getFontMetrics(NULL); } // check skew { paint.setLCDRenderText(false); SkAutoCanvasRestore acr(canvas, true); canvas->skew(0.0f, 0.151515f); paint.setTextSize(SkIntToScalar(32)); canvas->drawText(text, textLen, 745, 70, paint); } { paint.setLCDRenderText(true); SkAutoCanvasRestore acr(canvas, true); canvas->skew(0.5f, 0.0f); paint.setTextSize(SkIntToScalar(32)); canvas->drawText(text, textLen, 580, 230, paint); } // check color emoji paint.setTypeface(fTypeface); #ifdef SK_BUILD_FOR_ANDROID paint.setTextSize(SkIntToScalar(19)); #else paint.setTextSize(SkIntToScalar(22)); #endif canvas->drawText(text, textLen, 670, 100, paint); #if SK_SUPPORT_GPU // render offscreen buffer if (surface) { SkAutoCanvasRestore acr(inputCanvas, true); // since we prepended this matrix already, we blit using identity inputCanvas->resetMatrix(); SkImage* image = surface->newImageSnapshot(); inputCanvas->drawImage(image, 0, 0, NULL); image->unref(); } #endif }