void onDraw(int loops, SkCanvas* canvas) override { SkFont font; font.setEdging(SkFont::Edging::kAntiAlias); const uint16_t* array = gUniqueGlyphIDs; while (*array != gUniqueGlyphIDs_Sentinel) { int count = count_glyphs(array); for (int i = 0; i < loops; ++i) { (void)font.measureText(array, count * sizeof(uint16_t), SkTextEncoding::kGlyphID); } array += count + 1; // skip the sentinel } }
static void add_run(SkTextBlobBuilder* builder, const char text[], SkScalar x, SkScalar y, sk_sp<SkTypeface> tf) { SkFont font; font.setEdging(SkFont::Edging::kAntiAlias); font.setSubpixel(true); font.setSize(16); font.setTypeface(tf); int glyphCount = font.countText(text, strlen(text), SkTextEncoding::kUTF8); SkTextBlobBuilder::RunBuffer buffer = builder->allocRun(font, glyphCount, x, y); (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, buffer.glyphs, glyphCount); }
void drawText(SkCanvas* canvas) { static const int kSizes[] = {8, 9, 10, 11, 12, 13, 18, 20, 25}; static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), SkString("abcdefghijklmnopqrstuvwxyz"), SkString("0123456789"), SkString("!@#$%^&*()<>[]{}")}; SkFont font; font.setEdging(SkFont::Edging::kAntiAlias); font.setSubpixel(true); static const SkScalar kSubPixelInc = 1 / 2.f; SkScalar x = 0; SkScalar y = 10; SkScalar subpixelX = 0; SkScalar subpixelY = 0; bool offsetX = true; if (GrContextOptions::Enable::kYes == fAllowMultipleTextures) { canvas->scale(10, 10); } do { for (auto s : kSizes) { auto size = 2 * s; font.setSize(size); for (const auto& typeface : fTypefaces) { font.setTypeface(typeface); for (const auto& text : kTexts) { x = size + draw_string(canvas, text, x + subpixelX, y + subpixelY, font); x = SkScalarCeilToScalar(x); if (x + 100 > kSize) { x = 0; y += SkScalarCeilToScalar(size + 3); if (y > kSize) { return; } } } } (offsetX ? subpixelX : subpixelY) += kSubPixelInc; offsetX = !offsetX; } } while (true); }
// Verify that text-related properties are captured in run paints. static void TestPaintProps(skiatest::Reporter* reporter) { SkFont font; // Kitchen sink font. font.setSize(42); font.setScaleX(4.2f); font.setTypeface(ToolUtils::create_portable_typeface()); font.setSkewX(0.42f); font.setHinting(SkFontHinting::kFull); font.setEdging(SkFont::Edging::kSubpixelAntiAlias); font.setEmbolden(true); font.setLinearMetrics(true); font.setSubpixel(true); font.setEmbeddedBitmaps(true); font.setForceAutoHinting(true); // Ensure we didn't pick default values by mistake. SkFont defaultFont; REPORTER_ASSERT(reporter, defaultFont.getSize() != font.getSize()); REPORTER_ASSERT(reporter, defaultFont.getScaleX() != font.getScaleX()); REPORTER_ASSERT(reporter, defaultFont.getTypefaceOrDefault() != font.getTypefaceOrDefault()); REPORTER_ASSERT(reporter, defaultFont.getSkewX() != font.getSkewX()); REPORTER_ASSERT(reporter, defaultFont.getHinting() != font.getHinting()); REPORTER_ASSERT(reporter, defaultFont.getEdging() != font.getEdging()); REPORTER_ASSERT(reporter, defaultFont.isEmbolden() != font.isEmbolden()); REPORTER_ASSERT(reporter, defaultFont.isLinearMetrics() != font.isLinearMetrics()); REPORTER_ASSERT(reporter, defaultFont.isSubpixel() != font.isSubpixel()); REPORTER_ASSERT(reporter, defaultFont.isEmbeddedBitmaps() != font.isEmbeddedBitmaps()); REPORTER_ASSERT(reporter, defaultFont.isForceAutoHinting() != font.isForceAutoHinting()); SkTextBlobBuilder builder; AddRun(font, 1, SkTextBlobRunIterator::kDefault_Positioning, SkPoint::Make(0, 0), builder); AddRun(font, 1, SkTextBlobRunIterator::kHorizontal_Positioning, SkPoint::Make(0, 0), builder); AddRun(font, 1, SkTextBlobRunIterator::kFull_Positioning, SkPoint::Make(0, 0), builder); sk_sp<SkTextBlob> blob(builder.make()); SkTextBlobRunIterator it(blob.get()); while (!it.done()) { REPORTER_ASSERT(reporter, it.font() == font); it.next(); } }
static void draw_scene(SkCanvas* canvas, const SkHighContrastConfig& config) { SkRect bounds = SkRect::MakeLTRB(0.0f, 0.0f, 1.0f, 1.0f); SkPaint xferPaint; xferPaint.setColorFilter(SkHighContrastFilter::Make(config)); canvas->saveLayer(&bounds, &xferPaint); SkPaint paint; bounds = SkRect::MakeLTRB(0.1f, 0.2f, 0.9f, 0.4f); paint.setARGB(0xff, 0x66, 0x11, 0x11); canvas->drawRect(bounds, paint); SkFont font; font.setSize(0.15f); font.setEdging(SkFont::Edging::kAlias); paint.setARGB(0xff, 0xbb, 0x77, 0x77); canvas->drawString("A", 0.15f, 0.35f, font, paint); bounds = SkRect::MakeLTRB(0.1f, 0.8f, 0.9f, 1.0f); paint.setARGB(0xff, 0xcc, 0xcc, 0xff); canvas->drawRect(bounds, paint); paint.setARGB(0xff, 0x88, 0x88, 0xbb); canvas->drawString("Z", 0.75f, 0.95f, font, paint); bounds = SkRect::MakeLTRB(0.1f, 0.4f, 0.9f, 0.6f); SkPoint pts[] = { { 0, 0 }, { 1, 0 } }; SkColor colors[] = { SK_ColorWHITE, SK_ColorBLACK }; SkScalar pos[] = { 0.2f, 0.8f }; paint.setShader(SkGradientShader::MakeLinear( pts, colors, pos, SK_ARRAY_COUNT(colors), SkTileMode::kClamp)); canvas->drawRect(bounds, paint); bounds = SkRect::MakeLTRB(0.1f, 0.6f, 0.9f, 0.8f); SkColor colors2[] = { SK_ColorGREEN, SK_ColorWHITE }; paint.setShader(SkGradientShader::MakeLinear( pts, colors2, pos, SK_ARRAY_COUNT(colors2), SkTileMode::kClamp)); canvas->drawRect(bounds, paint); canvas->restore(); }
static void draw_label(SkCanvas* canvas, const SkHighContrastConfig& config) { char labelBuffer[256]; const char* invertStr = (config.fInvertStyle == InvertStyle::kInvertBrightness ? "InvBrightness" : (config.fInvertStyle == InvertStyle::kInvertLightness ? "InvLightness" : "NoInvert")); snprintf(labelBuffer, sizeof(labelBuffer), "%s%s contrast=%.1f", config.fGrayscale ? "Gray " : "", invertStr, config.fContrast); SkFont font; font.setTypeface(ToolUtils::create_portable_typeface()); font.setSize(0.05f); font.setEdging(SkFont::Edging::kAlias); size_t len = strlen(labelBuffer); SkScalar width = font.measureText(labelBuffer, len, SkTextEncoding::kUTF8); canvas->drawSimpleText(labelBuffer, len, SkTextEncoding::kUTF8, 0.5f - width / 2, 0.16f, font, SkPaint()); }
sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) { SkTextBlobBuilder builder; SkFont font; font.setSubpixel(true); font.setEdging(SkFont::Edging::kAntiAlias); font.setTypeface(fTypeface); for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) { unsigned currentGlyph = 0; for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) { const BlobCfg* cfg = &blobConfigs[blobIndex][l][c]; unsigned count = cfg->count; if (count > fGlyphs.count() - currentGlyph) { count = fGlyphs.count() - currentGlyph; } if (0 == count) { break; } font.setSize(kFontSize * cfg->scale); const SkScalar advanceX = font.getSize() * 0.85f; const SkScalar advanceY = font.getSize() * 1.5f; SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX, advanceY * l); switch (cfg->pos) { case kDefault_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count, offset.x(), offset.y()); memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); } break; case kScalar_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count, offset.y()); SkTDArray<SkScalar> pos; for (unsigned i = 0; i < count; ++i) { *pos.append() = offset.x() + i * advanceX; } memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar)); } break; case kPoint_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count); SkTDArray<SkScalar> pos; for (unsigned i = 0; i < count; ++i) { *pos.append() = offset.x() + i * advanceX; *pos.append() = offset.y() + i * (advanceY / count); } memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2); } break; default: SK_ABORT("unhandled pos value"); } currentGlyph += count; } } return builder.make(); }
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { if (!fAnim) { *errorMsg = "No animation."; return DrawResult::kFail; } SkMatrix44 camera, perspective, mv; SkMatrix viewport; { float w = this->width(); float h = this->height(); float s = std::min(w, h); viewport.setTranslate(1, -1); viewport.postScale(s/2, -s/2); draw_viewport(canvas, viewport); } Sk3Perspective(&perspective, fNear, fFar, fAngle); Sk3LookAt(&camera, fEye, fCOA, fUp); mv.postConcat(camera); mv.postConcat(perspective); SkPoint pts[8]; Sk3MapPts(pts, mv, fP3, 8); viewport.mapPoints(pts, 8); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); SkFont font; font.setEdging(SkFont::Edging::kAlias); SkPath cube; cube.moveTo(pts[0]); cube.lineTo(pts[2]); cube.lineTo(pts[6]); cube.lineTo(pts[4]); cube.close(); cube.moveTo(pts[1]); cube.lineTo(pts[3]); cube.lineTo(pts[7]); cube.lineTo(pts[5]); cube.close(); cube.moveTo(pts[0]); cube.lineTo(pts[1]); cube.moveTo(pts[2]); cube.lineTo(pts[3]); cube.moveTo(pts[4]); cube.lineTo(pts[5]); cube.moveTo(pts[6]); cube.lineTo(pts[7]); canvas->drawPath(cube, paint); { SkPoint3 src[4] = { { 0, 0, 0 }, { 2, 0, 0 }, { 0, 2, 0 }, { 0, 0, 2 }, }; SkPoint dst[4]; mv.setConcat(perspective, camera); Sk3MapPts(dst, mv, src, 4); viewport.mapPoints(dst, 4); const char* str[3] = { "X", "Y", "Z" }; for (int i = 1; i <= 3; ++i) { canvas->drawLine(dst[0], dst[i], paint); } for (int i = 0; i < 3; ++i) { canvas->drawString(str[i], dst[i + 1].fX, dst[i + 1].fY, font, paint); } } fAnim->seek(fAnimT); draw_skia(canvas, mv, viewport, fAnim.get()); return DrawResult::kOk; }