TextExtractor
Linear text extraction (ISO 32000-1 §9.4).
Walks content-stream operations for text-showing operators:
Tj: show a stringTJ: show an array of strings/spacing adjustments': move to next line and show": set spacing, move to next line, and show
Show strings are decoded through the current font (set by Tf), so each font's /Encoding and /ToUnicode CMap apply. This is what makes composite Type 0 fonts (Identity-H, 2-byte codes) and embedded CJK extract correctly rather than byte-for-byte. When no font is resolvable the bytes fall back to PdfString.asText() (PDFDocEncoding / UTF-16BE BOM detection).
Line breaks are inserted on BT/ET, Td, TD, T*, Tm heuristics because PDF text positioning is geometric, not line-based. Those size-scaled heuristics read the Tf size times the Tm scale, since a producer may set Tf to 1 and carry the real size in the matrix.
A form XObject that the page draws with Do adds its text in place, read with the form's own fonts (ISO 32000-1, 8.10, #459). A marked-content sequence with /ActualText adds that text in place of the text it encloses (14.9.4, #468).
A label that the page draws twice in one place reads once (#644). A fake bold fills a label and then strokes it, or fills it again a fraction of a point aside, and a halo strokes it in white under its fill, each pass a text-showing operator of its own (9.4.3). So the walk also moves a pen as the renderer does, through the text matrix, the advance of each glyph and the CTM (9.4.2 and 9.4.4), and skips a show when an earlier show that stayed drew the same text there: at the same size within a tenth, in the same direction, and with both ends less than a tenth of an em away. RedrawnText makes the same test glyph by glyph for the structured text. This walk compares whole shows, so a second pass that splits its text into other shows than the first reads twice here. Shows that follow each other along a line never match each other, and a space never matches, so double letters in tight type and the gap after a leader stay.
This is the cheap linear path: the order is the order of the content stream, and the line breaks follow Tm and Td alone. PdfPage.structuredText gives positions and reading order.