void draw(SkCanvas* canvas) { SkPaint paint; paint.setTextSize(128); SkPath path, path2; paint.getTextPath("A", 1, 60, 100, &path); paint.getTextPath("Z", 1, 60, 100, &path2); SkPoint pt, pt2; path.getLastPt(&pt); path2.getLastPt(&pt2); path.setLastPt(pt2); path2.setLastPt(pt); canvas->drawPath(path, paint); canvas->drawPath(path2, paint); }
static void lettersToBitmap2(SkBitmap* dst, const char chars[], const SkPaint& original, SkBitmap::Config config) { SkPath path; SkScalar x = 0; SkScalar width; SkPath p; for (size_t i = 0; i < strlen(chars); i++) { original.getTextPath(&chars[i], 1, x, 0, &p); path.addPath(p); original.getTextWidths(&chars[i], 1, &width); x += width; } SkRect bounds = path.getBounds(); SkScalar sw = -original.getStrokeWidth(); bounds.inset(sw, sw); path.offset(-bounds.fLeft, -bounds.fTop); bounds.offset(-bounds.fLeft, -bounds.fTop); int w = SkScalarRound(bounds.width()); int h = SkScalarRound(bounds.height()); SkPaint paint(original); paint.setAntiAlias(true); paint.setXfermodeMode(SkXfermode::kDstATop_Mode); paint.setColor(original.getColor()); paint.setStyle(SkPaint::kStroke_Style); dst->setConfig(config, w, h); dst->allocPixels(); dst->eraseColor(SK_ColorWHITE); SkCanvas canvas(*dst); canvas.drawPath(path, paint); }
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); 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]); SkLCGRandom 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* canvas) { if (false) test_rev(canvas); // avoid bit rot, suppress warning SkRect r = { 10, 10, 100, 60 }; SkPath path; path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.offset(20, 20); path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.reset(); path.moveTo(10, 10); path.lineTo(30, 30); path.addOval(r); r.offset(50, 20); path.addOval(r); test_rev(canvas, path); SkPaint paint; paint.setTextSize(SkIntToScalar(100)); SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal); SkSafeUnref(paint.setTypeface(hira)); path.reset(); paint.getTextPath("e", 1, 50, 50, &path); canvas->translate(0, 100); test_rev(canvas, path); }
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; }
static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; if (flags & HB_ShaperFlag_UseDesignMetrics) return HB_Err_Invalid_Argument; // This is requesting pre-hinted positions. We can't support this. font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkPath path; paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); int numPoints = path.getPoints(0, 0); if (point >= static_cast<unsigned>(numPoints)) return HB_Err_Invalid_SubTable; SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1))); if (!points) return HB_Err_Invalid_SubTable; // Skia does let us get a single point from the path. path.getPoints(points, point + 1); *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX); *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY); *resultingNumPoints = numPoints; fastFree(points); return HB_Err_Ok; }
static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { if (flags & HB_ShaperFlag_UseDesignMetrics) // This is requesting pre-hinted positions. We can't support this. return HB_Err_Invalid_Argument; SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkPath path; paint->getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); uint32_t numPoints = path.getPoints(0, 0); if (point >= numPoints) return HB_Err_Invalid_SubTable; SkPoint* points = static_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1))); if (!points) return HB_Err_Invalid_SubTable; // Skia does let us get a single point from the path. path.getPoints(points, point + 1); *xPos = SkScalarToHBFixed(points[point].fX); *yPos = SkScalarToHBFixed(points[point].fY); *resultingNumPoints = numPoints; delete points; return HB_Err_Ok; }
void SkTextToPath::onEndElement(SkAnimateMaker& maker) { if (paint == NULL || path == NULL || text == NULL) { // !!! add error message here maker.setErrorCode(SkDisplayXMLParserError::kErrorInAttributeValue); return; } SkPaint realPaint; paint->setupPaint(&realPaint); realPaint.getTextPath(text->getText(), text->getSize(), text->x, text->y, &path->getPath()); }
void draw(SkCanvas* canvas) { SkPaint paint; paint.setTextSize(80); SkPath path, path2; paint.getTextPath("ABC", 3, 20, 80, &path); path.offset(20, 20, &path2); Op(path, path2, SkPathOp::kDifference_SkPathOp, &path); path.addPath(path2); paint.setStyle(SkPaint::kStroke_Style); canvas->drawPath(path, paint); }
static inline void getSkiaBoundsForGlyph(SkPaint& paint, Glyph glyph, SkRect& bounds) { paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkPath path; paint.getTextPath(&glyph, sizeof(glyph), 0, 0, &path); bounds = path.getBounds(); if (!paint.isSubpixelText()) { SkIRect ir; bounds.round(&ir); bounds.set(ir); } }
static void drawdots(SkCanvas* canvas, const SkPaint& orig) { SkTDArray<SkPoint> pts; SkPathEffect* pe = makepe(0, &pts); SkScalar width = -1; SkPath path, dstPath; orig.getTextPath("9", 1, 0, 0, &path); pe->filterPath(&dstPath, path, &width); SkPaint p; p.setAntiAlias(true); p.setStrokeWidth(10); p.setColor(SK_ColorRED); canvas->drawPoints(SkCanvas::kPoints_PointMode, pts.count(), pts.begin(), p); }
void draw(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(256); SkPath asterisk, path; paint.getTextPath("*", 1, 50, 192, &asterisk); SkPath::Iter iter(asterisk, true); SkPoint start[4], pts[4]; iter.next(start); // skip moveTo iter.next(start); // first quadTo path.moveTo((start[0] + start[1]) * 0.5f); while (SkPath::kClose_Verb != iter.next(pts)) { path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f); } path.quadTo(start[0], (start[0] + start[1]) * 0.5f); canvas->drawPath(path, paint); }
static void output_path_data(const SkPaint& paint, const char* used, int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs, SkTDArray<unsigned>* charCodes, SkTDArray<SkScalar>* widths) { while (*used) { SkUnichar index = SkUTF8_NextUnichar(&used); SkPath path; paint.getTextPath((const void*) &index, 2, 0, 0, &path); SkPath::RawIter iter(path); SkPath::Verb verb; SkPoint pts[4]; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { *verbs->append() = verb; switch (verb) { case SkPath::kMove_Verb: output_points(&pts[0], emSize, 1, ptsOut); break; case SkPath::kLine_Verb: output_points(&pts[1], emSize, 1, ptsOut); break; case SkPath::kQuad_Verb: output_points(&pts[1], emSize, 2, ptsOut); break; case SkPath::kCubic_Verb: output_points(&pts[1], emSize, 3, ptsOut); break; case SkPath::kClose_Verb: break; default: SkDEBUGFAIL("bad verb"); SkASSERT(0); } } *verbs->append() = SkPath::kDone_Verb; *charCodes->append() = index; SkScalar width; SkDEBUGCODE(int charCount =) paint.getTextWidths((const void*) &index, 2, &width); SkASSERT(charCount == 1); // SkASSERT(floor(width) == width); // not true for Hiragino Maru Gothic Pro *widths->append() = width; } }
static void draw_vector_logo(SkCanvas* canvas, const SkRect& viewBox) { constexpr char kSkiaStr[] = "SKIA"; constexpr SkScalar kGradientPad = .1f; constexpr SkScalar kVerticalSpacing = 0.25f; constexpr SkScalar kAccentScale = 1.20f; SkPaint paint; paint.setAntiAlias(true); paint.setSubpixelText(true); paint.setFakeBoldText(true); sk_tool_utils::set_portable_typeface(&paint); SkPath path; SkRect iBox, skiBox, skiaBox; paint.getTextPath("SKI", 3, 0, 0, &path); TightBounds(path, &skiBox); paint.getTextPath("I", 1, 0, 0, &path); TightBounds(path, &iBox); iBox.offsetTo(skiBox.fRight - iBox.width(), iBox.fTop); const size_t textLen = strlen(kSkiaStr); paint.getTextPath(kSkiaStr, textLen, 0, 0, &path); TightBounds(path, &skiaBox); skiaBox.outset(0, 2 * iBox.width() * (kVerticalSpacing + 1)); const SkScalar accentSize = iBox.width() * kAccentScale; const SkScalar underlineY = iBox.bottom() + (kVerticalSpacing + SkScalarSqrt(3) / 2) * accentSize; SkMatrix m; m.setRectToRect(skiaBox, viewBox, SkMatrix::kFill_ScaleToFit); SkAutoCanvasRestore acr(canvas, true); canvas->concat(m); canvas->drawCircle(iBox.centerX(), iBox.y() - (0.5f + kVerticalSpacing) * accentSize, accentSize / 2, paint); path.reset(); path.moveTo(iBox.centerX() - accentSize / 2, iBox.bottom() + kVerticalSpacing * accentSize); path.rLineTo(accentSize, 0); path.lineTo(iBox.centerX(), underlineY); canvas->drawPath(path, paint); SkRect underlineRect = SkRect::MakeLTRB(iBox.centerX() - iBox.width() * accentSize * 3, underlineY, iBox.centerX(), underlineY + accentSize / 10); const SkPoint pts1[] = { SkPoint::Make(underlineRect.x(), 0), SkPoint::Make(iBox.centerX(), 0) }; const SkScalar pos1[] = { 0, 0.75f }; const SkColor colors1[] = { SK_ColorTRANSPARENT, SK_ColorBLACK }; SkASSERT(SK_ARRAY_COUNT(pos1) == SK_ARRAY_COUNT(colors1)); paint.setShader(SkGradientShader::MakeLinear(pts1, colors1, pos1, SK_ARRAY_COUNT(pos1), SkShader::kClamp_TileMode)); canvas->drawRect(underlineRect, paint); const SkPoint pts2[] = { SkPoint::Make(iBox.x() - iBox.width() * kGradientPad, 0), SkPoint::Make(iBox.right() + iBox.width() * kGradientPad, 0) }; const SkScalar pos2[] = { 0, .01f, 1.0f/3, 1.0f/3, 2.0f/3, 2.0f/3, .99f, 1 }; const SkColor colors2[] = { SK_ColorBLACK, 0xffca5139, 0xffca5139, 0xff8dbd53, 0xff8dbd53, 0xff5460a5, 0xff5460a5, SK_ColorBLACK }; SkASSERT(SK_ARRAY_COUNT(pos2) == SK_ARRAY_COUNT(colors2)); paint.setShader(SkGradientShader::MakeLinear(pts2, colors2, pos2, SK_ARRAY_COUNT(pos2), SkShader::kClamp_TileMode)); canvas->drawText(kSkiaStr, textLen, 0, 0, paint); }
void onDrawContent(SkCanvas* canvas) override { SkPath path; SkScalar width = fWidth; if (fCubicButton.fEnabled) { path.moveTo(fPts[0]); path.cubicTo(fPts[1], fPts[2], fPts[3]); setForGeometry(); draw_stroke(canvas, path, width, 950, false); } if (fConicButton.fEnabled) { path.moveTo(fPts[4]); path.conicTo(fPts[5], fPts[6], fWeight); setForGeometry(); draw_stroke(canvas, path, width, 950, false); } if (fQuadButton.fEnabled) { path.reset(); path.moveTo(fPts[7]); path.quadTo(fPts[8], fPts[9]); setForGeometry(); draw_stroke(canvas, path, width, 950, false); } if (fRRectButton.fEnabled) { SkScalar rad = 32; SkRect r; r.set(&fPts[10], 2); path.reset(); SkRRect rr; rr.setRectXY(r, rad, rad); path.addRRect(rr); setForGeometry(); draw_stroke(canvas, path, width, 950, false); path.reset(); SkRRect rr2; rr.inset(width/2, width/2, &rr2); path.addRRect(rr2, SkPath::kCCW_Direction); rr.inset(-width/2, -width/2, &rr2); path.addRRect(rr2, SkPath::kCW_Direction); SkPaint paint; paint.setAntiAlias(true); paint.setColor(0x40FF8844); canvas->drawPath(path, paint); } if (fCircleButton.fEnabled) { path.reset(); SkRect r; r.set(&fPts[12], 2); path.addOval(r); setForGeometry(); if (fCircleButton.fFill) { draw_fill(canvas, r, width); } else { draw_stroke(canvas, path, width, 950, false); } } if (fTextButton.fEnabled) { path.reset(); SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(fTextSize); paint.getTextPath(fText.c_str(), fText.size(), 0, fTextSize, &path); setForText(); draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true); } if (fAnimate) { fWidth += fDWidth; if (fDWidth > 0 && fWidth > kWidthMax) { fDWidth = -fDWidth; } else if (fDWidth < 0 && fWidth < kWidthMin) { fDWidth = -fDWidth; } } setAsNeeded(); if (fConicButton.fEnabled) { draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight"); } #ifdef SK_DEBUG draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax, "error"); #endif draw_control(canvas, fWidthControl, fWidth * fWidthScale, kWidthMin * fWidthScale, kWidthMax * fWidthScale, "width"); draw_button(canvas, fQuadButton); draw_button(canvas, fCubicButton); draw_button(canvas, fConicButton); draw_button(canvas, fRRectButton); draw_button(canvas, fCircleButton); draw_button(canvas, fTextButton); this->inval(NULL); }
static int count_char_points(const SkPaint& paint, char c) { SkPath path; paint.getTextPath(&c, 1, 0, 0, &path); return path.getPoints(NULL, 0); }