You can achieve this effect using only CoreText and CoreGraphics.
I was able to achieve this using a variety of approximation methods. Most of what I used with the approximation (via CGPathCreateCopyByDashingPath) could theoretically be replaced with smarter math. This can both increase productivity and make the resulting path smoother.
In principle, you can parameterize the top and base paths (or zoom in the parameterization, as I did). (You can define a function that gets a point in a given percentage along the way.)
CoreText can convert each glyph to CGPath. Run CGPathApply on each of the glyph paths using a function that maps each point along the path to the appropriate percentage along the line of text. Once you have a point with a horizontal percentage, you can scale it along the line defined by two points in this percentage along the top line and the baseline. Scale the point along this line depending on the line length and glyph height, and this will create a new point. Save each scaled point in the new CGPath. Fill this way.
I used CGPathCreateCopyByDashingPath for each glyph, and also to create enough points where I don't need to handle the math for the curve of a long LineTo element (for example). This makes math easier, but can leave the path a little jagged. To fix this, you can transfer the resulting image to a smoothing filter (for example, CoreImage) or pass the path to the library, which can smooth and simplify the path.
(First I tried CoreImage distortion filters to solve the whole problem, but the effects never gave the right effect.)
Here is the result (note the slightly jagged edges from using approximation): 
Here it is with lines drawn between each percent of two lines: 
Here's how I earned (180 lines, scrolls):
static CGPoint pointAtPercent(CGFloat percent, NSArray<NSValue *> *pointArray) { percent = MAX(percent, 0.f); percent = MIN(percent, 1.f); int floorIndex = floor(([pointArray count] - 1) * percent); int ceilIndex = ceil(([pointArray count] - 1) * percent); CGPoint floorPoint = [pointArray[floorIndex] CGPointValue]; CGPoint ceilPoint = [pointArray[ceilIndex] CGPointValue]; CGPoint midpoint = CGPointMake((floorPoint.x + ceilPoint.x) / 2.f, (floorPoint.y + ceilPoint.y) / 2.f); return midpoint; } static void applierSavePoints(void* info, const CGPathElement* element) { NSMutableArray *pointArray = (__bridge NSMutableArray*)info;
The incoming code is also far from "complete." For example, there are many parts of CoreText that I have been looking through. Characters with descenders work, but not very well. Some thought it would be necessary to figure out how to deal with them. Also, my spacing between letters is messy.
Clearly, this is a non-trivial task. I am sure there are better ways to do this with third-party libraries that can effectively distort Bezier's paths. However, in order to intellectually examine whether this can be done without third-party libraries, I think this demonstrates that this is possible.
Source: https://developer.apple.com/library/mac/samplecode/CoreTextArcCocoa/Introduction/Intro.html
Source: http://www.planetclegg.com/projects/WarpingTextToSplines.html
Source (to enhance mathematics): Get the position of the path in time