Bot forums

This commit is contained in:
Isaac
2025-08-19 17:24:33 +02:00
parent bdaf5f5a02
commit ee749050f0
35 changed files with 990 additions and 144 deletions

View File

@@ -1018,6 +1018,30 @@ public final class InteractiveTextNodeLayout: NSObject {
}
return nil
}
public func sizeForGlyphCount(glyphCount: Int) -> CGSize {
var height: CGFloat = 0.0
if !self.segments.isEmpty, let line = self.segments[0].lines.first {
height = line.frame.maxY
}
var count = 0
for segment in self.segments {
for line in segment.lines {
if count >= glyphCount {
break
}
let glyphRuns = CTLineGetGlyphRuns(line.line) as NSArray
for run in glyphRuns {
let run = run as! CTRun
let glyphCount = CTRunGetGlyphCount(run)
count += Int(glyphCount)
}
height = max(height, line.frame.maxY)
}
}
height += self.insets.top + self.insets.bottom + 2.0
return CGSize(width: self.size.width + self.insets.left + self.insets.right, height: ceil(height))
}
}
private func addSpoiler(line: InteractiveTextNodeLine, ascent: CGFloat, descent: CGFloat, startIndex: Int, endIndex: Int) {
@@ -1144,6 +1168,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
}
public internal(set) var cachedLayout: InteractiveTextNodeLayout?
public internal(set) var revealGlyphCount: Int?
public var renderContentTypes: RenderContentTypes = .all
private var contentItemLayers: [Int: TextContentItemLayer] = [:]
@@ -2068,6 +2093,65 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
})
}
}
public func getGlyphCount() -> Int {
guard let cachedLayout = self.cachedLayout else {
return 0
}
var count: Int = 0
for segment in cachedLayout.segments {
for line in segment.lines {
let glyphRuns = CTLineGetGlyphRuns(line.line) as NSArray
for run in glyphRuns {
let run = run as! CTRun
let glyphCount = CTRunGetGlyphCount(run)
count += Int(glyphCount)
}
}
}
return count
}
public func updateRevealGlyphCount(count: Int?) {
guard let cachedLayout = self.cachedLayout else {
return
}
self.revealGlyphCount = count
if let count {
var nextItemId = 0
var currentCount = 0
for segment in cachedLayout.segments {
let itemId = nextItemId
nextItemId += 1
var segmentGlyphCount = 0
for line in segment.lines {
let glyphRuns = CTLineGetGlyphRuns(line.line) as NSArray
for run in glyphRuns {
let run = run as! CTRun
let glyphCount = CTRunGetGlyphCount(run)
segmentGlyphCount += Int(glyphCount)
}
}
let segmentInnerCount = min(max(0, count - currentCount), segmentGlyphCount)
if let item = self.contentItemLayers[itemId] {
item.updateMaxGlyphDrawCount(value: segmentInnerCount)
}
currentCount += segmentGlyphCount
}
} else {
for (_, item) in self.contentItemLayers {
item.updateMaxGlyphDrawCount(value: nil)
}
}
}
}
final class TextContentItem {
@@ -2148,11 +2232,13 @@ final class TextContentItemLayer: SimpleLayer {
let size: CGSize
let item: TextContentItem
let mask: RenderMask?
let maxGlyphDrawCount: Int?
init(size: CGSize, item: TextContentItem, mask: RenderMask?) {
init(size: CGSize, item: TextContentItem, mask: RenderMask?, maxGlyphDrawCount: Int?) {
self.size = size
self.item = item
self.mask = mask
self.maxGlyphDrawCount = maxGlyphDrawCount
super.init()
}
@@ -2232,6 +2318,8 @@ final class TextContentItemLayer: SimpleLayer {
let offset = params.item.contentOffset
let alignment: NSTextAlignment = .left
var drawnGlyphCount = 0
for i in 0 ..< params.item.segment.lines.count {
let line = params.item.segment.lines[i]
@@ -2261,6 +2349,15 @@ final class TextContentItemLayer: SimpleLayer {
for run in glyphRuns {
let run = run as! CTRun
let glyphCount = CTRunGetGlyphCount(run)
var runDrawGlyphCount = glyphCount
if let maxGlyphDrawCount = params.maxGlyphDrawCount {
if drawnGlyphCount >= maxGlyphDrawCount {
break
}
runDrawGlyphCount = CFIndex(max(0, min(Int(glyphCount), maxGlyphDrawCount - drawnGlyphCount)))
}
let attributes = CTRunGetAttributes(run) as NSDictionary
if attributes["Attribute__EmbeddedItem"] != nil {
continue
@@ -2310,12 +2407,14 @@ final class TextContentItemLayer: SimpleLayer {
let stringRange = CTRunGetStringRange(run)
if line.attachments.contains(where: { $0.range.contains(stringRange.location) }) {
} else {
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
CTRunDraw(run, context, CFRangeMake(0, runDrawGlyphCount))
}
} else {
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
CTRunDraw(run, context, CFRangeMake(0, runDrawGlyphCount))
}
drawnGlyphCount += Int(glyphCount)
if fixDoubleEmoji {
context.setBlendMode(.normal)
}
@@ -2464,6 +2563,8 @@ final class TextContentItemLayer: SimpleLayer {
private var isAnimating: Bool = false
private var currentContentMask: RenderMask?
private var maxGlyphDrawCount: Int?
init(displaysAsynchronously: Bool) {
self.renderNode = RenderNode()
self.renderNode.displaysAsynchronously = displaysAsynchronously
@@ -2483,6 +2584,17 @@ final class TextContentItemLayer: SimpleLayer {
fatalError("init(coder:) has not been implemented")
}
func updateMaxGlyphDrawCount(value: Int?) {
if self.maxGlyphDrawCount != value {
self.maxGlyphDrawCount = value
if let renderParams = self.renderNode.params {
self.renderNode.params = RenderParams(size: renderParams.size, item: renderParams.item, mask: renderParams.mask, maxGlyphDrawCount: self.maxGlyphDrawCount)
self.renderNode.displayImmediately()
}
}
}
func update(
params: Params,
animation: ListViewItemUpdateAnimation,
@@ -2735,7 +2847,7 @@ final class TextContentItemLayer: SimpleLayer {
self.currentContentMask = contentMask
self.renderNode.params = RenderParams(size: contentFrame.size, item: params.item, mask: staticContentMask)
self.renderNode.params = RenderParams(size: contentFrame.size, item: params.item, mask: staticContentMask, maxGlyphDrawCount: self.maxGlyphDrawCount)
if synchronously {
if let spoilerExpandRect, animation.isAnimated {
let localSpoilerExpandRect = spoilerExpandRect.offsetBy(dx: -self.renderNode.frame.minX, dy: -self.renderNode.frame.minY)