ReadViewSDK/Doc/WXRead/decompiled/WRCoreTextLayoutFrame.h
2026-05-21 19:40:51 +08:00

350 lines
9.6 KiB
Objective-C

//
// WRCoreTextLayoutFrame.h
// WeRead
//
// Reverse-engineered from binary analysis
// Single page layout frame for WeRead's reading engine
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreText/CoreText.h>
@class WRBookCoverView;
@class WRDiscover;
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Layout Line
/**
* Represents a single line of laid-out text.
* Wrapper around CTLine with additional metadata.
*/
@interface WRCoreTextLayoutLine : NSObject
/** The CTLine this wraps */
@property (nonatomic, assign, readonly) CTLineRef ctLine;
/** Origin point of this line in the frame */
@property (nonatomic, assign) CGPoint origin;
/** The range of characters in this line */
@property (nonatomic, assign) NSRange stringRange;
/** Ascent of the line */
@property (nonatomic, assign, readonly) CGFloat ascent;
/** Desent of the line */
@property (nonatomic, assign, readonly) CGFloat descent;
/** Leading of the line */
@property (nonatomic, assign, readonly) CGFloat leading;
/** Total height of the line (ascent + descent + leading) */
@property (nonatomic, assign, readonly) CGFloat height;
/** Width of the line */
@property (nonatomic, assign, readonly) CGFloat width;
/** Whether this line is the last line in a paragraph */
@property (nonatomic, assign) BOOL isLastLineInParagraph;
@end
#pragma mark - WRCoreTextLayoutFrame
/**
* WRCoreTextLayoutFrame - Manages a single page of text layout.
*
* This class wraps CTFrame and provides high-level access to the
* layout of a single page. It handles:
* - Text rendering to CGContext
* - Image placement within text
* - avoidPageBreakInside CSS property
* - Render height calculation
* - Line-by-line access for hit testing and selection
*
* Architecture:
* - Contains CTFrame internally
* - Manages array of WRCoreTextLayoutLine objects
* - Supports direct drawing to CGContext
* - Handles image attachments inline
* - Integrates with RACSubject for reactive updates
*/
@interface WRCoreTextLayoutFrame : NSObject
#pragma mark - Core Layout Data
/** The attributed string that was laid out */
@property (nonatomic, strong, nullable) NSAttributedString *attributedString;
/** The range of the attributed string represented by this frame */
@property (nonatomic, assign) NSRange stringRange;
/** Array of WRCoreTextLayoutLine objects for this frame */
@property (nonatomic, strong, readonly) NSArray<WRCoreTextLayoutLine *> *layoutLines;
/** The bounding rectangle for this frame */
@property (nonatomic, assign) CGRect frame;
/** The CTFrame reference (accessor for internal use) */
@property (nonatomic, assign, readonly) CTFrameRef ctFrame;
#pragma mark - Layout Properties
/** Whether to avoid page breaks inside certain elements */
@property (nonatomic, assign) BOOL avoidPageBreakInside;
/** The rendered content height (may differ from frame height) */
@property (nonatomic, assign, readonly) CGFloat renderedContentHeight;
/** Padding around the content area */
@property (nonatomic, assign) UIEdgeInsets contentInsets;
/** Number of columns in this frame */
@property (nonatomic, assign) NSUInteger numberOfColumns;
/** Gap between columns */
@property (nonatomic, assign) CGFloat columnGap;
#pragma mark - Content Arrays
/** Array of attachment objects (images, etc.) */
@property (nonatomic, strong, nullable) NSArray *attachments;
/** Array of strikethrough ranges */
@property (nonatomic, strong, nullable) NSArray *strikethroughRanges;
/** Array of underline ranges */
@property (nonatomic, strong, nullable) NSArray *underlineRanges;
/** Array of highlight ranges */
@property (nonatomic, strong, nullable) NSArray *highlightRanges;
/** Set of selected line indices */
@property (nonatomic, strong, nullable) NSMutableSet *selectedLineIndices;
/** Current selection string */
@property (nonatomic, copy, nullable) NSString *selectionString;
/** Array of link ranges for tap handling */
@property (nonatomic, strong, nullable) NSArray *linkRanges;
/** Search result string */
@property (nonatomic, copy, nullable) NSString *searchResultString;
/** Array of search result ranges */
@property (nonatomic, strong, nullable) NSArray *searchResultRanges;
#pragma mark - Reactive Components
/** Subject for layout change notifications */
@property (nonatomic, strong, nullable) RACSubject *layoutChangeSubject;
#pragma mark - UI Elements
/** Long press gesture recognizer for text selection */
@property (nonatomic, strong, nullable) UILongPressGestureRecognizer *longPressRecognizer;
/** Book cover view (for cover pages) */
@property (nonatomic, strong, nullable) WRBookCoverView *bookCoverView;
/** Layer for custom drawing */
@property (nonatomic, strong, nullable) CALayer *customDrawingLayer;
/** Discover view (for social features) */
@property (nonatomic, strong, nullable) WRDiscover *discoverView;
/** Additional layout data */
@property (nonatomic, strong, nullable) NSArray *additionalLayoutData;
/** Frame identifier */
@property (nonatomic, copy, nullable) NSString *frameId;
/** Content identifier */
@property (nonatomic, copy, nullable) NSString *contentId;
/** Mutable dictionary for custom attributes */
@property (nonatomic, strong, nullable) NSMutableDictionary *customAttributes;
/** Mutable array for tracking visible elements */
@property (nonatomic, strong, nullable) NSMutableArray *visibleElements;
/** Mutable array for tracking accessibility elements */
@property (nonatomic, strong, nullable) NSMutableArray *accessibilityElements;
/** Mutable dictionary for caching computed values */
@property (nonatomic, strong, nullable) NSMutableDictionary *computedValueCache;
#pragma mark - Initialization
/**
* Initialize with a CTFrame and string range.
*
* @param ctFrame The CoreText frame
* @param range The string range
* @return Initialized layout frame
*/
- (instancetype)initWithCTFrame:(CTFrameRef)ctFrame
range:(NSRange)range;
/**
* Set the CTFrame and range (used by WRCoreTextLayouter).
*/
- (void)setCTFrame:(CTFrameRef)ctFrame range:(NSRange)range;
#pragma mark - Line Access
/**
* Returns the array of layout lines.
* This triggers line extraction from the CTFrame if not already done.
*
* @return Array of WRCoreTextLayoutLine objects
*/
- (NSArray<WRCoreTextLayoutLine *> *)lines;
/**
* Returns the number of lines in this frame.
*/
- (NSUInteger)lineCount;
/**
* Returns the layout line at the specified index.
*/
- (nullable WRCoreTextLayoutLine *)lineAtIndex:(NSUInteger)index;
#pragma mark - Height Calculation
/**
* Returns the rendered content height.
*
* This calculates the actual height of the rendered content,
* which may be less than the frame height if there's unused space.
*
* @return The height of the rendered content in points
*/
- (CGFloat)getRenderHeight;
/**
* Returns the height of the last line's descent.
* Used for precise baseline alignment.
*/
- (CGFloat)lastLineDescent;
#pragma mark - Drawing
/**
* Draw the layout frame content into a CGContext.
*
* This is the primary rendering method. It draws:
* 1. Text content using CTFrameDraw
* 2. Image attachments at their calculated positions
* 3. Decorative elements (strikethrough, underline, etc.)
*
* @param context The CGContext to draw into
* @param image Optional image to draw (for cover pages)
* @param size The size of the drawing area
* @param rect The rectangle to draw within
* @param position The position offset for the content
*/
- (void)drawInContext:(CGContextRef)context
image:(nullable UIImage *)image
size:(CGSize)size
inRect:(CGRect)rect
position:(CGPoint)position;
/**
* Draw only the text content (no images).
*/
- (void)drawTextInContext:(CGContextRef)context
inRect:(CGRect)rect;
/**
* Draw image attachments.
*/
- (void)drawAttachmentsInContext:(CGContextRef)context
inRect:(CGRect)rect;
#pragma mark - Page Break Avoidance
/**
* Removes the last lines if needed to avoid page breaks inside certain elements.
*
* This implements the CSS 'avoid-page-break-inside' property. When an element
* (like a table, code block, or list) cannot fit entirely on the current page,
* this method removes lines from the end until the element can fit.
*
* @return YES if lines were removed, NO otherwise
*/
- (BOOL)avoidPageBreakInsideByRemovingLastLinesIfNeeded;
/**
* Check if a range of text has the avoid-page-break-inside property.
*/
- (BOOL)shouldAvoidPageBreakInRange:(NSRange)range;
#pragma mark - Hit Testing
/**
* Returns the character index at a given point.
*
* @param point The point to test (in the frame's coordinate system)
* @return The character index, or NSNotFound if no character at that point
*/
- (NSUInteger)characterIndexAtPoint:(CGPoint)point;
/**
* Returns the line index at a given point.
*
* @param point The point to test
* @return The line index, or NSNotFound
*/
- (NSUInteger)lineIndexAtPoint:(CGPoint)point;
/**
* Returns the rect for a character at the given index.
*/
- (CGRect)rectForCharacterAtIndex:(NSUInteger)index;
#pragma mark - Selection
/**
* Returns the selected text string.
*/
- (nullable NSString *)selectedText;
/**
* Returns the ranges of selected text.
*/
- (NSArray<NSValue *> *)selectedRanges;
/**
* Selects text in the given range.
*/
- (void)selectTextInRange:(NSRange)range;
/**
* Clears the current selection.
*/
- (void)clearSelection;
#pragma mark - Search
/**
* Highlights search results within this frame.
*
* @param searchString The string to highlight
* @return The number of matches found
*/
- (NSUInteger)highlightSearchResults:(NSString *)searchString;
/**
* Clears all search result highlights.
*/
- (void)clearSearchHighlights;
@end
NS_ASSUME_NONNULL_END