// S H O W // errors 700 // // ICC assignment coding: // 0 => not yet assigned in this font load // 1 => assigned in this font load, but not yet used on this page // -1 => transition from 1 when used (i.e., used on this page; old) // -2 => transition from 0 when used (i.e., used on this page; new) //get "Spruce.d" makes dictionary too big get "SpruceInLdOutLdEC.d" // InLd/OutLd messages for spooler <-> service communication // get "SprucePrinters.d" // only use mPimFiles get "Sprucedoc.d" get "Sprucefont.d" get "Spruceband.d" get "spruceShow.d" get "Sprucefiles.d" get "PressFile.d" // defined here external [ ShowInit ShowClose ShowPage FSGetRelease ShowCharSet ShowCharFont ShowCharSetSpace ShowCharacters ShowCharactersImmediate ShowRectangle ShowX ShowY ShowXY ShowOnCopy ShowDots ] // external external [ //SpruceUtils EmergencyAverted EmergencyOver FSGet FSGetX FSPut SpruceError SpruceCondition Max IsOverlayPresent // SPRUCEDIR UseEntry //SPRUCEML OrbitCharSize DoubleAdd Min MulDiv MulDivNR // no rounding (truncate) MulDivRU // always round up GetCode0 GetCode1 DoubleCop DoubleSub RowRotate // (inBuf-1, outBuf-1, wordsPerRow) SafeAdd // fails on unsigned overflow //CURSOR CursorChar CursorDigit CursorClear //BAND BandInit BandClose BandBeginPage BandEndPage BandFlush //BAND ml BandEnter SetupShowFonts // ML linkages to microcode, setting up semi-permanent values SetupShowChars // ML linkages to microcode, setting up base values for one string ShowChars // ML linkages to microcode, process one string // PARTS SkipinPart //WINDOW FILES CurrentPos FileStuff WindowReadBlock WindowGetPosition WindowNextPage WindowPositionPtr WindowSetPosition WindowReadByte WindowRead SetupWindowStream //OS Zero oneBits MoveBlock CallSwat ] // incoming statics external [ BandFile; BandWindow DebugSystem FontWindow maxPrintPassRecs logBandRecordSize nVisibleBands onlyOnCopy partNumber LandscapeDevice Capabilities printerDevice ResolutionS ResolutionB XOffset YOffset FA PermanentBottom OverlayBottom OverlayTable SpruceZone emergencyStorage xmFonts ] // external for ShowChars microcode specifications -- see below external [ BandFree; BandAvail; fspn; fspo; ICCUses; ICCOffset; bc; ec WidthPointer; BandTable CurS; CurB; CopyTable // not part of contiguous entries, but part of ShowChars linkage ] // internal statics static [ mpFontFN nFontLoads maxBandRecsSoFar //Size of band records before this page begun maxFontSizeSoFar //Size of font storage before this page begun FontSizePageNew //Total size of new chars assigned this page FontSizePageOld //Total size of chars on this page previously assinged currentFontSet currentFont fontComplaintGiven Installed; InEffect; SpaceS; SpaceB // for setting variable space widths pDoc //Pointer to document we are working on showCount = 0 // specifications for ShowChars Microcode -- see SprintStatics.bj BandTable CopyTable ICCUses ICCOffset bc ec WidthPointer fspn fspo BandFree BandAvail // not within controlled address area, but also supplied to microcode CurS CurB ] // ****** These codes must match those in ShowCharMc. They must also match the // ****** positions of a dispatch table in the machine language linkage to ShowChars manifest // microcode return codes [ MUDone = 0 // entire string complete MUCharRange = 1 // character not found in font MUOffPage = 2 // character would be placed off page // MUBufFull = 3 // band buffer must be flushed before next char shown (ML does) ] manifest mPimFiles = 1 // from SprucePrinters.d (no room) structure [ Bytes^1, 2 byte ] // ----------------------------------------------------------- // ShowInit(doc) ShowClose() // ----------------------------------------------------------- let ShowInit(doc) be [ CursorChar($S); CursorDigit(0) pDoc=doc let nPages=pDoc>>DocG.nPages let Pages=FSGetX(nPages*(size PageG/16)) pDoc>>DocG.Pages=Pages // Position band file down far enough to let header be put // out that contains DocG, PageG and FontG structures: let bandInitPos=vec 1 bandInitPos!0=0 bandInitPos!1=(size DocG/16)+nPages*(size PageG/16+size FontG/16) WindowSetPosition(BandWindow, bandInitPos) // Now compute number of records available to printing pass let csiz=(PermanentBottom-OverlayBottom-bandInitPos!1) // the calculation below doesn't allow for discarding the Print Overlay initialization ~~~~ csiz=csiz-(OverlayTable!(OVPrint+1)-OverlayTable!OVPrint)*256-loSize-10 let ovdev=selecton printerDevice into [ case printerDover: OVDover case printerPenguin: OVPenguin case printerSequoia: OVSequoia case printerPimlico: OVPimlico case printerPuffin: OVPuffin ] csiz=csiz-(OverlayTable!(ovdev+1)-OverlayTable!ovdev)*256 if IsOverlayPresent(OVT80) then csiz = csiz-(OverlayTable!(OVT80+1)-OverlayTable!OVT80)*256 if (DebugSystem丠) ne 0 then csiz = csiz-2000 // measure table size maxPrintPassRecs=csiz rshift logBandRecordSize let icc=pDoc>>DocG.ICCtotal ICCUses=FSGetX(icc) Zero(ICCUses, icc) // 0=> not assigned mpFontFN=FSGetX(22) Zero(mpFontFN, 16) CurS= (mpFontFN+16+1)&(-2) // even-aligned CurB=CurS+2 Installed, InEffect, SpaceS, SpaceB = false, false, 0, 0 nFontLoads=0 onlyOnCopy = 0 maxFontSizeSoFar=4 // Account for dummy char maxBandRecsSoFar = 0 BandInit() ] and ShowClose() be [ MakeFI() //Flush last font load. FSPut(ICCUses) FSPut(mpFontFN) BandClose() pDoc>>DocG.nFontLoads=nFontLoads FSGetRelease(0) //Release all font width tables ] // ----------------------------------------------------------- // ShowPage(func, page, arg [, pass]) // ----------------------------------------------------------- and ShowPage(func, page, arg, pass; numargs na) be [ // If pass argument is present, it should be forwarded to "func" as "arg" // For a three color printer, produce three // color-separated pages, one per pass. CursorClear(); CursorDigit() test na eq 4 then [ arg=pass; if (Capabilities&mPimFiles) ne 0 then pass = -1 ] or pass = -1 if pass le 1 then [ BandBeginPage() FontSizePageOld=0 FontSizePageNew=0 ] // Call main function to spit out visible stuff func(pDoc, page, arg) // Finish writing the bands, and compute the length unless pass le 1 return // problem with real color puffin ~~~~~~~ BandEndPage(page) // If this page can be folded into the last one (for purposes of // font planning), it must be the case // that maxBandRecs+nFontRecs (2*maxBandRecs+nFontRecs if a Dover) is small enough to fit // (le maxPrintPassRecs). // If xmFonts (using bank 1 for fonts), then fonts must fit in bank 1, and ICC table must // fit in with maxBand. . . let ICCtotal=pDoc>>DocG.ICCtotal let m=maxBandRecsSoFar //Not including this page let nBandRecs=page>>PageG.nRecords if nBandRecs gr m then m=nBandRecs let nFontRecs, s = nil, maxFontSizeSoFar unless SafeAdd(lv s, FontSizePageNew)&SafeAdd(lv s, xmFonts? #1000, ICCtotal) do FontOverflow() let nFontRecs = xmFonts? BandRecords(ICCtotal), BandRecords(s) // If it does not fit, push out the earlier font load if nFontRecs+m*(printerDevice ne printerDover? 1,2) gr maxPrintPassRecs then [ if maxBandRecsSoFar then MakeFI() //Subroutine to push out current font load maxFontSizeSoFar=FontSizePageOld; unless SafeAdd(lv maxFontSizeSoFar, 4) do FontOverflow() for i=0 to ICCtotal-1 do if ICCUses!i gr 0 then ICCUses!i=0 maxBandRecsSoFar=0 ] page>>PageG.fontLoad=nFontLoads for i=0 to ICCtotal-1 do if ICCUses!i ls 0 then ICCUses!i=1 unless SafeAdd(lv maxFontSizeSoFar, FontSizePageNew) do FontOverflow() if nBandRecs gr maxBandRecsSoFar then maxBandRecsSoFar=nBandRecs ] and FontOverflow() be SpruceCondition(712, ECFileTerminate, partNumber) // Too many char shapes // ----------------------------------------------------------- // MakeFI() BandRecords(siz) FSGetRelease(siz) // ----------------------------------------------------------- // Make a font load entry (FI) that describes which ICC's // will be needed for this particular font load. The needed ICC's // are found by examining the ICC use table. and MakeFI() be [ let ICCtotal, s= pDoc>>DocG.ICCtotal, ICCtotal unless xmFonts%SafeAdd(lv s, maxFontSizeSoFar) do FontOverflow() if xmFonts then [ let t = maxFontSizeSoFar; unless SafeAdd(lv s, #1000) do FontOverflow() ] let nRecs=maxBandRecsSoFar+BandRecords(s) if nRecs gr maxPrintPassRecs then SpruceCondition(710, ECFileTerminate, partNumber) let wds=(ICCtotal+15)/16+(size FI/16) let oldBlock = pDoc>>DocG.fontLoadList let oldLen = oldBlock? -(oldBlock!-1)-1,0 let p = FSGet(wds+oldLen) test p then [ if oldBlock do [ let new = p+wds MoveBlock(new, oldBlock, oldLen) while oldBlock>>FI.next eq (oldBlock + wds) do [ new>>FI.next = new + wds; oldBlock = oldBlock>>FI.next; new = new>>FI.next ] FSPut(pDoc>>DocG.fontLoadList) //release old block pDoc>>DocG.fontLoadList =p+wds ] ] or p=FSGetRelease(wds) Zero(p, wds) p>>FI.fontLoad=nFontLoads; nFontLoads=nFontLoads+1 p>>FI.fontLength=maxFontSizeSoFar // Now build bit table for all ICC's used up to but not including // this page (i.e., coding=1 or -1) let q=p+(size FI/16) //Pointer to region for ICC bits let iccP=ICCUses [ if iccP-ICCUses ge ICCtotal then break for i=0 to 15 do [ let u=iccP!i if u eq 1 % u eq -1 then @q=@q % oneBits!i ] q=q+1; iccP=iccP+16 ] repeat // Thread on the queue p>>FI.next=pDoc>>DocG.fontLoadList pDoc>>DocG.fontLoadList=p ] and BandRecords(siz) = valof [ let r=1 lshift logBandRecordSize resultis (siz+r-1) rshift logBandRecordSize ] and FSGetRelease(siz, aligned; numargs na) = valof // +++fast microcode [ if na<2 then aligned = false // +++fast microcode let p=0 if siz then p=FSGet(siz+(aligned? 2, 0)) // +++fast microcode if p ne 0 then test not aligned then resultis p // +++fast microcode or [ // +++fast microcode -- align to even address, store real addr in prev. odd word let q = p; p=(p+2)&(-2) // +++fast microcode p!-1 = q; resultis p // +++fast microcode ] // +++fast microcode let q=pDoc>>DocG.fontList // ALL were aligned! // +++fast microcode while q ne 0 do [ if q>>FN.widthPtr ne 0 & q>>FN.widthPtr-(q>>FN.bc*(size CharWidth/16)) ne WidthPointer then [ FSPut((q>>FN.widthPtr)!(-1)) // +++fast microcode -- use stored pointer q>>FN.widthPtr=0 if siz break ] q=q>>FN.next ] if q eq 0 then [ if siz eq 0 then [ EmergencyOver(); resultis nil ] // dip into the emergency till (needed, given statement following?) if EmergencyAverted(SpruceZone) loop // last chance -- force band flush, see if things can get better BandFlush(); if emergencyStorage loop // else No room for widths! SpruceCondition(700,ECFileTerminate, pDoc>>DocG.PressFile>>SPruceFile.fileCode) ] ] repeat // ----------------------------------------------------------- // ShowCharSet(set) ShowCharFont(font) // ----------------------------------------------------------- // Font setup. First function is called when a font set is given. // Simply fills in mpFontFN with pointers to the FN structures // for the given fonts. The method is to search all known fonts. and ShowCharSet(set) be [ currentFontSet=set Zero(mpFontFN, 16) let p=pDoc>>DocG.fontList while p ne 0 do [ for i=1 to p>>FN.pressUses do [ let use = UseEntry(p, i); if use>>FNUse.uSet eq set then mpFontFN!(use>>FNUse.uFont)=p ] p=p>>FN.next ] ] // Establish a particular font number. Sets up statics: // bc,ec: Range of good character codes // ICCOffset: Thing to add to a character code to get icc // WidthPointer: Pointer to base of CharWidth structures and ShowCharFont(font) be [ currentFont=font ShowCharSetSpace(4) //Remove current space, if any WidthPointer=0 //So FSGetRelease will not see it let p=mpFontFN!font if p eq 0 then [ fontComplaintGiven=false bc=256+1; ec=-1 //No characters legal return ] bc=p>>FN.bc; ec=p>>FN.ec ICCOffset=p>>FN.ICCOffset-bc let w=p>>FN.widthPtr if w eq 0 then [ let len=(ec-bc+1)*(size CharWidth/16) w=FSGetRelease(len, true) p>>FN.widthPtr=w WindowSetPosition(FontWindow, lv p>>FN.widthSa) WindowReadBlock(FontWindow, w, len) ] WidthPointer=w-bc*(size CharWidth/16) unless p>>FN.widest for i = bc to ec do [ let q = WidthPointer+i*(size CharWidth/16) p>>FN.widest = Max(p>>FN.widest, q>>CharWidth.DS) p>>FN.tallest = Max(p>>FN.tallest, q>>CharWidth.DB) ] ShowCharSetSpace(3) //Install current space, if any SetupShowFonts() // Install font-based parameters in microcode registers ] // ------------------------------------------------------------------------- and ShowCharactersImmediate(adr, firstChar, numChars) be // ------------------------------------------------------------------------- [ let s = FSGetX(lFSx, SpruceZone, 0) s>>FSx.gets = WindowReadByte SetupWindowStream(s, adr, firstChar, (numChars+3)&2) ShowCharactersFromStream(s, numChars-firstChar) FSPut(s) ] // ------------------------------------------------------------------------- and ShowCharacters(s, numChars) be // ------------------------------------------------------------------------- [ let charsPerPage = s>>SS.spruceFile>>SPruceFile.pageSize lshift 1 [ if numChars eq 0 return let pos, leftThisPage=nil, nil [ // ~~ fraught with peril in error situations, on T-80 system particularly // ~~ will probably work forever, though pos = CurrentPos(s); leftThisPage = charsPerPage-pos if leftThisPage>0 break WindowNextPage(s) ] repeat let n = Min(numChars, leftThisPage) numChars = numChars-n ShowCharactersFromStream(s, n) WindowPositionPtr(s, pos+n) ] repeat ] // ------------------------------------------------------------------------- and ShowCharactersFromStream(s, numChars) be // ------------------------------------------------------------------------- [ if emergencyStorage eq 0 then BandFlush() showCount = showCount-1; // if showCount eq 0 then CallSwat("This one") // Assume font is set up (see above) // Also assumes CurS, CurB are double precision coordinates for the next position if ec<0 then [ unless fontComplaintGiven then SpruceCondition(701, ECWarning, currentFontSet, currentFont) fontComplaintGiven=true return ] SetupShowChars(numChars, lv s>>FS.fsp) // setup font, count, stream parameters let c, band = nil, nil [ let condition = 703 switchon ShowChars(lv c) into [ case MUDone: break case MUCharRange: unless c endcase condition = 702 case MUOffPage: // condition=703 SpruceCondition(condition, ECWarning, mpFontFN!currentFont, c) endcase // case MUBufFull: BandFlush(); endcase // (Done within ShowChars ML) default: SpruceError(102) // terrible thing ] ] repeat unless SafeAdd(lv FontSizePageNew, fspn)&SafeAdd(lv FontSizePageOld, fspo) do FontOverflow() ] // approximation to Setup routine -- real one is ML linkage to microcode // ------------------------------------------------------------------------- // and SetupShowChar(specs, numChars, streamFsp) be // SetupShowChar, SetupShowFont // ------------------------------------------------------------------------- // [ // see SprintStatics.bj for specs layout // rICCUses=ICCUses // rICCOffSet=ICCOffSet // rbcM1=bc-1 // rec=ec // rWidthPointer=WidthPointer // rBandTable=BandTable // rnVisibleBands=nVisibleBands // above happens in SetupShowFonts, once per font change -- below happens before each ShowChars loop // rCurS0=CurS!0; rCurS1=CurS!1 // rCurB0=CurB!0; rCurB1=CurB!1 // ronlyOnCopy=onlyOnCopy // rfspn, rfspo = 0, 0 // rbyteIdx= 0-streamFsp>>FSp.charPtr-1; 0 if 1st is odd, 1 else // rbase=streamFsp>>FSp.wordPtr+byteIdx; word containing first byte // rdata = @base // rct=numChars // ] // approximation to ShowChars routine -- real one is ML linkage to microcode // ------------------------------------------------------------------------- // and ShowChars(lvC, lvBand) = valof // ------------------------------------------------------------------------- // [ // // rBandFree=BandFree // rBandAvail=BandAvail // loop: // rct = rct-1; if rct<0 goto FullReturn // let c = Gets(stream) // simulated using ct, base, byteIdx // if c le bcM1 goto RangeError // if c > ec goto RangeError // icc=ICCOffset+c // let p=WidthPointer + c lsh 3 // *size charWidth/16, that is // b_CurB0+p!5 // CharWidth.OB // let t = CurS0+p!4 // lineBand = t rrot 4 // band is top 12 bits, line in band is bottom 4 // AC2 (ds) = p!6 // CharWidth.DS // AC1 (db) = p!7 // CharWidth.DB // if b>4096 goto OffPage // if db < 0 goto OffPage // band_lineBand&7777 // if band>nVisibleBands goto OffPage // BandFree!0 = 100000+icc // BandFree!1 = (lineBand&170000)+b // DoubleAdd(CurS(0, 1), lv p.WS) // DoubleAdd(CurB(0, 1), lv p.WB) // let uses, a = lv ICCUses!icc, @uses // if a ge 0 then // [ // (AC0, AC1) = AC1*AC2+63 // db*ds+63, via MUL instr. // let siz = (AC0, AC1) RSH 4 // / 16 // test a eq 0 then fspn = fspn+siz or fspo = fspo+siz // @uses = a-2 // ] // BandEnter(band, size BEChar/16) // if onlyOnCopy goto OnCopy // goto loop // FullReturn: // let t = specs.CurS; t!0 = CurS0; t!1 = CurS1 // let t = specs.CurB; t!0 = CurB0; t!1 = CurB1 // specs.fspn = fspn // specs.fspo = fspo // res = MUDone; goto AlwaysRet // RangeError: res=MURangeError; goto AlwaysRet // OffPage: res = MUOffPage; goto AlwaysRet // OnCopy: res = MUOnCopy; goto AlwaysRet // need updated BandAvail, etc.! Restore returning! // BufFull: res = MUBufFull; goto alwaysRet // AlwaysRet: // specs.BandFree = BandFree // specs.BandAvail = BandAvail // AC2_band; AC1_c // (@lvC = AC1; @lvBand = AC2) // resultis res // ] repeat // loops on std. case, above // ------------------------------------------------------------------------- // ShowRectangle(width, height) // ------------------------------------------------------------------------- and ShowRectangle(width, height) be [ // width is dX, height is dY relative to Press File Page // X and WidthM1 below refer to scan direction (left to right for Landscape) // Y and mHeight refer to bit direction (bottom to top for Landscape) // ~~ Portrait-Landscape treatments not optimized if emergencyStorage eq 0 then BandFlush() if width eq 0 % height eq 0 return BandFree>>BERectangle.H=BERectangleH let smin=CurS!0 let bmin=CurB!0 let dB = MulDivRU(ResolutionB, height, 25400) // delta-B if Landscape let dS = MulDivRU(ResolutionS, width, 25400) // delta-S if Landscape unless LandscapeDevice do // Portrait, transform [ let temp = dS; dS = dB; dB = temp smin = smin-dS+1 // Must start rectangle at [ +height, 0 ] ] BandFree>>BERectangle.WidthM1=dS-1 BandFree>>BERectangle.mHeight=-dB BandFree>>BERectangle.X=smin BandFree>>BERectangle.Y=bmin let band=smin rshift 4 test smin ge 0 & band ls nVisibleBands & bmin ge 0 then BandEnter(band, size BERectangle/16) or SpruceCondition(704, ECWarning) ] // ------------------------------------------------------------------------- // ShowDots(DL, nn, opaque) Get parameters // ------------------------------------------------------------------------- and ShowDots(DL, nn, opaque) be // opaque is false [ let finalPos = vec 1 WindowGetPosition(DL, finalPos) // for backing out if invalid specs. DoubleAdd(finalPos, nn) // enable dot font let savedSet, savedFont = currentFontSet, currentFont ShowCharSet(64); ShowCharFont(2); ShowCharSetSpace(4) // No proportional spacing let in, out = 0, 0 // Standard Return sequence if false then Resultis: //(errorCode) [ let errorCode = GetCode0() // error code, passed as argument, 0: no error let arg = GetCode1() // ~~ these are not adequate for multi-args if in then FSPut(in-1) if out&LandscapeDevice then FSPut(out) // ~~ should check that dots end DL, errorCode = 780 if errorCode then SpruceCondition(errorCode, ECWarning, arg) WindowSetPosition(DL, finalPos) ShowCharSet(savedSet); ShowCharFont(savedFont) // will reinstate proportional, if needed return ] let code, mode, lines, dots, pl, pd, dl, dd, width, height = nil, 3, nil, nil, 0, 0, -1, -1, nil, nil let seen = 0 // flag for parts // gather parameters [ let a = WindowRead(DL) let al = a𫓸 let ar = a± switchon al into [ case DDotCode: [ if ar ge 1 & ar le 16 then code = ar dots = WindowRead(DL) lines = WindowRead(DL) seen = seen%1 endcase ] case DDotMode: mode = ar; seen = seen%2; endcase default: break case 0: switchon ar into [ case DSampleProps: SkipinPart(DL, 2, WindowRead(DL)); endcase case DDotWindow: pd, dd = WindowRead(DL), WindowRead(DL) pl, dl = WindowRead(DL), WindowRead(DL) seen = seen%4; endcase case DDotSize: width = WindowRead(DL) height = WindowRead(DL) seen = seen % 8; endcase case DDotsFromPressFile: case DDotsFromFile: Resultis(808) // not implemented case DDotsFollow: seen = seen%16; break ]; endcase ] ] repeat let required = seen& (1+8+16) unless required eq (1+8+16) do Resultis(740+required) unless (seen&4) ne 0 do [ dd = dots; dl = lines ] // ShowDots (cont) Checking, setup for main loop // Consistency checking if pd+dd>dots % pl+dl>lines % dl eq 0 % dd eq 0 then Resultis(720) for i = 0 to 7 do if (lv lines)!i < 0 then Resultis(720) // Alto resolution restrictions unless mode eq 3 do Resultis(732) if width/dots ne 32 % (width/dots)*dots ne width then Resultis(730) // 32 mica dots if (dots) ne 0 then Resultis(731) // integral # words let CurX, CurY, ResolutionX, ResolutionY = nil, nil, nil, nil // X-Y versions for S-B values test LandscapeDevice then [ CurX, CurY, ResolutionX, ResolutionY = CurS, CurB, ResolutionS, ResolutionB ] or [ CurX, CurY, ResolutionX, ResolutionY = CurB, CurS, ResolutionB, ResolutionS ] // Auxiliary values let base = vec 2 WindowGetPosition(DL, base, charItem) let oldCurX = vec 1 let savedCurX, savedCurY = vec 1, vec 1 DoubleCop(oldCurX, CurX) DoubleCop(savedCurX, CurX); DoubleCop(savedCurY, CurY) // More auxiliary values -- line oriented let lineBase = pl+dl-1 // index of bottom line let groups = (dl+7)/8 let groupLines = (groups-1)*8 // floor (dl|8) // 8 line groupings for loading into rotation array // More -- dots oriented // pl, pd, dl, dd window extended in dot direction to word boundaries during some calculations // variables representing this extended window or processing related thereto have suffix W let dotsBytes = dots rshift 3 // raster width in bytes let dotsWords = dotsBytes rshift 1 // in words let pdBytes = pd rshift 3 // nearest byte to unextended window let pdBytesW0, pdBytesW = 0, (pd rshift 4) lshift 1 // dp byte index to extended window let pdW = pdBytesW lshift 3 // pd to extended window let pdDifW = pd-pdW // dots from pdW to pd let pdBytesDifW = pdBytes-pdBytesW let pdMaskW = -1 rshift pdDifW // mask to clear dots in pdDifW range (portrait mode) let ddWordsW = (pdDifW+dd+15) rshift 4 // word width of extended window let ddBytesW = ddWordsW lshift 1 let ddBytes = (dd+7) rshift 3 let ddW = ddBytesW lshift 3 let ddMaskW = -1 lshift (ddW-dd-pdDifW) // mask to clear dots from dd to ddW (portrait mode) // Set values based on use of vertical or horizontal dot patterns let addOp, firstChar, charsPerLine, nLinesm1 = nil, nil, nil, nil test LandscapeDevice then [ addOp, firstChar, charsPerLine, nLinesm1 = DoubleAdd, pdDifW, dd+pdDifW, 0 ] or [ addOp, firstChar, charsPerLine, nLinesm1 = DoubleSub, pdBytesDifW, ddBytes+pdBytesDifW, 7 // move X left pdDifW Altos, to compensate for pdDifW white bits due to word-alignment // pdDifW lshift 5 is pdDifW*32, 32 micas/dot savedCurX!0 = Max(0, savedCurX!0-MulDiv(pdDifW lshift 5, ResolutionB, 25400)) ] in, out = FSGetRelease(ddWordsW*8+2)+1, (LandscapeDevice? FSGetRelease(ddWordsW*8), in) // dots buffer for portrait device needs "guard words" for MaskEdges routine Zero(in, ddWordsW*8) let dyPrinterDots = vec 2; dyPrinterDots!1 = 0 let pos = vec 2; // ShowDots (cont.) Show the Dots for group = 0 to groups-1 do [ let gL = group*8 let linesInGroup = Min(8, dl-groupLines+gL) let firstWord = in+((8-linesInGroup)*ddWordsW) // usually = in for i = 0 to linesInGroup-1 do [ pos!0, pos!1 = 0, dotsBytes*(pl+i) DoubleAdd(pos, base) DoubleAdd(pos,lv pdBytesW0) WindowSetPosition(DL, pos, charItem) WindowReadBlock(DL, firstWord+i*ddWordsW, ddWordsW) ] test LandscapeDevice then RowRotate(in-1, out-1, ddWordsW) // See SpruceMl, RowRotateMC or MaskEdges(out, ddWordsW, pdMaskW, ddMaskW) for i = nLinesm1 by -1 to 0 do // nLinesm1 = 7 or 0 [ DoubleCop(CurX, savedCurX) @dyPrinterDots = MulDiv((groupLines-gL+i)*32, ResolutionY, 25400) DoubleCop(CurY, savedCurY) addOp(CurY, dyPrinterDots) // ****** RowRotate does not at present wipe out ShowChars' permanent registers. If it // ****** needs to, someday, add the following line. See SpruceMc, ShowCharsMc, RowRotateMc // ****** SetupShowFonts() ShowCharactersImmediate(out+(nLinesm1-i)*ddWordsW, firstChar, charsPerLine) ] pl = pl + linesInGroup ] DoubleCop(CurX, oldCurX) DoubleCop(CurY, savedCurY) // ~~ Should check to be sure last line ends DL, else result 780 Resultis(0) ] and MaskEdges(buf, wPL, leftMask, rightMask) be for i = 0 to 8 do [ let ptr = lv buf!(wPL*i) // buf must have one "guard word" preceding word 0 and one following word 8*wPL-1 ptr!(-1) = (ptr!(-1))&rightMask ptr!0 = (ptr!0)&leftMask ] // ----------------------------------------------------------- // ShowXY(x, y) ShowX(x) ShowY(y) // ----------------------------------------------------------- // Coordinate conversions and ShowXY(x, y) be [ ShowX(x) ShowY(y) ] // ~~ Portrait-Landscape treatments not optimized and ShowX(x) be test LandscapeDevice then [ CurS!0=MulDivNR(ResolutionS, x+XOffset, 25400) CurS!1=0 ] or [ CurB!0=MulDivNR(ResolutionB, x+XOffset, 25400)+(FA lshift 4) CurB!1 = 0 ] and ShowY(y) be test LandscapeDevice then [ CurB!0=MulDivNR(ResolutionB, y+YOffset, 25400)+(FA lshift 4) CurB!1=0 ] or [ // ~~ nVisibleBands lshift (4) is only an approx. to nScanLines CurS!0=(nVisibleBands lshift LogBANDWidth)-1- MulDivRU(ResolutionS, y+YOffset, 25400) CurS!1 = 0 ] // ----------------------------------------------------------- // ShowCharSetSpace(how, arg) ShowOnCopy(copyNo) // ----------------------------------------------------------- // Routine for handling "set space" commands. // how=0 Initialize for an entity // how=1 arg=X space // how=2 arg=Y space // how=3 Install values in current font if set space is in effect // how=4 Remove values from current font if installed in it and ShowCharSetSpace(how, arg) be [ let savedSpaces=table [ 0;0;0;0 ] switchon how into [ case 0: InEffect=false; docase 4; // In the cases below, reverse scan and bit dimensions if Portrait device, and // negate Y argument (since scan proceeds in -y) // Compute 16 times the appropriate width setting: case 1:unless LandscapeDevice docase 20 // reverse dimensions case 10: SpaceS=MulDiv(ResolutionS, ((arg < 0)? -arg, arg), 25400/16) if arg < 0 do SpaceS = -SpaceS InEffect=true; docase 3; case 2: unless LandscapeDevice do [ arg = -arg; docase 10] case 20: SpaceB=MulDiv(ResolutionB, ((arg < 0)? -arg, arg), 25400/16) if arg < 0 do SpaceB = -SpaceB InEffect=true; docase 3; case 3: [ if InEffect eq false % bc gr #40 % ec ls #40 then return let p=WidthPointer+#40*(size CharWidth/16) compileif offset CharWidth.WS ne 0 % offset CharWidth.WB ne 32 then [ foo=nil ] unless Installed do MoveBlock(savedSpaces, p, 4) Zero(p, 4) // ~~ not 100% absolutely sure this works for negative values p!0=SpaceS rshift 4+(SpaceS<0? #170000, 0); p!1=SpaceS lshift 12 p!2=SpaceB rshift 4+(SpaceB<0? #170000, 0); p!3=SpaceB lshift 12 Installed=true return ] case 4: [ unless Installed return Installed=false let p=WidthPointer+#40*(size CharWidth/16) MoveBlock(p, savedSpaces, 4) return ] ] ] and ShowOnCopy(copy) be [ if onlyOnCopy then for band = 0 to nVisibleBands-1 do [ // for each band, change proto-branch to branch let branchCount = CopyTable!band unless branchCount loop BandFree>>BEControl.H = 0 BandFree>>BEControl.type = BEBranchH BandFree>>BEControl.onCopy = onlyOnCopy BandFree>>BEControl.displacement = branchCount BandEnter(band, lenBEControl) ] Zero(CopyTable, nVisibleBands) onlyOnCopy = copy ] // -------------------------- // BandEnter(band, len) // -------------------------- // Must be called to make a new band entry official. // New band information has been placed in the table beginning at BandFree. // BandAvail is set to allow it to overflow by one maximum-sized entry // Insert new entry at the head of this band's list. If only-on-copy is in effect, include this entry // in the count for this band. // This routine is actually coded in assembly language compileif false then [ let BandEnter(band, len) be [ BandFree!-1 = BandTable!band BandTable!band = entry BandFree = BandFree+len+1 BandAvail = BandAvail+len+1 if onlyOnCopy then CopyTable!band = CopyTable!band+len if BandAvail ge 0 then BandFlush() ] ] // compileif false compileif false then [ // Now RowRotate in RowRotateMc does it -- interface in SpruceML let RotateEight(in, out, widthInWords) be test microRotate then RowRotate(in-1, out-1, widthInWords) or for wColumn = 0 to widthInWords-1 do [ let sa = vec 8 let bits = table [ 1; 2; 4; #10; #20; #40; #100; #200 ] for i = 0 to 7 do sa!i = in!(i*widthInWords) for pairs = 0 to 7 do [ let wd, once = 0, 0 [ for i = 0 to 7 do [ let t = sa!i if t < 0 then wd = wd + bits!i sa!i = t lshift 1 ] if once break; once = true; wd = wd lshift 8 ] repeat @out = wd out = out+1 ] in = in + 1 ] ] // compileif false // DCS, July 27, 1977 10:39 PM, repair duplicate error code problem // September 15, 1977 11:15 PM, Deal with Portrait mode devices // September 26, 1977 8:23 AM, handle Only On Copy // September 27, 1977 3:01 PM, Move BandEnter to ML // October 3, 1977 6:55 AM, handle three-color break page // October 3, 1977 7:30 AM, dots // October 12, 1977 11:39 AM, big page problems (maxBandRecs, etc.) // October 16, 1977 3:05 PM, add "vertical dot" shapes, clear vbl space settings each doc. // October 17, 1977 11:54 AM, move XOffset, YOffset from DocG to statics, version 4.(0,0) // October 17, 1977 9:29 PM, add FN.tallest, widest, v4.(0,0) // October 18, 1977 9:59 AM, ignore rectangles with zero dimensions, // fix allocation problem with portrait dots, v4.(0,2) // October 18, 1977 1:14 PM, dots bug when file is large, v4.(0,2) // December 16, 1977 11:28 AM, null chars do not cause "not in font" complaint; too // commonly used as fill character // January 27, 1978 2:02 PM, allocate left over table below bands // February 15, 1978 8:51 AM, remove restriction on number of references to one font // March 6, 1978 7:28 PM, add microcode RotateEight, using microRotate static to enable // March 11, 1978 1:34 PM, use FSGetRelease to minimize memory crashes // March 28, 1978 12:48 AM, FSGetRelease really checks for WidthPointer equality // April 13, 1978 8:47 AM, ShowDots was using proportional "spacing" // May 9, 1978 10:13 AM, accommodate IXTypeMultiChars // June 7, 1978 10:22 PM, allow pd, dd to be on arbitrary bit boundaries, disable RotateEight // June 9, 1978 8:33 AM, finish masking and offsetting operations for Portrait dots // September 22, 1978 8:47 PM, use SafeAdd to protect against undetected single-precision overflow // October 3, 1978 4:56 PM, add fast ShowCharacters inner loop (microcode) // October 4, 1978 11:25 AM, request even alignment for width tables // October 24, 1978 8:27 AM, use CopyTable approach to "only-on-copy" // November 10, 1978 2:36 PM, better bad char error message -- font identified by name // November 24, 1978 1:40 PM, repair bugs in only on copy code // December 6, 1978 11:56 AM use Capabilities instead of printerDevice to determine pass // April 25, 1979 2:39 PM change ~~.d names // if monitoring Dover performance (DebugSystem丠), reduce // maxPrintPassRecs by measureTable size (see SpruceMeasure, SpruceMeasureMl), by Swinehart // if xmFonts, don't count actual font load contribution to bank 0 memory // overflow (font load termination) tests, but do check font load size for bank 1 overflow // July 31, 1979 10:37 AM, change ~~.d files so dictionary isn't too big // November 14, 1979 4:04 PM, preserve sign thru MulDiv in ShowCharSetSpace // February 11, 1980 10:11 AM, double buffer maxBandRecs only for Dover, consolidate FI chain // (was causing corefragmentation and needless "page too complex" aborts). // February 5, 1981 5:19 PM, change error 800 to 808 (more informative) //