static bool calculatePointAndNormalOnPath(SkPathMeasure& measure, SkScalar length, FloatPoint& point, float& normalAngle, SkScalar* accumulatedLength = 0) { do { SkScalar contourLength = measure.getLength(); if (length <= contourLength) { SkVector tangent; SkPoint position; if (measure.getPosTan(length, &position, &tangent)) { normalAngle = rad2deg(SkScalarToFloat(SkScalarATan2(tangent.fY, tangent.fX))); point = FloatPoint(SkScalarToFloat(position.fX), SkScalarToFloat(position.fY)); return true; } } length -= contourLength; if (accumulatedLength) *accumulatedLength += contourLength; } while (measure.nextContour()); return false; }
static void morphpoints(SkPoint dst[], const SkPoint src[], int count, SkPathMeasure& meas, const SkMatrix& matrix) { SkMatrix::MapXYProc proc = matrix.getMapXYProc(); for (int i = 0; i < count; i++) { SkPoint pos; SkVector tangent; proc(matrix, src[i].fX, src[i].fY, &pos); SkScalar sx = pos.fX; SkScalar sy = pos.fY; if (!meas.getPosTan(sx, &pos, &tangent)) { // set to 0 if the measure failed, so that we just set dst == pos tangent.set(0, 0); } /* This is the old way (that explains our approach but is way too slow SkMatrix matrix; SkPoint pt; pt.set(sx, sy); matrix.setSinCos(tangent.fY, tangent.fX); matrix.preTranslate(-sx, 0); matrix.postTranslate(pos.fX, pos.fY); matrix.mapPoints(&dst[i], &pt, 1); */ dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), pos.fY + SkScalarMul(tangent.fX, sy)); } }
SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance, SkPathMeasure& meas) const { switch (fStyle) { case kTranslate_Style: { SkPoint pos; if (meas.getPosTan(distance, &pos, nullptr)) { dst->addPath(fPath, pos.fX, pos.fY); } } break; case kRotate_Style: { SkMatrix matrix; if (meas.getMatrix(distance, &matrix)) { dst->addPath(fPath, matrix); } } break; case kMorph_Style: morphpath(dst, fPath, meas, distance); break; default: SkDEBUGFAIL("unknown Style enum"); break; } return fAdvance; }
void TextArt::EnvelopeWarp::morphpoints(SkPoint dst[], const SkPoint src[], int count, SkPathMeasure& meas, const SkMatrix& matrix) { SkMatrix::MapXYProc proc = matrix.getMapXYProc(); for (int i = 0; i < count; i++) { SkPoint pos; SkVector tangent; SkPoint iSrc = src[i]; iSrc.fX = k1_ * iSrc.fX; proc(matrix, iSrc.fX, iSrc.fY, &pos); SkScalar sx = pos.fX; SkScalar sy = pos.fY; if (xWeightingMode_ & XWeightingMode_Linearly) { //in Linearly mode adjust Top text by TopLength/BottomLength relation if (isTop) { //move text below the Top skeleton sy -= boundsRect_.fTop; } } if (!meas.getPosTan(sx, &pos, &tangent)) { // set to 0 if the measure failed, so that we just set dst == pos tangent.set(0, 0); } /* This is the old way (that explains our approach but is way too slow SkMatrix matrix; SkPoint pt; pt.set(sx, sy); matrix.setSinCos(tangent.fY, tangent.fX); matrix.preTranslate(-sx, 0); matrix.postTranslate(pos.fX, pos.fY); matrix.mapPoints(&dst[i], &pt, 1); */ if (isNormalRotated_) { dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), pos.fY + SkScalarMul(tangent.fX, sy)); } else { dst[i].set(pos.fX, pos.fY + sy); } } }
static void morphpoints(SkPoint dst[], const SkPoint src[], int count, SkPathMeasure& meas, SkScalar dist) { for (int i = 0; i < count; i++) { SkPoint pos; SkVector tangent; SkScalar sx = src[i].fX; SkScalar sy = src[i].fY; meas.getPosTan(dist + sx, &pos, &tangent); SkMatrix matrix; SkPoint pt; pt.set(sx, sy); matrix.setSinCos(tangent.fY, tangent.fX, 0, 0); matrix.preTranslate(-sx, 0); matrix.postTranslate(pos.fX, pos.fY); matrix.mapPoints(&dst[i], &pt, 1); } }
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, SkPathMeasure& measure, SkPoint* position, SkVector* tangent) { const float halfWidth = glyph->mBitmapWidth * 0.5f; const float height = glyph->mBitmapHeight; vOffset += glyph->mBitmapTop + height; SkPoint destination[4]; bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent); if (!ok) { ALOGW("The path for drawTextOnPath is empty or null"); } // Move along the tangent and offset by the normal destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset, -tangent->fY * halfWidth + tangent->fX * vOffset); destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset, tangent->fY * halfWidth + tangent->fX * vOffset); destination[2].set(destination[1].fX + tangent->fY * height, destination[1].fY - tangent->fX * height); destination[3].set(destination[0].fX + tangent->fY * height, destination[0].fY - tangent->fX * height); const float u1 = glyph->mBitmapMinU; const float u2 = glyph->mBitmapMaxU; const float v1 = glyph->mBitmapMinV; const float v2 = glyph->mBitmapMaxV; mState->appendRotatedMeshQuad( position->x() + destination[0].x(), position->y() + destination[0].y(), u1, v2, position->x() + destination[1].x(), position->y() + destination[1].y(), u2, v2, position->x() + destination[2].x(), position->y() + destination[2].y(), u2, v1, position->x() + destination[3].x(), position->y() + destination[3].y(), u1, v1, glyph->mCacheTexture); }