Skip to content

Commit

Permalink
Added support for stroking text
Browse files Browse the repository at this point in the history
  • Loading branch information
buba447 committed Sep 26, 2019
1 parent e77ab19 commit 5d9e297
Showing 1 changed file with 48 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class TextCompositionLayer: CompositionLayer {
let interpolatableScale: KeyframeInterpolator<Vector3D>?

let textLayer: DisabledTextLayer = DisabledTextLayer()
let textStrokeLayer: DisabledTextLayer = DisabledTextLayer()
var textProvider: AnimationTextProvider

init(textLayer: TextLayerModel, textProvider: AnimationTextProvider) {
Expand All @@ -65,18 +66,19 @@ class TextCompositionLayer: CompositionLayer {
}
self.rootNode = rootNode
self.textDocument = KeyframeInterpolator(keyframes: textLayer.text.keyframes)

self.textProvider = textProvider

// TODO: this has to be somewhere that can be interpolated
// TODO: look for inspiration from other composite layer
self.interpolatableAnchorPoint = KeyframeInterpolator(keyframes: textLayer.transform.anchorPoint.keyframes)
self.interpolatableScale = KeyframeInterpolator(keyframes: textLayer.transform.scale.keyframes)

super.init(layer: textLayer, size: .zero)
contentsLayer.addSublayer(self.textLayer)
contentsLayer.addSublayer(self.textStrokeLayer)
self.textLayer.masksToBounds = false

self.textStrokeLayer.masksToBounds = false
}

required init?(coder aDecoder: NSCoder) {
Expand All @@ -90,19 +92,21 @@ class TextCompositionLayer: CompositionLayer {
}
self.rootNode = nil
self.textDocument = nil

self.textProvider = DefaultTextProvider()

self.interpolatableAnchorPoint = nil
self.interpolatableScale = nil

super.init(layer: layer)
}

override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) {
guard let textDocument = textDocument else { return }

textLayer.contentsScale = self.renderScale
textStrokeLayer.contentsScale = self.renderScale

let documentUpdate = textDocument.hasUpdate(frame: frame)
let animatorUpdate = rootNode?.updateContents(frame, forceLocalUpdate: forceUpdates) ?? false
guard documentUpdate == true || animatorUpdate == true else { return }
Expand All @@ -116,31 +120,34 @@ class TextCompositionLayer: CompositionLayer {
let strokeColor = rootNode?.textOutputNode.strokeColor ?? text.strokeColorData?.cgColorValue
let strokeWidth = rootNode?.textOutputNode.strokeWidth ?? CGFloat(text.strokeWidth ?? 0)
let tracking = (CGFloat(text.fontSize) * (rootNode?.textOutputNode.tracking ?? CGFloat(text.tracking))) / 1000.0
// TODO LINE HEIGHT

let matrix = rootNode?.textOutputNode.xform ?? CATransform3DIdentity
let ctFont = CTFontCreateWithName(text.fontFamily as CFString, CGFloat(text.fontSize), nil)

let textString = textProvider.textFor(keypathName: self.keypathName, sourceText: text.text)

var attributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font: ctFont,
NSAttributedString.Key.foregroundColor: fillColor,
NSAttributedString.Key.kern: tracking,
]

if let strokeColor = strokeColor {
attributes[NSAttributedString.Key.strokeColor] = strokeColor
attributes[NSAttributedString.Key.strokeWidth] = strokeWidth
}


let textString = textProvider.textFor(keypathName: self.keypathName, sourceText: text.text)
]

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = CGFloat(text.lineHeight)
paragraphStyle.alignment = text.justification.textAlignment
attributes[NSAttributedString.Key.paragraphStyle] = paragraphStyle

let attributedString = NSAttributedString(string: textString, attributes: attributes )
let baseAttributedString = NSAttributedString(string: textString, attributes: attributes )

if let strokeColor = strokeColor {
textStrokeLayer.isHidden = false
attributes[NSAttributedString.Key.strokeColor] = strokeColor
attributes[NSAttributedString.Key.strokeWidth] = strokeWidth
} else {
textStrokeLayer.isHidden = true
}

let attributedString: NSAttributedString = NSAttributedString(string: textString, attributes: attributes )

let framesetter = CTFramesetterCreateWithAttributedString(attributedString)

Expand All @@ -162,15 +169,34 @@ class TextCompositionLayer: CompositionLayer {
textAnchor = CGPoint(x: size.width * 0.5, y: baselinePosition)
}
let anchor = textAnchor + anchorPoint.pointValue

textLayer.anchorPoint = CGPoint(x: anchor.x.remap(fromLow: 0, fromHigh: size.width, toLow: 0, toHigh: 1),
y: anchor.y.remap(fromLow: 0, fromHigh: size.height, toLow: 0, toHigh: 1))
let normalizedAnchor = CGPoint(x: anchor.x.remap(fromLow: 0, fromHigh: size.width, toLow: 0, toHigh: 1),
y: anchor.y.remap(fromLow: 0, fromHigh: size.height, toLow: 0, toHigh: 1))

if textStrokeLayer.isHidden == false {
if text.strokeOverFill ?? false {
textStrokeLayer.removeFromSuperlayer()
contentsLayer.addSublayer(textStrokeLayer)
} else {
textLayer.removeFromSuperlayer()
contentsLayer.addSublayer(textLayer)
}
textStrokeLayer.anchorPoint = normalizedAnchor
textStrokeLayer.opacity = Float(rootNode?.textOutputNode.opacity ?? 1)
textStrokeLayer.transform = CATransform3DIdentity
textStrokeLayer.frame = CGRect(origin: .zero, size: size)
textStrokeLayer.position = CGPoint.zero
textStrokeLayer.transform = matrix
textStrokeLayer.string = attributedString
textStrokeLayer.alignmentMode = text.justification.caTextAlignement
}

textLayer.anchorPoint = normalizedAnchor
textLayer.opacity = Float(rootNode?.textOutputNode.opacity ?? 1)
textLayer.transform = CATransform3DIdentity
textLayer.frame = CGRect(origin: .zero, size: size)
textLayer.position = CGPoint.zero
textLayer.transform = matrix
textLayer.string = attributedString
textLayer.string = baseAttributedString
textLayer.alignmentMode = text.justification.caTextAlignement
}
}

0 comments on commit 5d9e297

Please sign in to comment.