import UIKit /// EPUB WebView 路径的原生装饰覆盖层。 /// 用于在 WebView 上方叠加高亮、下划线等视觉装饰。 /// 对标 WXRead 的页面级装饰绘制思路:JS 只负责提供 rect,实际视觉绘制由原生 CGContext 完成。 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") } /// 应用装饰数据并触发重绘 /// - Parameter decorations: 装饰项数组(高亮、下划线等) 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() } } } } }