PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/texlive-2007/texk/xdv2pdf/xdv2pdf.cpp

#
C++ | 2349 lines | 2149 code | 138 blank | 62 comment | 175 complexity | 080f1174f88565ab7b5212ff2e33fbdf MD5 | raw file
Possible License(s): AGPL-1.0, BSD-3-Clause, LGPL-3.0, GPL-2.0, CPL-1.0, LGPL-2.1, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /****************************************************************************\
  2. Part of the XeTeX typesetting system
  3. copyright (c) 1994-2005 by SIL International
  4. written by Jonathan Kew
  5. This software is distributed under the terms of the Common Public License,
  6. version 1.0.
  7. For details, see <http://www.opensource.org/licenses/cpl1.0.php> or the file
  8. cpl1.0.txt included with the software.
  9. \****************************************************************************/
  10. /*
  11. xdv2pdf
  12. Convert xdv file from XeTeX to PDF format for viewing/printing
  13. usage: xdv2pdf [-d debug] [-m mag] [-p papersize] [-v] xdvfile [-o pdffile]
  14. -m override magnification from xdv file
  15. -v show progress messages (page counters)
  16. -d set kpathsea_debug values
  17. -p papersize [default: from Mac OS X printing system]
  18. known papersize values:
  19. a0-a10
  20. b0-b10
  21. c0-c10
  22. jb0-jb10
  23. letter
  24. legal
  25. ledger
  26. tabloid
  27. can append ":landscape"
  28. or use "x,y" where x and y are dimensions in "big points" or with units
  29. output file defaults to <xdvfile>.pdf
  30. also permissible to omit xdvfile but specify pdffile; then input is from stdin
  31. */
  32. #ifdef __POWERPC__
  33. #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_2
  34. #else
  35. #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
  36. #endif
  37. #include "config.h"
  38. #include <ApplicationServices/ApplicationServices.h>
  39. #include <QuickTime/QuickTime.h>
  40. #include <string>
  41. #include <vector>
  42. #include <list>
  43. #include <map>
  44. #include <sys/stat.h>
  45. #include "DVIops.h"
  46. #define XDV_ID 5 // current id_byte value for .xdv files from xetex
  47. #define XDV_FLAG_FONTTYPE_ATSUI 0x0001
  48. #define XDV_FLAG_FONTTYPE_ICU 0x0002
  49. #define XDV_FLAG_VERTICAL 0x0100
  50. #define XDV_FLAG_COLORED 0x0200
  51. #define XDV_FLAG_FEATURES 0x0400
  52. #define XDV_FLAG_VARIATIONS 0x0800
  53. #define pdfbox_crop 1
  54. #define pdfbox_media 2
  55. #define pdfbox_bleed 3
  56. #define pdfbox_trim 4
  57. #define pdfbox_art 5
  58. #define DEFINE_GLOBALS 1
  59. #include "xdv2pdf_globals.h"
  60. paperSizeRec gPaperSizes[] =
  61. {
  62. { "a0", 2383.937008, 3370.393701 },
  63. { "a1", 1683.779528, 2383.937008 },
  64. { "a2", 1190.551181, 1683.779528 },
  65. { "a3", 841.8897638, 1190.551181 },
  66. { "a4", 595.2755906, 841.8897638 },
  67. { "a5", 419.5275591, 595.2755906 },
  68. { "a6", 297.6377953, 419.5275591 },
  69. { "a7", 209.7637795, 297.6377953 },
  70. { "a8", 147.4015748, 209.7637795 },
  71. { "a9", 104.8818898, 147.4015748 },
  72. { "a10", 73.7007874, 104.8818898 },
  73. { "b0", 2834.645669, 4008.188976 },
  74. { "b1", 2004.094488, 2834.645669 },
  75. { "b2", 1417.322835, 2004.094488 },
  76. { "b3", 1000.629921, 1417.322835 },
  77. { "b4", 708.6614173, 1000.629921 },
  78. { "b5", 498.8976378, 708.6614173 },
  79. { "b6", 354.3307087, 498.8976378 },
  80. { "b7", 249.4488189, 354.3307087 },
  81. { "b8", 175.7480315, 249.4488189 },
  82. { "b9", 124.7244094, 175.7480315 },
  83. { "b10", 87.87401575, 124.7244094 },
  84. { "c0", 2599.370079, 3676.535433 },
  85. { "c1", 1836.850394, 2599.370079 },
  86. { "c2", 1298.267717, 1836.850394 },
  87. { "c3", 918.4251969, 1298.267717 },
  88. { "c4", 649.1338583, 918.4251969 },
  89. { "c5", 459.2125984, 649.1338583 },
  90. { "c6", 323.1496063, 459.2125984 },
  91. { "c7", 229.6062992, 323.1496063 },
  92. { "c8", 161.5748031, 229.6062992 },
  93. { "c9", 113.3858268, 161.5748031 },
  94. { "c10", 79.37007874, 113.3858268 },
  95. { "jb0", 2919.685039, 4127.244094 },
  96. { "jb1", 2063.622047, 2919.685039 },
  97. { "jb2", 1459.84252, 2063.622047 },
  98. { "jb3", 1031.811024, 1459.84252 },
  99. { "jb4", 728.503937, 1031.811024 },
  100. { "jb5", 515.9055118, 728.503937 },
  101. { "jb6", 362.8346457, 515.9055118 },
  102. { "jb7", 257.9527559, 362.8346457 },
  103. { "jb8", 181.4173228, 257.9527559 },
  104. { "jb9", 127.5590551, 181.4173228 },
  105. { "jb10", 90.70866142, 127.5590551 },
  106. { "letter", 612.0, 792.0 },
  107. { "legal", 612.0, 1008.0 },
  108. { "tabloid", 792.0, 1224.0 },
  109. { "ledger", 1224.0, 792.0 },
  110. { 0, 0, 0 }
  111. };
  112. static CGAffineTransform horizontalMatrix = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
  113. static CGAffineTransform verticalMatrix = { 0.0, 1.0, -1.0, 0.0, 0.0, 0.0 };
  114. struct nativeFont {
  115. nativeFont()
  116. : cgFont(0)
  117. , atsFont(0)
  118. , atsuStyleH(0)
  119. , atsuStyleV(0)
  120. , size(Long2Fix(10))
  121. , isColored(false)
  122. , isVertical(false)
  123. {
  124. }
  125. CGFontRef cgFont;
  126. ATSFontRef atsFont;
  127. ATSUStyle atsuStyleH; // only present if isVertical is true
  128. ATSUStyle atsuStyleV;
  129. Fixed size;
  130. CGColorRef color;
  131. bool isColored;
  132. bool isVertical;
  133. };
  134. static std::map<UInt32,nativeFont> sNativeFonts;
  135. static UInt32 sMag = 0;
  136. static bool sVerbose = false;
  137. static std::map<ATSFontRef,CGFontRef> sCGFonts;
  138. static CGFontRef
  139. getCGFontForATSFont(ATSFontRef fontRef)
  140. {
  141. std::map<ATSFontRef,CGFontRef>::const_iterator i = sCGFonts.find(fontRef);
  142. if (i != sCGFonts.end()) {
  143. return i->second;
  144. }
  145. CGFontRef newFont;
  146. if (fontRef == 0) {
  147. ATSFontRef tmpRef = ATSFontFindFromPostScriptName(CFSTR("Helvetica"), kATSOptionFlagsDefault);
  148. newFont = CGFontCreateWithPlatformFont(&tmpRef);
  149. }
  150. else
  151. newFont = CGFontCreateWithPlatformFont(&fontRef);
  152. sCGFonts[fontRef] = newFont;
  153. return newFont;
  154. }
  155. inline UInt32
  156. SWAP(UInt32 v)
  157. {
  158. #ifdef WORDS_BIGENDIAN
  159. return v;
  160. #else
  161. return (v << 24)
  162. + ((v << 8) & 0x00FF0000)
  163. + ((v >> 8) & 0x0000FF00)
  164. + (v >> 24);
  165. #endif
  166. }
  167. inline SInt32
  168. SWAP(SInt32 v)
  169. {
  170. #ifdef WORDS_BIGENDIAN
  171. return v;
  172. #else
  173. return (v << 24)
  174. + ((v << 8) & 0x00FF0000)
  175. + ((v >> 8) & 0x0000FF00)
  176. + ((v >> 24) & 0x000000FF);
  177. #endif
  178. }
  179. inline UInt16
  180. SWAP(UInt16 v)
  181. {
  182. #ifdef WORDS_BIGENDIAN
  183. return v;
  184. #else
  185. return (v << 8) + (v >> 8);
  186. #endif
  187. }
  188. inline SInt16
  189. SWAP(SInt16 v)
  190. {
  191. #ifdef WORDS_BIGENDIAN
  192. return v;
  193. #else
  194. return (v << 8) + ((v >> 8) & 0xFF);
  195. #endif
  196. }
  197. /* precaution, just in case we apply these to byte-sized values! */
  198. inline UInt8
  199. SWAP(UInt8 v)
  200. {
  201. return v;
  202. }
  203. inline SInt8
  204. SWAP(SInt8 v)
  205. {
  206. return v;
  207. }
  208. void
  209. initAnnotBox()
  210. {
  211. gAnnotBox.llx = gPageWd;
  212. gAnnotBox.lly = 0;
  213. gAnnotBox.urx = 0;
  214. gAnnotBox.ury = gPageHt;
  215. }
  216. void
  217. flushAnnotBox()
  218. {
  219. char buf[200];
  220. sprintf(buf, "ABOX [%f %f %f %f]",
  221. kDvi2Scr * gAnnotBox.llx + 72.0,
  222. kDvi2Scr * (gPageHt - gAnnotBox.lly) - 72.0,
  223. kDvi2Scr * gAnnotBox.urx + 72.0,
  224. kDvi2Scr * (gPageHt - gAnnotBox.ury) - 72.0);
  225. doPDFspecial(buf);
  226. initAnnotBox();
  227. }
  228. static void
  229. mergeBox(const box& b)
  230. {
  231. if (b.llx < gAnnotBox.llx)
  232. gAnnotBox.llx = b.llx;
  233. if (b.lly > gAnnotBox.lly)
  234. gAnnotBox.lly = b.lly; // NB positive is downwards!
  235. if (b.urx > gAnnotBox.urx)
  236. gAnnotBox.urx = b.urx;
  237. if (b.ury < gAnnotBox.ury)
  238. gAnnotBox.ury = b.ury;
  239. }
  240. long
  241. readSigned(FILE* f, int k)
  242. {
  243. long s = (long)(signed char)getc(f);
  244. while (--k > 0) {
  245. s <<= 8;
  246. s += (getc(f) & 0xff);
  247. }
  248. return s;
  249. }
  250. unsigned long
  251. readUnsigned(FILE* f, int k)
  252. {
  253. unsigned long u = getc(f);
  254. while (--k > 0) {
  255. u <<= 8;
  256. u += (getc(f) & 0xff);
  257. }
  258. return u;
  259. }
  260. void
  261. setColor(CGColorRef color, bool force = false)
  262. {
  263. if (force || !gCurrentColor || !CGColorEqualToColor(color, gCurrentColor))
  264. CGContextSetFillColorWithColor(gCtx, color);
  265. gCurrentColor = color;
  266. }
  267. inline double
  268. radians(double degrees)
  269. {
  270. return degrees / 180.0 * M_PI;
  271. }
  272. void
  273. ensurePageStarted()
  274. {
  275. if (gPageStarted)
  276. return;
  277. CGContextSaveGState(gCtx);
  278. CGContextBeginPage(gCtx, &gMediaBox);
  279. static CGAffineTransform sInitTextMatrix;
  280. if (gPageIndex == 1) {
  281. sInitTextMatrix = CGContextGetTextMatrix(gCtx);
  282. }
  283. else
  284. CGContextSetTextMatrix(gCtx, sInitTextMatrix);
  285. gCurrentColor = NULL; /* ensure color will get set by first drawing op */
  286. CGContextTranslateCTM(gCtx, 72.0, -72.0);
  287. gPageWd = kScr2Dvi * gMediaBox.size.width;
  288. gPageHt = kScr2Dvi * gMediaBox.size.height;
  289. cur_cgFont = kUndefinedFont;
  290. gPageStarted = true;
  291. paintBackground();
  292. }
  293. void
  294. paintBackground()
  295. {
  296. if (gBackground != NULL) {
  297. if (!gPageStarted)
  298. ensurePageStarted(); /* this will call paintBackground() again */
  299. else {
  300. CGContextSaveGState(gCtx);
  301. CGContextSetFillColorWithColor(gCtx, gBackground);
  302. CGContextTranslateCTM(gCtx, -72.0, 72.0);
  303. CGContextFillRect(gCtx, gMediaBox);
  304. CGContextRestoreGState(gCtx);
  305. }
  306. }
  307. }
  308. #define MAX_BUFFERED_GLYPHS 1024
  309. int gGlyphCount = 0;
  310. CGGlyph gGlyphs[MAX_BUFFERED_GLYPHS];
  311. CGSize gAdvances[MAX_BUFFERED_GLYPHS+1];
  312. CGPoint gStartLoc;
  313. CGPoint gPrevLoc;
  314. static void
  315. myShowGlyphsWithAdvances(CGContextRef c, const CGGlyph* glyphs, const CGSize* advances, int count)
  316. {
  317. CGPoint loc = CGContextGetTextPosition(c);
  318. while (count > 0) {
  319. CGContextShowGlyphsAtPoint(c, loc.x, loc.y, glyphs, 1);
  320. loc.x += advances->width;
  321. loc.y += advances->height;
  322. ++advances;
  323. ++glyphs;
  324. --count;
  325. }
  326. }
  327. void
  328. flushGlyphs()
  329. {
  330. if (gGlyphCount > 0) {
  331. CGContextSetTextPosition(gCtx, gStartLoc.x, gStartLoc.y);
  332. gAdvances[gGlyphCount].width = 0;
  333. gAdvances[gGlyphCount].height = 0;
  334. if (sNativeFonts[cur_cgFont].isColored)
  335. setColor(sNativeFonts[cur_cgFont].color);
  336. else
  337. setColor(gTextColor);
  338. if (&CGContextShowGlyphsWithAdvances != NULL)
  339. CGContextShowGlyphsWithAdvances(gCtx, gGlyphs, gAdvances, gGlyphCount);
  340. else
  341. myShowGlyphsWithAdvances(gCtx, gGlyphs, gAdvances, gGlyphCount);
  342. gGlyphCount = 0;
  343. }
  344. }
  345. void
  346. bufferGlyph(CGGlyph g)
  347. {
  348. ensurePageStarted();
  349. CGPoint curLoc;
  350. curLoc.x = kDvi2Scr * dvi.h;
  351. curLoc.y = kDvi2Scr * (gPageHt - dvi.v);
  352. if (gGlyphCount == 0)
  353. gStartLoc = curLoc;
  354. else {
  355. gAdvances[gGlyphCount-1].width = curLoc.x - gPrevLoc.x;
  356. gAdvances[gGlyphCount-1].height = curLoc.y - gPrevLoc.y;
  357. }
  358. gPrevLoc = curLoc;
  359. gGlyphs[gGlyphCount] = g;
  360. if (++gGlyphCount == MAX_BUFFERED_GLYPHS)
  361. flushGlyphs();
  362. }
  363. void
  364. setChar(UInt32 c, bool adv)
  365. {
  366. OSStatus status;
  367. ensurePageStarted();
  368. if (f != cur_cgFont) {
  369. flushGlyphs();
  370. CGContextSetFont(gCtx, gTeXFonts[f].cgFont);
  371. CGContextSetFontSize(gCtx, Fix2X(gTeXFonts[f].size) * gMagScale);
  372. CGContextSetTextMatrix(gCtx, horizontalMatrix);
  373. cur_cgFont = f;
  374. }
  375. CGGlyph g;
  376. if (gTeXFonts[f].charMap != NULL) {
  377. if (c < gTeXFonts[f].charMap->size())
  378. g = (*gTeXFonts[f].charMap)[c];
  379. else
  380. g = c;
  381. }
  382. else
  383. // default: glyph ID = char + 1, works for the majority of the CM PS fonts
  384. g = c + 1;
  385. bufferGlyph(g);
  386. if (gTrackingBoxes) {
  387. if (gTeXFonts[f].hasMetrics) {
  388. box b = {
  389. dvi.h,
  390. dvi.v + gTeXFonts[f].depths[c],
  391. dvi.h + gTeXFonts[f].widths[c],
  392. dvi.v - gTeXFonts[f].heights[c] };
  393. mergeBox(b);
  394. }
  395. }
  396. if (adv && gTeXFonts[f].hasMetrics)
  397. dvi.h += gTeXFonts[f].widths[c];
  398. }
  399. static FixedPoint
  400. getGlyphVOrg(const nativeFont& f, UInt16 gid)
  401. {
  402. FixedPoint vorg;
  403. ATSGlyphIdealMetrics metrics;
  404. OSStatus status = ATSUGlyphGetIdealMetrics(f.atsuStyleV, 1, &gid, 0, &metrics);
  405. /*
  406. fprintf(stderr, "\nmetrics(V) for glyph %d: adv = (%.3f, %.3f) sb = (%.3f, %.3f) os = (%.3f, %.3f)\n", gid,
  407. metrics.advance.x, metrics.advance.y, metrics.sideBearing.x, metrics.sideBearing.y,
  408. metrics.otherSideBearing.x, metrics.otherSideBearing.y);
  409. */
  410. vorg.y = X2Fix(-metrics.advance.y/* - metrics.otherSideBearing.y*/);
  411. status = ATSUGlyphGetIdealMetrics(f.atsuStyleH, 1, &gid, 0, &metrics);
  412. /*
  413. fprintf(stderr, "metrics(H) for glyph %d: adv = (%.3f, %.3f) sb = (%.3f, %.3f) os = (%.3f, %.3f)\n", gid,
  414. metrics.advance.x, metrics.advance.y, metrics.sideBearing.x, metrics.sideBearing.y,
  415. metrics.otherSideBearing.x, metrics.otherSideBearing.y);
  416. */
  417. vorg.x = X2Fix(metrics.advance.x / 2);
  418. return vorg;
  419. }
  420. static void
  421. doGlyphArray(FILE* xdv, bool yLocs)
  422. {
  423. static int maxGlyphs = 0;
  424. static FixedPoint* locations = 0;
  425. static CGSize* advances = 0;
  426. static UInt16* glyphs = 0;
  427. flushGlyphs();
  428. Fixed wid = readUnsigned(xdv, 4);
  429. int glyphCount = readUnsigned(xdv, 2);
  430. if (glyphCount >= maxGlyphs) {
  431. maxGlyphs = glyphCount + 100;
  432. if (glyphs != 0)
  433. delete[] glyphs;
  434. glyphs = new UInt16[maxGlyphs];
  435. if (locations != 0)
  436. delete[] locations;
  437. locations = new FixedPoint[maxGlyphs];
  438. if (advances != 0)
  439. delete[] advances;
  440. advances = new CGSize[maxGlyphs];
  441. }
  442. for (int i = 0; i < glyphCount; ++i) {
  443. locations[i].x = readSigned(xdv, 4);
  444. locations[i].y = yLocs ? readSigned(xdv, 4) : 0;
  445. }
  446. for (int i = 0; i < glyphCount; ++i)
  447. glyphs[i] = readUnsigned(xdv, 2);
  448. if (f != cur_cgFont) {
  449. CGContextSetFont(gCtx, sNativeFonts[f].cgFont);
  450. CGContextSetFontSize(gCtx, Fix2X(sNativeFonts[f].size));
  451. CGContextSetTextMatrix(gCtx, sNativeFonts[f].isVertical
  452. ? verticalMatrix : horizontalMatrix);
  453. cur_cgFont = f;
  454. }
  455. if (sNativeFonts[f].isColored)
  456. setColor(sNativeFonts[f].color);
  457. else
  458. setColor(gTextColor);
  459. if (sNativeFonts[f].isVertical) {
  460. for (int i = 0; i < glyphCount; ++i) {
  461. // need to adjust position to right by VOrg.y and down by VOrg.x
  462. FixedPoint vorg = getGlyphVOrg(sNativeFonts[f], glyphs[i]);
  463. locations[i].x += vorg.y;
  464. locations[i].y += vorg.x;
  465. }
  466. }
  467. CGContextSetTextPosition(gCtx, kDvi2Scr * dvi.h + Fix2X(locations[0].x) * 72 / 72.27,
  468. kDvi2Scr * (gPageHt - dvi.v) - Fix2X(locations[0].y) * 72 / 72.27);
  469. for (int i = 0; i < glyphCount - 1; ++i) {
  470. advances[i].width = gMagScale * Fix2X(locations[i+1].x - locations[i].x) * 72 / 72.27;
  471. advances[i].height = gMagScale * Fix2X(locations[i].y - locations[i+1].y) * 72 / 72.27;
  472. }
  473. advances[glyphCount-1].width = 0.0;
  474. advances[glyphCount-1].height = 0.0;
  475. if (&CGContextShowGlyphsWithAdvances != NULL)
  476. CGContextShowGlyphsWithAdvances(gCtx, glyphs, advances, glyphCount);
  477. else
  478. myShowGlyphsWithAdvances(gCtx, glyphs, advances, glyphCount);
  479. if (gTrackingBoxes) {
  480. box b = {
  481. dvi.h,
  482. dvi.v + (sNativeFonts[f].size / 3),
  483. dvi.h + wid,
  484. dvi.v - (2 * sNativeFonts[f].size / 3) };
  485. mergeBox(b);
  486. }
  487. dvi.h += wid;
  488. }
  489. /* code lifted almost verbatim from Apple sample "QTtoCG" */
  490. typedef struct {
  491. size_t width;
  492. size_t height;
  493. size_t bitsPerComponent;
  494. size_t bitsPerPixel;
  495. size_t bytesPerRow;
  496. size_t size;
  497. CGImageAlphaInfo ai;
  498. CGColorSpaceRef cs;
  499. unsigned char *data;
  500. CMProfileRef prof;
  501. } BitmapInfo;
  502. void readBitmapInfo(GraphicsImportComponent gi, BitmapInfo *bi)
  503. {
  504. ComponentResult result;
  505. ImageDescriptionHandle imageDescH = NULL;
  506. ImageDescription *desc;
  507. Handle profile = NULL;
  508. result = GraphicsImportGetImageDescription(gi, &imageDescH);
  509. if( noErr != result || imageDescH == NULL ) {
  510. fprintf(stderr, "Error while retrieving image description");
  511. exit(1);
  512. }
  513. desc = *imageDescH;
  514. bi->width = desc->width;
  515. bi->height = desc->height;
  516. bi->bitsPerComponent = 8;
  517. bi->bitsPerPixel = 32;
  518. bi->bytesPerRow = (bi->bitsPerPixel * bi->width + 7)/8;
  519. bi->ai = (desc->depth == 32) ? kCGImageAlphaFirst : kCGImageAlphaNoneSkipFirst;
  520. bi->size = bi->bytesPerRow * bi->height;
  521. bi->data = (unsigned char*)malloc(bi->size);
  522. bi->cs = NULL;
  523. bi->prof = NULL;
  524. GraphicsImportGetColorSyncProfile(gi, &profile);
  525. if( NULL != profile ) {
  526. CMError err;
  527. CMProfileLocation profLoc;
  528. Boolean bValid, bPreferredCMMNotFound;
  529. profLoc.locType = cmHandleBasedProfile;
  530. profLoc.u.handleLoc.h = profile;
  531. err = CMOpenProfile(&bi->prof, &profLoc);
  532. if( err != noErr ) {
  533. fprintf(stderr, "Cannot open profile");
  534. exit(1);
  535. }
  536. /* Not necessary to validate profile, but good for debugging */
  537. err = CMValidateProfile(bi->prof, &bValid, &bPreferredCMMNotFound);
  538. if( err != noErr ) {
  539. fprintf(stderr, "Cannot validate profile : Valid: %d, Preferred CMM not found : %d", bValid,
  540. bPreferredCMMNotFound);
  541. exit(1);
  542. }
  543. bi->cs = CGColorSpaceCreateWithPlatformColorSpace( bi->prof );
  544. if( bi->cs == NULL ) {
  545. fprintf(stderr, "Error creating cg colorspace from csync profile");
  546. exit(1);
  547. }
  548. DisposeHandle(profile);
  549. }
  550. if( imageDescH != NULL)
  551. DisposeHandle((Handle)imageDescH);
  552. }
  553. void getBitmapData(GraphicsImportComponent gi, BitmapInfo *bi)
  554. {
  555. GWorldPtr gWorld;
  556. QDErr err = noErr;
  557. Rect boundsRect = { 0, 0, bi->height, bi->width };
  558. ComponentResult result;
  559. if( bi->data == NULL ) {
  560. fprintf(stderr, "no bitmap buffer available");
  561. exit(1);
  562. }
  563. err = NewGWorldFromPtr( &gWorld, k32ARGBPixelFormat, &boundsRect, NULL, NULL, 0,
  564. (char*)bi->data, bi->bytesPerRow );
  565. if (noErr != err) {
  566. fprintf(stderr, "error creating new gworld - %d", err);
  567. exit(1);
  568. }
  569. if( (result = GraphicsImportSetGWorld(gi, gWorld, NULL)) != noErr ) {
  570. fprintf(stderr, "error while setting gworld");
  571. exit(1);
  572. }
  573. if( (result = GraphicsImportDraw(gi)) != noErr ) {
  574. fprintf(stderr, "error while drawing image through qt");
  575. exit(1);
  576. }
  577. DisposeGWorld(gWorld);
  578. }
  579. /* end of code from "QTtoCG" */
  580. struct imageRec {
  581. CGImageRef ref;
  582. CGRect bounds;
  583. };
  584. std::map<std::string,imageRec> sCGImages;
  585. std::map<std::string,CGPDFDocumentRef> sPdfDocs;
  586. static void
  587. doPicFile(FILE* xdv, int pdfBoxType) // t[4][6] p[2] l[2] a[l]
  588. {
  589. CGAffineTransform t;
  590. t.a = Fix2X(readSigned(xdv, 4));
  591. t.b = Fix2X(readSigned(xdv, 4));
  592. t.c = Fix2X(readSigned(xdv, 4));
  593. t.d = Fix2X(readSigned(xdv, 4));
  594. t.tx = Fix2X(readSigned(xdv, 4));
  595. t.ty = Fix2X(readSigned(xdv, 4));
  596. if (sMag != 1000)
  597. t = CGAffineTransformConcat(t, CGAffineTransformMakeScale(gMagScale, gMagScale));
  598. int p = readSigned(xdv, 2);
  599. int l = readUnsigned(xdv, 2);
  600. unsigned char* pathname = new unsigned char[l + 1];
  601. for (int i = 0; i < l; ++i)
  602. pathname[i] = readUnsigned(xdv, 1);
  603. pathname[l] = 0;
  604. CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, pathname, l, false);
  605. if (url != NULL) {
  606. std::string pathString((char*)pathname, l); // key for our map<>s of already-used images
  607. // is it a \pdffile instance?
  608. CGPDFDocumentRef document = NULL;
  609. CGImageRef image = NULL;
  610. CGRect bounds;
  611. CGPDFBox cgPdfBoxType;
  612. if (pdfBoxType > 0) {
  613. std::map<std::string,CGPDFDocumentRef>::const_iterator i = sPdfDocs.find(pathString);
  614. if (i != sPdfDocs.end())
  615. document = i->second;
  616. else {
  617. document = CGPDFDocumentCreateWithURL(url);
  618. sPdfDocs[pathString] = document;
  619. }
  620. if (document != NULL) {
  621. int nPages = CGPDFDocumentGetNumberOfPages(document);
  622. if (p < 0) p = nPages + 1 + p;
  623. if (p > nPages) p = nPages;
  624. if (p < 1) p = 1;
  625. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
  626. if (&CGPDFDocumentGetPage == NULL) {
  627. switch (pdfBoxType) {
  628. case pdfbox_crop:
  629. default:
  630. bounds = CGPDFDocumentGetCropBox(document, p);
  631. break;
  632. case pdfbox_media:
  633. bounds = CGPDFDocumentGetMediaBox(document, p);
  634. break;
  635. case pdfbox_bleed:
  636. bounds = CGPDFDocumentGetBleedBox(document, p);
  637. break;
  638. case pdfbox_trim:
  639. bounds = CGPDFDocumentGetTrimBox(document, p);
  640. break;
  641. case pdfbox_art:
  642. bounds = CGPDFDocumentGetArtBox(document, p);
  643. break;
  644. }
  645. }
  646. else
  647. #endif
  648. {
  649. CGPDFPageRef pageRef = CGPDFDocumentGetPage(document, p);
  650. switch (pdfBoxType) {
  651. case pdfbox_crop:
  652. default:
  653. cgPdfBoxType = kCGPDFCropBox;
  654. break;
  655. case pdfbox_media:
  656. cgPdfBoxType = kCGPDFMediaBox;
  657. break;
  658. case pdfbox_bleed:
  659. cgPdfBoxType = kCGPDFBleedBox;
  660. break;
  661. case pdfbox_trim:
  662. cgPdfBoxType = kCGPDFTrimBox;
  663. break;
  664. case pdfbox_art:
  665. cgPdfBoxType = kCGPDFArtBox;
  666. break;
  667. }
  668. bounds = CGPDFPageGetBoxRect(pageRef, cgPdfBoxType);
  669. }
  670. }
  671. }
  672. // otherwise use GraphicsImport
  673. else {
  674. std::map<std::string,imageRec>::const_iterator i = sCGImages.find(pathString);
  675. if (i != sCGImages.end()) {
  676. image = i->second.ref;
  677. bounds = i->second.bounds;
  678. }
  679. else {
  680. FSRef ref;
  681. if (CFURLGetFSRef(url, &ref)) {
  682. FSSpec spec;
  683. if (FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, &spec, NULL) == noErr) {
  684. ComponentInstance gi;
  685. OSErr result = GetGraphicsImporterForFile(&spec, &gi);
  686. if (result == noErr) {
  687. BitmapInfo bi;
  688. readBitmapInfo(gi, &bi);
  689. getBitmapData(gi, &bi);
  690. if (bi.cs == NULL)
  691. bi.cs = CGColorSpaceCreateDeviceRGB();
  692. CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bi.data, bi.size, NULL);
  693. image = CGImageCreate(bi.width, bi.height, bi.bitsPerComponent, bi.bitsPerPixel,
  694. bi.bytesPerRow, bi.cs, bi.ai, provider, NULL, 0, kCGRenderingIntentDefault);
  695. CGColorSpaceRelease(bi.cs);
  696. ImageDescriptionHandle desc = NULL;
  697. result = GraphicsImportGetImageDescription(gi, &desc);
  698. bounds.origin.x = 0;
  699. bounds.origin.y = 0;
  700. bounds.size.width = (*desc)->width * 72.0 / Fix2X((*desc)->hRes);
  701. bounds.size.height = (*desc)->height * 72.0 / Fix2X((*desc)->vRes);
  702. DisposeHandle((Handle)desc);
  703. result = CloseComponent(gi);
  704. }
  705. imageRec ir = { image, bounds };
  706. sCGImages[pathString] = ir;
  707. }
  708. }
  709. }
  710. }
  711. CGContextSaveGState(gCtx);
  712. CGContextTranslateCTM(gCtx, kDvi2Scr * dvi.h, kDvi2Scr * (gPageHt - dvi.v));
  713. CGContextConcatCTM(gCtx, t);
  714. if (document != NULL) {
  715. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
  716. if (&CGPDFDocumentGetPage == NULL) {
  717. CGRect mediaBox = CGPDFDocumentGetMediaBox(document, p);
  718. CGRect cropBox = CGPDFDocumentGetCropBox(document, p);
  719. CGContextClipToRect(gCtx, cropBox);
  720. CGContextDrawPDFDocument(gCtx, mediaBox, document, p);
  721. }
  722. else
  723. #endif
  724. {
  725. CGPDFPageRef pageRef = CGPDFDocumentGetPage(document, p);
  726. CGAffineTransform xf = CGPDFPageGetDrawingTransform(pageRef, cgPdfBoxType, bounds, 0, true);
  727. CGContextConcatCTM(gCtx, xf);
  728. CGRect cropBox = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
  729. CGContextClipToRect(gCtx, cropBox);
  730. CGContextDrawPDFPage(gCtx, pageRef);
  731. }
  732. }
  733. else if (image != NULL)
  734. CGContextDrawImage(gCtx, bounds, image);
  735. if (gTrackingBoxes) {
  736. // figure out the corners of the transformed and positioned image,
  737. // and remember the lower left and upper right of the result
  738. CGPoint p[4];
  739. p[0].x = bounds.origin.x;
  740. p[0].y = bounds.origin.y;
  741. p[1].x = bounds.origin.x;
  742. p[1].y = bounds.origin.y + bounds.size.height;
  743. p[2].x = bounds.origin.x + bounds.size.width;
  744. p[2].y = bounds.origin.y + bounds.size.height;
  745. p[3].x = bounds.origin.x + bounds.size.width;
  746. p[3].y = bounds.origin.y;
  747. CGPoint ll = { MAXFLOAT, MAXFLOAT };
  748. CGPoint ur = { -MAXFLOAT, -MAXFLOAT };
  749. t = CGContextGetCTM(gCtx);
  750. // now t is the CTM, including positioning as well as transformations of the image
  751. for (int i = 0; i < 4; ++i) {
  752. p[i] = CGPointApplyAffineTransform(p[i], t);
  753. if (p[i].x < ll.x)
  754. ll.x = p[i].x;
  755. if (p[i].y < ll.y)
  756. ll.y = p[i].y;
  757. if (p[i].x > ur.x)
  758. ur.x = p[i].x;
  759. if (p[i].y > ur.y)
  760. ur.y = p[i].y;
  761. }
  762. // convert back to dvi space and add to the annotation area
  763. box b = {
  764. (ll.x - 72.0) * kScr2Dvi,
  765. gPageHt - (ur.y + 72.0) * kScr2Dvi,
  766. (ur.x - 72.0) * kScr2Dvi,
  767. gPageHt - (ll.y + 72.0) * kScr2Dvi
  768. };
  769. mergeBox(b);
  770. }
  771. CGContextRestoreGState(gCtx);
  772. CFRelease(url);
  773. }
  774. }
  775. /* declarations of KPATHSEARCH functions we use for finding TFMs and OTFs */
  776. extern "C" {
  777. UInt8* kpse_find_file(const UInt8* name, int type, int must_exist);
  778. UInt8* uppercasify(const UInt8* s);
  779. };
  780. extern unsigned kpathsea_debug;
  781. #include "xdv_kpse_formats.h"
  782. static void
  783. loadMetrics(struct texFont& font, UInt8* name, Fixed d, Fixed s)
  784. {
  785. UInt8* pathname = kpse_find_file(name, xdv_kpse_tfm_format, true);
  786. if (pathname) {
  787. FILE* tfmFile = fopen((char*)pathname, "rb");
  788. if (tfmFile != 0) {
  789. enum { lf = 0, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np };
  790. SInt16 directory[12];
  791. for (int i = 0; i < 12; ++i)
  792. directory[i] = readSigned(tfmFile, 2);
  793. fseek(tfmFile, directory[lh] * 4, SEEK_CUR);
  794. int nChars = directory[ec] - directory[bc] + 1;
  795. double_t factor = Fix2X(d) / 16.0;
  796. if (s != d)
  797. factor = factor * Fix2X(s) / Fix2X(d);
  798. if (nChars > 0) {
  799. struct s_charinfo {
  800. UInt8 widthIndex;
  801. UInt8 heightDepth;
  802. UInt8 italicIndex;
  803. UInt8 remainder;
  804. };
  805. s_charinfo* charInfo = new s_charinfo[nChars];
  806. for (int i = 0; i < nChars; ++i) {
  807. charInfo[i].widthIndex = readUnsigned(tfmFile, 1);
  808. charInfo[i].heightDepth = readUnsigned(tfmFile, 1);
  809. charInfo[i].italicIndex = readUnsigned(tfmFile, 1);
  810. charInfo[i].remainder = readUnsigned(tfmFile, 1);
  811. }
  812. Fixed* widths = new Fixed[directory[nw]];
  813. for (int i = 0; i < directory[nw]; ++i)
  814. widths[i] = readSigned(tfmFile, 4);
  815. Fixed* heights = new Fixed[directory[nh]];
  816. for (int i = 0; i < directory[nh]; ++i)
  817. heights[i] = readSigned(tfmFile, 4);
  818. Fixed* depths = new Fixed[directory[nd]];
  819. for (int i = 0; i < directory[nd]; ++i)
  820. depths[i] = readSigned(tfmFile, 4);
  821. font.widths.reserve(directory[ec] + 1);
  822. font.heights.reserve(directory[ec] + 1);
  823. font.depths.reserve(directory[ec] + 1);
  824. font.charMap = new std::vector<UInt16>;
  825. font.charMap->reserve(directory[ec] + 1);
  826. for (int i = 0; i < directory[bc]; ++i) {
  827. font.widths.push_back(0);
  828. font.heights.push_back(0);
  829. font.depths.push_back(0);
  830. font.charMap->push_back(0);
  831. }
  832. int g = 0;
  833. for (int i = 0; i < nChars; ++i) {
  834. if (charInfo[i].widthIndex == 0) {
  835. font.widths.push_back(0);
  836. font.heights.push_back(0);
  837. font.depths.push_back(0);
  838. font.charMap->push_back(0);
  839. }
  840. else {
  841. double_t wid = Fix2X(widths[charInfo[i].widthIndex]) * factor;
  842. font.widths.push_back(X2Fix(wid));
  843. int heightIndex = (charInfo[i].heightDepth >> 4);
  844. double_t ht = Fix2X(heights[heightIndex]) * factor;
  845. font.heights.push_back(X2Fix(ht));
  846. int depthIndex = (charInfo[i].heightDepth & 0x0f);
  847. double_t dp = Fix2X(depths[depthIndex]) * factor;
  848. font.depths.push_back(X2Fix(dp));
  849. font.charMap->push_back(++g);
  850. }
  851. }
  852. delete[] widths;
  853. delete[] heights;
  854. delete[] depths;
  855. delete[] charInfo;
  856. }
  857. font.hasMetrics = true;
  858. fclose(tfmFile);
  859. }
  860. free(pathname);
  861. }
  862. }
  863. typedef std::vector<std::string> encoding;
  864. std::map<std::string,encoding> sEncodings;
  865. class fontMapRec {
  866. public:
  867. fontMapRec()
  868. : cgFont(0)
  869. , cmap(NULL)
  870. , loaded(false)
  871. { }
  872. std::string psName;
  873. std::string encName;
  874. std::string pfbName;
  875. CGFontRef cgFont;
  876. std::vector<UInt16>* cmap;
  877. bool loaded;
  878. };
  879. std::map<std::string,fontMapRec> psFontsMap;
  880. static void
  881. clearFontMap()
  882. {
  883. std::map<std::string,fontMapRec>::iterator i;
  884. for (i = psFontsMap.begin(); i != psFontsMap.end(); ++i) {
  885. if (i->second.cmap != NULL)
  886. delete i->second.cmap;
  887. }
  888. psFontsMap.clear();
  889. }
  890. void
  891. doPdfMapLine(const char* line, char mode)
  892. {
  893. if (*line == '%')
  894. return;
  895. while (*line == ' ' || *line == '\t')
  896. ++line;
  897. if (*line < ' ')
  898. return;
  899. if (mode == 0) {
  900. switch (*line) {
  901. case '+':
  902. case '-':
  903. case '=':
  904. mode = *line;
  905. ++line;
  906. while (*line == ' ' || *line == '\t')
  907. ++line;
  908. if (*line < ' ')
  909. return;
  910. break;
  911. default:
  912. clearFontMap();
  913. mode = '+';
  914. break;
  915. }
  916. }
  917. const char* b = line;
  918. const char* e = b;
  919. while (*e > ' ')
  920. ++e;
  921. std::string tfmName(b, e - b);
  922. if (mode == '-') {
  923. psFontsMap.erase(tfmName);
  924. return;
  925. // erase existing entry
  926. }
  927. if ((mode == '+') && (psFontsMap.find(tfmName) != psFontsMap.end()))
  928. return;
  929. // don't add if entry already exists
  930. while (*e && *e <= ' ')
  931. ++e;
  932. b = e;
  933. while (*e > ' ')
  934. ++e;
  935. if (e > b) {
  936. fontMapRec fr;
  937. fr.psName.assign(b, e - b);
  938. while (*e && *e <= ' ')
  939. ++e;
  940. if (*e == '"') { // skip quoted string; we don't do oblique, stretch, etc. (yet)
  941. ++e;
  942. while (*e && *e != '"')
  943. ++e;
  944. if (*e == '"')
  945. ++e;
  946. while (*e && *e <= ' ')
  947. ++e;
  948. }
  949. while (*e == '<') {
  950. ++e;
  951. b = e;
  952. while (*e > ' ')
  953. ++e;
  954. if (strncmp(e - 4, ".enc", 4) == 0) {
  955. fr.encName.assign(b, e - b);
  956. }
  957. else if (strncmp(e - 4, ".pfb", 4) == 0) {
  958. fr.pfbName.assign(b, e - b);
  959. }
  960. /*
  961. else if (strncmp(e - 4, ".pfa", 4) == 0) {
  962. fr.otfName.assign(b, e - b - 4);
  963. }
  964. */
  965. while (*e && *e <= ' ')
  966. ++e;
  967. }
  968. psFontsMap[tfmName] = fr;
  969. }
  970. }
  971. static bool sMapFileLoaded = false;
  972. void
  973. doPdfMapFile(const char* fileName)
  974. {
  975. char mode = 0;
  976. while (*fileName == ' ' || *fileName == '\t')
  977. ++fileName;
  978. if (*fileName < ' ')
  979. return;
  980. switch (*fileName) {
  981. case '+':
  982. case '-':
  983. case '=':
  984. mode = *fileName;
  985. ++fileName;
  986. break;
  987. default:
  988. clearFontMap();
  989. mode = '+';
  990. break;
  991. }
  992. while (*fileName == ' ' || *fileName == '\t')
  993. ++fileName;
  994. if (*fileName < ' ')
  995. return;
  996. bool loaded = false;
  997. UInt8* pathname = kpse_find_file((UInt8*)fileName, xdv_kpse_font_map_format, true);
  998. if (pathname) {
  999. FILE* f = fopen((char*)pathname, "r");
  1000. if (f != NULL) {
  1001. char line[1000];
  1002. while (!feof(f)) {
  1003. if (fgets(line, 999, f) == 0)
  1004. break;
  1005. doPdfMapLine(line, mode);
  1006. }
  1007. loaded = true;
  1008. fclose(f);
  1009. if (sVerbose)
  1010. fprintf(stderr, "\n{fontmap: %s} ", pathname);
  1011. }
  1012. free(pathname);
  1013. }
  1014. if (!loaded)
  1015. fprintf(stderr, "\n*** fontmap %s not found; texmf.cnf may be broken\n", fileName);
  1016. else
  1017. sMapFileLoaded = true;
  1018. }
  1019. // return a pointer to the encoding vector with the given name, loading it if necessary
  1020. // we don't really "parse" the .enc file
  1021. static const encoding*
  1022. getEncoding(const std::string& name)
  1023. {
  1024. std::map<std::string,encoding>::iterator i = sEncodings.find(name);
  1025. if (i == sEncodings.end()) {
  1026. encoding enc;
  1027. UInt8* pathname = kpse_find_file((UInt8*)(name.c_str()), xdv_kpse_enc_format, true);
  1028. if (pathname != NULL) {
  1029. FILE* f = fopen((char*)pathname, "r");
  1030. if (f != NULL) {
  1031. int c;
  1032. bool inVector = false;
  1033. std::string str;
  1034. while ((c = getc(f)) != EOF) {
  1035. got_ch:
  1036. if (c == '%') { // comment: skip rest of line
  1037. while ((c = getc(f)) != EOF && c != '\r' && c != '\n')
  1038. ;
  1039. goto got_ch;
  1040. }
  1041. if (c == '[') {
  1042. inVector = true;
  1043. }
  1044. else if (c == '/' || c <= ' ' || c == ']' || c == EOF) {
  1045. if (inVector && str.length() > 0)
  1046. enc.push_back(str);
  1047. str.clear();
  1048. }
  1049. else if (inVector && c != EOF)
  1050. str.append(1, (char)c);
  1051. }
  1052. if (sVerbose)
  1053. fprintf(stderr, "\n{encoding: %s} ", pathname);
  1054. fclose(f);
  1055. }
  1056. free(pathname);
  1057. }
  1058. sEncodings[name] = enc;
  1059. return &(sEncodings[name]);
  1060. }
  1061. return &(i->second);
  1062. }
  1063. static ATSFontRef
  1064. activateFromPath(const char* pathName)
  1065. {
  1066. if (sVerbose)
  1067. fprintf(stderr, "\n{activate %s", pathName);
  1068. ItemCount count = 0;
  1069. FSRef fontFileRef;
  1070. bzero(&fontFileRef, sizeof(fontFileRef));
  1071. OSStatus status = FSPathMakeRef((UInt8*)pathName, &fontFileRef, 0);
  1072. if (status == noErr) {
  1073. ++count;
  1074. FSSpec fontFileSpec;
  1075. bzero(&fontFileSpec, sizeof(fontFileSpec));
  1076. status = FSGetCatalogInfo(&fontFileRef, 0, 0, 0, &fontFileSpec, 0);
  1077. if (status == noErr) {
  1078. ++count;
  1079. ATSFontContainerRef containerRef = 0;
  1080. status = ATSFontActivateFromFileSpecification(&fontFileSpec, kATSFontContextLocal,
  1081. kATSFontFormatUnspecified, 0, kATSOptionFlagsDefault, &containerRef);
  1082. if (status == noErr) {
  1083. ++count;
  1084. ATSFontRef fontRef;
  1085. status = ATSFontFindFromContainer(containerRef, 0, 1, &fontRef, &count);
  1086. if (status == noErr && count == 1) {
  1087. if (sVerbose)
  1088. fprintf(stderr, "}");
  1089. return fontRef;
  1090. }
  1091. // failed, or container contained multiple fonts(!) -- confused
  1092. ATSFontDeactivate(containerRef, 0, kATSOptionFlagsDefault);
  1093. }
  1094. }
  1095. }
  1096. if (sVerbose)
  1097. fprintf(stderr, "... failed: status=%d, count=%d}", status, count);
  1098. return 0;
  1099. }
  1100. struct postTable {
  1101. Fixed format;
  1102. Fixed italicAngle;
  1103. SInt16 underlinePosition;
  1104. SInt16 underlineThickness;
  1105. UInt16 isFixedPitch;
  1106. UInt16 reserved;
  1107. UInt32 minMemType42;
  1108. UInt32 maxMemType42;
  1109. UInt32 minMemType1;
  1110. UInt32 maxMemType1;
  1111. };
  1112. #include "appleGlyphNames.c"
  1113. #define sfntCacheDir "/Library/Caches/Type1-sfnt-fonts/"
  1114. #define sfntWrapCommand "T1Wrap"
  1115. #define sfntWrapSuffix "-sfnt.otf"
  1116. static ATSFontRef
  1117. activatePFB(const char* pfbName)
  1118. {
  1119. static std::map<std::string,ATSFontRef> sActivatedFonts;
  1120. std::map<std::string,ATSFontRef>::iterator i = sActivatedFonts.find(pfbName);
  1121. if (i != sActivatedFonts.end())
  1122. return i->second;
  1123. ATSFontRef fontRef = 0;
  1124. OSStatus status = noErr;
  1125. static int firstTime = 1;
  1126. if (firstTime) {
  1127. firstTime = 0;
  1128. status = mkdir(sfntCacheDir, S_IRWXU | S_IRWXG | S_IRWXO);
  1129. if (status != 0) {
  1130. if (errno == EEXIST) {
  1131. // clean up possible residue from past failed conversions
  1132. system("/usr/bin/find " sfntCacheDir " -maxdepth 1 -empty -type f -delete");
  1133. status = 0;
  1134. }
  1135. else
  1136. fprintf(stderr, "*** failed to create sfnt cache directory %s (errno = %d), cannot activate .pfb fonts\n",
  1137. sfntCacheDir, errno);
  1138. }
  1139. }
  1140. char* sfntName = new char[strlen(sfntCacheDir) + strlen(pfbName) + strlen(sfntWrapSuffix) + 1];
  1141. strcpy(sfntName, sfntCacheDir);
  1142. strcat(sfntName, pfbName);
  1143. strcat(sfntName, sfntWrapSuffix);
  1144. FSRef ref;
  1145. status = FSPathMakeRef((const UInt8*)sfntName, &ref, NULL);
  1146. if (status == fnfErr) {
  1147. char* pathName = (char*)kpse_find_file((UInt8*)pfbName, xdv_kpse_pfb_format, true);
  1148. if (pathName != NULL) {
  1149. char* cmd = new char[strlen(sfntWrapCommand) + strlen(pathName) + strlen(sfntName) + 6];
  1150. strcpy(cmd, sfntWrapCommand " ");
  1151. strcat(cmd, pathName);
  1152. strcat(cmd, " > ");
  1153. strcat(cmd, sfntName);
  1154. status = system(cmd);
  1155. delete[] cmd;
  1156. free(pathName);
  1157. }
  1158. }
  1159. if (status == noErr)
  1160. fontRef = activateFromPath(sfntName);
  1161. delete[] sfntName;
  1162. if (fontRef == 0) {
  1163. // try removing extension (.pfb) and looking for an .otf font...
  1164. char* baseName = new char[strlen(pfbName) + 1];
  1165. strcpy(baseName, pfbName);
  1166. char* dot = strrchr(baseName, '.');
  1167. if (dot != NULL)
  1168. *dot = 0;
  1169. char* pathName = (char*)kpse_find_file((UInt8*)baseName, xdv_kpse_otf_format, true);
  1170. delete[] baseName;
  1171. if (pathName != NULL) {
  1172. fontRef = activateFromPath(pathName);
  1173. free(pathName);
  1174. }
  1175. }
  1176. if (fontRef == 0)
  1177. fprintf(stderr, "\n*** font activation failed (status=%d): %s\n", status, pfbName);
  1178. sActivatedFonts[pfbName] = fontRef;
  1179. return fontRef;
  1180. }
  1181. static std::vector<UInt16>*
  1182. readMacRomanCmap(ATSFontRef fontRef)
  1183. {
  1184. std::vector<UInt16>* cmap = NULL;
  1185. ByteCount size;
  1186. OSStatus status = ATSFontGetTable(fontRef, 'cmap', 0, 0, 0, &size);
  1187. if (status == noErr) {
  1188. UInt8* buffer = new UInt8[size];
  1189. ATSFontGetTable(fontRef, 'cmap', 0, size, buffer, &size);
  1190. struct cmapHeader {
  1191. UInt16 version;
  1192. UInt16 numSubtables;
  1193. };
  1194. struct subtableHeader {
  1195. UInt16 platform;
  1196. UInt16 encoding;
  1197. UInt32 offset;
  1198. };
  1199. struct format0 {
  1200. UInt16 format;
  1201. UInt16 length;
  1202. UInt16 language;
  1203. UInt8 glyphIndex[256];
  1204. };
  1205. struct format6 {
  1206. UInt16 format;
  1207. UInt16 length;
  1208. UInt16 language;
  1209. UInt16 firstCode;
  1210. UInt16 entryCount;
  1211. UInt16 glyphIndex[1];
  1212. };
  1213. struct cmapHeader* h = (struct cmapHeader*)buffer;
  1214. struct subtableHeader* sh = (struct subtableHeader*)(buffer + sizeof(struct cmapHeader));
  1215. int subtable = 0;
  1216. cmap = new std::vector<UInt16>;
  1217. cmap->reserve(256);
  1218. while (subtable < SWAP(h->numSubtables)) {
  1219. if ((SWAP(sh->platform) == 1) && (SWAP(sh->encoding) == 0)) {
  1220. struct format0* f0 = (struct format0*)(buffer + SWAP(sh->offset));
  1221. if (SWAP(f0->format) == 0) {
  1222. for (int ch = 0; ch < 256; ++ch) {
  1223. cmap->push_back(SWAP(f0->glyphIndex[ch]));
  1224. }
  1225. }
  1226. else if (SWAP(f0->format) == 6) {
  1227. struct format6* f6 = (struct format6*)f0;
  1228. for (int ch = 0; ch < 256; ++ch) {
  1229. if ((ch < SWAP(f6->firstCode)) || (ch >= SWAP(f6->firstCode) + SWAP(f6->entryCount)))
  1230. cmap->push_back(0);
  1231. else
  1232. cmap->push_back(SWAP(f6->glyphIndex[ch - SWAP(f6->firstCode)]));
  1233. }
  1234. }
  1235. else {
  1236. // unsupported cmap subtable format
  1237. fprintf(stderr, "\n*** unsupported 'cmap' subtable format (%d)\n", SWAP(f0->format));
  1238. }
  1239. break;
  1240. }
  1241. ++subtable;
  1242. ++sh;
  1243. }
  1244. delete[] buffer;
  1245. }
  1246. return cmap;
  1247. }
  1248. static const fontMapRec*
  1249. getFontRec(const std::string& name)
  1250. {
  1251. if (!sMapFileLoaded)
  1252. doPdfMapFile("psfonts.map");
  1253. std::map<std::string,fontMapRec>::iterator i = psFontsMap.find(name);
  1254. if (i == psFontsMap.end())
  1255. return NULL;
  1256. fontMapRec& fr = i->second;
  1257. if (fr.loaded)
  1258. return &fr;
  1259. ATSFontRef fontRef = 0;
  1260. // if a filename is known, try to find and activate it
  1261. if (fr.pfbName.length() > 0)
  1262. fontRef = activatePFB(fr.pfbName.c_str());
  1263. // if no downloadable file, see if it's installed in the OS
  1264. if (fontRef == 0)
  1265. fontRef = ATSFontFindFromPostScriptName(CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, fr.psName.c_str(),
  1266. CFStringGetSystemEncoding(), kCFAllocatorNull), kATSOptionFlagsDefault);
  1267. if (fontRef == 0)
  1268. fprintf(stderr, "\n*** font %s (%s: file '%s') not found\n", name.c_str(), fr.psName.c_str(), fr.pfbName.c_str());
  1269. if (fontRef != 0) {
  1270. // if re-encoding was called for, load the encoding vector and build a new cmap
  1271. if (fr.encName.length() > 0) {
  1272. const encoding* enc = getEncoding(fr.encName);
  1273. if (enc != 0) {
  1274. ByteCount size;
  1275. OSStatus status = ATSFontGetTable(fontRef, 'post', 0, 0, 0, &size);
  1276. if (status == noErr) {
  1277. UInt8* buffer = new UInt8[size];
  1278. ATSFontGetTable(fontRef, 'post', 0, size, buffer, &size);
  1279. postTable* p = (postTable*)&buffer[0];
  1280. std::map<std::string,UInt16> name2gid;
  1281. UInt16 g = 0;
  1282. switch (SWAP(p->format)) {
  1283. case 0x00010000:
  1284. {
  1285. char* cp;
  1286. while ((cp = appleGlyphNames[g]) != 0) {
  1287. name2gid[cp] = g;
  1288. ++g;
  1289. }
  1290. }
  1291. break;
  1292. case 0x00020000:
  1293. {
  1294. UInt16* n = (UInt16*)(p + 1);
  1295. UInt16 numGlyphs = SWAP(*n++);
  1296. UInt8* ps = (UInt8*)(n + numGlyphs);
  1297. std::vector<std::string> newNames;
  1298. while (ps < buffer + size) {
  1299. newNames.push_back(std::string((char*)ps + 1, *ps));
  1300. ps += *ps + 1;
  1301. }
  1302. for (g = 0; g < numGlyphs; ++g) {
  1303. if (SWAP(*n) < 258)
  1304. name2gid[appleGlyphNames[SWAP(*n)]] = g;
  1305. else
  1306. name2gid[newNames[SWAP(*n) - 258]] = g;
  1307. ++n;
  1308. }
  1309. }
  1310. break;
  1311. case 0x00028000:
  1312. fprintf(stderr, "\n*** format 2.5 'post' table not supported\n");
  1313. break;
  1314. case 0x00030000:
  1315. // TODO: see if it's a CFF OpenType font, and if so, get the glyph names from the CFF data
  1316. fprintf(stderr, "\n*** format 3 'post' table; cannot reencode font %s\n", name.c_str());
  1317. break;
  1318. case 0x00040000:
  1319. fprintf(stderr, "\n*** format 4 'post' table not supported\n");
  1320. break;
  1321. default:
  1322. fprintf(stderr, "\n*** unknown 'post' table format %08x\n");
  1323. break;
  1324. }
  1325. if (fr.cmap != NULL)
  1326. delete fr.cmap;
  1327. fr.cmap = new std::vector<UInt16>;
  1328. for (encoding::const_iterator i = enc->begin(); i != enc->end(); ++i) {
  1329. std::map<std::string,UInt16>::const_iterator g = name2gid.find(*i);
  1330. if (g == name2gid.end())
  1331. fr.cmap->push_back(0);
  1332. else
  1333. fr.cmap->push_back(g->second);
  1334. }
  1335. }
  1336. else {
  1337. fprintf(stderr, "\n*** no 'post' table found, unable to re-encode font %s\n", name.c_str());
  1338. }
  1339. }
  1340. }
  1341. else {
  1342. // read the MacOS/Roman cmap, if available
  1343. std::vector<UInt16>* cmap = readMacRomanCmap(fontRef);
  1344. if (fr.cmap != NULL)
  1345. delete fr.cmap;
  1346. fr.cmap = cmap;
  1347. }
  1348. }
  1349. if (fontRef == 0) {
  1350. fprintf(stderr, "\n*** font %s (%s) not found, will substitute Helvetica glyphs\n", name.c_str(), fr.pfbName.c_str());
  1351. fontRef = ATSFontFindFromPostScriptName(CFSTR("Helvetica"), kATSOptionFlagsDefault);
  1352. if (fr.cmap != NULL)
  1353. delete fr.cmap;
  1354. fr.cmap = readMacRomanCmap(fontRef);
  1355. }
  1356. fr.cgFont = getCGFontForATSFont(fontRef);
  1357. fr.loaded = true;
  1358. return &fr;
  1359. }
  1360. static void
  1361. doFontDef(FILE* xdv, int k)
  1362. {
  1363. OSStatus status;
  1364. UInt32 f = readUnsigned(xdv, k); // font number we're defining
  1365. UInt32 c = readUnsigned(xdv, 4); // TFM checksum
  1366. Fixed s = readUnsigned(xdv, 4); // at size
  1367. Fixed d = readUnsigned(xdv, 4); // design size
  1368. UInt16 alen = readUnsigned(xdv, 1); // area length
  1369. UInt16 nlen = readUnsigned(xdv, 1); // name length
  1370. UInt8* name = new UInt8[alen + nlen + 2];
  1371. if (alen > 0) {
  1372. fread(name, 1, alen, xdv);
  1373. name[alen] = '/';
  1374. fread(name + alen + 1, 1, nlen, xdv);
  1375. nlen += alen + 1;
  1376. }
  1377. else
  1378. fread(name, 1, nlen, xdv);
  1379. name[nlen] = 0;
  1380. texFont font;
  1381. loadMetrics(font, name, d, s);
  1382. if (alen > 0)
  1383. name = name + alen + 1; // point past the area to get the name by itself for the remaining operations
  1384. ATSFontRef fontRef;
  1385. // look for a map entry for this font name
  1386. std::string nameStr((char*)name);
  1387. const fontMapRec* fr = getFontRec(nameStr);
  1388. if (fr != NULL) {
  1389. font.cgFont = fr->cgFont;
  1390. if (fr->cmap->size() > 0) {
  1391. if (font.charMap != NULL)
  1392. delete font.charMap;
  1393. font.charMap = fr->cmap; // replacing map that was synthesized from the tfm coverage
  1394. }
  1395. }
  1396. else {
  1397. /* try to find the font without the benefit of psfonts.map...
  1398. first try the name as a pfb or otf filename
  1399. and then as the PS name of an installed font
  1400. */
  1401. // ****** FIXME ****** this needs re-working to read the 'cmap' properly
  1402. fontRef = ATSFontFindFromPostScriptName(CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, (char*)name,
  1403. CFStringGetSystemEncoding(), kCFAllocatorNull), kATSOptionFlagsDefault);
  1404. UInt8* ucname = 0;
  1405. if (fontRef == 0) {
  1406. ucname = uppercasify(name);
  1407. fontRef = ATSFontFindFromPostScriptName(CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, (char*)ucname,
  1408. CFStringGetSystemEncoding(), kCFAllocatorNull), kATSOptionFlagsDefault);
  1409. }
  1410. if (ucname != 0)
  1411. free(ucname);
  1412. if (fontRef == 0) {
  1413. fprintf(stderr, "\n*** font %s not found in psfonts.map or host system; will substitute Helvetica glyphs\n", (char*)name);
  1414. fontRef = ATSFontFindFromPostScriptName(CFSTR("Helvetica"), kATSOptionFlagsDefault);
  1415. if (font.charMap != NULL)
  1416. delete font.charMap;
  1417. font.charMap = readMacRomanCmap(fontRef);
  1418. }
  1419. font.cgFont = getCGFontForATSFont(fontRef);
  1420. delete[] name;
  1421. }
  1422. font.size = s;
  1423. gTeXFonts.insert(std::pair<const UInt32,texFont>(f, font));
  1424. }
  1425. static void
  1426. variationWarning()
  1427. {
  1428. static bool alreadyWarned = false;
  1429. if (alreadyWarned)
  1430. return;
  1431. fprintf(stderr, "\n"
  1432. "## xdv2pdf: AAT variation axes/multiple master fonts not supported on this system\n"
  1433. "## (at least Mac OS X 10.4 is required)\n");
  1434. alreadyWarned = true;
  1435. }
  1436. static void
  1437. doNativeFontDef(FILE* xdv)
  1438. {
  1439. UInt32 f = readUnsigned(xdv, 4); // font ID
  1440. Fixed s = X2Fix(Fix2X(readUnsigned(xdv, 4)) * 72 / 72.27); // size, converted to "big" points
  1441. if (sMag != 1000)
  1442. s = X2Fix(gMagScale * Fix2X(s));
  1443. UInt16 flags = readUnsigned(xdv, 2);
  1444. int psLen = readUnsigned(xdv, 1); // PSName length
  1445. int skipLen = readUnsigned(xdv, 1); // family name length
  1446. skipLen += readUnsigned(xdv, 1); // style name length
  1447. char* name = new char[psLen+1];
  1448. fread(name, 1, psLen, xdv);
  1449. name[psLen] = 0;
  1450. // don't use fseek, doesn't work when reading from a pipe!
  1451. while (skipLen-- > 0)
  1452. (void)readUnsigned(xdv, 1);
  1453. UInt32 rgba = 0x000000FF;
  1454. if (flags & XDV_FLAG_COLORED)
  1455. rgba = readUnsigned(xdv, 4);
  1456. ATSFontRef fontRef = 0;
  1457. ATSUFontID fontID = kATSUInvalidFontID;
  1458. if (name[0] == '[') { // uninstalled font specified by filename: not supported
  1459. fprintf(stderr, "\n"
  1460. "## xdv2pdf: use of uninstalled fonts (specified by filename) such as\n"
  1461. "## %s\n"
  1462. "## is not supported; try using the xdvipdfmx driver instead.\n", name);
  1463. }
  1464. else {
  1465. CFStringRef psNameStr = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingMacRoman);
  1466. fontRef = ATSFontFindFromPostScriptName(psNameStr, kATSOptionFlagsDefault);
  1467. CFRelease(psNameStr);
  1468. fontID = FMGetFontFromATSFontRef(fontRef);
  1469. }
  1470. if (fontID == kATSUInvalidFontID)
  1471. rgba = 0xFF0000FF;
  1472. CGFontRef cgFont = getCGFontForATSFont(fontRef);
  1473. OSStatus status = noErr;
  1474. if (flags & XDV_FLAG_VARIATIONS) {
  1475. int n = readUnsigned(xdv, 2); // number of variations
  1476. if (n > 0) {
  1477. bool applyVars = true;
  1478. CFStringRef* axes = new CFStringRef[n];
  1479. for (int i = 0; i < n; ++i) {
  1480. UInt32 axis = readUnsigned(xdv, 4);
  1481. FontNameCode nameCode;
  1482. status = ATSUGetFontVariationNameCode(fontID, axis, &nameCode);
  1483. ByteCount len;
  1484. status = ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontRomanScript,
  1485. (FontLanguageCode)kFontNoLanguage, 0, NULL, &len, NULL);
  1486. if (status == noErr) {
  1487. char* buf = new char[len + 1];
  1488. status = ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontRomanScript,
  1489. (FontLanguageCode)kFontNoLanguage, len, buf, &len, NULL);
  1490. buf[len] = 0;
  1491. axes[i] = CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingMacRoman);
  1492. delete[] buf;
  1493. }
  1494. else
  1495. applyVars = false;
  1496. }
  1497. CFNumberRef* values = new CFNumberRef[n];
  1498. for (int i = 0; i < n; ++i) {
  1499. SInt32 v = readSigned(xdv, 4);
  1500. Float32 f = Fix2X(v);
  1501. values[i] = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &f);
  1502. }
  1503. if (&CGFontCreateCopyWithVariations != NULL) {
  1504. CFDictionaryRef variations = CFDictionaryCreate(kCFAllocatorDefault,
  1505. (const void**)axes, (const void**)values, n,
  1506. &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  1507. cgFont = CGFontCreateCopyWithVariations(cgFont, variations);
  1508. CFRelease(variations);
  1509. }
  1510. else
  1511. variationWarning();
  1512. for (int i = 0; i < n; ++i) {
  1513. CFRelease(axes[i]);
  1514. CFRelease(values[i]);
  1515. }
  1516. delete[] values;
  1517. delete[] axes;
  1518. }
  1519. }
  1520. nativeFont fontRec;
  1521. fontRec.cgFont = cgFont;
  1522. fontRec.atsFont = fontRef;
  1523. fontRec.size = s;
  1524. fontRec.isColored = (flags & XDV_FLAG_COLORED) != 0 || fontID == kATSUInvalidFontID;
  1525. fontRec.isVertical = (flags & XDV_FLAG_VERTICAL) != 0;
  1526. if (fontRec.isColored) {
  1527. float values[4];
  1528. values[0] = (rgba >> 24) / 255.0;
  1529. values[1] = ((rgba >> 16) & 0xFF) / 255.0;
  1530. values[2] = ((rgba >> 8) & 0xFF) / 255.0;
  1531. values[3] = ( rgba & 0xFF) / 255.0;
  1532. fontRec.color = CGColorCreate(gRGBColorSpace, values);
  1533. }
  1534. else
  1535. fontRec.color = NULL;
  1536. if (fontRec.isVertical) {
  1537. ATSUStyle style;
  1538. status = ATSUCreateStyle(&style);
  1539. ATSUVerticalCharacterType vert = kATSUStronglyHorizontal;
  1540. ATSUAttributeTag tags[] = { kATSUFontTag, kATSUSizeTag, kATSUVerticalCharacterTag };
  1541. ByteCount sizes[] = { sizeof(fontID), sizeof(s), sizeof(vert) };
  1542. ATSUAttributeValuePtr values[] = { &fontID, &s, &vert };
  1543. ItemCount numTags = sizeof(tags) / sizeof(ATSUAttributeTag);
  1544. status = ATSUSetAttributes(style, numTags, tags, sizes, values);
  1545. fontRec.atsuStyleH = style;
  1546. status = ATSUCreateStyle(&style);
  1547. vert = kATSUStronglyVertical;
  1548. status = ATSUSetAttributes(style, numTags, tags, sizes, values);
  1549. fontRec.atsuStyleV = style;
  1550. }
  1551. sNativeFonts.insert(std::pair<const UInt32,nativeFont>(f, fontRec));
  1552. }
  1553. static void
  1554. processPage(FILE* xdv)
  1555. {
  1556. /* enter here having just read BOP from xdv file */
  1557. ++gPageIndex;
  1558. OSStatus status;
  1559. int i;
  1560. std::list<dviVars> stack;
  1561. gDviLevel = 0;
  1562. int j = 0;
  1563. for (i = 0; i < 10; ++i) { // read counts
  1564. gCounts[i] = readSigned(xdv, 4);
  1565. if (gCounts[i] != 0)
  1566. j = i;
  1567. }
  1568. if (sVerbose) {
  1569. fprintf(stderr, "[");
  1570. for (i = 0; i < j; ++i)
  1571. fprintf(stderr, "%d.", gCounts[i]);
  1572. fprintf(stderr, "%d", gCounts[j]);
  1573. }
  1574. (void)readUnsigned(xdv, 4); // skip prev-BOP pointer
  1575. cur_cgFont = kUndefinedFont;
  1576. dvi.h = dvi.v = 0;
  1577. dvi.w = dvi.x = dvi.y = dvi.z = 0;
  1578. f = 0;
  1579. unsigned int cmd = DVI_BOP;
  1580. while (cmd != DVI_EOP) {
  1581. UInt32 u;
  1582. SInt32 s;
  1583. SInt32 ht, wd;
  1584. int k = 1;
  1585. cmd = readUnsigned(xdv, 1);
  1586. switch (cmd) {
  1587. default:
  1588. if (cmd < DVI_SET1)
  1589. setChar(cmd, true);
  1590. else if (cmd >= DVI_FNTNUM0 && cmd <= DVI_FNTNUM0 + 63)
  1591. f = cmd - DVI_FNTNUM0;
  1592. else
  1593. goto ABORT_PAGE;
  1594. break;
  1595. case DVI_EOP:
  1596. flushGlyphs();
  1597. break;
  1598. case DVI_NOP:
  1599. break;
  1600. case DVI_FNT4:
  1601. ++k;
  1602. case DVI_FNT3:
  1603. ++k;
  1604. case DVI_FNT2:
  1605. ++k;
  1606. case DVI_FNT1:
  1607. f = readUnsigned(xdv, k); // that's it: just set |f|
  1608. break;
  1609. case DVI_XXX4:
  1610. ++k;
  1611. case DVI_XXX3:
  1612. ++k;
  1613. case DVI_XXX2:
  1614. ++k;
  1615. case DVI_XXX1:
  1616. flushGlyphs();
  1617. u = readUnsigned(xdv, k);
  1618. if (u > 0) {
  1619. char* special = new char[u+1];
  1620. fread(special, 1, u, xdv);
  1621. special[u] = '\0';
  1622. doSpecial(special);
  1623. delete[] special;
  1624. }
  1625. break;
  1626. case DVI_SETRULE:
  1627. case DVI_PUTRULE:
  1628. ensurePageStarted();
  1629. ht = readSigned(xdv, 4);
  1630. wd = readSigned(xdv, 4);
  1631. if (ht > 0 && wd > 0) {
  1632. CGRect r = CGRectMake(kDvi2Scr * dvi.h, kDvi2Scr * (gPageHt - dvi.v), kDvi2Scr * wd, kDvi2Scr * ht);
  1633. setColor(gRuleColor);
  1634. CGContextFillRect(gCtx, r);
  1635. if (gTrackingBoxes) {
  1636. box b = {
  1637. dvi.h,
  1638. dvi.v,
  1639. dvi.h + wd,
  1640. dvi.v - ht };
  1641. mergeBox(b);
  1642. }
  1643. }
  1644. if (cmd == DVI_SETRULE)
  1645. dvi.h += wd;
  1646. break;
  1647. case DVI_SET4:
  1648. ++k;
  1649. case DVI_SET3:
  1650. ++k;
  1651. case DVI_SET2:
  1652. ++k;
  1653. case DVI_SET1:
  1654. u = readUnsigned(xdv, k);
  1655. setChar(u, true);
  1656. break;
  1657. case DVI_PUT4:
  1658. ++k;
  1659. case DVI_PUT3:

Large files files are truncated, but you can click here to view the full file