import UIKit #if canImport(DTCoreText) import DTCoreText #endif public struct RDEPUBDTCoreTextRenderer: RDEPUBTextRenderer { public init() {} public static var isAvailable: Bool { #if canImport(DTCoreText) return true #else return false #endif } public func renderChapter( request: RDEPUBTextChapterRenderRequest ) throws -> RDEPUBRenderedChapterContent { #if canImport(DTCoreText) let chapterContext = request.context guard let data = chapterContext.html.data(using: .utf8) else { throw RDEPUBTextRenderingError.htmlEncodingFailed } guard let rendered = makeAttributedString(from: data, request: request) else { return fallbackRenderedContent(request: request) } let attributedString = NSMutableAttributedString(attributedString: rendered) let fragmentOffsets = RDEPUBTextRendererSupport.extractFragmentOffsets(from: attributedString) RDEPUBTextRendererSupport.normalizeReadingAttributes(in: attributedString, style: request.style) return RDEPUBRenderedChapterContent( attributedString: attributedString, fragmentOffsets: fragmentOffsets, resourceDiagnostics: chapterContext.resourceDiagnostics ) #else return fallbackRenderedContent(request: request) #endif } public func renderChapter( html: String, baseURL: URL?, style: RDEPUBTextRenderStyle ) throws -> RDEPUBRenderedChapterContent { let request = RDEPUBTextRendererSupport.makeChapterRenderRequest( href: "", title: "", rawHTML: html, baseURL: baseURL, style: style, resourceResolver: nil ) return try renderChapter(request: request) } private func fallbackRenderedContent(request: RDEPUBTextChapterRenderRequest) -> RDEPUBRenderedChapterContent { let attributedString = RDEPUBTextRendererSupport.fallbackAttributedString(for: request.context.html, style: request.style) let fragmentOffsets = RDEPUBTextRendererSupport.extractFragmentOffsets(from: attributedString) RDEPUBTextRendererSupport.normalizeReadingAttributes(in: attributedString, style: request.style) return RDEPUBRenderedChapterContent( attributedString: attributedString, fragmentOffsets: fragmentOffsets, resourceDiagnostics: request.context.resourceDiagnostics ) } #if canImport(DTCoreText) private func makeAttributedString(from data: Data, request: RDEPUBTextChapterRenderRequest) -> NSAttributedString? { let builder = DTHTMLAttributedStringBuilder( html: data, options: dtOptions(request: request), documentAttributes: nil ) return builder?.generatedAttributedString() } private func dtOptions(request: RDEPUBTextChapterRenderRequest) -> [AnyHashable: Any] { let style = request.style var options: [AnyHashable: Any] = [ NSTextSizeMultiplierDocumentOption: 1.0, DTDefaultFontFamily: style.font.familyName, DTDefaultFontName: style.font.fontName, DTDefaultFontSize: style.font.pointSize, DTDefaultLineHeightMultiplier: max((style.font.lineHeight + style.lineSpacing) / max(style.font.lineHeight, 1), 1), DTUseiOS6Attributes: true ] if let baseURL = request.context.baseURL { options[NSBaseURLDocumentOption] = baseURL } if let textColor = style.textColor { options[DTDefaultTextColor] = textColor } return options } #endif }