The editor processor: run through RewriteContent(ContentEditor) or RewriteContent(ContentEditor), it sees every operator of the page's or form's own content with its byte range (CurrentOperator, GetOperator(Int32)) alongside the usual events, and removes, replaces, inserts before or after, or wraps operators. When the run ends the content is written again as one stream: untouched bytes are copied as they were, edits take the place of the operators they name.
public abstract class ContentEditor : ContentProcessor
ISO 32000-2 §7.8.2: content is a sequence of operators, each preceded by its operands, so an operator's range (first operand
through keyword) can be removed, replaced or surrounded without reading anything else again. A page's Contents array is
read and rewritten as one stream, its parts joined by the line feed the interpreter reads between them (Table 31: the parts
behave as if concatenated with at least one white-space character between them).
Operators are numbered from 0 in the order they appear in the stream being rewritten; operators of nested content (form
XObjects, Type 3 glyphs, patterns, soft masks) are not numbered, and while their events arrive CurrentOperator is
the operator of the rewritten stream that started them, such as the Do of a form. Edits may name any operator already
numbered, during the run or in EndRun(ContentContext); they are applied together after the run.
Order of edits at one operator: text inserted before it is written in the order it was inserted, after the opening text of every wrap that starts there; text inserted after it in insertion order, before the closing text of every wrap that ends there. Wraps nest: one that covers more operators encloses one that covers fewer, and of two wraps over the same operators the later encloses the earlier. The last Remove(Int32) or Replace(Int32, ReadOnlySpan<Byte>) of an operator wins. Inserted and replacing text is separated from its neighbours by a line feed, and a removal that would join two tokens leaves a space between them, so the tokens on each side of an edit read as they did.
The bookkeeping is done by the rewrite itself, so an editor overrides any ContentProcessor member freely without calling the base. Run any other way (ProcessContent(ContentProcessor)), an editor numbers nothing and its edit methods throw. One editor serves one rewrite at a time and keeps its buffers for the next, so a reused editor allocates nothing per operator.
kind:method, kind:property, kind:ctor. Press Esc to clear.ContentEditor()Initializes a new instance of the ContentEditor class.ContentGets the content being rewritten: the decoded stream, or the parts of a Contents array joined; empty outside a rewrite.CurrentOperatorGets the number of the operator of the rewritten stream that is executing (the one whose events are being reported, or that started the nested content being reported); -1 before the first operator and outside a rewrite.OperatorCountGets the number of operators numbered so far in the running rewrite; 0 outside a rewrite.GetOperator(Int32)Returns where an operator of the rewritten stream is.InsertAfter(Int32, ReadOnlySpan<Byte>)Inserts content after an operator's keyword.InsertBefore(Int32, ReadOnlySpan<Byte>)Inserts content before an operator's first operand.Remove(Int32)Removes an operator and its operands.Replace(Int32, ReadOnlySpan<Byte>)Replaces an operator and its operands with content.Wrap(Int32, Int32, ReadOnlySpan<Byte>, ReadOnlySpan<Byte>)Surrounds the operators first through last, such as a text object in a marked-content sequence (/P <</MCID 0>> BDC … EMC) or a group of paints in q … Q.