import UIKit final class RDEPUBWebDecorationOverlayView: UIView { private var decorations: [RDEPUBTextOverlayDecoration] = [] private let verticalAdjustment: CGFloat = -1 override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear isOpaque = false isUserInteractionEnabled = false } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func applyDecorations(_ decorations: [RDEPUBTextOverlayDecoration]) { self.decorations = decorations.filter { !$0.rects.isEmpty } setNeedsDisplay() } override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } for decoration in decorations { switch decoration.kind { case .underline: context.setStrokeColor(decoration.color.cgColor) context.setLineWidth(2) for underlineRect in decoration.rects { let y = underlineRect.maxY - 1 context.move(to: CGPoint(x: underlineRect.minX, y: y)) context.addLine(to: CGPoint(x: underlineRect.maxX, y: y)) context.strokePath() } default: context.setFillColor(decoration.color.cgColor) for selectionRect in decoration.rects { let adjustedRect = selectionRect.offsetBy(dx: 0, dy: verticalAdjustment) let path = UIBezierPath(roundedRect: adjustedRect.insetBy(dx: -1, dy: -1), cornerRadius: 4) context.addPath(path.cgPath) context.fillPath() } } } } }