DIRECTORY Atom USING [GetPName, GetPropFromList, PropList, PutPropOnList], Char USING [Widen], Commander USING [Handle], Convert USING [RopeFromInt], Imager USING [Box, ConcatT, Context, Correct, DoSave, SetCorrectMeasure, SetCorrectTolerance, SetFont, SetXY, ShowRope, ShowXChar, TranslateT], ImagerBox USING [BoundingBox, BoxFromExtents, BoxFromRectangle, RectangleFromBox], ImagerFont USING [Amplified, BoundingBox, Font, RopeBoundingBox, RopeEscapement, Escapement, XChar], ImagerTransformation USING [Concat, InverseTransform, Transformation, TransformRectangle, TransformVec], IO USING [PutRope, STREAM], NodeProps USING [GetProp], NodeStyle USING [Ref, RealParam, StyleKind, GetReal, GetInt, PointsPerFil], NodeStyleFont USING [FontFromStyleParams], NodeStyleOps USING [Alloc, ApplyAll, ApplyFormat, Free, GetStyleParam, OfStyle, nonNumeric], Process USING [CheckForAbort], ProcessProps USING [GetProp], Real USING [LargestNumber, Round], Rope USING [Cat, Concat, Equal, ROPE, Size], Scaled USING [Float, FromReal, PLUS, Value, zero], SimpleFeedback USING [Append], TEditFormat USING [Allocate, FormatLine, LineInfo, Paint, Release, Resolve], TextEdit USING [Size], TextNode USING [Forward, Level, Location, LocNumber, nullLocation, Ref, Root, StepForward], TiogaImager USING [Box, Boxes, BoxRep, Class, ClassRep, FilterProc, Fix, FormattedNodes, FormattedPage, InsertID, SepProc], TJaM USING [Stop], Vector2 USING [Add, Sub, VEC]; TiogaImagerImpl: CEDAR PROGRAM IMPORTS Atom, Char, Convert, Imager, ImagerBox, ImagerFont, IO, Process, ProcessProps, ImagerTransformation, Real, Rope, NodeProps, NodeStyle, NodeStyleFont, NodeStyleOps, Scaled, SimpleFeedback, TEditFormat, TextEdit, TextNode, TJaM, Vector2 EXPORTS TiogaImager ~ BEGIN Context: TYPE ~ Imager.Context; Font: TYPE ~ ImagerFont.Font; Transformation: TYPE ~ ImagerTransformation.Transformation; VEC: TYPE ~ Vector2.VEC; XChar: TYPE ~ ImagerFont.XChar; ROPE: TYPE ~ Rope.ROPE; Box: TYPE ~ TiogaImager.Box; Boxes: TYPE ~ TiogaImager.Boxes; BoxRep: TYPE ~ TiogaImager.BoxRep; Class: TYPE ~ TiogaImager.Class; ClassRep: TYPE ~ TiogaImager.ClassRep; Fix: TYPE ~ TiogaImager.Fix; FilterProc: TYPE ~ TiogaImager.FilterProc; FormattedNodes: TYPE ~ TiogaImager.FormattedNodes; InsertID: TYPE ~ TiogaImager.InsertID; SepProc: TYPE ~ PROC [InsertID] RETURNS [TiogaImager.Box]; Marks: TYPE ~ Atom.PropList; FormattedPage: TYPE ~ TiogaImager.FormattedPage; FormatLine: PUBLIC PROC [start: TextNode.Location, lineWidth: REAL, style: NodeStyle.Ref] RETURNS [box: Box] ~ { lineInfo: TEditFormat.LineInfo ¬ TEditFormat.Allocate[]; bounds: Imager.Box; xOffset: REAL; Process.CheckForAbort[]; TEditFormat.FormatLine[lineInfo: lineInfo, node: start.node, startOffset: MAX[start.where, 0], nodeStyle: style, lineWidth: Scaled.FromReal[lineWidth], doLigsAndKern: TRUE]; Process.CheckForAbort[]; bounds ¬ [xmin: lineInfo.xmin, ymin: lineInfo.ymin, xmax: lineInfo.xmax, ymax: lineInfo.ymax]; xOffset ¬ Scaled.Float[lineInfo.xOffset]; bounds.xmin ¬ bounds.xmin + xOffset; bounds.xmax ¬ bounds.xmax + xOffset; box ¬ NEW[BoxRep ¬ [ nChars: lineInfo.nChars, bounds: bounds, expansion: [0, 0], escapement: [0, -NodeStyle.GetReal[style, leading]], stretch: [0, 0], shrink: [0, 0], class: tiogaClass, data: lineInfo ]]; }; InsertIDFromRope: PROC [rope: ROPE] RETURNS [InsertID] ~ { RETURN [SELECT TRUE FROM Rope.Equal[rope, "top", FALSE] => top, Rope.Equal[rope, NIL, FALSE] => normal, Rope.Equal[rope, "bottom", FALSE] => bottom, Rope.Equal[rope, "foot", FALSE] => foot, ENDCASE => nil ] }; Msg: PROC [rope: ROPE] ~ { WITH ProcessProps.GetProp[$CommanderHandle] SELECT FROM cmd: Commander.Handle => { msgStream: IO.STREAM ¬ cmd.err; IO.PutRope[msgStream, " "]; IO.PutRope[msgStream, rope]; IO.PutRope[msgStream, "\n"]; }; ENDCASE => { SimpleFeedback.Append[$TiogaImager, begin, $Error, "TiogaImagerImpl: "]; SimpleFeedback.Append[$TiogaImager, end, $Error, rope]; }; }; GetStyleParam: PROC [style: NodeStyle.Ref, param: ATOM, default: REAL, kind: NodeStyle.StyleKind] RETURNS [REAL] ~ { val: REAL ¬ default; val ¬ NodeStyleOps.GetStyleParam[s: style, name: param, styleName: style.name[style], kind: kind ! TJaM.Stop, NodeStyleOps.nonNumeric => {Msg[Rope.Concat["Undefined StyleParam: ", Atom.GetPName[param]]]; CONTINUE}]; RETURN [val] }; insertOrder: ARRAY [0..4) OF InsertID ¬ [top, normal, foot, bottom]; FormatNodes: PUBLIC PROC [start: TextNode.Location, bounds: VEC, styleKind: NodeStyle.StyleKind, filter: FilterProc, sep: TiogaImager.SepProc] RETURNS [FormattedNodes] ~ { loc: TextNode.Location ¬ start; nodeSize: INT ¬ TextEdit.Size[loc.node]; nodeStyle: NodeStyle.Ref ¬ NodeStyleOps.Alloc[]; insertID: InsertID ¬ InsertIDFromRope[NARROW[NodeProps.GetProp[loc.node, $Insert]]]; NextNode: PROC ~ { nx: TextNode.Ref; levelDelta: INTEGER; [nx, levelDelta] ¬ TextNode.Forward[loc.node]; level ¬ level + levelDelta; loc.node ¬ nx; loc.where ¬ 0; nodeSize ¬ TextEdit.Size[loc.node]; IF loc.node # NIL THEN { NodeStyleOps.ApplyAll[nodeStyle, loc.node, styleKind]; insertID ¬ InsertIDFromRope[NARROW[NodeProps.GetProp[loc.node, $Insert]]]; }; }; boxes: ARRAY InsertID OF Boxes ¬ ALL[[NIL, NIL]]; lastNode: ARRAY InsertID OF TextNode.Ref ¬ ALL[NIL]; result: Boxes ¬ [NIL, NIL]; h: REAL ¬ 0.0; level: INT ¬ TextNode.Level[loc.node]; stopper: NAT ¬ 10000; -- to prevent runaways firstTime: BOOL ¬ TRUE; -- do loop body at least once, to assure progress HeightOfSep: PROC [id: InsertID] RETURNS [REAL] ~ { hTemp: REAL ¬ 0.0; b: LIST OF Box ¬ sep[id]; FOR p: LIST OF Box ¬ b, p.rest UNTIL p=NIL DO hTemp ¬ hTemp - p.first.escapement.y; ENDLOOP; RETURN [hTemp]; }; InsertSep: PROC [id: InsertID] ~ { b: LIST OF Box ¬ sep[id]; bxs: Boxes ¬ [NIL, NIL]; FOR p: LIST OF Box ¬ b, p.rest UNTIL p=NIL DO Duplicate[p.first]; bxs ¬ AppendBox[bxs, p.first]; h ¬ h - p.first.escapement.y; ENDLOOP; boxes[id] ¬ AppendList[bxs, boxes[id].list]; }; kind: NodeStyle.StyleKind ~ styleKind; keepStretch: REAL ¬ 0.0; box: Box ¬ NIL; boxToStretch: Box ¬ NIL; maxVerticalExpansion: REAL ¬ 0; NodeStyleOps.ApplyAll[nodeStyle, loc.node, kind]; maxVerticalExpansion ¬ NodeStyle.GetReal[nodeStyle, $maxVerticalExpansion]; h ¬ 0; WHILE firstTime OR (loc.node # NIL AND h <= bounds.y) DO skip, stop: BOOL ¬ FALSE; xbound: REAL ¬ Real.LargestNumber; IF filter#NIL THEN [skip, stop, xbound] ¬ filter[loc, level, [0, -h]]; IF stop THEN {IF skip OR loc.where = nodeSize THEN NextNode[]; EXIT}; IF NOT skip AND NOT firstTime AND loc.where = 0 THEN { keep: REAL ~ GetStyleParam[nodeStyle, $keep, 0, kind]; IF h + keep > bounds.y THEN { keepStretch ¬ GetStyleParam[nodeStyle, $keepStretch, NodeStyle.PointsPerFil, kind]; EXIT; }; }; IF NOT skip THEN { lineBox: Box ¬ FormatLine[loc, MIN[bounds.x, xbound], nodeStyle]; lineBox.stretch.y ¬ -NodeStyle.GetReal[nodeStyle, leadingStretch]; lineBox.shrink.y ¬ -NodeStyle.GetReal[nodeStyle, leadingShrink]; stopper ¬ stopper - 1; IF boxes[insertID].list = NIL THEN { topIndent: REAL ¬ NodeStyle.GetReal[nodeStyle, topIndent]; topIndentStretch: REAL ¬ GetStyleParam[nodeStyle, $topIndentStretch, 0, kind]; IF sep#NIL THEN { hTemp: REAL ¬ h + topIndent - lineBox.escapement.y; IF insertID # normal OR boxes[top].list # NIL THEN hTemp ¬ hTemp + HeightOfSep[insertID]; IF insertID = top AND boxes[normal].list # NIL THEN hTemp ¬ hTemp + HeightOfSep[normal]; IF hTemp > bounds.y AND NOT firstTime THEN EXIT; IF hTemp <= bounds.y THEN { IF insertID # normal OR boxes[top].list # NIL THEN InsertSep[insertID]; IF insertID = top AND boxes[normal].list # NIL THEN InsertSep[normal]; }; }; boxes[insertID] ¬ AppendBox[boxes[insertID], EmptyBox[escapement: [0, -topIndent], stretch: [0, -topIndentStretch]]]; h ¬ h + topIndent; } ELSE IF loc.where = 0 THEN { prevBox: Box ~ boxes[insertID].last.first; prevSkip: REAL ~ -prevBox.escapement.y; newSkip: REAL ~ MAX[prevSkip, NodeStyle.GetReal[nodeStyle, topLeading]]; IF h - lineBox.escapement.y + (newSkip-prevSkip) > bounds.y AND NOT firstTime THEN EXIT; h ¬ h + (newSkip-prevSkip); prevBox.escapement.y ¬ -newSkip; prevBox.shrink.y ¬ prevBox.shrink.y-NodeStyle.GetReal[nodeStyle, topLeadingShrink]; prevBox.stretch.y ¬ prevBox.stretch.y-NodeStyle.GetReal[nodeStyle, topLeadingStretch]; lineBox.stretch.y ¬ -NodeStyle.GetReal[nodeStyle, leadingStretch]; }; IF h - lineBox.escapement.y > bounds.y AND NOT firstTime THEN EXIT; IF lineBox.nChars = 0 AND nodeSize > 0 THEN ERROR; loc.where ¬ loc.where + lineBox.nChars; IF loc.where = nodeSize THEN { lineBox.escapement.y ¬ -NodeStyle.GetReal[nodeStyle, bottomLeading]; lineBox.shrink.y ¬ -NodeStyle.GetReal[nodeStyle, bottomLeadingShrink]; lineBox.stretch.y ¬ -NodeStyle.GetReal[nodeStyle, bottomLeadingStretch]; }; boxes[insertID] ¬ AppendBox[boxes[insertID], lineBox]; lastNode[insertID] ¬ loc.node; h ¬ h - lineBox.escapement.y; }; IF skip OR loc.where = nodeSize THEN NextNode[]; firstTime ¬ FALSE; ENDLOOP; IF loc.node = NIL THEN { keepStretch ¬ keepStretch + NodeStyle.PointsPerFil; }; FOR insertNumber: NAT IN [0..LENGTH[insertOrder]) DO i: InsertID ~ insertOrder[insertNumber]; IF boxes[i].last # NIL AND lastNode[i] # NIL THEN { lastBox: Box ¬ boxes[i].last.first; NodeStyleOps.ApplyAll[nodeStyle, lastNode[i], kind]; lastBox.escapement.y ¬ -NodeStyle.GetReal[nodeStyle, bottomIndent]; lastBox.stretch.y ¬ -GetStyleParam[nodeStyle, $bottomIndentStretch, 0, kind]; IF i = normal THEN { lastBox.stretch.y ¬ lastBox.stretch.y - keepStretch; boxToStretch ¬ lastBox; }; lastBox.shrink.y ¬ 0; }; result ¬ AppendList[result, boxes[i].list]; ENDLOOP; box ¬ BoxFromList[result.list, [], [size, -bounds.y]]; IF box.expansion.y > maxVerticalExpansion AND boxToStretch#NIL THEN { boxToStretch.stretch.y ¬ boxToStretch.stretch.y - NodeStyle.PointsPerFil; box ¬ BoxFromList[result.list, [], [size, -bounds.y]]; }; NodeStyleOps.Free[nodeStyle]; RETURN [[box: box, resume: loc]]; }; GetNodeStyle: PROC [node: TextNode.Ref, kind: NodeStyleOps.OfStyle] RETURNS [nodeStyle: NodeStyle.Ref] ~ { nodeStyle ¬ NodeStyleOps.Alloc[]; NodeStyleOps.ApplyAll[nodeStyle, node, kind]; }; validMarks: LIST OF ATOM ¬ LIST[ $invisible, $insideRectoHeader, $centerRectoHeader, $outsideRectoHeader, $centerVersoHeader, $insideVersoHeader, $outsideVersoHeader, $insideHeader, $centerHeader, $outsideHeader, $insideRectoFooter, $centerRectoFooter, $outsideRectoFooter, $outsideVersoFooter, $centerVersoFooter, $insideVersoFooter, $insideFooter, $centerFooter, $outsideFooter, $headSeparator, $topSeparator, $bottomSeparator, $footSeparator, $headSep, $topSep, $bottomSep, $footSep ]; GetMarkAtom: PROC [mark: ROPE, location: TextNode.Location] RETURNS [ATOM] ~ { atom: ATOM ¬ NIL; realAtom: ATOM ¬ NIL; FOR p: LIST OF ATOM ¬ validMarks, p.rest UNTIL p = NIL DO atom ¬ p.first; IF Rope.Equal[Atom.GetPName[atom], mark, FALSE] THEN { realAtom ¬ SELECT atom FROM $headSep => $headSeparator, $topSep => $topSeparator, $bottomSep => $bottomSeparator, $footSep => $footSeparator, ENDCASE => atom; EXIT; }; atom ¬ NIL; ENDLOOP; IF realAtom = NIL OR realAtom # atom THEN { msg: ROPE ¬ NIL; IF realAtom = NIL THEN { msg ¬ msg.Cat["Unrecognized mark property \"", mark, "\""]; } ELSE { msg ¬ msg.Cat["Obsolete mark property ", Atom.GetPName[atom]]; msg ¬ msg.Cat[" (Use ", Atom.GetPName[realAtom], ")"]; }; msg ¬ msg.Cat[" at location ", Convert.RopeFromInt[TextNode.LocNumber[at: location, skipCommentNodes: TRUE]]]; Msg[msg]; }; RETURN [realAtom] }; topVersoItems: LIST OF LIST OF ATOM ¬ LIST[ LIST[$outsideVersoHeader, $outsideHeader, $PAGE], LIST[$centerVersoHeader, $centerHeader], LIST[$insideVersoHeader, $insideHeader] ]; botVersoItems: LIST OF LIST OF ATOM ¬ LIST[ LIST[$PAGE, $outsideVersoFooter, $outsideFooter], LIST[$DROPFOLIO, $centerVersoFooter, $centerFooter], LIST[$insideVersoFooter, $insideFooter] ]; topRectoItems: LIST OF LIST OF ATOM ¬ LIST[ LIST[$insideRectoHeader, $insideHeader], LIST[$centerRectoHeader, $centerHeader], LIST[$outsideRectoHeader, $outsideHeader, $PAGE] ]; botRectoItems: LIST OF LIST OF ATOM ¬ LIST[ LIST[$insideRectoFooter, $insideFooter], LIST[$DROPFOLIO, $centerRectoFooter, $centerFooter], LIST[$PAGE, $outsideRectoFooter, $outsideFooter] ]; FormatPage: PUBLIC PROC [pageCounter: INT, startLoc: TextNode.Location, filter: FilterProc ¬ NIL, marks: Marks ¬ NIL, styleKind: NodeStyle.StyleKind] RETURNS [FormattedPage] ~ { pageNeedsNumber: BOOL ¬ TRUE; topMarks: Atom.PropList ~ marks; botMarks: Atom.PropList ¬ marks; GetSeparator: PROC [i: InsertID] RETURNS [LIST OF Box ¬ NIL] ~ { key: ATOM ~ SELECT i FROM top => $headSeparator, normal => $topSeparator, bottom => $bottomSeparator, foot => $footSeparator, ENDCASE => NIL; IF key # NIL THEN RETURN [NARROW[Atom.GetPropFromList[botMarks, key]]] }; root: TextNode.Ref ~ TextNode.Root[startLoc.node]; nodeStyle: NodeStyle.Ref ¬ GetNodeStyle[root, styleKind]; GetStylePoints: PROC [param: NodeStyle.RealParam] RETURNS [REAL] ~ { RETURN [NodeStyle.GetReal[nodeStyle, param]] }; loc: TextNode.Location ¬ IF startLoc.node = root THEN [TextNode.StepForward[root], 0] ELSE startLoc; leftMargin: REAL ~ GetStylePoints[leftMargin]; rightMargin: REAL ~ GetStylePoints[rightMargin]; bindingMargin: REAL ~ GetStylePoints[bindingMargin]; topMargin: REAL ~ GetStylePoints[topMargin]; headerMargin: REAL ~ GetStylePoints[headerMargin]; bottomMargin: REAL ~ GetStylePoints[bottomMargin]; footerMargin: REAL ~ GetStylePoints[footerMargin]; nColumns: INT ~ MAX[NodeStyle.GetInt[nodeStyle, columns], 1]; columnGap: REAL ~ GetStyleParam[nodeStyle, $columnGap, 36, styleKind]; pageWidth: REAL ~ GetStylePoints[pageWidth]; pageLength: REAL ~ GetStylePoints[pageLength]; totalWidth: REAL ~ MAX[pageWidth-leftMargin-rightMargin-bindingMargin, 0.0]; lineWidth: REAL ~ MAX[(totalWidth-(nColumns-1)*columnGap)/nColumns, 0.0]; pageBodyHeight: REAL ~ MAX[pageLength-topMargin-bottomMargin-headerMargin-footerMargin, 0.0]; bodyHeight: REAL ¬ pageBodyHeight; firstFolio: INT ~ Real.Round[GetStyleParam[nodeStyle, $firstFolio, 1, styleKind]]; firstVisibleFolio: INT ~ Real.Round[GetStyleParam[nodeStyle, $firstVisibleFolio, 1, styleKind]]; lastDropFolio: INT ~ Real.Round[GetStyleParam[nodeStyle, $lastDropFolio, 0, styleKind]]; twoSided: BOOL ~ GetStyleParam[nodeStyle, $sided, 1.0, styleKind] > 1.5; firstHeaders: INT ~ Real.Round[GetStyleParam[nodeStyle, $firstHeaders, 0.0, styleKind]]; myFilter: FilterProc ~ { IF filter # NIL THEN [skip: skip, stop: stop, maxLineLength: maxLineLength] ¬ filter[node, level, position]; IF NOT skip THEN { filterStart: TextNode.Location ¬ node; markFilter: FilterProc ~ { IF node # filterStart THEN skip ¬ stop ¬ TRUE; }; markProp: ROPE ~ NARROW[NodeProps.GetProp[node.node, $Mark]]; IF Rope.Size[markProp]#0 THEN { markAtom: ATOM ~ GetMarkAtom[markProp, filterStart]; inColumn: BOOL ~ SELECT markAtom FROM $headSeparator, $topSeparator, $bottomSeparator, $footSeparator => TRUE ENDCASE => FALSE; width: REAL ~ IF inColumn THEN lineWidth ELSE totalWidth; height: REAL ~ ( SELECT markAtom FROM $insideRectoHeader, $centerRectoHeader, $outsideRectoHeader, $centerVersoHeader, $insideVersoHeader, $outsideVersoHeader, $insideHeader, $centerHeader, $outsideHeader => headerMargin, $insideRectoFooter, $centerRectoFooter, $outsideRectoFooter, $outsideVersoFooter, $centerVersoFooter, $insideVersoFooter, $insideFooter, $centerFooter, $outsideFooter => footerMargin, ENDCASE => pageBodyHeight ); IF markAtom # NIL THEN { IF TextEdit.Size[node.node] = 0 THEN { botMarks ¬ Atom.PutPropOnList[botMarks, markAtom, NIL]; } ELSE { bx: Box ~ FormatNodes[start: node, bounds: [width, height], styleKind: styleKind, filter: markFilter, sep: NIL].box; mark: LIST OF Box ~ UnBox[bx]; Duplicate[bx]; FOR p: LIST OF Box ¬ mark, p.rest UNTIL p=NIL DO IF p.first = NIL THEN ERROR; Duplicate[p.first]; ENDLOOP; botMarks ¬ Atom.PutPropOnList[botMarks, markAtom, mark]; }; }; skip ¬ TRUE; }; }; }; CatMarks: PROC [items: LIST OF LIST OF ATOM] RETURNS [Box] ~ { pageNumber: INT ¬ pageCounter+firstFolio; boxes: Boxes ¬ []; result: Box ¬ NIL; pageKey: ATOM ~ IF pageNumber <= lastDropFolio THEN $DROPFOLIO ELSE $PAGE; FOR p: LIST OF LIST OF ATOM ¬ items, p.rest UNTIL p=NIL DO b: Box ¬ NIL; FOR q: LIST OF ATOM ¬ p.first, q.rest UNTIL b # NIL OR q = NIL DO key: ATOM ~ q.first; IF key = pageKey AND pageNeedsNumber AND pageNumber >= firstVisibleFolio THEN { pageFigure: ROPE ~ Convert.RopeFromInt[pageNumber]; b ¬ BoxFromRope[pageNumberFont, pageFigure]; b.escapement ¬ [0, -pageNumberBotIndent]; b ¬ BoxFromList[LIST[ EmptyBox[escapement: [x: 0, y: -pageNumberTopIndent]], b]]; b.escapement ¬ [x: b.bounds.xmax, y: 0]; pageNeedsNumber ¬ FALSE; } ELSE { list: LIST OF Box ¬ NARROW[Atom.GetPropFromList[botMarks, key]]; IF list#NIL THEN { b ¬ BoxFromList[list]; Duplicate[b]; b.escapement ¬ [x: b.bounds.xmax, y: 0]; }; }; ENDLOOP; IF b = NIL THEN b ¬ EmptyBox[]; b.stretch ¬ [x: NodeStyle.PointsPerFil, y: 0]; boxes ¬ AppendBox[boxes, b]; ENDLOOP; IF boxes.last # NIL THEN boxes.last.first.stretch.x ¬ 0; result ¬ BoxFromList[list: boxes.list, xFix: [size, totalWidth]]; RETURN [result] }; leftMarg: REAL ~ leftMargin + (IF (NOT twoSided OR ((pageCounter+firstFolio) MOD 2 = 1)) THEN bindingMargin ELSE 0.0); HeadersAndFooters: PROC RETURNS [Box] ~ { topItems: LIST OF LIST OF ATOM ¬ topRectoItems; botItems: LIST OF LIST OF ATOM ¬ botRectoItems; b: Box ¬ EmptyBox[]; IF twoSided THEN SELECT (pageCounter+firstFolio) MOD 2 FROM 0 => {topItems ¬ topVersoItems; botItems ¬ botVersoItems}; 1 => {topItems ¬ topRectoItems; botItems ¬ botRectoItems}; ENDCASE => NULL; IF (pageCounter+firstFolio) >= firstHeaders THEN { headerBox: Box ~ CatMarks[topItems]; footerBox: Box ~ CatMarks[botItems]; b ¬ Overlay[b, footerBox, [leftMarg, bottomMargin-footerBox.bounds.ymin]]; b ¬ Overlay[b, headerBox, [leftMarg, pageLength-topMargin]]; }; RETURN [b]; }; pageList: Boxes ¬ [NIL, NIL]; pageTitleBox: Box ¬ NIL; pageBox: Box ¬ NIL; pageNumberFont: Font ¬ NIL; pageNumberTopIndent: REAL ¬ 0; pageNumberBotIndent: REAL ¬ 0; NodeStyleOps.ApplyFormat[nodeStyle, $pagenumber, $default, styleKind]; pageNumberFont ¬ NodeStyleFont.FontFromStyleParams[prefix: nodeStyle.name[fontPrefix], family: nodeStyle.name[fontFamily], face: nodeStyle.fontFace, size: NodeStyle.GetReal[nodeStyle, fontSize], alphabets: nodeStyle.fontAlphabets]; pageNumberTopIndent ¬ NodeStyle.GetReal[nodeStyle, topIndent]; pageNumberBotIndent ¬ NodeStyle.GetReal[nodeStyle, bottomIndent]; IF nColumns > 1 THEN { haveTitle: BOOL ¬ FALSE; titleFilter: FilterProc ~ { NodeStyleOps.ApplyAll[nodeStyle, node.node, styleKind]; IF NodeStyle.GetInt[nodeStyle, columns] # 1 THEN { stop ¬ TRUE; RETURN }; [skip, stop, maxLineLength] ¬ myFilter[node, level, position]; IF NOT (skip OR stop) THEN haveTitle ¬ TRUE; }; formattedTitle: FormattedNodes ¬ FormatNodes[start: loc, bounds: [totalWidth, bodyHeight], styleKind: styleKind, filter: titleFilter, sep: GetSeparator]; IF haveTitle THEN { boxes: LIST OF Box ~ UnBox[formattedTitle.box]; rebox: Box ~ BoxFromList[boxes]; pageTitleBox ¬ rebox; bodyHeight ¬ MAX[bodyHeight - ABS[rebox.escapement.y], 0.0]; loc ¬ formattedTitle.resume; }; }; NodeStyleOps.Free[nodeStyle]; nodeStyle ¬ NIL; FOR c: INT IN [0..nColumns) WHILE loc.node # NIL DO formatted: FormattedNodes ¬ FormatNodes[start: loc, bounds: [lineWidth, bodyHeight], styleKind: styleKind, filter: myFilter, sep: GetSeparator]; formatted.box.escapement ¬ [lineWidth+columnGap, 0]; pageList ¬ AppendBox[pageList, formatted.box]; loc ¬ formatted.resume; ENDLOOP; pageBox ¬ BoxFromList[pageList.list]; IF pageTitleBox # NIL THEN { t: Boxes ¬ [NIL, NIL]; t ¬ AppendBox[t, pageTitleBox]; t ¬ AppendBox[t, pageBox]; pageBox ¬ BoxFromList[t.list]; }; pageBox ¬ Overlay[HeadersAndFooters[], pageBox, [leftMarg, pageLength-topMargin-headerMargin]]; RETURN [[box: pageBox, nextLoc: loc, marks: botMarks, pageFigure: pageCounter+firstFolio]] }; tiogaClass: Class ¬ NEW[ClassRep ¬ [ Composite: NIL, UnBox: NIL, Render: TiogaRender, Resolve: TiogaResolve, Destroy: TiogaDestroy ]]; useCorrect: BOOL ¬ TRUE; TiogaRender: PROC [box: Box, context: Context, position: VEC] ~ { lineInfo: TEditFormat.LineInfo ~ NARROW[box.data]; position.x ¬ position.x + Scaled.Float[lineInfo.xOffset]; Imager.SetXY[context, position]; IF useCorrect AND lineInfo.artworkClass = NIL AND lineInfo.amplifySpace # 1.0 AND lineInfo.startAmplifyIndex <= lineInfo.nChars THEN { Action: PROC = { TEditFormat.Paint[lineInfo, context] }; w: Scaled.Value ¬ Scaled.zero; nChars: NAT ~ lineInfo.nChars+(IF lineInfo.nBlankCharsAtEnd=NAT.LAST THEN 1 ELSE -lineInfo.nBlankCharsAtEnd); FOR i: NAT IN [0..nChars) DO w ¬ Scaled.PLUS[w, lineInfo.charInfo[i].width]; ENDLOOP; Imager.SetCorrectTolerance[context: context, v: [0.1, 0.1]]; Imager.SetCorrectMeasure[context: context, v: [Scaled.Float[w], 0.0]]; Imager.Correct[context: context, action: Action]; } ELSE { TEditFormat.Paint[lineInfo, context]; }; }; realInteger: REAL ¬ LAST[INTEGER]; TiogaResolve: PROC [box: Box, p: VEC] RETURNS [loc: TextNode.Location ¬ TextNode.nullLocation] ~ { lineInfo: TEditFormat.LineInfo ~ NARROW[box.data]; IF NOT InBox[p, box] THEN RETURN; loc ¬ TEditFormat.Resolve[lineInfo, Real.Round[MIN[MAX[p.x, -realInteger], realInteger]]].loc; }; TiogaDestroy: PROC [box: Box] ~ { lineInfo: TEditFormat.LineInfo ~ NARROW[box.data]; box.data ¬ NIL; TEditFormat.Release[lineInfo]; }; EmptyBox: PUBLIC PROC [escapement: VEC ¬ [0,0], stretch: VEC ¬ [0,0], shrink: VEC ¬ [0,0]] RETURNS [box: Box] ~ { box ¬ NEW[BoxRep ¬ [ nChars: 0, bounds: [0, 0, 0, 0], expansion: [0, 0], escapement: escapement, stretch: stretch, shrink: shrink, class: emptyClass, data: NIL ]]; }; emptyClass: Class ¬ NEW[ClassRep ¬ [ UnBox: NIL, Render: NIL, Resolve: NIL, Destroy: NIL ]]; BoxFromChar: PUBLIC PROC [font: Font, char: CHAR] RETURNS [Box] ~ { RETURN [BoxFromXChar[font, Char.Widen[char]]] }; BoxFromXChar: PUBLIC PROC [font: Font, xchar: XChar] RETURNS [box: Box] ~ { w: VEC ¬ ImagerFont.Escapement[font, xchar]; flex: VEC ¬ IF ImagerFont.Amplified[font, xchar] THEN w ELSE [0, 0]; box ¬ NEW[BoxRep ¬ [ nChars: 1, bounds: ImagerBox.BoxFromExtents[ImagerFont.BoundingBox[font, xchar]], expansion: [0, 0], escapement: w, stretch: flex, shrink: flex, class: xCharClass, data: NEW[XCharBoxDataRep ¬ [font, xchar]] ]]; }; XCharBoxDataRep: TYPE ~ RECORD [font: Font, xchar: XChar]; xCharClass: Class ¬ NEW[ClassRep ¬ [ UnBox: NIL, Render: XCharRender, Resolve: NIL, Destroy: NIL ]]; XCharRender: PROC [box: Box, context: Context, position: VEC] ~ { data: REF XCharBoxDataRep ~ NARROW[box.data]; Imager.SetFont[context, data.font]; Imager.SetXY[context, position]; Imager.ShowXChar[context, data.xchar]; }; BoxFromRope: PUBLIC PROC [font: Font, rope: Rope.ROPE] RETURNS [box: Box] ~ { box ¬ NEW[BoxRep ¬ [ nChars: Rope.Size[rope], bounds: ImagerBox.BoxFromExtents[ImagerFont.RopeBoundingBox[font, rope]], expansion: [0, 0], escapement: ImagerFont.RopeEscapement[font, rope], stretch: [0, 0], shrink: [0, 0], class: ropeClass, data: NEW[RopeBoxDataRep ¬ [font, rope]] ]]; }; RopeBoxDataRep: TYPE ~ RECORD [font: Font, rope: ROPE]; ropeClass: Class ¬ NEW[ClassRep ¬ [ Composite: NIL, UnBox: NIL, Render: RopeRender, Resolve: NIL, Destroy: NIL ]]; RopeRender: PROC [box: Box, context: Context, position: VEC] ~ { data: REF RopeBoxDataRep ~ NARROW[box.data]; Imager.SetFont[context, data.font]; Imager.SetXY[context, position]; Imager.ShowRope[context, data.rope]; }; CalculateExpansion: PROC [fix: Fix, w, stretch, shrink: REAL] RETURNS [e: REAL] ~ { IF fix.what = expansion THEN e ¬ fix.value ELSE { denom: REAL ¬ IF fix.value = 0 OR w/fix.value > 1.0 THEN shrink ELSE stretch; e ¬ IF ABS[denom] > 1.0e-10 THEN (fix.value-w)/denom ELSE 0.0; }; IF e < -1 THEN e ¬ -1; }; Advance: PROC [w: VEC, by: Box, expansion: VEC] RETURNS [VEC]~ { w ¬ w.Add[by.escapement]; SELECT expansion.x FROM = 0.0 => NULL; < 0.0 => w.x ¬ w.x + expansion.x*by.shrink.x; > 0.0 => w.x ¬ w.x + expansion.x*by.stretch.x; ENDCASE => NULL; SELECT expansion.y FROM = 0.0 => NULL; < 0.0 => w.y ¬ w.y + expansion.y*by.shrink.y; > 0.0 => w.y ¬ w.y + expansion.y*by.stretch.y; ENDCASE => NULL; RETURN [w]; }; CopyList: PROC [list: LIST OF Box] RETURNS [LIST OF Box] ~ { boxes: Boxes ¬ [NIL, NIL]; FOR p: LIST OF Box ¬ list, list.rest UNTIL p = NIL DO Duplicate[p.first]; boxes ¬ AppendBox[boxes, p.first]; ENDLOOP; RETURN [boxes.list]; }; BoxFromList: PUBLIC PROC [list: LIST OF Box, xFix: Fix ¬ [], yFix: Fix ¬ []] RETURNS [box: Box] ~ { w: VEC ¬ [0, 0]; min: VEC ¬ [Real.LargestNumber, Real.LargestNumber]; max: VEC ¬ [-Real.LargestNumber, -Real.LargestNumber]; stretch: VEC ¬ [0, 0]; shrink: VEC ¬ [0, 0]; expansion: VEC ¬ [0, 0]; FOR p: LIST OF Box ¬ list, p.rest UNTIL p=NIL DO w ¬ w.Add[p.first.escapement]; stretch ¬ stretch.Add[p.first.stretch]; shrink ¬ shrink.Add[p.first.shrink]; ENDLOOP; expansion ¬ [CalculateExpansion[xFix, w.x, stretch.x, shrink.x], CalculateExpansion[yFix, w.y, stretch.y, shrink.y]]; w ¬ [0, 0]; FOR p: LIST OF Box ¬ list, p.rest UNTIL p=NIL DO min.x ¬ MIN[min.x, w.x + p.first.bounds.xmin]; min.y ¬ MIN[min.y, w.y + p.first.bounds.ymin]; max.x ¬ MAX[max.x, w.x + p.first.bounds.xmax]; max.y ¬ MAX[max.y, w.y + p.first.bounds.ymax]; w ¬ Advance[w, p.first, expansion]; ENDLOOP; IF list = NIL THEN min ¬ max ¬ [0, 0]; IF xFix.what = size THEN w.x ¬ xFix.value; IF yFix.what = size THEN w.y ¬ yFix.value; box ¬ NEW[BoxRep ¬ [ nChars: 0, bounds: [xmin: min.x, ymin: min.y, xmax: max.x, ymax: max.y], expansion: expansion, escapement: w, stretch: [0, 0], shrink: [0, 0], class: listBoxClass, data: list ]]; }; listBoxClass: Class ¬ NEW[ClassRep ¬ [ Composite: NIL, UnBox: ListUnBox, Render: ListRender, Resolve: ListResolve, Destroy: ListDestroy ]]; ListUnBox: PROC [box: Box] RETURNS [list: LIST OF Box] ~ { list ¬ NARROW[box.data]; }; ListRender: PROC [box: Box, context: Context, position: VEC] ~ { w: VEC ¬ position; expansion: VEC ¬ box.expansion; FOR p: LIST OF Box ¬ NARROW[box.data], p.rest UNTIL p=NIL DO Render[p.first, context, w]; w ¬ Advance[w, p.first, expansion]; ENDLOOP; }; InBox: PROC [p: VEC, box: Box] RETURNS [BOOL] ~ { RETURN [p.x IN [box.bounds.xmin..box.bounds.xmax] AND p.y IN [box.bounds.ymin..box.bounds.ymax]] }; ListResolve: PROC [box: Box, p: VEC] RETURNS [loc: TextNode.Location ¬ TextNode.nullLocation] ~ { w: VEC ¬ [0, 0]; expansion: VEC ¬ box.expansion; list: LIST OF Box ¬ NARROW[box.data]; IF NOT InBox[p, box] THEN RETURN; list ¬ NARROW[box.data]; FOR l: LIST OF Box ¬ list, l.rest UNTIL l=NIL DO pRel: VEC ~ p.Sub[w]; loc ¬ Resolve[l.first, pRel]; IF loc # TextNode.nullLocation THEN RETURN; w ¬ Advance[w, l.first, expansion]; ENDLOOP; }; ListDestroy: PROC [box: Box] ~ { list: LIST OF Box ¬ NARROW[box.data]; rest: LIST OF Box ¬ NIL; box.data ¬ NIL; FOR l: LIST OF Box ¬ list, rest UNTIL l=NIL DO Destroy[l.first]; rest ¬ l.rest; l.first ¬ NIL; l.rest ¬ NIL; ENDLOOP; }; Overlay: PUBLIC PROC [base, new: Box, offset: VEC] RETURNS [Box] ~ { data: OverlayData ~ NEW[OverlayDataRep ¬ [base, new, offset]]; RETURN [NEW[BoxRep ¬ [ nChars: 0, bounds: ImagerBox.BoundingBox[base.bounds, new.bounds], expansion: [0,0], escapement: base.escapement, stretch: base.stretch, shrink: base.shrink, class: overlayBoxClass, data: data ]]]; }; overlayBoxClass: Class ¬ NEW[ClassRep ¬ [ Composite: NIL, UnBox: NIL, Render: OverlayRender, Resolve: OverlayResolve, Destroy: OverlayDestroy ]]; OverlayData: TYPE ~ REF OverlayDataRep; OverlayDataRep: TYPE ~ RECORD [base, new: Box, offset: VEC]; OverlayRender: PROC [box: Box, context: Context, position: VEC] ~ { data: OverlayData ~ NARROW[box.data]; Render[data.base, context, position]; Render[data.new, context, Vector2.Add[position, data.offset]]; }; OverlayResolve: PROC [box: Box, p: VEC] RETURNS [loc: TextNode.Location ¬ TextNode.nullLocation] ~ { data: OverlayData ~ NARROW[box.data]; loc ¬ Resolve[data.new, Vector2.Sub[p, data.offset]]; IF loc.node = NIL THEN loc ¬ Resolve[data.base, p]; }; OverlayDestroy: PROC [box: Box] ~ { data: OverlayData ~ NARROW[box.data]; Destroy[data.new]; Destroy[data.base]; data.new ¬ NIL; data.base ¬ NIL; box.data ¬ NIL; }; Composite: PUBLIC PROC [box: Box] RETURNS [BOOL] ~ { RETURN [IF box.class.Composite = NIL THEN (box.class.UnBox # NIL) ELSE box.class.Composite[box]] }; UnBox: PUBLIC PROC [box: Box] RETURNS [list: LIST OF Box] ~ { list ¬ IF box.class.UnBox # NIL THEN box.class.UnBox[box] ELSE NIL; }; ModifyBox: PUBLIC PROC [box: Box, m: Transformation] RETURNS [new: Box] ~ { data: REF ModifiedBoxDataRep ~ NEW[ModifiedBoxDataRep ¬ [box, m]]; WITH box.data SELECT FROM modified: REF ModifiedBoxDataRep => { data.box ¬ modified.box; data.m ¬ ImagerTransformation.Concat[modified.m, m]; }; ENDCASE => NULL; new ¬ NEW[BoxRep ¬ [ nChars: box.nChars, bounds: ImagerBox.BoxFromRectangle[ImagerTransformation.TransformRectangle[m, ImagerBox.RectangleFromBox[box.bounds]]], expansion: box.expansion, escapement: ImagerTransformation.TransformVec[m, box.escapement], stretch: ImagerTransformation.TransformVec[m, box.stretch], shrink: ImagerTransformation.TransformVec[m, box.shrink], class: modifiedBoxClass, data: NEW[ModifiedBoxDataRep ¬ [box, m]] ]]; }; ModifiedBoxDataRep: TYPE ~ RECORD [box: Box, m: Transformation]; modifiedBoxClass: Class ¬ NEW[ClassRep ¬ [ Composite: ModifiedComposite, UnBox: ModifiedUnBox, Render: ModifiedRender, Resolve: ModifiedResolve, Destroy: ModifiedDestroy ]]; ModifiedComposite: PROC [box: Box] RETURNS [BOOL] ~ { modified: REF ModifiedBoxDataRep ~ NARROW[box.data]; RETURN [Composite[modified.box]] }; ModifiedUnBox: PROC [box: Box] RETURNS [LIST OF Box] ~ { modified: REF ModifiedBoxDataRep ~ NARROW[box.data]; m: Transformation ~ modified.m; b: Boxes ¬ [NIL, NIL]; unmodified: LIST OF Box ¬ UnBox[modified.box]; FOR p: LIST OF Box ¬ unmodified, p.rest UNTIL p = NIL DO b ¬ AppendBox[b, ModifyBox[p.first, m]]; ENDLOOP; RETURN [b.list]; }; ModifiedRender: PROC [box: Box, context: Context, position: VEC] ~ { modified: REF ModifiedBoxDataRep ~ NARROW[box.data]; proc: PROC ~ { Imager.TranslateT[context, position]; Imager.ConcatT[context, modified.m]; Render[modified.box, context, [0, 0]]; }; Imager.DoSave[context, proc]; }; ModifiedResolve: PROC [box: Box, p: VEC] RETURNS [loc: TextNode.Location ¬ TextNode.nullLocation] ~ { modified: REF ModifiedBoxDataRep ~ NARROW[box.data]; RETURN [Resolve[modified.box, ImagerTransformation.InverseTransform[modified.m, p]]] }; ModifiedDestroy: PROC [box: Box] ~ { modified: REF ModifiedBoxDataRep ~ NARROW[box.data]; Destroy[modified.box]; modified.box ¬ NIL; }; Render: PUBLIC PROC [box: Box, context: Context, position: VEC] ~ { IF box.class.Render # NIL THEN box.class.Render[box, context, position]; }; Resolve: PUBLIC PROC [box: Box, p: VEC] RETURNS [loc: TextNode.Location] ~ { loc ¬ IF box.class.Resolve # NIL THEN box.class.Resolve[box, p] ELSE TextNode.nullLocation; }; FirstLocWithin: PUBLIC PROC [box: Box] RETURNS [loc: TextNode.Location] ~ { loc ¬ IF box.class.FirstLocWithin # NIL THEN box.class.FirstLocWithin[box] ELSE TextNode.nullLocation; }; doDestroy: BOOL ¬ TRUE; Destroy: PUBLIC PROC [box: Box] ~ { IF doDestroy AND box.class # NIL AND box.class.Destroy # NIL AND NOT box.duplicate THEN box.class.Destroy[box]; }; Duplicate: PUBLIC PROC [box: Box] ~ { IF box # NIL THEN box.duplicate ¬ TRUE; }; AppendList: PUBLIC PROC [boxes: Boxes, list: LIST OF Box] RETURNS [Boxes] ~ { IF list = NIL THEN RETURN [boxes] ELSE IF boxes.list = NIL THEN boxes.list ¬ list ELSE { IF boxes.last.rest # NIL THEN ERROR; boxes.last.rest ¬ list; }; UNTIL list.rest = NIL DO list ¬ list.rest ENDLOOP; boxes.last ¬ list; RETURN [boxes]; }; AppendBox: PUBLIC PROC [boxes: Boxes, box: Box] RETURNS [Boxes] ~ { list: LIST OF Box ¬ LIST[box]; IF boxes.list = NIL THEN boxes ¬ [list: list, last: list] ELSE { IF boxes.last.rest # NIL THEN ERROR; boxes.last.rest ¬ list; boxes.last ¬ list; }; RETURN [boxes]; }; END. T TiogaImagerImpl.mesa Copyright Σ 1985, 1986, 1987, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved. Michael Plass, March 10, 1992 2:29 pm PST JKF February 24, 1989 1:21:18 pm PST Doug Wyatt, March 23, 1992 3:55 pm PST MessageWindow.Append["TiogaImagerImpl: ", TRUE]; MessageWindow.Append[rope, FALSE]; N.B. h is the non-negative height of the page built so far. Note that since the y escapements, and glue are normally negative, we need to subtract them. IF debugPattern # NIL AND Rope.Match[pattern: debugPattern, object: loc.node.rope, case: TRUE] THEN debugCount _ debugCount + 1; Check for keep processing. This is the first thing in this insert. Put any separators before it, along with the appropriate topIndent and topIndentStretch. Don't want to put in separators if, in so doing, the inserts won't fit. Now either the insert is the only thing on the page, or it will fit along with its separators. It all fits. This code is complicated a little by the fact that we don't want a separator above the normal text unless there is a top insert. This is the first line of a node, but not the first thing in this insert. Adjust the topLeading accordingly. For the rest of the lines in the node, the leading is already correct. IF node.node.formatName = $pagebreak THEN skip _ stop _ TRUE; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - _ &td _ PutGet.FromFile["TiogaDoc.Tioga"] _ &c _ ImagerTerminal.BWContext[Terminal.Current[], TRUE] _ &b _ TiogaImager.FormatNodes[[&td, 0], [400, 600], TRUE, NIL] _ TiogaImager.Render[&b.box, &c, [10, 700]] Κ){–(cedarcode) style•NewlineDelimiter ™code™Kšœ ΟeœU™`K™)K™$K™&K™—šΟk ˜ Kšœžœ6˜@Kšœžœ ˜Kšœ žœ ˜Kšœžœ˜Kšœžœƒ˜Kšœ žœC˜RKšœ žœT˜dKšœžœN˜hKšžœžœ žœ˜Kšœ žœ ˜Kšœ žœ<˜KKšœžœ˜*Kšœ žœJ˜\Kšœžœ˜Kšœ žœ ˜Kšœžœ˜"Kšœžœžœ˜,Kšœžœžœ˜2Kšœžœ ˜Kšœ žœ;˜LKšœ žœ˜Kšœ žœM˜[Kšœ žœj˜{Kšœžœ˜Kšœžœ žœ˜—K˜KšΟnœžœž˜Kšžœ5žœ΄˜ςKšžœ ˜šœž˜K˜Kšœ žœ˜Kšœžœ˜Kšœžœ'˜;Kšžœžœ žœ˜Kšœžœ˜šžœžœžœ˜K˜—Kšœžœ˜Kšœžœ˜ Kšœžœ˜"Kšœžœ˜ Kšœ žœ˜&Kšœžœ˜Kšœ žœ˜*Kšœžœ˜2Kšœ žœ˜&Kšœ žœžœ žœ˜:Kšœžœ˜Kšœžœ˜0K˜—š Ÿ œžœžœ'žœžœ˜pK˜8K˜Kšœ žœ˜Kšœ˜KšœJžœZžœ˜­Kšœ˜K˜^K˜)K˜$K˜$šœžœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ4˜4Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜K˜—šŸœžœžœžœ˜:šžœžœžœž˜Kšœžœ ˜&Kšœžœžœ ˜'Kšœžœ ˜,Kšœžœ ˜(Kšžœ˜Kšœ˜—Kšœ˜K˜—šŸœžœžœ˜šžœ(žœž˜7˜Kšœ žœžœ ˜Kšžœ˜Kšžœ˜Kšžœ˜K˜—šžœ˜ KšΟy*Πky ™0Kš ‘ ™"KšœH˜HKšœ7˜7Kšœ˜——Kšœ˜K˜—š Ÿ œžœžœ žœžœžœ˜tKšœžœ ˜KšœΜžœ˜ΧKšžœ˜ Kšœ˜K˜—šœ žœžœ(˜DK˜—š Ÿ œžœžœ$žœPžœ˜«K•StartOfExpansionΰ[lineInfo: TEditFormat.LineInfo, node: TextEdit.RefTextNode, startOffset: TextEdit.Offset, nodeStyle: NodeStyle.Ref, lineWidth: Scaled.Value, doLigsAndKern: BOOLEAN _ FALSE, kind: NodeStyleOps.OfStyle _ screen]˜Kšœ žœ˜(K˜0Kšœ&žœ(˜TšŸœžœ˜Kšœ˜Kšœ žœ˜K˜.K˜K˜K˜K˜#šžœ žœžœ˜Kšœ6˜6Kšœžœ(˜JKšœ˜—Kšœ˜—Kš œžœ žœ žœžœžœ˜1Kš œ žœ žœžœžœ˜4Kšœžœžœ˜šœžœ˜KšΟbœ•™™—Kšœžœ˜&Kšœ žœ Οc˜,Kšœ žœžœ£1˜IšŸ œžœžœžœ˜3Kšœžœ˜Kšœžœžœ˜š žœžœžœžœžœž˜-K˜%Kšžœ˜—Kšžœ ˜Kšœ˜—šŸ œžœ˜"Kšœžœžœ˜Kšœžœžœ˜š žœžœžœžœžœž˜-Kšœ˜K˜K˜Kšžœ˜—K˜,Kšœ˜—Kšœ&˜&Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ1˜1K˜KK˜š žœ žœ žœžœž˜8Kšœ žœžœ˜Kšœžœ˜"K–6[pattern: ROPE, object: ROPE, case: BOOL _ TRUE]š žœžœžœ@žœžœ™€Kšžœžœžœ4˜FKš žœžœžœžœžœ žœ˜Eš žœžœžœžœ žœžœ˜6K™Kšœžœ,˜6šžœžœž˜K˜SKšžœ˜K˜—Kšœ˜—šžœžœžœ˜Kšœžœ˜AK˜BK˜@K˜šžœž˜šžœ˜K™Kšœ žœ+˜:Kšœžœ8˜Nšžœžœžœ˜K™GKšœžœ(˜3Kšžœžœžœžœ'˜YKšžœžœžœžœ%˜XKš žœžœžœ žœžœ˜0K™^šžœžœ˜K™Kšžœžœžœžœ˜GKšžœžœžœžœ˜FKšœ˜—Kšœ˜—K˜uK˜Kšœ˜—šžœžœžœ˜K™΅Kšœ*˜*Kšœ žœ˜'Kšœ žœžœ5˜HKš žœ:žœžœ žœžœ˜XK˜K˜ K˜SK˜VK˜BKšœ˜——Kš žœ%žœžœ žœžœ˜DKšžœžœžœžœ˜2K˜'šžœžœ˜K˜DK˜FK˜HKšœ˜—K˜6K˜K˜Kšœ˜—Kšžœžœžœ ˜0Kšœ žœ˜Kšžœ˜—šžœ žœžœ˜K˜3Kšœ˜—š žœžœžœžœž˜4Kšœ(˜(š žœžœžœžœžœ˜3K˜#Kšœ4˜4K˜CK˜Mšžœ žœ˜K˜4K˜Kšœ˜—K˜Kšœ˜—K˜+Kšžœ˜—K˜6šžœ(žœžœžœ˜EK˜IK˜6Kšœ˜—Kšœ˜Kšžœ˜!Kšœ˜K˜—šŸ œžœ2žœ˜jK˜!Kšœ-˜-Kšœ˜K˜—š œ žœžœžœžœ˜ K˜ Kšœ<˜K˜6Kšœ˜——Kšœfžœ˜nK˜ Kšœ˜—Kšžœ ˜Kšœ˜K˜—š œžœžœžœžœžœžœ˜+Kšžœ-˜1Kšžœ$˜(Kšžœ#˜'Kšœ˜K˜—š œžœžœžœžœžœžœ˜+Kšžœ-˜1Kšžœ0˜4Kšžœ#˜'Kšœ˜K˜—š œžœžœžœžœžœžœ˜+Kšžœ$˜(Kšžœ$˜(Kšžœ,˜0Kšœ˜K˜—š œžœžœžœžœžœžœ˜+Kšžœ$˜(Kšžœ0˜4Kšžœ,˜0Kšœ˜K˜—šŸ œžœžœžœ4žœžœ"žœ˜±Kšœžœžœ˜Kšœ ˜ K˜ š Ÿ œžœžœžœžœžœ˜@Kš œžœžœžœežœžœ˜Kš žœžœžœžœžœ&˜FKšœ˜—Kšœ2˜2K˜9šŸœžœžœžœ˜DKšžœ&˜,Kšœ˜—K–o[node: TextEdit.RefTextNode, name: ROPE, event: TextEdit.Event _ NIL, root: TextEdit.RefTextNode _ NIL]šœžœžœ!žœ ˜dKšœ žœ˜.Kšœ žœ˜0Kšœžœ!˜4Kšœ žœ˜,Kšœžœ ˜2Kšœžœ ˜2Kšœžœ ˜2Kšœ žœžœ*˜=Kšœ žœ7˜FKšœ žœ˜,Kšœ žœ˜.Kšœ žœžœ6˜LKšœ žœžœ4˜IKšœžœžœC˜]Kšœ žœ˜"Kšœ žœC˜RKšœžœJ˜`KšœžœF˜XKšœ žœ:˜HKšœžœG˜Xšœ˜Kšžœ žœžœX˜lšžœžœžœ˜K˜&šœ˜Kšžœžœžœ˜.Kšœ˜—Kšœ žœžœ&˜=Kšžœ#žœžœ™=šžœžœ˜Kšœ žœ&˜4šœ žœ˜Kš žœ žœDžœžœžœ˜n—Kš œžœžœ žœ žœ ˜9šœžœ˜šžœ ž˜Kšœ<˜Kšœ žœ˜)K˜Kšœžœ˜Kš œ žœžœžœ žœ˜Jšžœžœžœžœžœžœžœžœž˜:Kšœ žœ˜ šžœžœžœžœžœžœžœžœž˜AKšœžœ ˜šžœžœžœ ˜Hšžœ˜Kšœ žœ#˜3K˜,K˜)šœžœ˜Kšœ6˜6Kšœ˜—K˜(Kšœžœ˜Kšœ˜—šžœ˜Kšœžœžœžœ&˜@šžœžœžœ˜K˜Kšœ ˜ K˜(Kšœ˜—Kšœ˜——Kšžœ˜—Kšžœžœžœ˜K˜.K˜Kšžœ˜—Kšžœžœžœ ˜8K˜AKšžœ ˜Kšœ˜—Kšœ žœžœžœ žœžœ žœžœ˜všŸœžœžœ ˜)Kš œ žœžœžœžœžœ˜/Kš œ žœžœžœžœžœ˜/K˜š žœ žœžœžœž˜;K˜:K˜:Kšžœžœ˜—šžœ*žœ˜2Kšœ$˜$K–j[start: TextNode.Location, bounds: VEC, screenStyle: BOOL _ FALSE, filter: TiogaImager.FilterProc]šœ$˜$K–j[start: TextNode.Location, bounds: VEC, screenStyle: BOOL _ FALSE, filter: TiogaImager.FilterProc]˜JK˜K˜Ašžœžœ˜Kšœ žœžœ˜šœ˜Kšœ7˜7Kšžœ*žœ žœžœ˜IK˜>Kš žœžœžœžœ žœ˜,Kšœ˜—K˜™šžœ žœ˜Kšœžœžœ!˜/Kšœ ˜ K˜Kšœ žœžœ˜Kšœ˜—Kšžœžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜@K˜šžœ ž˜Kšœ žœ˜K˜-K˜.Kšžœžœ˜—šžœ ž˜Kšœ žœ˜K˜-K˜.Kšžœžœ˜—Kšžœ˜ Kšœ˜K˜—šŸœžœžœžœžœžœžœ ˜šžœžœ ˜Kšœ ˜ Kšœ7˜7Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ ˜ Kšœ˜—Kšœ˜—K˜šœžœ ˜)Kšœ žœ˜Kšœžœ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šœ žœžœ˜'K˜—šœžœžœžœ˜˜>Kšœ˜K˜—šŸœžœžœžœ5˜dKšœžœ ˜%K˜5Kšžœ žœžœ˜3Kšœ˜K˜—šŸœžœ˜#Kšœžœ ˜%Kšœ˜Kšœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ˜K˜—š Ÿ œžœžœ žœžœ˜4Kš žœžœžœžœžœžœ˜`Kšœ˜K˜—š Ÿœžœžœ žœžœžœ ˜=Kš œžœžœžœžœžœ˜CKšœ˜K˜—šŸ œžœžœžœ˜KKšœžœžœ ˜Bšžœ žœž˜šœ žœ˜%K˜K˜4Kšœ˜—Kšžœžœ˜—šœžœ ˜Kšœ˜Kšœw˜wKšœ˜KšœA˜AKšœ;˜;Kšœ9˜9Kšœ˜Kšœžœ˜(Kšœ˜—Kšœ˜K˜—Kšœžœžœ˜@šœžœ ˜*Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šŸœžœ žœžœ˜5Kšœ žœžœ ˜4Kšžœ˜ Kšœ˜K˜—š Ÿ œžœ žœžœžœ ˜8Kšœ žœžœ ˜4Kšœ˜Kšœ žœžœ˜Kšœ žœžœ˜.š žœžœžœžœžœž˜8K˜(Kšžœ˜—Kšžœ ˜Kšœ˜K˜—šŸœžœ(žœ˜DKšœ žœžœ ˜4šœžœ˜Kšœ%˜%Kšœ$˜$Kšœ&˜&Kšœ˜—Kšœ˜Kšœ˜K˜—šŸœžœžœžœ5˜eKšœ žœžœ ˜4KšžœN˜TKšœ˜K˜—šŸœžœ˜$Kšœ žœžœ ˜4Kšœ˜Kšœžœ˜Kšœ˜K˜—šŸœžœžœ(žœ˜CKšžœžœžœ*˜HKšœ˜K˜—š Ÿœžœžœžœžœ˜LKš œžœžœžœžœžœ˜[Kšœ˜K˜—šŸœžœžœ žœ˜KKš œžœžœžœžœ˜fKšœ˜K˜—Kšœ žœžœ˜šŸœžœžœ˜#Kšžœ žœ žœžœžœžœžœžœ˜oKšœ˜K™—šŸ œžœžœ˜%Kšžœžœžœžœ˜'Kšœ˜K˜—š Ÿ œžœžœžœžœžœ ˜MKšžœžœžœžœ˜!Kšžœžœžœžœ˜/šžœ˜Kšžœžœžœžœ˜$K˜Kšœ˜—Kšžœ žœžœžœ˜2K˜Kšžœ ˜Kšœ˜K˜—šŸ œžœžœžœ ˜CKšœžœžœžœ˜Kšžœžœžœ!˜9šžœ˜Kšžœžœžœžœ˜$K˜K˜K˜—Kšžœ ˜Kšœ˜K™—Kšžœ˜K˜Kšœ)™)Kšœ9™9Kšœ?™?Kšœ+™+K˜K˜—…—|"«ρ