You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PDFPainter.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.pdf;
  19. import java.awt.Color;
  20. import java.awt.Dimension;
  21. import java.awt.Paint;
  22. import java.awt.Point;
  23. import java.awt.Rectangle;
  24. import java.awt.geom.AffineTransform;
  25. import java.io.FileNotFoundException;
  26. import java.io.IOException;
  27. import java.util.HashSet;
  28. import java.util.Locale;
  29. import java.util.Set;
  30. import org.w3c.dom.Document;
  31. import org.apache.xmlgraphics.image.loader.ImageException;
  32. import org.apache.xmlgraphics.image.loader.ImageInfo;
  33. import org.apache.xmlgraphics.image.loader.ImageManager;
  34. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  35. import org.apache.fop.ResourceEventProducer;
  36. import org.apache.fop.fonts.CustomFont;
  37. import org.apache.fop.fonts.Font;
  38. import org.apache.fop.fonts.FontTriplet;
  39. import org.apache.fop.fonts.LazyFont;
  40. import org.apache.fop.fonts.SingleByteFont;
  41. import org.apache.fop.fonts.Typeface;
  42. import org.apache.fop.pdf.PDFArray;
  43. import org.apache.fop.pdf.PDFDictionary;
  44. import org.apache.fop.pdf.PDFName;
  45. import org.apache.fop.pdf.PDFNumber;
  46. import org.apache.fop.pdf.PDFStructElem;
  47. import org.apache.fop.pdf.PDFTextUtil;
  48. import org.apache.fop.pdf.PDFXObject;
  49. import org.apache.fop.render.RenderingContext;
  50. import org.apache.fop.render.intermediate.AbstractIFPainter;
  51. import org.apache.fop.render.intermediate.BorderPainter;
  52. import org.apache.fop.render.intermediate.GraphicsPainter;
  53. import org.apache.fop.render.intermediate.IFContext;
  54. import org.apache.fop.render.intermediate.IFException;
  55. import org.apache.fop.render.intermediate.IFState;
  56. import org.apache.fop.render.intermediate.IFUtil;
  57. import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
  58. import org.apache.fop.traits.BorderProps;
  59. import org.apache.fop.traits.Direction;
  60. import org.apache.fop.traits.RuleStyle;
  61. import org.apache.fop.util.CharUtilities;
  62. /**
  63. * IFPainter implementation that produces PDF.
  64. */
  65. public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
  66. /** The current content generator */
  67. protected PDFContentGenerator generator;
  68. private final GraphicsPainter graphicsPainter;
  69. private final BorderPainter borderPainter;
  70. private boolean accessEnabled;
  71. private MarkedContentInfo imageMCI;
  72. private PDFLogicalStructureHandler logicalStructureHandler;
  73. private final LanguageAvailabilityChecker languageAvailabilityChecker;
  74. private static class LanguageAvailabilityChecker {
  75. private final IFContext context;
  76. private final Set<String> reportedLocations = new HashSet<String>();
  77. LanguageAvailabilityChecker(IFContext context) {
  78. this.context = context;
  79. }
  80. private void checkLanguageAvailability(String text) {
  81. Locale locale = context.getLanguage();
  82. if (locale == null && containsLettersOrDigits(text)) {
  83. String location = context.getLocation();
  84. if (!reportedLocations.contains(location)) {
  85. PDFEventProducer.Provider.get(context.getUserAgent().getEventBroadcaster())
  86. .unknownLanguage(this, location);
  87. reportedLocations.add(location);
  88. }
  89. }
  90. }
  91. private boolean containsLettersOrDigits(String text) {
  92. for (int i = 0; i < text.length(); i++) {
  93. if (Character.isLetterOrDigit(text.charAt(i))) {
  94. return true;
  95. }
  96. }
  97. return false;
  98. }
  99. }
  100. /**
  101. * Default constructor.
  102. * @param documentHandler the parent document handler
  103. * @param logicalStructureHandler the logical structure handler
  104. */
  105. public PDFPainter(PDFDocumentHandler documentHandler,
  106. PDFLogicalStructureHandler logicalStructureHandler) {
  107. super(documentHandler);
  108. this.logicalStructureHandler = logicalStructureHandler;
  109. this.generator = documentHandler.getGenerator();
  110. this.graphicsPainter = new PDFGraphicsPainter(this.generator);
  111. this.borderPainter = new BorderPainter(this.graphicsPainter);
  112. this.state = IFState.create();
  113. accessEnabled = this.getUserAgent().isAccessibilityEnabled();
  114. languageAvailabilityChecker = accessEnabled
  115. ? new LanguageAvailabilityChecker(documentHandler.getContext())
  116. : null;
  117. }
  118. /** {@inheritDoc} */
  119. public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect)
  120. throws IFException {
  121. generator.saveGraphicsState();
  122. generator.concatenate(toPoints(transform));
  123. if (clipRect != null) {
  124. clipRect(clipRect);
  125. }
  126. }
  127. /** {@inheritDoc} */
  128. public void endViewport() throws IFException {
  129. generator.restoreGraphicsState();
  130. }
  131. /** {@inheritDoc} */
  132. public void startGroup(AffineTransform transform, String layer) throws IFException {
  133. generator.saveGraphicsState(layer);
  134. generator.concatenate(toPoints(transform));
  135. }
  136. /** {@inheritDoc} */
  137. public void endGroup() throws IFException {
  138. generator.restoreGraphicsState();
  139. }
  140. /** {@inheritDoc} */
  141. public void drawImage(String uri, Rectangle rect)
  142. throws IFException {
  143. PDFXObject xobject = getDocumentHandler().getPDFDocument().getXObject(uri);
  144. if (xobject != null) {
  145. if (accessEnabled) {
  146. PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
  147. prepareImageMCID(structElem);
  148. placeImageAccess(rect, xobject);
  149. } else {
  150. placeImage(rect, xobject);
  151. }
  152. } else {
  153. addStructTreeBBox(rect);
  154. drawImageUsingURI(uri, rect);
  155. if (!getDocumentHandler().getPDFDocument().isLinearizationEnabled()) {
  156. flushPDFDoc();
  157. }
  158. }
  159. }
  160. private void addStructTreeBBox(Rectangle rect) {
  161. if (accessEnabled && getDocumentHandler().getPDFDocument().getProfile().getPDFUAMode().isEnabled()) {
  162. PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
  163. PDFDictionary d = new PDFDictionary();
  164. int x = rect.x / 1000;
  165. int y = rect.y / 1000;
  166. int w = rect.width / 1000;
  167. int h = rect.height / 1000;
  168. d.put("BBox", new PDFArray(x, y, w, h));
  169. d.put("O", new PDFName("Layout"));
  170. structElem.put("A", d);
  171. }
  172. }
  173. @Override
  174. protected void drawImageUsingURI(String uri, Rectangle rect) {
  175. ImageManager manager = getUserAgent().getImageManager();
  176. ImageInfo info = null;
  177. try {
  178. ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
  179. info = manager.getImageInfo(uri, sessionContext);
  180. if (accessEnabled) {
  181. PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
  182. String mimeType = info.getMimeType();
  183. if (!mimeType.equalsIgnoreCase("application/pdf")) {
  184. prepareImageMCID(structElem);
  185. }
  186. }
  187. drawImageUsingImageHandler(info, rect);
  188. } catch (ImageException ie) {
  189. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  190. getUserAgent().getEventBroadcaster());
  191. eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null);
  192. } catch (FileNotFoundException fe) {
  193. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  194. getUserAgent().getEventBroadcaster());
  195. eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null);
  196. } catch (IOException ioe) {
  197. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  198. getUserAgent().getEventBroadcaster());
  199. eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null);
  200. }
  201. }
  202. private void prepareImageMCID(PDFStructElem structElem) {
  203. imageMCI = logicalStructureHandler.addImageContentItem(structElem);
  204. if (structElem != null) {
  205. languageAvailabilityChecker.checkLanguageAvailability((String) structElem.get("Alt"));
  206. }
  207. }
  208. /** {@inheritDoc} */
  209. @Override
  210. protected RenderingContext createRenderingContext() {
  211. PDFRenderingContext pdfContext = new PDFRenderingContext(
  212. getUserAgent(), generator, getDocumentHandler().getCurrentPage(), getFontInfo());
  213. pdfContext.setMarkedContentInfo(imageMCI);
  214. pdfContext.setPageNumbers(getDocumentHandler().getPageNumbers());
  215. pdfContext.setPdfLogicalStructureHandler(logicalStructureHandler);
  216. pdfContext.setCurrentSessionStructElem((PDFStructElem) getContext().getStructureTreeElement());
  217. return pdfContext;
  218. }
  219. /**
  220. * Places a previously registered image at a certain place on the page.
  221. * @param rect the rectangle for the image
  222. * @param xobj the image XObject
  223. */
  224. private void placeImage(Rectangle rect, PDFXObject xobj) {
  225. generator.saveGraphicsState();
  226. generator.add(format(rect.width) + " 0 0 "
  227. + format(-rect.height) + " "
  228. + format(rect.x) + " "
  229. + format(rect.y + rect.height)
  230. + " cm " + xobj.getName() + " Do\n");
  231. generator.restoreGraphicsState();
  232. }
  233. /**
  234. * Places a previously registered image at a certain place on the page - Accessibility version
  235. * @param rect the rectangle for the image
  236. * @param xobj the image XObject
  237. */
  238. private void placeImageAccess(Rectangle rect, PDFXObject xobj) {
  239. generator.saveGraphicsState(imageMCI.tag, imageMCI.mcid);
  240. generator.add(format(rect.width) + " 0 0 "
  241. + format(-rect.height) + " "
  242. + format(rect.x) + " "
  243. + format(rect.y + rect.height)
  244. + " cm " + xobj.getName() + " Do\n");
  245. generator.restoreGraphicsStateAccess();
  246. }
  247. /** {@inheritDoc} */
  248. public void drawImage(Document doc, Rectangle rect) throws IFException {
  249. if (accessEnabled) {
  250. PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
  251. prepareImageMCID(structElem);
  252. addStructTreeBBox(rect);
  253. }
  254. drawImageUsingDocument(doc, rect);
  255. if (!getDocumentHandler().getPDFDocument().isLinearizationEnabled()) {
  256. flushPDFDoc();
  257. }
  258. }
  259. private void flushPDFDoc() throws IFException {
  260. // output new data
  261. try {
  262. generator.flushPDFDoc();
  263. } catch (IOException ioe) {
  264. throw new IFException("I/O error flushing the PDF document", ioe);
  265. }
  266. }
  267. /**
  268. * Formats a integer value (normally coordinates in millipoints) to a String.
  269. * @param value the value (in millipoints)
  270. * @return the formatted value
  271. */
  272. protected static String format(int value) {
  273. return PDFNumber.doubleOut(value / 1000f);
  274. }
  275. /** {@inheritDoc} */
  276. public void clipRect(Rectangle rect) throws IFException {
  277. generator.endTextObject();
  278. generator.clipRect(rect);
  279. }
  280. /** {@inheritDoc} */
  281. public void clipBackground(Rectangle rect,
  282. BorderProps bpsBefore, BorderProps bpsAfter,
  283. BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
  284. try {
  285. borderPainter.clipBackground(rect,
  286. bpsBefore, bpsAfter, bpsStart, bpsEnd);
  287. } catch (IOException ioe) {
  288. throw new IFException("I/O error while clipping background", ioe);
  289. }
  290. }
  291. /** {@inheritDoc} */
  292. public void fillRect(Rectangle rect, Paint fill) throws IFException {
  293. if (fill == null) {
  294. return;
  295. }
  296. if (rect.width != 0 && rect.height != 0) {
  297. generator.endTextObject();
  298. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  299. generator.beginMarkedContentSequence(null, 0, null);
  300. }
  301. if (fill != null) {
  302. if (fill instanceof Color) {
  303. generator.updateColor((Color)fill, true, null);
  304. } else {
  305. throw new UnsupportedOperationException("Non-Color paints NYI");
  306. }
  307. }
  308. StringBuffer sb = new StringBuffer();
  309. sb.append(format(rect.x)).append(' ');
  310. sb.append(format(rect.y)).append(' ');
  311. sb.append(format(rect.width)).append(' ');
  312. sb.append(format(rect.height)).append(" re");
  313. if (fill != null) {
  314. sb.append(" f");
  315. }
  316. /* Removed from method signature as it is currently not used
  317. if (stroke != null) {
  318. sb.append(" S");
  319. }*/
  320. sb.append('\n');
  321. generator.add(sb.toString());
  322. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  323. generator.endMarkedContentSequence();
  324. }
  325. }
  326. }
  327. /** {@inheritDoc} */
  328. @Override
  329. public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
  330. BorderProps left, BorderProps right, Color innerBackgroundColor) throws IFException {
  331. if (top != null || bottom != null || left != null || right != null) {
  332. generator.endTextObject();
  333. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  334. generator.beginMarkedContentSequence(null, 0, null);
  335. }
  336. this.borderPainter.drawBorders(rect, top, bottom, left, right, innerBackgroundColor);
  337. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  338. generator.endMarkedContentSequence();
  339. }
  340. }
  341. }
  342. /** {@inheritDoc} */
  343. @Override
  344. public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
  345. throws IFException {
  346. generator.endTextObject();
  347. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  348. generator.beginMarkedContentSequence(null, 0, null);
  349. }
  350. try {
  351. this.graphicsPainter.drawLine(start, end, width, color, style);
  352. } catch (IOException ioe) {
  353. throw new IFException("Cannot draw line", ioe);
  354. }
  355. if (accessEnabled && getUserAgent().isPdfUAEnabled()) {
  356. generator.endMarkedContentSequence();
  357. }
  358. }
  359. private Typeface getTypeface(String fontName) {
  360. if (fontName == null) {
  361. throw new NullPointerException("fontName must not be null");
  362. }
  363. Typeface tf = getFontInfo().getFonts().get(fontName);
  364. if (tf instanceof LazyFont) {
  365. tf = ((LazyFont)tf).getRealFont();
  366. }
  367. return tf;
  368. }
  369. /** {@inheritDoc} */
  370. public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[][] dp,
  371. String text)
  372. throws IFException {
  373. if (accessEnabled) {
  374. PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
  375. languageAvailabilityChecker.checkLanguageAvailability(text);
  376. MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(structElem);
  377. String actualText = getContext().isHyphenated() ? text.substring(0, text.length() - 1) : null;
  378. generator.endTextObject();
  379. generator.updateColor(state.getTextColor(), true, null);
  380. generator.beginTextObject(mci.tag, mci.mcid, actualText);
  381. } else {
  382. generator.updateColor(state.getTextColor(), true, null);
  383. generator.beginTextObject();
  384. }
  385. FontTriplet triplet = new FontTriplet(
  386. state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
  387. if ((dp == null) || IFUtil.isDPOnlyDX(dp)) {
  388. drawTextWithDX(x, y, text, triplet, letterSpacing,
  389. wordSpacing, IFUtil.convertDPToDX(dp));
  390. } else {
  391. drawTextWithDP(x, y, text, triplet, letterSpacing,
  392. wordSpacing, dp);
  393. }
  394. }
  395. private void drawTextWithDX(int x, int y, String text, FontTriplet triplet,
  396. int letterSpacing, int wordSpacing, int[] dx) throws IFException {
  397. //TODO Ignored: state.getFontVariant()
  398. //TODO Opportunity for font caching if font state is more heavily used
  399. String fontKey = getFontKey(triplet);
  400. int sizeMillipoints = state.getFontSize();
  401. float fontSize = sizeMillipoints / 1000f;
  402. // This assumes that *all* CIDFonts use a /ToUnicode mapping
  403. Typeface tf = getTypeface(fontKey);
  404. SingleByteFont singleByteFont = null;
  405. if (tf instanceof SingleByteFont) {
  406. singleByteFont = (SingleByteFont)tf;
  407. }
  408. Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
  409. String fontName = font.getFontName();
  410. PDFTextUtil textutil = generator.getTextUtil();
  411. textutil.updateTf(fontKey, fontSize, tf.isMultiByte());
  412. double shear = 0;
  413. boolean simulateStyle = tf instanceof CustomFont && ((CustomFont) tf).getSimulateStyle();
  414. if (simulateStyle) {
  415. if (triplet.getWeight() == 700) {
  416. generator.add("q\n");
  417. generator.add("2 Tr 0.31543 w\n");
  418. }
  419. if (triplet.getStyle().equals("italic")) {
  420. shear = 0.3333;
  421. }
  422. }
  423. generator.updateCharacterSpacing(letterSpacing / 1000f);
  424. textutil.writeTextMatrix(new AffineTransform(1, 0, shear, -1, x / 1000f, y / 1000f));
  425. int l = text.length();
  426. int dxl = (dx != null ? dx.length : 0);
  427. if (dx != null && dxl > 0 && dx[0] != 0) {
  428. textutil.adjustGlyphTJ(-dx[0] / fontSize);
  429. }
  430. for (int i = 0; i < l; i++) {
  431. char orgChar = text.charAt(i);
  432. char ch;
  433. float glyphAdjust = 0;
  434. if (font.hasChar(orgChar)) {
  435. ch = font.mapChar(orgChar);
  436. ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize, textutil, ch);
  437. if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
  438. glyphAdjust += wordSpacing;
  439. }
  440. } else {
  441. if (CharUtilities.isFixedWidthSpace(orgChar)) {
  442. //Fixed width space are rendered as spaces so copy/paste works in a reader
  443. ch = font.mapChar(CharUtilities.SPACE);
  444. int spaceDiff = font.getCharWidth(CharUtilities.SPACE) - font.getCharWidth(orgChar);
  445. glyphAdjust = -spaceDiff;
  446. } else {
  447. ch = font.mapChar(orgChar);
  448. if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
  449. glyphAdjust += wordSpacing;
  450. }
  451. }
  452. ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize,
  453. textutil, ch);
  454. }
  455. textutil.writeTJMappedChar(ch);
  456. if (dx != null && i < dxl - 1) {
  457. glyphAdjust += dx[i + 1];
  458. }
  459. if (glyphAdjust != 0) {
  460. textutil.adjustGlyphTJ(-glyphAdjust / fontSize);
  461. }
  462. }
  463. textutil.writeTJ();
  464. if (simulateStyle && triplet.getWeight() == 700) {
  465. generator.add("Q\n");
  466. }
  467. }
  468. private static int[] paZero = new int[4];
  469. private void drawTextWithDP(int x, int y, String text, FontTriplet triplet,
  470. int letterSpacing, int wordSpacing, int[][] dp) {
  471. assert text != null;
  472. assert triplet != null;
  473. assert dp != null;
  474. String fk = getFontInfo().getInternalFontKey(triplet);
  475. Typeface tf = getTypeface(fk);
  476. if (tf.isMultiByte()) {
  477. int fs = state.getFontSize();
  478. float fsPoints = fs / 1000f;
  479. Font f = getFontInfo().getFontInstance(triplet, fs);
  480. PDFTextUtil tu = generator.getTextUtil();
  481. double xc = 0f;
  482. double yc = 0f;
  483. double xoLast = 0f;
  484. double yoLast = 0f;
  485. double wox = wordSpacing;
  486. tu.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f));
  487. tu.updateTf(fk, fsPoints, true);
  488. generator.updateCharacterSpacing(letterSpacing / 1000f);
  489. for (int i = 0, n = text.length(); i < n; i++) {
  490. char ch = text.charAt(i);
  491. int[] pa = ((i >= dp.length) || (dp[i] == null)) ? paZero : dp[i];
  492. double xo = xc + pa[0];
  493. double yo = yc + pa[1];
  494. double xa = f.getCharWidth(ch) + maybeWordOffsetX(wox, ch, null);
  495. double ya = 0;
  496. double xd = (xo - xoLast) / 1000f;
  497. double yd = (yo - yoLast) / 1000f;
  498. tu.writeTd(xd, yd);
  499. tu.writeTj(f.mapChar(ch));
  500. xc += xa + pa[2];
  501. yc += ya + pa[3];
  502. xoLast = xo;
  503. yoLast = yo;
  504. }
  505. }
  506. }
  507. private double maybeWordOffsetX(double wox, char ch, Direction dir) {
  508. if ((wox != 0)
  509. && CharUtilities.isAdjustableSpace(ch)
  510. && ((dir == null) || dir.isHorizontal())) {
  511. return wox;
  512. } else {
  513. return 0;
  514. }
  515. }
  516. /*
  517. private double maybeWordOffsetY ( double woy, char ch, Direction dir ) {
  518. if ( ( woy != 0 )
  519. && CharUtilities.isAdjustableSpace ( ch ) && dir.isVertical()
  520. && ( ( dir != null ) && dir.isVertical() ) ) {
  521. return woy;
  522. } else {
  523. return 0;
  524. }
  525. }
  526. */
  527. private char selectAndMapSingleByteFont(SingleByteFont singleByteFont, String fontName,
  528. float fontSize, PDFTextUtil textutil, char ch) {
  529. if (singleByteFont != null && singleByteFont.hasAdditionalEncodings()) {
  530. int encoding = ch / 256;
  531. if (encoding == 0) {
  532. textutil.updateTf(fontName, fontSize, singleByteFont.isMultiByte());
  533. } else {
  534. textutil.updateTf(fontName + "_" + Integer.toString(encoding),
  535. fontSize, singleByteFont.isMultiByte());
  536. ch = (char)(ch % 256);
  537. }
  538. }
  539. return ch;
  540. }
  541. }