static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 index, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); if (flags & HB_ShaperFlag_UseDesignMetrics) { paint.setHinting(SkPaint::kNo_Hinting); } SkPath path; uint16_t glyph16 = SkToU16(glyph); paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); int numPoints = path.countPoints(); if (index >= numPoints) { return HB_Err_Invalid_SubTable; } SkPoint pt = path.getPoint(index); *xPos = SkScalarToHarfbuzzFixed(pt.fX); *yPos = SkScalarToHarfbuzzFixed(pt.fY); *resultingNumPoints = numPoints; return HB_Err_Ok; }
SkRect Text::onRevalidate(InvalidationController*, const SkMatrix&) { // TODO: we could potentially track invals which don't require rebuilding the blob. SkPaint font; font.setFlags(fFlags); font.setTypeface(fTypeface); font.setTextSize(fSize); font.setTextScaleX(fScaleX); font.setTextSkewX(fSkewX); font.setTextAlign(fAlign); font.setHinting(fHinting); // First, convert to glyphIDs. font.setTextEncoding(SkPaint::kUTF8_TextEncoding); SkSTArray<256, SkGlyphID, true> glyphs; glyphs.reset(font.textToGlyphs(fText.c_str(), fText.size(), nullptr)); SkAssertResult(font.textToGlyphs(fText.c_str(), fText.size(), glyphs.begin()) == glyphs.count()); font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); // Next, build the cached blob. SkTextBlobBuilder builder; const auto& buf = builder.allocRun(font, glyphs.count(), 0, 0, nullptr); if (!buf.glyphs) { fBlob.reset(); return SkRect::MakeEmpty(); } memcpy(buf.glyphs, glyphs.begin(), glyphs.count() * sizeof(SkGlyphID)); fBlob = builder.make(); return fBlob ? fBlob->bounds().makeOffset(fPosition.x(), fPosition.y()) : SkRect::MakeEmpty(); }
virtual void onDraw(SkCanvas* originalCanvas) { SkISize size = this->getISize(); SkBitmap bitmap; bitmap.allocN32Pixels(size.width(), size.height()); SkDeviceProperties properties = SkDeviceProperties::Make( SkDeviceProperties::Geometry::Make(SkDeviceProperties::Geometry::kVertical_Orientation, SkDeviceProperties::Geometry::kBGR_Layout), SK_Scalar1); SkBitmapDevice device(bitmap, properties); SkCanvas canvas(&device); canvas.drawColor(SK_ColorWHITE); SkPaint paint; paint.setAntiAlias(true); paint.setLCDRenderText(true); //With freetype the default (normal hinting) can be really ugly. //Most distros now set slight (vertical hinting only) in any event. paint.setHinting(SkPaint::kSlight_Hinting); sk_tool_utils::set_portable_typeface(&paint, "Times Roman", SkTypeface::kNormal); const char* text = "Hamburgefons ooo mmm"; const size_t textLen = strlen(text); for (int j = 0; j < 2; ++j) { for (int i = 0; i < 6; ++i) { SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(20); SkAutoCanvasRestore acr(&canvas, true); canvas.translate(SkIntToScalar(50 + i * 230), SkIntToScalar(20)); rotate_about(&canvas, SkIntToScalar(i * 5), x, y * 10); { SkPaint p; p.setAntiAlias(true); SkRect r; r.set(x - SkIntToScalar(3), SkIntToScalar(15), x - SkIntToScalar(1), SkIntToScalar(280)); canvas.drawRect(r, p); } int index = 0; for (int ps = 6; ps <= 22; ps++) { paint.setTextSize(SkIntToScalar(ps)); canvas.drawText(text, textLen, x, y, paint); y += paint.getFontMetrics(NULL); index += 1; } } canvas.translate(0, SkIntToScalar(360)); paint.setSubpixelText(true); } originalCanvas->drawBitmap(bitmap, 0, 0); }
static SkPaint make_paint() { SkPaint paint; if (fuzz->exhausted()) { return paint; } paint.setHinting(make_paint_hinting()); paint.setAntiAlias(make_bool()); paint.setDither(make_bool()); paint.setLinearText(make_bool()); paint.setSubpixelText(make_bool()); paint.setLCDRenderText(make_bool()); paint.setEmbeddedBitmapText(make_bool()); paint.setAutohinted(make_bool()); paint.setVerticalText(make_bool()); paint.setFakeBoldText(make_bool()); paint.setDevKernText(make_bool()); paint.setFilterQuality(make_filter_quality()); paint.setStyle(make_paint_style()); paint.setColor(make_color()); paint.setStrokeWidth(make_number(false)); paint.setStrokeMiter(make_number(false)); paint.setStrokeCap(make_paint_cap()); paint.setStrokeJoin(make_paint_join()); paint.setColorFilter(make_color_filter()); paint.setBlendMode(make_blendmode()); paint.setPathEffect(make_path_effect()); paint.setMaskFilter(make_mask_filter()); if (false) { // our validating buffer does not support typefaces yet, so skip this for now paint.setTypeface(SkTypeface::MakeFromName(make_font_name().c_str(),make_typeface_style())); } SkLayerRasterizer::Builder rasterizerBuilder; SkPaint paintForRasterizer; if (make_bool()) { paintForRasterizer = make_paint(); } rasterizerBuilder.addLayer(paintForRasterizer); paint.setRasterizer(rasterizerBuilder.detach()); paint.setImageFilter(make_image_filter()); bool a, b, c; fuzz->next(&a, &b, &c); sk_sp<SkData> data(make_3Dlut(nullptr, a, b, c)); paint.setTextAlign(make_paint_align()); SkScalar d, e, f; fuzz->next(&d, &e, &f); paint.setTextSize(d); paint.setTextScaleX(e); paint.setTextSkewX(f); paint.setTextEncoding(make_paint_text_encoding()); return paint; }
static SkPaint make_paint() { SkPaint paint; paint.setHinting(make_paint_hinting()); paint.setAntiAlias(make_bool()); paint.setDither(make_bool()); paint.setLinearText(make_bool()); paint.setSubpixelText(make_bool()); paint.setLCDRenderText(make_bool()); paint.setEmbeddedBitmapText(make_bool()); paint.setAutohinted(make_bool()); paint.setVerticalText(make_bool()); paint.setUnderlineText(make_bool()); paint.setStrikeThruText(make_bool()); paint.setFakeBoldText(make_bool()); paint.setDevKernText(make_bool()); paint.setFilterQuality(make_filter_quality()); paint.setStyle(make_paint_style()); paint.setColor(make_color()); paint.setStrokeWidth(make_scalar()); paint.setStrokeMiter(make_scalar()); paint.setStrokeCap(make_paint_cap()); paint.setStrokeJoin(make_paint_join()); paint.setColorFilter(make_color_filter()); paint.setXfermodeMode(make_xfermode()); paint.setPathEffect(make_path_effect()); paint.setMaskFilter(make_mask_filter()); if (false) { // our validating buffer does not support typefaces yet, so skip this for now SkAutoTUnref<SkTypeface> typeface( SkTypeface::CreateFromName(make_font_name().c_str(), make_typeface_style())); paint.setTypeface(typeface); } SkLayerRasterizer::Builder rasterizerBuilder; SkPaint paintForRasterizer; if (R(2) == 1) { paintForRasterizer = make_paint(); } rasterizerBuilder.addLayer(paintForRasterizer); paint.setRasterizer(rasterizerBuilder.detach()); paint.setImageFilter(make_image_filter()); sk_sp<SkData> data(make_3Dlut(nullptr, make_bool(), make_bool(), make_bool())); paint.setTextAlign(make_paint_align()); paint.setTextSize(make_scalar()); paint.setTextScaleX(make_scalar()); paint.setTextSkewX(make_scalar()); paint.setTextEncoding(make_paint_text_encoding()); return paint; }
static void paintOp_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState* state) { size_t offset = reader->offset(); size_t stop = offset + PaintOp_unpackData(op32); SkPaint* p = state->editPaint(); do { uint32_t p32 = reader->readU32(); unsigned op = PaintOp_unpackOp(p32); unsigned data = PaintOp_unpackData(p32); // SkDebugf(" read %08X op=%d flags=%d data=%d\n", p32, op, done, data); switch (op) { case kReset_PaintOp: p->reset(); break; case kFlags_PaintOp: p->setFlags(data); break; case kColor_PaintOp: p->setColor(reader->readU32()); break; case kFilterLevel_PaintOp: p->setFilterQuality((SkFilterQuality)data); break; case kStyle_PaintOp: p->setStyle((SkPaint::Style)data); break; case kJoin_PaintOp: p->setStrokeJoin((SkPaint::Join)data); break; case kCap_PaintOp: p->setStrokeCap((SkPaint::Cap)data); break; case kWidth_PaintOp: p->setStrokeWidth(reader->readScalar()); break; case kMiter_PaintOp: p->setStrokeMiter(reader->readScalar()); break; case kEncoding_PaintOp: p->setTextEncoding((SkPaint::TextEncoding)data); break; case kHinting_PaintOp: p->setHinting((SkPaint::Hinting)data); break; case kAlign_PaintOp: p->setTextAlign((SkPaint::Align)data); break; case kTextSize_PaintOp: p->setTextSize(reader->readScalar()); break; case kTextScaleX_PaintOp: p->setTextScaleX(reader->readScalar()); break; case kTextSkewX_PaintOp: p->setTextSkewX(reader->readScalar()); break; case kFlatIndex_PaintOp: { PaintFlats pf = (PaintFlats)PaintOp_unpackFlags(p32); unsigned index = data; set_paintflat(p, state->getFlat(index), pf); break; } case kTypeface_PaintOp: SkASSERT(SkToBool(state->getFlags() & SkGPipeWriter::kCrossProcess_Flag)); p->setTypeface(state->getTypeface(data)); break; default: SkDEBUGFAIL("bad paintop"); return; } SkASSERT(reader->offset() <= stop); } while (reader->offset() < stop); }
SkExclusiveStrikePtr SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) { SkPaint tmpPaint; tmpPaint.setHinting(SkPaint::kNo_Hinting); tmpPaint.setTypeface(sk_ref_sp(face)); int unitsPerEm = face->getUnitsPerEm(); if (unitsPerEm <= 0) { unitsPerEm = 1024; } if (size) { *size = unitsPerEm; } tmpPaint.setTextSize((SkScalar)unitsPerEm); const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); return SkStrikeCache::FindOrCreateStrikeExclusive( tmpPaint, &props, SkScalerContextFlags::kFakeGammaAndBoostContrast, nullptr); }
const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, SkPDFCanon* canon) { SkASSERT(typeface); SkFontID id = typeface->uniqueID(); if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) { return ptr->get(); // canon retains ownership. } int count = typeface->countGlyphs(); if (count <= 0 || count > 1 + SK_MaxU16) { // Cache nullptr to skip this check. Use SkSafeUnref(). canon->fTypefaceMetrics.set(id, nullptr); return nullptr; } std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics(); if (!metrics) { metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>(); } if (0 == metrics->fStemV || 0 == metrics->fCapHeight) { SkPaint tmpPaint; tmpPaint.setHinting(SkPaint::kNo_Hinting); tmpPaint.setTypeface(sk_ref_sp(typeface)); tmpPaint.setTextSize(1000); // glyph coordinate system if (0 == metrics->fStemV) { // Figure out a good guess for StemV - Min width of i, I, !, 1. // This probably isn't very good with an italic font. int16_t stemV = SHRT_MAX; for (char c : {'i', 'I', '!', '1'}) { SkRect bounds; tmpPaint.measureText(&c, 1, &bounds); stemV = SkTMin(stemV, SkToS16(SkScalarRoundToInt(bounds.width()))); } metrics->fStemV = stemV; } if (0 == metrics->fCapHeight) { // Figure out a good guess for CapHeight: average the height of M and X. SkScalar capHeight = 0; for (char c : {'M', 'X'}) { SkRect bounds; tmpPaint.measureText(&c, 1, &bounds); capHeight += bounds.height(); } metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2)); } } return canon->fTypefaceMetrics.set(id, std::move(metrics))->get(); }
virtual void onDraw(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setLCDRenderText(true); //With freetype the default (normal hinting) can be really ugly. //Most distros now set slight (vertical hinting only) in any event. paint.setHinting(SkPaint::kSlight_Hinting); SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal))); const char* text = "Hamburgefons ooo mmm"; const size_t textLen = strlen(text); for (int j = 0; j < 2; ++j) { // This used to do 6 iterations but it causes the N4 to crash in the MSAA4 config. for (int i = 0; i < 5; ++i) { SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(20); SkAutoCanvasRestore acr(canvas, true); canvas->translate(SkIntToScalar(50 + i * 230), SkIntToScalar(20)); rotate_about(canvas, SkIntToScalar(i * 5), x, y * 10); { SkPaint p; p.setAntiAlias(true); SkRect r; r.set(x - SkIntToScalar(3), SkIntToScalar(15), x - SkIntToScalar(1), SkIntToScalar(280)); canvas->drawRect(r, p); } int index = 0; for (int ps = 6; ps <= 22; ps++) { paint.setTextSize(SkIntToScalar(ps)); canvas->drawText(text, textLen, x, y, paint); y += paint.getFontMetrics(NULL); index += 1; } } canvas->translate(0, SkIntToScalar(360)); paint.setSubpixelText(true); } }
static SkPaint make_paint() { SkPaint paint; paint.setHinting(make_paint_hinting()); paint.setAntiAlias(make_bool()); paint.setDither(make_bool()); paint.setLinearText(make_bool()); paint.setSubpixelText(make_bool()); paint.setLCDRenderText(make_bool()); paint.setEmbeddedBitmapText(make_bool()); paint.setAutohinted(make_bool()); paint.setVerticalText(make_bool()); paint.setFakeBoldText(make_bool()); paint.setDevKernText(make_bool()); paint.setFilterQuality(make_filter_quality()); paint.setStyle(make_paint_style()); paint.setColor(make_color()); paint.setStrokeWidth(make_scalar()); paint.setStrokeMiter(make_scalar()); paint.setStrokeCap(make_paint_cap()); paint.setStrokeJoin(make_paint_join()); paint.setColorFilter(make_color_filter()); paint.setBlendMode(make_xfermode()); paint.setPathEffect(make_path_effect()); paint.setMaskFilter(make_mask_filter()); if (false) { // our validating buffer does not support typefaces yet, so skip this for now paint.setTypeface(SkTypeface::MakeFromName(make_font_name().c_str(), make_typeface_style())); } paint.setImageFilter(make_image_filter()); sk_sp<SkData> data(make_3Dlut(nullptr, make_bool(), make_bool(), make_bool())); paint.setTextAlign(make_paint_align()); paint.setTextSize(make_scalar()); paint.setTextScaleX(make_scalar()); paint.setTextSkewX(make_scalar()); paint.setTextEncoding(make_paint_text_encoding()); return paint; }
static void test_cachedfont(skiatest::Reporter* reporter) { static const char* const faces[] = { nullptr, // default font "Arial", "Times", "Times New Roman", "Helvetica", "Courier", "Courier New", "Verdana", "monospace", }; static const struct { SkPaint::Hinting hinting; unsigned flags; } settings[] = { { SkPaint::kNo_Hinting, 0 }, { SkPaint::kNo_Hinting, SkPaint::kLinearText_Flag }, { SkPaint::kNo_Hinting, SkPaint::kSubpixelText_Flag }, { SkPaint::kSlight_Hinting, 0 }, { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag }, { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag }, { SkPaint::kNormal_Hinting, 0 }, { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag }, { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag }, }; static const struct { SkScalar fScaleX; SkScalar fSkewX; } gScaleRec[] = { { SK_Scalar1, 0 }, { SK_Scalar1/2, 0 }, // these two exercise obliquing (skew) { SK_Scalar1, -SK_Scalar1/4 }, { SK_Scalar1/2, -SK_Scalar1/4 }, }; SkPaint paint; char txt[] = "long.text.with.lots.of.dots."; for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) { SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal)); paint.setTypeface(face); for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) { paint.setHinting(settings[j].hinting); paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0); paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0); for (size_t k = 0; k < SK_ARRAY_COUNT(gScaleRec); ++k) { paint.setTextScaleX(gScaleRec[k].fScaleX); paint.setTextSkewX(gScaleRec[k].fSkewX); test_cachedfont(reporter, paint); SkRect bounds; // For no hinting and light hinting this should take the // optimized generateAdvance path. SkScalar width1 = paint.measureText(txt, strlen(txt)); // Requesting the bounds forces a generateMetrics call. SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds); REPORTER_ASSERT(reporter, width1 == width2); SkAutoTUnref<SkFont> font(SkFont::Testing_CreateFromPaint(paint)); SkScalar font_width1 = font->measureText(txt, strlen(txt), kUTF8_SkTextEncoding); // measureText not yet implemented... REPORTER_ASSERT(reporter, font_width1 == -1); // REPORTER_ASSERT(reporter, width1 == font_width1); } } } }