ps2ascii.ps 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. % Copyright (C) 1991, 1995, 1996, 1998, 1999 Aladdin Enterprises. All rights reserved.
  2. %
  3. % This file is part of AFPL Ghostscript.
  4. %
  5. % AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  6. % distributor accepts any responsibility for the consequences of using it, or
  7. % for whether it serves any particular purpose or works at all, unless he or
  8. % she says so in writing. Refer to the Aladdin Free Public License (the
  9. % "License") for full details.
  10. %
  11. % Every copy of AFPL Ghostscript must include a copy of the License, normally
  12. % in a plain ASCII text file named PUBLIC. The License grants you the right
  13. % to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14. % conditions described in the License. Among other things, the License
  15. % requires that the copyright notice and this notice be preserved on all
  16. % copies.
  17. % $Id: ps2ascii.ps,v 1.3 2001/07/22 20:43:32 igorm Exp $
  18. % Extract the ASCII text from a PostScript file. Nothing is displayed.
  19. % Instead, ASCII information is written to stdout. The idea is similar to
  20. % Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
  21. % If SIMPLE is defined, just the text is written, with a guess at line
  22. % breaks and word spacing. If SIMPLE is not defined, lines are written
  23. % to stdout as follows:
  24. %
  25. % F <height> <width> (<fontname>)
  26. % Indicate the font height and the width of a space.
  27. %
  28. % P
  29. % Indicate the end of the page.
  30. %
  31. % S <x> <y> (<string>) <width>
  32. % Display a string.
  33. %
  34. % <width> and <height> are integer dimensions in units of 1/720".
  35. % <x> and <y> are integer coordinates, in units of 1/720", with the origin
  36. % at the lower left.
  37. % <string> and <fontname> are strings represented with the standard
  38. % PostScript escape conventions.
  39. % If COMPLEX is defined, the following additional types of lines are
  40. % written to stdout.
  41. %
  42. % C <r> <g> <b>
  43. % Indicate the current color.
  44. %
  45. % I <x> <y> <width> <height>
  46. % Note the presence of an image.
  47. %
  48. % R <x> <y> <width> <height>
  49. % Fill a rectangle.
  50. %
  51. % <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
  52. %
  53. % Note that future versions of this program (in COMPLEX mode) may add
  54. % other output elements, so programs parsing the output should be
  55. % prepared to ignore elements that they do not recognize.
  56. % Note that this code will only work in all cases if systemdict is writable
  57. % and if `binding' the definitions of operators defined as procedures
  58. % is deferred. For this reason, it is normally invoked with
  59. % gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT ps2ascii.ps
  60. % Thanks to:
  61. % J Greely <jgreely@cis.ohio-state.edu> for improvements to this code;
  62. % Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements;
  63. % David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below.
  64. %% Additional modifications by David M. Jones
  65. %% (dmjones@theory.lcs.mit.edu), December 23, 1997
  66. %%
  67. %% (a) Rewrote forall loop at the end of .show.write. This fixes a
  68. %% stack leakage problem, but the changes are more significant
  69. %% than that.
  70. %%
  71. %% .char.map includes the names of all characters in the
  72. %% StandardEncoding, ISOLatin1Encoding, OT1Encoding and
  73. %% T1Encoding vectors. Thus, if the Encoding vector for the
  74. %% current font contains a name that is not in .char.map, it's
  75. %% redundant to check if the Encoding vector is equal to one of
  76. %% the known vectors. Previous versions of ps2ascii would give
  77. %% up at this point, and substitute an asterisk (*) for the
  78. %% character. I've taken the liberty of instead using the
  79. %% OT1Encoding vector to translate the character, on the grounds
  80. %% that in the cases I'm most interested in, a font without a
  81. %% useful Encoding vector was most likely created by a DVI to PS
  82. %% converter such as dvips or DVILASER (and OT1Encoding is
  83. %% largely compatible with StandardEncoding anyway). [Note that
  84. %% this does not make my earlier changes to support dvips (see
  85. %% fix (a) under my 1996 changes) completely obsolete, since
  86. %% there's additional useful information I can extract in that
  87. %% case.]
  88. %%
  89. %% Overall, this should provide better support for some documents
  90. %% (e.g, DVILASER documents will no longer be translated into a
  91. %% series of *'s) without breaking any other documents any worse
  92. %% than they already were broken.
  93. %%
  94. %% (b) Fixed two bugs in dvips.df-tail: (1) changed "dup 127" to "dup
  95. %% 128" to fix fencepost error, and (2) gave each font it's own
  96. %% FontName rather than having all fonts share the same name.
  97. %%
  98. %% (c) Added one further refinement to the heuristic for detecting
  99. %% paragraph breaks: do not ever start a new paragraph after a
  100. %% line ending in a hyphen.
  101. %%
  102. %% (d) Added a bunch of missing letters from the T1Encoding,
  103. %% OT1Encoding and ISOLatin1Encoding vectors to .letter.chars to
  104. %% improve hyphen-elimination algorithm. This still won't help
  105. %% if there's no useful Encoding vector.
  106. %%
  107. %% NOTE: A better solution to the problem of missing Encoding vectors
  108. %% might be to redefine definefont to check whether the Encoding
  109. %% vector is sensible and, if not, replace it by a default. This
  110. %% would alleviate the need for constant tests in the .show.write
  111. %% loop, as well as automatically solving the problem noted in fix
  112. %% (d) above, and the similar problem with .break.chars. This should
  113. %% be investigated. Also, the hyphen-elimination algorithm really
  114. %% needs to be looked at carefully and rethought.
  115. %%* Modifications to ps2ascii.ps by David M. Jones
  116. %%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996
  117. %%* Modifications:
  118. %%*
  119. %%* (a) added code to give better support for dvips files by providing
  120. %%* FontBBox's, FontName's and Encoding vectors for downloaded
  121. %%* bitmap fonts. This is done by using dvips's start-hook to
  122. %%* overwrite the df-tail and D procedures that dvips uses to
  123. %%* define its Type 3 bitmap fonts. Thus, this change should
  124. %%* provide better support for dvips-generated PS files without
  125. %%* affecting the handling of other documents.
  126. %%*
  127. %%* (b) Fixed two bugs that could potentially affect any PS file, not
  128. %%* just those created by dvips: (1) added missing "get" operator
  129. %%* in .show.write and (2) fixed bug that caused a hyphen at the
  130. %%* end of a line to be replaced by a space rather than begin
  131. %%* deleted. Note that the first bug was a source of stack
  132. %%* leakage, causing ps2ascii to run out of operand stack space
  133. %%* occasionally.
  134. %%*
  135. %%* Search for "%%* BF" to find these modifications.
  136. %%*
  137. %%* (c) Improved the heuristic for determining whether a line break
  138. %%* has occurred and whether a line break represents a paragraph
  139. %%* break. Previously, any change in the vertical position caused
  140. %%* a line break; now a line break is only registered if the
  141. %%* change is larger than the height of the current font. This
  142. %%* means that superscripts, subscripts, and such things as
  143. %%* shifted accents generated by TeX won't cause line breaks.
  144. %%* Paragraph-recognition is now done by comparing the indentation
  145. %%* of the new line to the indentation of the previous line and by
  146. %%* comparing the vertical distance between the new line and the
  147. %%* previous line to the vertical distance between the previous
  148. %%* line and its predecessor.
  149. %%*
  150. %%* (d) Added a hook for renaming the files where stdout and stderr
  151. %%* go.
  152. %%*
  153. %%* In general, my additions or changes to the code are described in
  154. %%* comments beginning with "%%*". However, there are numerous other
  155. %%* places where I have either re-formatted code or added comments to
  156. %%* the code while I was trying to understand it. These are usually
  157. %%* not specially marked.
  158. %%*
  159. /QUIET true def
  160. systemdict wcheck { systemdict } { userdict } ifelse begin
  161. /.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
  162. /COMPLEX dup where { pop true } { false } ifelse def
  163. /SIMPLE dup where { pop true } { false } ifelse def
  164. /setglobal where
  165. { pop currentglobal /setglobal load true setglobal }
  166. { { } }
  167. ifelse
  168. % Define a way to store and retrieve integers that survives save/restore.
  169. /.i.string0 (0 ) def
  170. /.i.string .i.string0 length string def
  171. /.iget { cvi } bind def
  172. /.iput { exch //.i.string exch copy cvs pop } bind def
  173. /.inew { //.i.string0 dup length string copy } bind def
  174. % We only want to redefine operators if they are defined already.
  175. /codef { 1 index where { pop def } { pop pop } ifelse } def
  176. % Redefine the end-of-page operators.
  177. /erasepage { } codef
  178. /copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
  179. /showpage { copypage erasepage initgraphics } codef
  180. % Redefine the fill operators to detect rectangles.
  181. /.orderrect % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
  182. { % Ensure llx <= urx, lly <= ury.
  183. 1 index 4 index lt { 4 2 roll } if
  184. dup 3 index lt { 3 1 roll exch } if
  185. exch 3 index sub exch 2 index sub
  186. } odef
  187. /.fillcomplex
  188. { % Do a first pass to see if the path is all rectangles in
  189. % the output coordinate system. We don't worry about overlapping
  190. % rectangles that might be partially not filled.
  191. % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
  192. mark true mark
  193. % Add a final moveto so we pick up any trailing unclosed subpath.
  194. 0 0 itransform moveto
  195. { .coord counttomark 2 gt
  196. { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop } ifelse }
  197. if
  198. }
  199. { .coord }
  200. { cleartomark not mark exit }
  201. { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
  202. pathforall cleartomark
  203. { .showcolor counttomark 4 idiv
  204. { counttomark -4 roll .orderrect
  205. (R ) //print .show==4
  206. }
  207. repeat pop
  208. }
  209. { cleartomark
  210. }
  211. ifelse
  212. } odef
  213. /.fillcheckrect
  214. { % Check whether the current subpath is a rectangle.
  215. % If it is, add it to the list of rectangles being accumulated;
  216. % if not exit the .fillcomplex loop.
  217. % The subpath has not been closed.
  218. % Stack: as in .fillcomplex, + newx newy
  219. counttomark 10 eq { 9 index 9 index 4 2 roll } if
  220. counttomark 12 ne { cleartomark not mark exit } if
  221. 12 2 roll
  222. % Check for the two possible forms of rectangles:
  223. % x0 y0 x0 y1 x1 y1 x1 y0 x0 y0
  224. % x0 y0 x1 y0 x1 y1 x0 y1 x0 y0
  225. 9 index 2 index eq 9 index 2 index eq and
  226. 10 index 9 index eq
  227. { % Check for first form.
  228. 7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
  229. }
  230. { % Check for second form.
  231. 9 index 8 index eq and
  232. 8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
  233. }
  234. ifelse not { cleartomark not mark exit } if
  235. % We have a rectangle.
  236. pop pop pop pop 4 2 roll pop pop 8 4 roll
  237. } odef
  238. /eofill { COMPLEX { .fillcomplex } if newpath } codef
  239. /fill { COMPLEX { .fillcomplex } if newpath } codef
  240. /rectfill { gsave newpath .rectappend fill grestore } codef
  241. /ueofill { gsave newpath uappend eofill grestore } codef
  242. /ufill { gsave newpath uappend fill grestore } codef
  243. % Redefine the stroke operators to detect rectangles.
  244. /rectstroke
  245. { gsave newpath
  246. dup type dup /arraytype eq exch /packedarraytype eq or
  247. { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
  248. { .rectappend }
  249. ifelse stroke grestore
  250. } codef
  251. /.strokeline % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
  252. % Note: fromx and fromy are in output coordinates;
  253. % tox and toy are in user coordinates.
  254. { .coord 2 copy 6 2 roll .orderrect
  255. % Add in the line width. Assume square or round caps.
  256. currentlinewidth 2 div dup .dcoord add abs 1 max 5 1 roll
  257. 4 index add 4 1 roll 4 index add 4 1 roll
  258. 4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
  259. (R ) //print .show==4
  260. } odef
  261. /.strokecomplex
  262. { % Do a first pass to see if the path is all horizontal and vertical
  263. % lines in the output coordinate system.
  264. % Stack: true mark origx origy curx cury
  265. true mark null null null null
  266. { .coord 6 2 roll pop pop pop pop 2 copy }
  267. { .coord 1 index 4 index eq 1 index 4 index eq or
  268. { 4 2 roll pop pop }
  269. { cleartomark not mark exit }
  270. ifelse
  271. }
  272. { cleartomark not mark exit }
  273. { counttomark -2 roll 2 copy counttomark 2 roll
  274. 1 index 4 index eq 1 index 4 index eq or
  275. { pop pop 2 copy }
  276. { cleartomark not mark exit }
  277. ifelse
  278. }
  279. pathforall cleartomark
  280. 0 currentlinewidth .dcoord 0 eq exch 0 eq or and
  281. % Do the second pass to write out the rectangles.
  282. % Stack: origx origy curx cury
  283. { .showcolor null null null null
  284. { 6 2 roll pop pop pop pop 2 copy .coord }
  285. { .strokeline }
  286. { }
  287. { 3 index 3 index .strokeline }
  288. pathforall pop pop pop pop
  289. }
  290. if
  291. } odef
  292. /stroke { COMPLEX { .strokecomplex } if newpath } codef
  293. /ustroke
  294. { gsave newpath
  295. dup length 6 eq { exch uappend concat } { uappend } ifelse
  296. stroke grestore
  297. } codef
  298. % The image operators must read the input and note the dimensions.
  299. % Eventually we should redefine these to detect 1-bit-high all-black images,
  300. % since this is how dvips does underlining (!).
  301. /.noteimagerect % <width> <height> <matrix> .noteimagerect -
  302. { COMPLEX
  303. { gsave setmatrix itransform 0 0 itransform
  304. grestore .coord 4 2 roll .coord .orderrect
  305. (I ) //print .show==4
  306. }
  307. { pop pop pop
  308. }
  309. ifelse
  310. } odef
  311. /colorimage where
  312. { pop /colorimage
  313. { 1 index
  314. { dup 6 add index 1 index 6 add index 2 index 5 add index }
  315. { 6 index 6 index 5 index }
  316. ifelse .noteimagerect gsave nulldevice //colorimage grestore
  317. } codef
  318. } if
  319. /.noteimage % Arguments as for image[mask]
  320. { dup type /dicttype eq
  321. { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
  322. { 4 index 4 index 3 index }
  323. ifelse .noteimagerect
  324. } odef
  325. /image { .noteimage gsave nulldevice //image grestore } codef
  326. /imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
  327. % Output the current color if necessary.
  328. /.color.r .inew def
  329. .color.r -1 .iput % make sure we write the color at the beginning
  330. /.color.g .inew def
  331. /.color.b .inew def
  332. /.showcolor
  333. { COMPLEX
  334. { currentrgbcolor
  335. 1000 mul round cvi
  336. 3 1 roll 1000 mul round cvi
  337. exch 1000 mul round cvi
  338. % Stack: b g r
  339. dup //.color.r .iget eq
  340. 2 index //.color.g .iget eq and
  341. 3 index //.color.b .iget eq and
  342. { pop pop pop
  343. }
  344. { (C ) //print
  345. dup //.color.r exch .iput .show==only
  346. ( ) //print dup //.color.g exch .iput .show==only
  347. ( ) //print dup //.color.b exch .iput .show==only
  348. (\n) //print
  349. }
  350. ifelse
  351. }
  352. if
  353. } bind def
  354. % Redefine `show'.
  355. % Set things up so our output will be in tenths of a point, with origin at
  356. % lower left. This isolates us from the peculiarities of individual devices.
  357. /.show.ident.matrix matrix def
  358. /.show.ident { % - .show.ident <scale> <matrix>
  359. % //.show.ident.matrix defaultmatrix
  360. % % Assume the original transformation is well-behaved.
  361. % 0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
  362. % 0.1 dup 3 -1 roll scale
  363. gsave initmatrix
  364. % Assume the original transformation is well-behaved...
  365. 0.1 0 dtransform abs exch abs .max
  366. 0.1 dup scale .show.ident.matrix currentmatrix
  367. % ... but undo any rotation into landscape orientation.
  368. dup 0 get 0 eq {
  369. 1 get dup abs div 90 mul rotate
  370. .show.ident.matrix currentmatrix
  371. } if
  372. grestore
  373. } bind def
  374. /.coord { % <x> <y> .coord <x'> <y'>
  375. transform .show.ident exch pop itransform
  376. exch round cvi exch round cvi
  377. } odef
  378. /.dcoord { % <dx> <dy> .coord <dx'> <dy'>
  379. % Transforming distances is trickier, because
  380. % the coordinate system might be rotated.
  381. .show.ident pop 3 1 roll
  382. exch 0 dtransform
  383. dup mul exch dup mul add sqrt
  384. 2 index div round cvi
  385. exch 0 exch dtransform
  386. dup mul exch dup mul add sqrt
  387. 3 -1 roll div round cvi
  388. } odef
  389. % Remember the current X, Y, and height.
  390. /.show.x .inew def
  391. /.show.y .inew def
  392. /.show.height .inew def
  393. % Remember the last character of the previous string; if it was a
  394. % hyphen preceded by a letter, we didn't output the hyphen.
  395. /.show.last (\000) def
  396. % Remember the current font.
  397. /.font.name 130 string def
  398. /.font.name.length .inew def
  399. /.font.height .inew def
  400. /.font.width .inew def
  401. %%* Also remember indentation of current line and previous vertical
  402. %%* skip
  403. /.show.indent .inew def
  404. /.show.dy .inew def
  405. % We have to redirect stdout somehow....
  406. /.show.stdout { (%stdout) (w) file } bind def
  407. % Make sure writing will work even if a program uses =string.
  408. /.show.string =string length string def
  409. /.show.=string =string length string def
  410. /.show==only
  411. { //=string //.show.=string copy pop
  412. dup type /stringtype eq
  413. { dup length //.show.string length le
  414. { dup rcheck { //.show.string copy } if
  415. } if
  416. } if
  417. .show.stdout exch write==only
  418. //.show.=string //=string copy pop
  419. } odef
  420. /.show==4
  421. { 4 -1 roll .show==only ( ) //print
  422. 3 -1 roll .show==only ( ) //print
  423. exch .show==only ( ) //print
  424. .show==only (\n) //print
  425. } odef
  426. /.showwidth % Same as stringwidth, but disable COMPLEX so that
  427. % we don't try to detect rectangles during BuildChar.
  428. { COMPLEX
  429. { /COMPLEX false def stringwidth /COMPLEX true def }
  430. { stringwidth }
  431. ifelse
  432. } odef
  433. /.showfont % <string> .showfont <string>
  434. { gsave
  435. % Try getting the height and width of the font from the FontBBox.
  436. currentfont /FontBBox .knownget not { {0 0 0 0} } if
  437. aload pop % llx lly urx ury
  438. exch 4 -1 roll % lly ury urx llx
  439. sub % lly ury dx
  440. 3 1 roll exch % dx ury lly
  441. sub % dx dy
  442. 2 copy .max 0 ne
  443. { currentfont /FontMatrix get dtransform
  444. }
  445. { pop pop
  446. % Fonts produced by dvips, among other applications, have
  447. % BuildChar procedures that bomb out when given unexpected
  448. % characters, and there is no way to determine whether a given
  449. % character will do this. So for Type 1 fonts, we measure a
  450. % typical character ('X'); for others, we punt.
  451. currentfont /FontType get 1 eq
  452. { (X) .showwidth pop dup 1.3 mul
  453. }
  454. { % No safe way to get the character size. Punt.
  455. 0 0
  456. }
  457. ifelse
  458. }
  459. ifelse .dcoord exch
  460. currentfont /FontName .knownget not { () } if
  461. dup type /stringtype ne { //.show.string cvs } if
  462. grestore
  463. % Stack: height width fontname
  464. SIMPLE
  465. { pop pop //.show.height exch .iput }
  466. { 2 index //.font.height .iget eq
  467. 2 index //.font.width .iget eq and
  468. 1 index //.font.name 0 //.font.name.length .iget getinterval eq and
  469. { pop pop pop
  470. }
  471. { (F ) //print
  472. 3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
  473. exch dup //.font.width exch .iput .show==only ( ) //print
  474. dup length //.font.name.length exch .iput
  475. //.font.name cvs .show==only (\n) //print
  476. }
  477. ifelse
  478. }
  479. ifelse
  480. } odef
  481. % Define the letters -- characters which, if they occur followed by a hyphen
  482. % at the end of a line, cause the hyphen and line break to be ignored.
  483. /.letter.chars 100 dict def
  484. mark
  485. 65 1 90 { dup 32 add } for
  486. counttomark
  487. { StandardEncoding exch get .letter.chars exch dup put }
  488. repeat
  489. pop
  490. %%* Add the rest of the letters from the [O]T1Encoding and
  491. %%* ISOLatin1Encoding vectors
  492. mark
  493. /AE
  494. /Aacute
  495. /Abreve
  496. /Acircumflex
  497. /Adieresis
  498. /Agrave
  499. /Aogonek
  500. /Aring
  501. /Atilde
  502. /Cacute
  503. /Ccaron
  504. /Ccedilla
  505. /Dcaron
  506. /Eacute
  507. /Ecaron
  508. /Ecircumflex
  509. /Edieresis
  510. /Egrave
  511. /Eng
  512. /Eogonek
  513. /Eth
  514. /Gbreve
  515. /Germandbls
  516. /IJ
  517. /Iacute
  518. /Icircumflex
  519. /Idieresis
  520. /Idot
  521. /Igrave
  522. /Lacute
  523. /Lcaron
  524. /Lslash
  525. /Nacute
  526. /Ncaron
  527. /Ntilde
  528. /OE
  529. /Oacute
  530. /Ocircumflex
  531. /Odieresis
  532. /Ograve
  533. /Ohungarumlaut
  534. /Oslash
  535. /Otilde
  536. /Racute
  537. /Rcaron
  538. /Sacute
  539. /Scaron
  540. /Scedilla
  541. /Tcaron
  542. /Tcedilla
  543. /Thorn
  544. /Uacute
  545. /Ucircumflex
  546. /Udieresis
  547. /Ugrave
  548. /Uhungarumlaut
  549. /Uring
  550. /Yacute
  551. /Ydieresis
  552. /Zacute
  553. /Zcaron
  554. /Zdot
  555. /aacute
  556. /abreve
  557. /acircumflex
  558. /adieresis
  559. /ae
  560. /agrave
  561. /aogonek
  562. /aring
  563. /atilde
  564. /cacute
  565. /ccaron
  566. /ccedilla
  567. /dbar
  568. /dcaron
  569. /dotlessi
  570. /dotlessj
  571. /eacute
  572. /ecaron
  573. /ecircumflex
  574. /edieresis
  575. /egrave
  576. /eng
  577. /eogonek
  578. /eth
  579. /exclamdown
  580. /ff
  581. /ffi
  582. /ffl
  583. /fi
  584. /fl
  585. /gbreve
  586. /germandbls
  587. /iacute
  588. /icircumflex
  589. /idieresis
  590. /igrave
  591. /ij
  592. /lacute
  593. /lcaron
  594. /lslash
  595. /nacute
  596. /ncaron
  597. /ntilde
  598. /oacute
  599. /ocircumflex
  600. /odieresis
  601. /oe
  602. /ograve
  603. /ohungarumlaut
  604. /oslash
  605. /otilde
  606. /questiondown
  607. /racute
  608. /rcaron
  609. /sacute
  610. /scaron
  611. /scedilla
  612. /section
  613. /sterling
  614. /tcaron
  615. /tcedilla
  616. /thorn
  617. /uacute
  618. /ucircumflex
  619. /udieresis
  620. /ugrave
  621. /uhungarumlaut
  622. /uring
  623. /yacute
  624. /ydieresis
  625. /zacute
  626. /zcaron
  627. /zdot
  628. counttomark
  629. { .letter.chars exch dup put }
  630. repeat
  631. pop
  632. % Define a set of characters which, if they occur at the start of a line,
  633. % are taken as indicating a paragraph break.
  634. /.break.chars 50 dict def
  635. mark
  636. /bullet /dagger /daggerdbl /periodcentered /section
  637. counttomark
  638. { .break.chars exch dup put }
  639. repeat
  640. pop
  641. % Define character translation to ASCII.
  642. % We have to do this for the entire character set.
  643. /.char.map 500 dict def
  644. /.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
  645. % Encode the printable ASCII characters.
  646. mark 32 1 126
  647. { 1 string dup 0 4 -1 roll put
  648. dup 0 get StandardEncoding exch get exch
  649. }
  650. for .chars.def
  651. % Encode accents.
  652. mark
  653. /acute (')
  654. /caron (^)
  655. /cedilla (,)
  656. /circumflex (^)
  657. /dieresis (")
  658. /grave (`)
  659. /ring (*)
  660. /tilde (~)
  661. .chars.def
  662. % Encode the ISO accented characters.
  663. mark 192 1 255
  664. { ISOLatin1Encoding exch get =string cvs
  665. dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
  666. .char.map 2 index known .char.map 2 index known and
  667. { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
  668. .char.map 3 1 roll put
  669. }
  670. { pop pop pop
  671. }
  672. ifelse
  673. }
  674. for .chars.def
  675. % Encode the remaining standard and ISO alphabetic characters.
  676. mark
  677. /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
  678. /ae (ae) /eth (dh)
  679. /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
  680. /germandbls (ss) /oe (oe) /thorn (th)
  681. .chars.def
  682. % Encode the other standard and ISO characters.
  683. mark
  684. /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
  685. /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
  686. /dotlessi (i)
  687. /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
  688. /florin (f) /fraction (/)
  689. /guillemotleft (<<) /guillemotright (>>)
  690. /guilsinglleft (<) /guilsinglright (>) /hungarumlaut ("") /logicalnot (~)
  691. /macron (_) /minus (-) /mu (u) /multiply (*)
  692. /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
  693. /ordfeminine (-a) /ordmasculine (-o)
  694. /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
  695. /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
  696. /quotesinglbase (,) /quotesingle (') /registered ((R))
  697. /section ($) /sterling (#)
  698. /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
  699. /yen (Y)
  700. .chars.def
  701. % Encode a few common Symbol characters.
  702. mark
  703. /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
  704. /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
  705. /trademarksans ((TM)) /trademarkserif ((TM))
  706. .chars.def
  707. %%* Add a few characters from StandardEncoding and ISOLatin1Encoding
  708. %%* that were missing.
  709. mark
  710. /cent (c)
  711. /guilsinglleft (<)
  712. /guilsinglright (>)
  713. /breve (*)
  714. /Lslash (L/)
  715. /lslash (l/)
  716. .chars.def
  717. %%* Define the OT1Encoding and T1Encoding vectors for use with dvips
  718. %%* files. Unfortunately, there's no way of telling what font is
  719. %%* really being used within a dvips document, so we can't provide an
  720. %%* appropriate encoding for each individual font. Instead, we'll
  721. %%* just provide support for the two most popular text encodings, the
  722. %%* OT1 and T1 encodings, and just accept the fact that any font not
  723. %%* using one of those encodings will be rendered as gibberish.
  724. %%*
  725. %%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1
  726. %%* (aka the Cork encoding) is the 8-bit encoding used by the DC
  727. %%* fonts, a preliminary version of the proposed Extended Computer
  728. %%* Modern fonts. Unfortunately, T1 is not a strict extension of OT1;
  729. %%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134,
  730. %%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same
  731. %%* vector for both.
  732. %%*
  733. %%* Of course, we also can't reliably tell the difference between an
  734. %%* OT1-encoded font and a T1-encoded font based on the information in
  735. %%* a dvips-created PostScript file. As a best-guess solution, we'll
  736. %%* use the T1 encoding if the font contains any characters in
  737. %%* positions above 8#177 and the OT1 encoding if it doesn't.
  738. /T1Encoding 256 array def
  739. /OT1Encoding 256 array def
  740. %%* T1Encoding shares a lot with StandardEncoding, so let's start
  741. %%* there.
  742. StandardEncoding T1Encoding copy pop
  743. /OT1.encode {
  744. counttomark
  745. 2 idiv
  746. { OT1Encoding 3 1 roll put }
  747. repeat
  748. cleartomark
  749. } def
  750. /T1.encode {
  751. counttomark
  752. 2 idiv
  753. { T1Encoding 3 1 roll put }
  754. repeat
  755. cleartomark
  756. } def
  757. mark
  758. 8#000 /grave
  759. 8#001 /acute
  760. 8#002 /circumflex
  761. 8#003 /tilde
  762. 8#004 /dieresis
  763. 8#005 /hungarumlaut
  764. 8#006 /ring
  765. 8#007 /caron
  766. 8#010 /breve
  767. 8#011 /macron
  768. 8#012 /dotaccent
  769. 8#013 /cedilla
  770. 8#014 /ogonek
  771. 8#015 /quotesinglbase
  772. 8#016 /guilsinglleft
  773. 8#017 /guilsinglright
  774. 8#020 /quotedblleft
  775. 8#021 /quotedblright
  776. 8#022 /quotedblbase
  777. 8#023 /guillemotleft
  778. 8#024 /guillemotright
  779. 8#025 /endash
  780. 8#026 /emdash
  781. 8#027 /cwm
  782. 8#030 /perthousandzero
  783. 8#031 /dotlessi
  784. 8#032 /dotlessj
  785. 8#033 /ff
  786. 8#034 /fi
  787. 8#035 /fl
  788. 8#036 /ffi
  789. 8#037 /ffl
  790. %% 8#040 through 8#176 follow StandardEncoding
  791. 8#177 /hyphen
  792. T1.encode
  793. mark
  794. 8#200 /Abreve
  795. 8#201 /Aogonek
  796. 8#202 /Cacute
  797. 8#203 /Ccaron
  798. 8#204 /Dcaron
  799. 8#205 /Ecaron
  800. 8#206 /Eogonek
  801. 8#207 /Gbreve
  802. 8#210 /Lacute
  803. 8#211 /Lcaron
  804. 8#212 /Lslash
  805. 8#213 /Nacute
  806. 8#214 /Ncaron
  807. 8#215 /Eng
  808. 8#216 /Ohungarumlaut
  809. 8#217 /Racute
  810. 8#220 /Rcaron
  811. 8#221 /Sacute
  812. 8#222 /Scaron
  813. 8#223 /Scedilla
  814. 8#224 /Tcaron
  815. 8#225 /Tcedilla
  816. 8#226 /Uhungarumlaut
  817. 8#227 /Uring
  818. 8#230 /Ydieresis
  819. 8#231 /Zacute
  820. 8#232 /Zcaron
  821. 8#233 /Zdot
  822. 8#234 /IJ
  823. 8#235 /Idot
  824. 8#236 /dbar
  825. 8#237 /section
  826. 8#240 /abreve
  827. 8#241 /aogonek
  828. 8#242 /cacute
  829. 8#243 /ccaron
  830. 8#244 /dcaron
  831. 8#245 /ecaron
  832. 8#246 /eogonek
  833. 8#247 /gbreve
  834. 8#250 /lacute
  835. 8#251 /lcaron
  836. 8#252 /lslash
  837. 8#253 /nacute
  838. 8#254 /ncaron
  839. 8#255 /eng
  840. 8#256 /ohungarumlaut
  841. 8#257 /racute
  842. 8#260 /rcaron
  843. 8#261 /sacute
  844. 8#262 /scaron
  845. 8#263 /scedilla
  846. 8#264 /tcaron
  847. 8#265 /tcedilla
  848. 8#266 /uhungarumlaut
  849. 8#267 /uring
  850. 8#270 /ydieresis
  851. 8#271 /zacute
  852. 8#272 /zcaron
  853. 8#273 /zdot
  854. 8#274 /ij
  855. 8#275 /exclamdown
  856. 8#276 /questiondown
  857. 8#277 /sterling
  858. 8#300 /Agrave
  859. 8#301 /Aacute
  860. 8#302 /Acircumflex
  861. 8#303 /Atilde
  862. 8#304 /Adieresis
  863. 8#305 /Aring
  864. 8#306 /AE
  865. 8#307 /Ccedilla
  866. 8#310 /Egrave
  867. 8#311 /Eacute
  868. 8#312 /Ecircumflex
  869. 8#313 /Edieresis
  870. 8#314 /Igrave
  871. 8#315 /Iacute
  872. 8#316 /Icircumflex
  873. 8#317 /Idieresis
  874. 8#320 /Eth
  875. 8#321 /Ntilde
  876. 8#322 /Ograve
  877. 8#323 /Oacute
  878. 8#324 /Ocircumflex
  879. 8#325 /Otilde
  880. 8#326 /Odieresis
  881. 8#327 /OE
  882. 8#330 /Oslash
  883. 8#331 /Ugrave
  884. 8#332 /Uacute
  885. 8#333 /Ucircumflex
  886. 8#334 /Udieresis
  887. 8#335 /Yacute
  888. 8#336 /Thorn
  889. 8#337 /Germandbls
  890. 8#340 /agrave
  891. 8#341 /aacute
  892. 8#342 /acircumflex
  893. 8#343 /atilde
  894. 8#344 /adieresis
  895. 8#345 /aring
  896. 8#346 /ae
  897. 8#347 /ccedilla
  898. 8#350 /egrave
  899. 8#351 /eacute
  900. 8#352 /ecircumflex
  901. 8#353 /edieresis
  902. 8#354 /igrave
  903. 8#355 /iacute
  904. 8#356 /icircumflex
  905. 8#357 /idieresis
  906. 8#360 /eth
  907. 8#361 /ntilde
  908. 8#362 /ograve
  909. 8#363 /oacute
  910. 8#364 /ocircumflex
  911. 8#365 /otilde
  912. 8#366 /odieresis
  913. 8#367 /oe
  914. 8#370 /oslash
  915. 8#371 /ugrave
  916. 8#372 /uacute
  917. 8#373 /ucircumflex
  918. 8#374 /udieresis
  919. 8#375 /yacute
  920. 8#376 /thorn
  921. 8#377 /germandbls
  922. T1.encode
  923. %%* Now copy OT1Encoding into T1Encoding and make a few changes.
  924. T1Encoding OT1Encoding copy pop
  925. mark
  926. 8#000 /Gamma
  927. 8#001 /Delta
  928. 8#002 /Theta
  929. 8#003 /Lambda
  930. 8#004 /Xi
  931. 8#005 /Pi
  932. 8#006 /Sigma
  933. 8#007 /Upsilon
  934. 8#010 /Phi
  935. 8#011 /Psi
  936. 8#012 /Omega
  937. 8#013 /ff
  938. 8#014 /fi
  939. 8#015 /fl
  940. 8#016 /ffi
  941. 8#017 /ffl
  942. 8#020 /dotlessi
  943. 8#021 /dotlessj
  944. 8#022 /grave
  945. 8#023 /acute
  946. 8#024 /caron
  947. 8#025 /breve
  948. 8#026 /macron
  949. 8#027 /ring
  950. 8#030 /cedilla
  951. 8#031 /germandbls
  952. 8#032 /ae
  953. 8#033 /oe
  954. 8#034 /oslash
  955. 8#035 /AE
  956. 8#036 /OE
  957. 8#037 /Oslash
  958. 8#040 /polishslash
  959. 8#042 /quotedblright
  960. 8#074 /exclamdown
  961. 8#076 /questiondown
  962. 8#134 /quotedblleft
  963. 8#137 /dotaccent
  964. 8#173 /endash
  965. 8#174 /emdash
  966. 8#175 /hungarumlaut
  967. 8#177 /dieresis
  968. OT1.encode
  969. %%* And add a few characters from the OT1Encoding
  970. mark
  971. /Gamma (\\Gamma )
  972. /Delta (\\Delta )
  973. /Theta (\\Theta )
  974. /Lambda (\\Lambda )
  975. /Xi (\\Xi )
  976. /Pi (\\Pi )
  977. /Sigma (\\Sigma )
  978. /Upsilon (\\Upsilon )
  979. /Phi (\\Phi )
  980. /Psi (\\Psi )
  981. /Omega (\\Omega )
  982. /dotlessj (j)
  983. /ff (ff)
  984. /cwm ()
  985. /perthousandzero (0)
  986. /polishslash ()
  987. /Abreve (A*)
  988. /Aogonek (A,)
  989. /Cacute (C')
  990. /Ccaron (C^)
  991. /Dcaron (D^)
  992. /Ecaron (E^)
  993. /Eogonek (E,)
  994. /Gbreve (G*)
  995. /Lacute (L')
  996. /Lcaron (L^)
  997. /Nacute (N')
  998. /Ncaron (N^)
  999. /Eng (NG)
  1000. /Ohungarumlaut (O"")
  1001. /Racute (R')
  1002. /Rcaron (R^)
  1003. /Sacute (S')
  1004. /Scaron (S^)
  1005. /Scedilla (S,)
  1006. /Tcaron (T^)
  1007. /Tcedilla (T,)
  1008. /Uhungarumlaut (U"")
  1009. /Uring (U*)
  1010. /Ydieresis (Y")
  1011. /Zacute (Z')
  1012. /Zcaron (Z^)
  1013. /Zdot (Z.)
  1014. /IJ (IJ)
  1015. /Idot (I.)
  1016. /dbar (d-)
  1017. /abreve (a*)
  1018. /aogonek (a,)
  1019. /cacute (c')
  1020. /ccaron (c^)
  1021. /dcaron (d^)
  1022. /ecaron (e^)
  1023. /eogonek (e,)
  1024. /gbreve (g*)
  1025. /lacute (l')
  1026. /lcaron (l^)
  1027. /nacute (n')
  1028. /ncaron (n^)
  1029. /eng (ng)
  1030. /ohungarumlaut (o"")
  1031. /racute (r')
  1032. /rcaron (r^)
  1033. /sacute (s')
  1034. /scaron (s^)
  1035. /scedilla (s,)
  1036. /tcaron (t^)
  1037. /tcedilla (t,)
  1038. /uhungarumlaut (u"")
  1039. /uring (u*)
  1040. /zacute (z')
  1041. /zcaron (z^)
  1042. /zdot (z.)
  1043. /ij (ij)
  1044. /Germandbls (SS)
  1045. .chars.def
  1046. %%* We extend the df-tail command to stick in an Encoding vector (see
  1047. %%* above for a discussion of the T1 and OT1 encodings), put in a
  1048. %%* FontName (which will just be dvips's name for the font, i.e., Fa,
  1049. %%* Fb, etc.) and give each font a separate FontBBox instead of
  1050. %%* letting them all share a single one.
  1051. /dvips.df-tail % id numcc maxcc df-tail
  1052. {
  1053. /nn 9 dict N
  1054. nn begin
  1055. %%
  1056. %% Choose an encoding based on the highest position occupied.
  1057. %%
  1058. dup 128 gt { T1Encoding } { OT1Encoding } ifelse
  1059. /Encoding X
  1060. /FontType 3 N
  1061. %%
  1062. %% It's ok for all the fonts to share a FontMatrix, but they
  1063. %% need to have separate FontBBoxes
  1064. %%
  1065. /FontMatrix fntrx N
  1066. /FontBBox [0 0 0 0] N
  1067. string /base X
  1068. array /BitMaps X
  1069. %%
  1070. %% And let's throw in a FontName for good measure
  1071. %%
  1072. dup ( ) cvs
  1073. %%
  1074. %% Make sure each font gets it own private FontName. -- dmj,
  1075. %% 12/23/97
  1076. %%
  1077. dup length string copy
  1078. /FontName X
  1079. /BuildChar {CharBuilder} N
  1080. end
  1081. dup { /foo setfont }
  1082. 2 array copy cvx N
  1083. load
  1084. 0 nn put
  1085. /ctr 0 N
  1086. [
  1087. } def
  1088. %%* This is functionally equivalent to dvips's /D procedure, but it
  1089. %%* also calculates the Font Bounding Box while defining the
  1090. %%* characters.
  1091. /dvips.D % char-data ch D - : define character bitmap in current font
  1092. {
  1093. /cc X % char-data
  1094. dup type /stringtype ne {]} if % char-data
  1095. /ch-data X
  1096. nn /base get cc ctr put % (adds ctr to cc'th position of BASE)
  1097. nn /BitMaps get
  1098. ctr
  1099. ch-data % BitMaps ctr char-data
  1100. sf 1 ne {
  1101. dup dup length 1 sub dup 2 index S get sf div put
  1102. } if
  1103. put % puts char-data into BitMaps at index ctr
  1104. /ctr ctr 1 add N
  1105. %%
  1106. %% Make sure the Font Bounding Box encloses the Bounding Box of the
  1107. %% current character
  1108. %%
  1109. nn /FontBBox get % BB
  1110. dup % calculate new llx
  1111. dup 0 get
  1112. ch-xoff
  1113. min
  1114. 0 exch put
  1115. dup % calculate new lly
  1116. dup 1 get
  1117. ch-yoff ch-height sub
  1118. min
  1119. 1 exch put
  1120. dup % calculate new urx
  1121. dup 2 get
  1122. ch-dx ch-width add
  1123. max
  1124. 2 exch put
  1125. dup 3 get % calculate new ury
  1126. ch-yoff
  1127. max
  1128. 3 exch put
  1129. } def
  1130. %%* Define start-hook to replace df-tail and D by our versions.
  1131. %%* Unfortunately, the user can redefine start-hook and thus bypass
  1132. %%* these changes, but I don't see an obvious way around that.
  1133. userdict /start-hook {
  1134. TeXDict /df-tail /dvips.df-tail load bind put
  1135. TeXDict /D /dvips.D load bind put
  1136. } put
  1137. %%* Introduce a symbolic constant for hyphens. (Need to make
  1138. %%* allowance for hyphen being in different place?)
  1139. /.hyphen 45 def
  1140. % Write out a string. If it ends in a letter and a hyphen,
  1141. % don't write the hyphen, and set .show.last to a hyphen;
  1142. % otherwise, set .show.last to the character (or \000 if it was a hyphen).
  1143. /.show.write % <string>
  1144. {
  1145. dup length 1 ge
  1146. { dup dup length 1 sub get % string last_char
  1147. dup .hyphen eq % string last_char hyphen?
  1148. { % string last_char
  1149. 1 index length 1 gt
  1150. { 1 index dup length 2 sub get }
  1151. { //.show.last 0 get }
  1152. ifelse % string last_char prev-char
  1153. currentfont /Encoding get exch get % look up prev-char
  1154. //.letter.chars exch known % is it a letter?
  1155. { % Remove the hyphen % string last_char
  1156. exch % last_char string
  1157. dup length 1 sub % last_char string len-1
  1158. 0 exch getinterval % last_char string-1
  1159. exch % string-1 last_char
  1160. }
  1161. { pop 0 } % string 0
  1162. ifelse
  1163. }
  1164. if
  1165. //.show.last 0 3 -1 roll put % store last_char
  1166. % in .show.last
  1167. % If .show.last ==
  1168. % hyphen, then
  1169. % last char of
  1170. % previous string
  1171. % was a hyphen
  1172. }
  1173. if % string
  1174. { % begin forall % c
  1175. dup % c c
  1176. currentfont /Encoding get % c c vec
  1177. exch get % c name
  1178. dup //.char.map exch known % c name bool
  1179. { exch pop }
  1180. { pop OT1Encoding exch get }
  1181. ifelse % name
  1182. //.char.map exch get % translation
  1183. .show.stdout exch writestring
  1184. }
  1185. forall
  1186. } odef
  1187. /.showstring1 { % string
  1188. currentpoint .coord % string x y
  1189. 3 -1 roll dup .showwidth % x y string dx dy
  1190. 1 index % x y string dx dy dx
  1191. 0 rmoveto % x y string dx dy
  1192. .dcoord pop % x y string width
  1193. SIMPLE
  1194. { % x y string width
  1195. 2 index % x y string width y
  1196. //.show.y .iget % x y string width y old.y
  1197. %%*
  1198. %%* Replaced test "has y changed" by "has y changed by more
  1199. %%* than the current font height" so that subscripts and
  1200. %%* superscripts won't cause line/paragraph breaks
  1201. %%*
  1202. sub abs dup % x y string width dy dy
  1203. //.show.height .iget
  1204. gt
  1205. { % x y string width dy
  1206. %%* Vertical position has changed by more than the font
  1207. %%* height, so we now try to figure out whether we've
  1208. %%* started a new paragraph or merely a new line, using a
  1209. %%* variety of heuristics.
  1210. %%* If any of the following is true, we start a new
  1211. %%* paragraph:
  1212. %%* (a) the current vertical shift is more than 1.1 times
  1213. %%* the previous vertical shift, where 1.1 is an
  1214. %%* arbitrarily chosen factor that could probably be
  1215. %%* refined.
  1216. dup % x y string width dy dy
  1217. //.show.dy .iget 1.1 mul
  1218. gt
  1219. exch
  1220. %%* Save the new vertical shift
  1221. //.show.dy exch .iput
  1222. %%* (b) The vertical shift is more than 1.3 times the
  1223. %%* "size" of the current font. I've removed this
  1224. %%* test since it's not really very useful.
  1225. %%* //.show.dy .iget
  1226. %%* //.show.height .iget 1.4 mul
  1227. %%* gt % x y string width bool
  1228. %%* .show.height .iget 0 gt and % only perform test if font
  1229. %%* % height is nonzero
  1230. %%* or
  1231. %%* (c) the first character of the new line is one of the
  1232. %%* .break.chars
  1233. 2 index length % x y string width newpar? len
  1234. 0 gt % x y string width newpar? len>0?
  1235. {
  1236. 2 index 0 get % x y string width newpar? s
  1237. currentfont /Encoding get
  1238. exch get % x y string width newpar? s_enc
  1239. //.break.chars exch known { pop true } if
  1240. }
  1241. if % x y string width newpar?
  1242. %%* (d) The indentation of the new line is greater than
  1243. %%* the indentation of the previous line.
  1244. 4 index
  1245. //.show.indent .iget
  1246. gt
  1247. or
  1248. %%* HOWEVER, if the line ends in a hyphen, we do NOT begin
  1249. %%* a new paragraph (cf. comment at end of BF2). --dmj,
  1250. %%* 12/23/97
  1251. //.show.last 0 get .hyphen ne
  1252. and
  1253. % newpar?
  1254. { (\n\n) } % Paragraph
  1255. { % Line
  1256. %%*
  1257. %%* BF2: If last character on a line is
  1258. %%* a hyphen, we omit the hyphen and
  1259. %%* run the lines together. Of
  1260. %%* course, this will fail if a word
  1261. %%* with an explicit hyphen (e.g.,
  1262. %%* X-ray) is split across two lines.
  1263. %%* Oh, well. (What should we do
  1264. %%* about a hyphen that ends a
  1265. %%* "paragraph"? Perhaps that should
  1266. %%* inhibit a paragraph break.)
  1267. %%*
  1268. //.show.last 0 get .hyphen eq
  1269. { () }
  1270. { ( ) }
  1271. ifelse % x y string width char
  1272. }
  1273. ifelse
  1274. //print
  1275. //.show.y 3 index .iput % x y string width
  1276. //.show.x 4 index .iput % x y string width
  1277. //.show.indent 4 index .iput
  1278. }
  1279. { % x y string width dy
  1280. % If the word processor split a hyphenated word within
  1281. % the same line, put out the hyphen now.
  1282. pop
  1283. //.show.last 0 get .hyphen eq { (-) //print } if
  1284. }
  1285. ifelse
  1286. %%*
  1287. %%* If have moved more than 1 point to
  1288. %%* the right, interpret it as a
  1289. %%* space? This need to be looked at
  1290. %%* more closely.
  1291. %%*
  1292. 3 index % x y string width x
  1293. //.show.x .iget 10 add gt % x y string width bool
  1294. { ( ) //print }
  1295. if
  1296. % x y string width
  1297. 4 1 roll % width x y string
  1298. .show.write pop % width x
  1299. add //.show.x exch .iput % <empty>
  1300. }
  1301. { (S ) //print .show==4 }
  1302. ifelse
  1303. } odef
  1304. /.showstring
  1305. { dup () eq { pop } { .showstring1 } ifelse
  1306. } bind def
  1307. % Redefine all the string display operators.
  1308. /show {
  1309. .showfont
  1310. .showcolor
  1311. .showstring
  1312. } codef
  1313. % We define all the other operators in terms of .show1.
  1314. /.show1.string ( ) def
  1315. /.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
  1316. /ashow
  1317. { .showfont .showcolor
  1318. { .show1 2 copy rmoveto } forall
  1319. pop pop
  1320. } codef
  1321. /awidthshow
  1322. { .showfont .showcolor
  1323. { dup .show1 4 index eq { 4 index 4 index rmoveto } if
  1324. 2 copy rmoveto
  1325. }
  1326. forall
  1327. pop pop pop pop pop
  1328. } codef
  1329. /widthshow
  1330. { .showfont .showcolor
  1331. //.show1.string 0 4 -1 roll put
  1332. { //.show1.string search not { exit } if
  1333. .showstring .showstring
  1334. 2 index 2 index rmoveto
  1335. } loop
  1336. .showstring pop pop
  1337. } codef
  1338. /kshow
  1339. { .showfont .showcolor
  1340. %**************** Should construct a closure, in case the procedure
  1341. %**************** affects the o-stack.
  1342. { .show1 dup exec } forall pop
  1343. } codef
  1344. % We don't really do the right thing with the Level 2 show operators,
  1345. % but we do something semi-reasonable.
  1346. /xshow { pop show } codef
  1347. /yshow { pop show } codef
  1348. /xyshow { pop show } codef
  1349. /glyphshow
  1350. { currentfont /Encoding .knownget not { {} } if
  1351. 0 1 2 index length 1 sub
  1352. { % Stack: glyph encoding index
  1353. 2 copy get 3 index eq { exch pop exch pop null exit } if
  1354. pop
  1355. }
  1356. for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
  1357. } codef
  1358. end
  1359. % Bind the operators we just defined, and all the others if we didn't
  1360. % do it before. Also reenable 'bind' for future files.
  1361. .bindoperators
  1362. NOBIND currentdict systemdict ne and
  1363. { systemdict begin .bindoperators end }
  1364. if
  1365. NOBIND
  1366. { /bind /.bind load def }
  1367. if
  1368. % Make systemdict read-only if it wasn't already.
  1369. systemdict wcheck { systemdict readonly pop } if
  1370. % Restore the current local/global VM mode.
  1371. exec