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.

IFParser.java 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  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.intermediate;
  19. import java.awt.Color;
  20. import java.awt.Dimension;
  21. import java.awt.Point;
  22. import java.awt.Rectangle;
  23. import java.awt.geom.AffineTransform;
  24. import java.util.HashMap;
  25. import java.util.Locale;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import javax.xml.transform.Source;
  29. import javax.xml.transform.Transformer;
  30. import javax.xml.transform.TransformerException;
  31. import javax.xml.transform.sax.SAXResult;
  32. import javax.xml.transform.sax.SAXTransformerFactory;
  33. import org.w3c.dom.DOMImplementation;
  34. import org.w3c.dom.Document;
  35. import org.xml.sax.Attributes;
  36. import org.xml.sax.ContentHandler;
  37. import org.xml.sax.SAXException;
  38. import org.xml.sax.helpers.AttributesImpl;
  39. import org.xml.sax.helpers.DefaultHandler;
  40. import org.apache.commons.logging.Log;
  41. import org.apache.commons.logging.LogFactory;
  42. import org.apache.xmlgraphics.util.QName;
  43. import org.apache.fop.accessibility.AccessibilityEventProducer;
  44. import org.apache.fop.accessibility.StructureTreeElement;
  45. import org.apache.fop.accessibility.StructureTreeEventHandler;
  46. import org.apache.fop.apps.FOUserAgent;
  47. import org.apache.fop.fo.ElementMapping;
  48. import org.apache.fop.fo.ElementMappingRegistry;
  49. import org.apache.fop.fo.expr.PropertyException;
  50. import org.apache.fop.fo.extensions.InternalElementMapping;
  51. import org.apache.fop.render.intermediate.extensions.DocumentNavigationExtensionConstants;
  52. import org.apache.fop.render.intermediate.extensions.DocumentNavigationHandler;
  53. import org.apache.fop.traits.BorderProps;
  54. import org.apache.fop.traits.RuleStyle;
  55. import org.apache.fop.util.ColorUtil;
  56. import org.apache.fop.util.ContentHandlerFactory;
  57. import org.apache.fop.util.ContentHandlerFactoryRegistry;
  58. import org.apache.fop.util.DOMBuilderContentHandlerFactory;
  59. import org.apache.fop.util.DefaultErrorListener;
  60. import org.apache.fop.util.LanguageTags;
  61. import org.apache.fop.util.XMLUtil;
  62. /**
  63. * This is a parser for the intermediate format XML which converts the intermediate file into
  64. * {@link IFPainter} events.
  65. */
  66. public class IFParser implements IFConstants {
  67. /** Logger instance */
  68. protected static final Log log = LogFactory.getLog(IFParser.class);
  69. private static SAXTransformerFactory tFactory
  70. = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
  71. private static Set<String> handledNamespaces = new java.util.HashSet<String>();
  72. static {
  73. handledNamespaces.add(XMLNS_NAMESPACE_URI);
  74. handledNamespaces.add(XML_NAMESPACE);
  75. handledNamespaces.add(NAMESPACE);
  76. handledNamespaces.add(XLINK_NAMESPACE);
  77. }
  78. /**
  79. * Parses an intermediate file and paints it.
  80. * @param src the Source instance pointing to the intermediate file
  81. * @param documentHandler the intermediate format document handler used to process the IF events
  82. * @param userAgent the user agent
  83. * @throws TransformerException if an error occurs while parsing the area tree XML
  84. * @throws IFException if an IF-related error occurs inside the target document handler
  85. */
  86. public void parse(Source src, IFDocumentHandler documentHandler, FOUserAgent userAgent)
  87. throws TransformerException, IFException {
  88. try {
  89. Transformer transformer = tFactory.newTransformer();
  90. transformer.setErrorListener(new DefaultErrorListener(log));
  91. SAXResult res = new SAXResult(getContentHandler(documentHandler, userAgent));
  92. transformer.transform(src, res);
  93. } catch (TransformerException te) {
  94. //Unpack original IFException if applicable
  95. if (te.getCause() instanceof SAXException) {
  96. SAXException se = (SAXException)te.getCause();
  97. if (se.getCause() instanceof IFException) {
  98. throw (IFException)se.getCause();
  99. }
  100. } else if (te.getCause() instanceof IFException) {
  101. throw (IFException)te.getCause();
  102. }
  103. throw te;
  104. }
  105. }
  106. /**
  107. * Creates a new ContentHandler instance that you can send the area tree XML to. The parsed
  108. * pages are added to the AreaTreeModel instance you pass in as a parameter.
  109. * @param documentHandler the intermediate format document handler used to process the IF events
  110. * @param userAgent the user agent
  111. * @return the ContentHandler instance to receive the SAX stream from the area tree XML
  112. */
  113. public ContentHandler getContentHandler(IFDocumentHandler documentHandler,
  114. FOUserAgent userAgent) {
  115. ElementMappingRegistry elementMappingRegistry
  116. = userAgent.getFactory().getElementMappingRegistry();
  117. return new Handler(documentHandler, userAgent, elementMappingRegistry);
  118. }
  119. private static class Handler extends DefaultHandler {
  120. private Map<String, ElementHandler> elementHandlers = new HashMap<String, ElementHandler>();
  121. private IFDocumentHandler documentHandler;
  122. private IFPainter painter;
  123. private FOUserAgent userAgent;
  124. private ElementMappingRegistry elementMappingRegistry;
  125. private Attributes lastAttributes;
  126. private StringBuffer content = new StringBuffer();
  127. private boolean ignoreCharacters = true;
  128. //private Stack delegateStack = new Stack();
  129. private int delegateDepth;
  130. private ContentHandler delegate;
  131. private boolean inForeignObject;
  132. private Document foreignObject;
  133. private ContentHandler navParser;
  134. private ContentHandler structureTreeHandler;
  135. private Attributes pageSequenceAttributes;
  136. private Map<String, StructureTreeElement> structureTreeElements
  137. = new HashMap<String, StructureTreeElement>();
  138. private final class StructureTreeHandler extends DefaultHandler {
  139. private final StructureTreeEventHandler structureTreeEventHandler;
  140. private StructureTreeHandler(StructureTreeEventHandler structureTreeEventHandler,
  141. Locale pageSequenceLanguage) throws SAXException {
  142. this.structureTreeEventHandler = structureTreeEventHandler;
  143. structureTreeEventHandler.startPageSequence(pageSequenceLanguage);
  144. }
  145. public void endDocument() throws SAXException {
  146. startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
  147. pageSequenceAttributes = null;
  148. }
  149. @Override
  150. public void startElement(String uri, String localName, String qName,
  151. Attributes attributes) throws SAXException {
  152. if (!"structure-tree".equals(localName)) {
  153. if (localName.equals("marked-content")) {
  154. localName = "#PCDATA";
  155. }
  156. String structID = attributes.getValue(InternalElementMapping.URI,
  157. InternalElementMapping.STRUCT_ID);
  158. if (structID == null) {
  159. structureTreeEventHandler.startNode(localName, attributes);
  160. } else if (localName.equals("external-graphic")
  161. || localName.equals("instream-foreign-object")) {
  162. StructureTreeElement structureTreeElement
  163. = structureTreeEventHandler.startImageNode(localName, attributes);
  164. structureTreeElements.put(structID, structureTreeElement);
  165. } else {
  166. StructureTreeElement structureTreeElement = structureTreeEventHandler
  167. .startReferencedNode(localName, attributes);
  168. structureTreeElements.put(structID, structureTreeElement);
  169. }
  170. }
  171. }
  172. @Override
  173. public void endElement(String uri, String localName, String arqNameg2)
  174. throws SAXException {
  175. if (!"structure-tree".equals(localName)) {
  176. structureTreeEventHandler.endNode(localName);
  177. }
  178. }
  179. }
  180. public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
  181. ElementMappingRegistry elementMappingRegistry) {
  182. this.documentHandler = documentHandler;
  183. this.userAgent = userAgent;
  184. this.elementMappingRegistry = elementMappingRegistry;
  185. elementHandlers.put(EL_DOCUMENT, new DocumentHandler());
  186. elementHandlers.put(EL_HEADER, new DocumentHeaderHandler());
  187. elementHandlers.put(EL_LOCALE, new LocaleHandler());
  188. elementHandlers.put(EL_TRAILER, new DocumentTrailerHandler());
  189. elementHandlers.put(EL_PAGE_SEQUENCE, new PageSequenceHandler());
  190. elementHandlers.put(EL_PAGE, new PageHandler());
  191. elementHandlers.put(EL_PAGE_HEADER, new PageHeaderHandler());
  192. elementHandlers.put(EL_PAGE_CONTENT, new PageContentHandler());
  193. elementHandlers.put(EL_PAGE_TRAILER, new PageTrailerHandler());
  194. //Page content
  195. elementHandlers.put(EL_VIEWPORT, new ViewportHandler());
  196. elementHandlers.put(EL_GROUP, new GroupHandler());
  197. elementHandlers.put(EL_ID, new IDHandler());
  198. elementHandlers.put(EL_FONT, new FontHandler());
  199. elementHandlers.put(EL_TEXT, new TextHandler());
  200. elementHandlers.put(EL_CLIP_RECT, new ClipRectHandler());
  201. elementHandlers.put(EL_RECT, new RectHandler());
  202. elementHandlers.put(EL_LINE, new LineHandler());
  203. elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
  204. elementHandlers.put(EL_IMAGE, new ImageHandler());
  205. }
  206. private void establishForeignAttributes(Map<QName, String> foreignAttributes) {
  207. documentHandler.getContext().setForeignAttributes(foreignAttributes);
  208. }
  209. private void resetForeignAttributes() {
  210. documentHandler.getContext().resetForeignAttributes();
  211. }
  212. /** {@inheritDoc} */
  213. public void startElement(String uri, String localName, String qName, Attributes attributes)
  214. throws SAXException {
  215. if (delegate != null) {
  216. delegateDepth++;
  217. delegate.startElement(uri, localName, qName, attributes);
  218. } else {
  219. boolean handled = true;
  220. if (NAMESPACE.equals(uri)) {
  221. if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) {
  222. pageSequenceAttributes = new AttributesImpl(attributes);
  223. Locale language = getLanguage(attributes);
  224. structureTreeHandler = new StructureTreeHandler(
  225. userAgent.getStructureTreeEventHandler(), language);
  226. } else if (localName.equals(EL_STRUCTURE_TREE)) {
  227. if (userAgent.isAccessibilityEnabled()) {
  228. delegate = structureTreeHandler;
  229. } else {
  230. /* Delegate to a handler that does nothing */
  231. delegate = new DefaultHandler();
  232. }
  233. delegateDepth++;
  234. delegate.startDocument();
  235. delegate.startElement(uri, localName, qName, attributes);
  236. } else {
  237. if (pageSequenceAttributes != null) {
  238. /*
  239. * This means that no structure-element tag was
  240. * found in the XML, otherwise a
  241. * StructureTreeBuilderWrapper object would have
  242. * been created, which would have reset the
  243. * pageSequenceAttributes field.
  244. */
  245. AccessibilityEventProducer.Provider
  246. .get(userAgent.getEventBroadcaster())
  247. .noStructureTreeInXML(this);
  248. }
  249. handled = startIFElement(localName, attributes);
  250. }
  251. } else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) {
  252. if (this.navParser == null) {
  253. this.navParser = new DocumentNavigationHandler(
  254. this.documentHandler.getDocumentNavigationHandler(),
  255. structureTreeElements);
  256. }
  257. delegate = this.navParser;
  258. delegateDepth++;
  259. delegate.startDocument();
  260. delegate.startElement(uri, localName, qName, attributes);
  261. } else {
  262. ContentHandlerFactoryRegistry registry
  263. = userAgent.getFactory().getContentHandlerFactoryRegistry();
  264. ContentHandlerFactory factory = registry.getFactory(uri);
  265. if (factory == null) {
  266. DOMImplementation domImplementation
  267. = elementMappingRegistry.getDOMImplementationForNamespace(uri);
  268. if (domImplementation == null) {
  269. domImplementation = ElementMapping.getDefaultDOMImplementation();
  270. /*
  271. throw new SAXException("No DOMImplementation could be"
  272. + " identified to handle namespace: " + uri);
  273. */
  274. }
  275. factory = new DOMBuilderContentHandlerFactory(uri, domImplementation);
  276. }
  277. delegate = factory.createContentHandler();
  278. delegateDepth++;
  279. delegate.startDocument();
  280. delegate.startElement(uri, localName, qName, attributes);
  281. }
  282. if (!handled) {
  283. if (uri == null || uri.length() == 0) {
  284. throw new SAXException("Unhandled element " + localName
  285. + " in namespace: " + uri);
  286. } else {
  287. log.warn("Unhandled element " + localName
  288. + " in namespace: " + uri);
  289. }
  290. }
  291. }
  292. }
  293. private static Locale getLanguage(Attributes attributes) {
  294. String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
  295. return (xmllang == null) ? null : LanguageTags.toLocale(xmllang);
  296. }
  297. private boolean startIFElement(String localName, Attributes attributes)
  298. throws SAXException {
  299. lastAttributes = new AttributesImpl(attributes);
  300. ElementHandler elementHandler = elementHandlers.get(localName);
  301. content.setLength(0);
  302. ignoreCharacters = true;
  303. if (elementHandler != null) {
  304. ignoreCharacters = elementHandler.ignoreCharacters();
  305. try {
  306. elementHandler.startElement(attributes);
  307. } catch (IFException ife) {
  308. handleIFException(ife);
  309. }
  310. return true;
  311. } else {
  312. return false;
  313. }
  314. }
  315. private void handleIFException(IFException ife) throws SAXException {
  316. if (ife.getCause() instanceof SAXException) {
  317. //unwrap
  318. throw (SAXException)ife.getCause();
  319. } else {
  320. //wrap
  321. throw new SAXException(ife);
  322. }
  323. }
  324. /** {@inheritDoc} */
  325. public void endElement(String uri, String localName, String qName) throws SAXException {
  326. if (delegate != null) {
  327. delegate.endElement(uri, localName, qName);
  328. delegateDepth--;
  329. if (delegateDepth == 0) {
  330. delegate.endDocument();
  331. if (delegate instanceof ContentHandlerFactory.ObjectSource) {
  332. Object obj = ((ContentHandlerFactory.ObjectSource)delegate).getObject();
  333. if (inForeignObject) {
  334. this.foreignObject = (Document)obj;
  335. } else {
  336. handleExternallyGeneratedObject(obj);
  337. }
  338. }
  339. delegate = null; //Sub-document is processed, return to normal processing
  340. }
  341. } else {
  342. if (NAMESPACE.equals(uri)) {
  343. ElementHandler elementHandler = elementHandlers.get(localName);
  344. if (elementHandler != null) {
  345. try {
  346. elementHandler.endElement();
  347. } catch (IFException ife) {
  348. handleIFException(ife);
  349. }
  350. content.setLength(0);
  351. }
  352. ignoreCharacters = true;
  353. } else {
  354. if (log.isTraceEnabled()) {
  355. log.trace("Ignoring " + localName + " in namespace: " + uri);
  356. }
  357. }
  358. }
  359. }
  360. // ============== Element handlers for the intermediate format =============
  361. private static interface ElementHandler {
  362. void startElement(Attributes attributes) throws IFException, SAXException;
  363. void endElement() throws IFException;
  364. boolean ignoreCharacters();
  365. }
  366. private abstract class AbstractElementHandler implements ElementHandler {
  367. public void startElement(Attributes attributes) throws IFException, SAXException {
  368. //nop
  369. }
  370. public void endElement() throws IFException {
  371. //nop
  372. }
  373. public boolean ignoreCharacters() {
  374. return true;
  375. }
  376. }
  377. private class DocumentHandler extends AbstractElementHandler {
  378. public void startElement(Attributes attributes) throws IFException {
  379. documentHandler.startDocument();
  380. }
  381. public void endElement() throws IFException {
  382. documentHandler.endDocument();
  383. }
  384. }
  385. private class DocumentHeaderHandler extends AbstractElementHandler {
  386. public void startElement(Attributes attributes) throws IFException {
  387. documentHandler.startDocumentHeader();
  388. }
  389. public void endElement() throws IFException {
  390. documentHandler.endDocumentHeader();
  391. }
  392. }
  393. private class LocaleHandler extends AbstractElementHandler {
  394. public void startElement(Attributes attributes) throws IFException {
  395. documentHandler.setDocumentLocale(getLanguage(attributes));
  396. }
  397. }
  398. private class DocumentTrailerHandler extends AbstractElementHandler {
  399. public void startElement(Attributes attributes) throws IFException {
  400. documentHandler.startDocumentTrailer();
  401. }
  402. public void endElement() throws IFException {
  403. documentHandler.endDocumentTrailer();
  404. }
  405. }
  406. private class PageSequenceHandler extends AbstractElementHandler {
  407. public void startElement(Attributes attributes) throws IFException {
  408. String id = attributes.getValue("id");
  409. Locale language = getLanguage(attributes);
  410. if (language != null) {
  411. documentHandler.getContext().setLanguage(language);
  412. }
  413. Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
  414. establishForeignAttributes(foreignAttributes);
  415. documentHandler.startPageSequence(id);
  416. resetForeignAttributes();
  417. }
  418. public void endElement() throws IFException {
  419. documentHandler.endPageSequence();
  420. documentHandler.getContext().setLanguage(null);
  421. }
  422. }
  423. private class PageHandler extends AbstractElementHandler {
  424. public void startElement(Attributes attributes) throws IFException {
  425. int index = Integer.parseInt(attributes.getValue("index"));
  426. String name = attributes.getValue("name");
  427. String pageMasterName = attributes.getValue("page-master-name");
  428. int width = Integer.parseInt(attributes.getValue("width"));
  429. int height = Integer.parseInt(attributes.getValue("height"));
  430. Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
  431. establishForeignAttributes(foreignAttributes);
  432. documentHandler.startPage(index, name, pageMasterName,
  433. new Dimension(width, height));
  434. resetForeignAttributes();
  435. }
  436. public void endElement() throws IFException {
  437. documentHandler.endPage();
  438. }
  439. }
  440. private class PageHeaderHandler extends AbstractElementHandler {
  441. public void startElement(Attributes attributes) throws IFException {
  442. documentHandler.startPageHeader();
  443. }
  444. public void endElement() throws IFException {
  445. documentHandler.endPageHeader();
  446. }
  447. }
  448. private class PageContentHandler extends AbstractElementHandler {
  449. public void startElement(Attributes attributes) throws IFException {
  450. painter = documentHandler.startPageContent();
  451. }
  452. public void endElement() throws IFException {
  453. painter = null;
  454. documentHandler.getContext().setID("");
  455. documentHandler.endPageContent();
  456. }
  457. }
  458. private class PageTrailerHandler extends AbstractElementHandler {
  459. public void startElement(Attributes attributes) throws IFException {
  460. documentHandler.startPageTrailer();
  461. }
  462. public void endElement() throws IFException {
  463. documentHandler.endPageTrailer();
  464. }
  465. }
  466. private class ViewportHandler extends AbstractElementHandler {
  467. public void startElement(Attributes attributes) throws IFException {
  468. String transform = attributes.getValue("transform");
  469. AffineTransform[] transforms
  470. = AffineTransformArrayParser.createAffineTransform(transform);
  471. int width = Integer.parseInt(attributes.getValue("width"));
  472. int height = Integer.parseInt(attributes.getValue("height"));
  473. Rectangle clipRect = XMLUtil.getAttributeAsRectangle(attributes, "clip-rect");
  474. painter.startViewport(transforms, new Dimension(width, height), clipRect);
  475. }
  476. public void endElement() throws IFException {
  477. painter.endViewport();
  478. }
  479. }
  480. private class GroupHandler extends AbstractElementHandler {
  481. public void startElement(Attributes attributes) throws IFException {
  482. String transform = attributes.getValue("transform");
  483. AffineTransform[] transforms
  484. = AffineTransformArrayParser.createAffineTransform(transform);
  485. painter.startGroup(transforms);
  486. }
  487. public void endElement() throws IFException {
  488. painter.endGroup();
  489. }
  490. }
  491. private class IDHandler extends AbstractElementHandler {
  492. @Override
  493. public void startElement(Attributes attributes) throws IFException, SAXException {
  494. String id = attributes.getValue("name");
  495. documentHandler.getContext().setID(id);
  496. }
  497. }
  498. private class FontHandler extends AbstractElementHandler {
  499. public void startElement(Attributes attributes) throws IFException {
  500. String family = attributes.getValue("family");
  501. String style = attributes.getValue("style");
  502. Integer weight = XMLUtil.getAttributeAsInteger(attributes, "weight");
  503. String variant = attributes.getValue("variant");
  504. Integer size = XMLUtil.getAttributeAsInteger(attributes, "size");
  505. Color color;
  506. try {
  507. color = getAttributeAsColor(attributes, "color");
  508. } catch (PropertyException pe) {
  509. throw new IFException("Error parsing the color attribute", pe);
  510. }
  511. painter.setFont(family, style, weight, variant, size, color);
  512. }
  513. }
  514. private class TextHandler extends AbstractElementHandler {
  515. public void endElement() throws IFException {
  516. int x = Integer.parseInt(lastAttributes.getValue("x"));
  517. int y = Integer.parseInt(lastAttributes.getValue("y"));
  518. String s = lastAttributes.getValue("letter-spacing");
  519. int letterSpacing = (s != null ? Integer.parseInt(s) : 0);
  520. s = lastAttributes.getValue("word-spacing");
  521. int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
  522. int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
  523. establishStructureTreeElement(lastAttributes);
  524. painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
  525. resetStructureTreeElement();
  526. }
  527. public boolean ignoreCharacters() {
  528. return false;
  529. }
  530. }
  531. private class ClipRectHandler extends AbstractElementHandler {
  532. public void startElement(Attributes attributes) throws IFException {
  533. int x = Integer.parseInt(attributes.getValue("x"));
  534. int y = Integer.parseInt(attributes.getValue("y"));
  535. int width = Integer.parseInt(attributes.getValue("width"));
  536. int height = Integer.parseInt(attributes.getValue("height"));
  537. painter.clipRect(new Rectangle(x, y, width, height));
  538. }
  539. }
  540. private class RectHandler extends AbstractElementHandler {
  541. public void startElement(Attributes attributes) throws IFException {
  542. int x = Integer.parseInt(attributes.getValue("x"));
  543. int y = Integer.parseInt(attributes.getValue("y"));
  544. int width = Integer.parseInt(attributes.getValue("width"));
  545. int height = Integer.parseInt(attributes.getValue("height"));
  546. Color fillColor;
  547. try {
  548. fillColor = getAttributeAsColor(attributes, "fill");
  549. } catch (PropertyException pe) {
  550. throw new IFException("Error parsing the fill attribute", pe);
  551. }
  552. painter.fillRect(new Rectangle(x, y, width, height), fillColor);
  553. }
  554. }
  555. private class LineHandler extends AbstractElementHandler {
  556. public void startElement(Attributes attributes) throws IFException {
  557. int x1 = Integer.parseInt(attributes.getValue("x1"));
  558. int y1 = Integer.parseInt(attributes.getValue("y1"));
  559. int x2 = Integer.parseInt(attributes.getValue("x2"));
  560. int y2 = Integer.parseInt(attributes.getValue("y2"));
  561. int width = Integer.parseInt(attributes.getValue("stroke-width"));
  562. Color color;
  563. try {
  564. color = getAttributeAsColor(attributes, "color");
  565. } catch (PropertyException pe) {
  566. throw new IFException("Error parsing the fill attribute", pe);
  567. }
  568. RuleStyle style = RuleStyle.valueOf(attributes.getValue("style"));
  569. painter.drawLine(new Point(x1, y1), new Point(x2, y2), width, color, style);
  570. }
  571. }
  572. private static final String[] SIDES = new String[] {"before", "after", "start", "end"};
  573. private class BorderRectHandler extends AbstractElementHandler {
  574. public void startElement(Attributes attributes) throws IFException {
  575. int x = Integer.parseInt(attributes.getValue("x"));
  576. int y = Integer.parseInt(attributes.getValue("y"));
  577. int width = Integer.parseInt(attributes.getValue("width"));
  578. int height = Integer.parseInt(attributes.getValue("height"));
  579. BorderProps[] borders = new BorderProps[4];
  580. for (int i = 0; i < 4; i++) {
  581. String b = attributes.getValue(SIDES[i]);
  582. if (b != null) {
  583. borders[i] = BorderProps.valueOf(userAgent, b);
  584. }
  585. }
  586. painter.drawBorderRect(new Rectangle(x, y, width, height),
  587. borders[0], borders[1], borders[2], borders[3]);
  588. }
  589. }
  590. private class ImageHandler extends AbstractElementHandler {
  591. public void startElement(Attributes attributes) throws IFException {
  592. inForeignObject = true;
  593. }
  594. public void endElement() throws IFException {
  595. int x = Integer.parseInt(lastAttributes.getValue("x"));
  596. int y = Integer.parseInt(lastAttributes.getValue("y"));
  597. int width = Integer.parseInt(lastAttributes.getValue("width"));
  598. int height = Integer.parseInt(lastAttributes.getValue("height"));
  599. Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
  600. establishForeignAttributes(foreignAttributes);
  601. establishStructureTreeElement(lastAttributes);
  602. if (foreignObject != null) {
  603. painter.drawImage(foreignObject,
  604. new Rectangle(x, y, width, height));
  605. foreignObject = null;
  606. } else {
  607. String uri = lastAttributes.getValue(
  608. XLINK_HREF.getNamespaceURI(), XLINK_HREF.getLocalName());
  609. if (uri == null) {
  610. throw new IFException("xlink:href is missing on image", null);
  611. }
  612. painter.drawImage(uri, new Rectangle(x, y, width, height));
  613. }
  614. resetForeignAttributes();
  615. resetStructureTreeElement();
  616. inForeignObject = false;
  617. }
  618. public boolean ignoreCharacters() {
  619. return false;
  620. }
  621. }
  622. // ====================================================================
  623. /**
  624. * Handles objects created by "sub-parsers" that implement the ObjectSource interface.
  625. * An example of object handled here are ExtensionAttachments.
  626. * @param obj the Object to be handled.
  627. * @throws SAXException if an error occurs while handling the extension object
  628. */
  629. protected void handleExternallyGeneratedObject(Object obj) throws SAXException {
  630. try {
  631. documentHandler.handleExtensionObject(obj);
  632. } catch (IFException ife) {
  633. handleIFException(ife);
  634. }
  635. }
  636. private Color getAttributeAsColor(Attributes attributes, String name)
  637. throws PropertyException {
  638. String s = attributes.getValue(name);
  639. if (s == null) {
  640. return null;
  641. } else {
  642. return ColorUtil.parseColorString(userAgent, s);
  643. }
  644. }
  645. private static Map<QName, String> getForeignAttributes(Attributes atts) {
  646. Map<QName, String> foreignAttributes = null;
  647. for (int i = 0, c = atts.getLength(); i < c; i++) {
  648. String ns = atts.getURI(i);
  649. if (ns.length() > 0) {
  650. if (handledNamespaces.contains(ns)) {
  651. continue;
  652. }
  653. if (foreignAttributes == null) {
  654. foreignAttributes = new java.util.HashMap<QName, String>();
  655. }
  656. QName qname = new QName(ns, atts.getQName(i));
  657. foreignAttributes.put(qname, atts.getValue(i));
  658. }
  659. }
  660. return foreignAttributes;
  661. }
  662. private void establishStructureTreeElement(Attributes attributes) {
  663. String structRef = attributes.getValue(InternalElementMapping.URI,
  664. InternalElementMapping.STRUCT_REF);
  665. if (structRef != null && structRef.length() > 0) {
  666. assert structureTreeElements.containsKey(structRef);
  667. StructureTreeElement structureTreeElement = structureTreeElements.get(structRef);
  668. documentHandler.getContext().setStructureTreeElement(structureTreeElement);
  669. }
  670. }
  671. private void resetStructureTreeElement() {
  672. documentHandler.getContext().resetStructureTreeElement();
  673. }
  674. /** {@inheritDoc} */
  675. public void characters(char[] ch, int start, int length) throws SAXException {
  676. if (delegate != null) {
  677. delegate.characters(ch, start, length);
  678. } else if (!ignoreCharacters) {
  679. this.content.append(ch, start, length);
  680. }
  681. }
  682. }
  683. }