DIRECTORY Atom USING [GetPName, GetPropFromList, PropList, PutPropOnList], Commander USING [Handle], Convert USING [RopeFromInt], Imager USING [Box, ConcatT, Context, DoSave, SetFont, SetXY, ShowRope, ShowXChar, TranslateT], ImagerBox USING [BoundingBox, BoxFromExtents, BoxFromRect, RectFromBox], ImagerFont USING [Amplified, BoundingBox, Font, RopeBoundingBox, RopeWidth, Width, XChar], ImagerTransformation USING [Concat, InverseTransform, Transformation, TransformRectangle, TransformVec], IO USING [PutRope, STREAM], MessageWindow USING [Append], NodeProps USING [GetProp], NodeStyle USING [GetBottomIndent, GetBottomLeading, GetBottomLeadingShrink, GetBottomLeadingStretch, GetColumns, GetFontSize, GetLeading, GetLeadingShrink, GetLeadingStretch, GetReal, GetTopIndent, GetTopLeading, GetTopLeadingShrink, GetTopLeadingStretch, PointsPerFil, RealParam, Ref], 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], 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, Convert, Imager, ImagerBox, ImagerFont, IO, Process, ProcessProps, ImagerTransformation, Rope, MessageWindow, NodeProps, NodeStyle, NodeStyleFont, NodeStyleOps, Scaled, 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, screenStyle: BOOL] 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, kind: IF screenStyle THEN screen ELSE print]; 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.GetLeading[style]], 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 => { MessageWindow.Append["TiogaImagerImpl: ", TRUE]; MessageWindow.Append[rope, FALSE]; }; }; GetStyleParam: PROC [style: NodeStyle.Ref, param: ATOM, default: REAL, kind: NodeStyleOps.OfStyle] 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] }; FormatNodes: PUBLIC PROC [start: TextNode.Location, bounds: VEC, screenStyle: BOOL, 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, IF screenStyle THEN screen ELSE print]; 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: NodeStyleOps.OfStyle ~ IF screenStyle THEN screen ELSE print; keepStretch: REAL _ 0.0; box: Box _ NIL; boxToStretch: Box _ NIL; maxVerticalExpansion: REAL _ 0; NodeStyleOps.ApplyAll[nodeStyle, loc.node, kind]; maxVerticalExpansion _ GetStyleParam[nodeStyle, $maxVerticalExpansion, 5, kind]; 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, screenStyle]; lineBox.stretch.y _ -NodeStyle.GetLeadingStretch[nodeStyle]; lineBox.shrink.y _ -NodeStyle.GetLeadingShrink[nodeStyle]; stopper _ stopper - 1; IF boxes[insertID].list = NIL THEN { topIndent: REAL _ NodeStyle.GetTopIndent[nodeStyle]; 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.GetTopLeading[nodeStyle]]; 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.GetTopLeadingShrink[nodeStyle]; prevBox.stretch.y _ prevBox.stretch.y-NodeStyle.GetTopLeadingStretch[nodeStyle]; lineBox.stretch.y _ -NodeStyle.GetLeadingStretch[nodeStyle]; }; 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.GetBottomLeading[nodeStyle]; lineBox.shrink.y _ -NodeStyle.GetBottomLeadingShrink[nodeStyle]; lineBox.stretch.y _ -NodeStyle.GetBottomLeadingStretch[nodeStyle]; }; 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 i: InsertID IN [top..foot] DO 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.GetBottomIndent[nodeStyle]; 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[ $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, screenStyle: BOOL _ FALSE] RETURNS [FormattedPage] ~ { kind: NodeStyleOps.OfStyle ~ IF screenStyle THEN screen ELSE print; 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, kind]; 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.GetColumns[nodeStyle], 1]; columnGap: REAL ~ GetStyleParam[nodeStyle, $columnGap, 36, kind]; 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, kind]]; firstVisibleFolio: INT ~ Real.Round[GetStyleParam[nodeStyle, $firstVisibleFolio, 1, kind]]; lastDropFolio: INT ~ Real.Round[GetStyleParam[nodeStyle, $lastDropFolio, 0, kind]]; twoSided: BOOL ~ GetStyleParam[nodeStyle, $sided, 1.0, kind] > 1.5; firstHeaders: INT ~ Real.Round[GetStyleParam[nodeStyle, $firstHeaders, 0.0, kind]]; 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], screenStyle: screenStyle, 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, kind]; pageNumberFont _ NodeStyleFont.FontFromStyleParams[prefix: nodeStyle.name[fontPrefix], family: nodeStyle.name[fontFamily], face: nodeStyle.fontFace, size: NodeStyle.GetFontSize[nodeStyle], alphabets: nodeStyle.fontAlphabets]; pageNumberTopIndent _ NodeStyle.GetTopIndent[nodeStyle]; pageNumberBotIndent _ NodeStyle.GetBottomIndent[nodeStyle]; IF nColumns > 1 THEN { haveTitle: BOOL _ FALSE; titleFilter: FilterProc ~ { NodeStyleOps.ApplyAll[nodeStyle, node.node, kind]; IF NodeStyle.GetColumns[nodeStyle] # 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], screenStyle: screenStyle, 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], screenStyle: screenStyle, 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 ]]; 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]; 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, [0, ORD[char]]]] }; BoxFromXChar: PUBLIC PROC [font: Font, xchar: XChar] RETURNS [box: Box] ~ { w: VEC _ ImagerFont.Width[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.RopeWidth[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.BoxFromRect[ImagerTransformation.TransformRectangle[m, ImagerBox.RectFromBox[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. œTiogaImagerImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Michael Plass, September 23, 1986 11:40:19 am PDT 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]] Κ)Ε˜code™Kšœ Οmœ7™BK™1K™—šΟk ˜ Jšœžœ6˜@Jšœ žœ ˜Jšœžœ˜JšœžœR˜^Jšœ žœ9˜HJšœ žœJ˜ZJšœžœN˜hJšžœžœ žœ˜Jšœžœ ˜Jšœ žœ ˜Jšœ žœ˜žJšœžœ˜*Jšœ žœJ˜\Jšœžœ˜Jšœ žœ ˜Jšœžœ˜"Jšœžœžœ˜,Jšœžœ˜Jšœ žœ;˜LJšœ žœ˜Jšœ žœM˜[Jšœ žœj˜{Jšœžœ˜Jšœžœ žœ˜—K˜KšΠlnœž ˜Kšžœ/žœ­˜εKšžœ ˜šœž˜K˜Kšœ žœ˜Kšœžœ˜Kšœžœ'˜;Kšžœžœ žœ˜Kšœžœ˜šžœžœžœ˜K˜—Kšœžœ˜Kšœžœ˜ Kšœžœ˜"Kšœžœ˜ Kšœ žœ˜&Kšœžœ˜Kšœ žœ˜*Kšœžœ˜2Kšœ žœ˜&Kšœ žœžœ žœ˜:Kšœžœ˜Kšœžœ˜0K˜—š Οn œžœžœ'žœ%žœžœ˜ƒKšœ8˜8K˜Kšœ žœ˜Kšœ˜Kš œJžœZžœžœ žœžœ˜Ϊ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˜Kšœ žœžœ ˜Kšžœ˜Kšžœ˜Kšžœ˜K˜—šžœ˜ Kšœ*žœ˜0Kšœžœ˜"Kšœ˜——Kšœ˜K˜—š   œžœžœ žœžœžœ˜uKšœžœ ˜KšœΜžœ˜ΧKšžœ˜ Kšœ˜K˜—š   œžœžœ$žœžœ0žœ˜ž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šœ0˜0Kšœ&žœ(˜Tš œžœ˜Kšœ˜Kšœ žœ˜Kšœ.˜.Kšœ˜Kšœ˜Kšœ˜Kšœ#˜#šžœ žœžœ˜Kšœ+žœ žœžœ˜RKšœžœ(˜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šœžœ žœžœ˜CKšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ1˜1KšœP˜PKšœ˜š žœ žœ žœžœž˜8Kšœ žœžœ˜Kšœžœ˜"K–6[pattern: ROPE, object: ROPE, case: BOOL _ TRUE]š žœžœžœ@žœžœ™€Kšžœžœžœ4˜FKš žœžœžœžœžœ žœ˜Eš žœžœžœžœ žœžœ˜6K™Kšœžœ,˜6šžœžœž˜KšœS˜SKšžœ˜K˜—Kšœ˜—šžœžœžœ˜Kšœžœ,˜NKšœ<˜˜>Kšœ@˜@KšœB˜BKšœ˜—Kšœ6˜6Kšœ˜Kšœ˜Kšœ˜—Kšžœžœžœ ˜0Kšœ žœ˜Kšžœ˜—šžœ žœžœ˜Kšœ3˜3Kšœ˜—šžœ žœ ž˜!š žœžœžœžœžœ˜3Kšœ#˜#Kšœ4˜4Kšœ=˜=KšœM˜Mšžœ žœ˜Kšœ4˜4Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšœ+˜+Kšžœ˜—Kšœ6˜6šžœ(žœžœžœ˜EKšœI˜IKšœ6˜6Kšœ˜—Kšœ˜Kšžœ˜!Kšœ˜K˜—š  œžœ2žœ˜jK˜!Kšœ-˜-Kšœ˜K˜—š œ žœžœžœžœ˜ Kšœ<˜˜>Kšœ6˜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šœžœ žœžœ˜CJšœžœžœ˜Kšœ ˜ Kšœ ˜ š   œžœžœžœžœžœ˜@Kš œžœžœžœežœžœ˜Kš žœžœžœžœžœ&˜FKšœ˜—Kšœ2˜2Kšœ4˜4š œžœžœžœ˜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šœ žœžœ%˜8Kšœ žœ2˜AKšœ žœ˜,Kšœ žœ˜.Kšœ žœžœ6˜LKšœ žœžœ4˜IKšœžœžœC˜]Kšœ žœ˜"Kšœ žœ>˜MKšœžœE˜[KšœžœA˜SKšœ žœ5˜CKšœžœB˜Sšœ˜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šœA˜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]šœJ˜JKšœ<˜˜>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šœ5˜5Kšžœ žœžœ˜3Kšœ˜K˜—š œžœ˜#Kšœžœ ˜%Kšœ˜Kšœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ˜K˜—š   œžœžœ žœžœ˜4Kš žœžœžœžœžœžœ˜`Kšœ˜K˜—š  œžœžœ žœžœžœ ˜=Kš œžœžœžœžœžœ˜CKšœ˜K˜—š  œžœžœžœ˜KKšœžœžœ ˜Bšžœ žœž˜šœ žœ˜%Kšœ˜Kšœ4˜4Kšœ˜—Kšžœžœ˜—šœžœ ˜Kšœ˜Kšœm˜mKšœ˜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šžœ˜J˜Jšœ)™)Jšœ9™9Jšœ?™?Jšœ+™+J˜—…—yb¨Γ