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 31KB

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