選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

AreaTreeParser.java 54KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  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.area;
  19. import java.awt.Color;
  20. import java.awt.Rectangle;
  21. import java.awt.geom.Rectangle2D;
  22. import java.io.FileNotFoundException;
  23. import java.io.IOException;
  24. import java.nio.CharBuffer;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.Stack;
  29. import javax.xml.transform.Source;
  30. import javax.xml.transform.Transformer;
  31. import javax.xml.transform.TransformerConfigurationException;
  32. import javax.xml.transform.TransformerException;
  33. import javax.xml.transform.dom.DOMResult;
  34. import javax.xml.transform.sax.SAXResult;
  35. import javax.xml.transform.sax.SAXTransformerFactory;
  36. import javax.xml.transform.sax.TransformerHandler;
  37. import org.w3c.dom.DOMImplementation;
  38. import org.w3c.dom.Document;
  39. import org.xml.sax.Attributes;
  40. import org.xml.sax.ContentHandler;
  41. import org.xml.sax.Locator;
  42. import org.xml.sax.SAXException;
  43. import org.xml.sax.helpers.AttributesImpl;
  44. import org.xml.sax.helpers.DefaultHandler;
  45. import org.apache.commons.logging.Log;
  46. import org.apache.commons.logging.LogFactory;
  47. import org.apache.xmlgraphics.image.loader.ImageException;
  48. import org.apache.xmlgraphics.image.loader.ImageInfo;
  49. import org.apache.xmlgraphics.image.loader.ImageManager;
  50. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  51. import org.apache.xmlgraphics.util.QName;
  52. import org.apache.fop.ResourceEventProducer;
  53. import org.apache.fop.accessibility.AccessibilityEventProducer;
  54. import org.apache.fop.accessibility.StructureTreeBuilder;
  55. import org.apache.fop.apps.FOUserAgent;
  56. import org.apache.fop.area.Trait.Background;
  57. import org.apache.fop.area.Trait.InternalLink;
  58. import org.apache.fop.area.inline.AbstractTextArea;
  59. import org.apache.fop.area.inline.ForeignObject;
  60. import org.apache.fop.area.inline.Image;
  61. import org.apache.fop.area.inline.InlineArea;
  62. import org.apache.fop.area.inline.InlineBlockParent;
  63. import org.apache.fop.area.inline.InlineParent;
  64. import org.apache.fop.area.inline.Leader;
  65. import org.apache.fop.area.inline.Space;
  66. import org.apache.fop.area.inline.SpaceArea;
  67. import org.apache.fop.area.inline.TextArea;
  68. import org.apache.fop.area.inline.Viewport;
  69. import org.apache.fop.area.inline.WordArea;
  70. import org.apache.fop.fo.Constants;
  71. import org.apache.fop.fo.ElementMappingRegistry;
  72. import org.apache.fop.fo.expr.PropertyException;
  73. import org.apache.fop.fo.extensions.ExtensionAttachment;
  74. import org.apache.fop.fonts.Font;
  75. import org.apache.fop.fonts.FontInfo;
  76. import org.apache.fop.traits.BorderProps;
  77. import org.apache.fop.util.ColorUtil;
  78. import org.apache.fop.util.ContentHandlerFactory;
  79. import org.apache.fop.util.ContentHandlerFactoryRegistry;
  80. import org.apache.fop.util.ConversionUtils;
  81. import org.apache.fop.util.DefaultErrorListener;
  82. import org.apache.fop.util.DelegatingContentHandler;
  83. import org.apache.fop.util.XMLConstants;
  84. import org.apache.fop.util.XMLUtil;
  85. /**
  86. * This is a parser for the area tree XML (intermediate format) which is used to reread an area
  87. * tree (or part of it) into memory again for rendering to the final output format.
  88. */
  89. public class AreaTreeParser {
  90. /** Logger instance */
  91. protected static Log log = LogFactory.getLog(AreaTreeParser.class);
  92. private static SAXTransformerFactory tFactory
  93. = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
  94. /**
  95. * Parses an intermediate file (area tree XML) into an AreaTreeModel instance by adding
  96. * pages to it.
  97. * @param src the Source instance pointing to the intermediate file
  98. * @param treeModel the AreaTreeModel that the parsed pages are added to
  99. * @param userAgent the user agent
  100. * @throws TransformerException if an error occurs while parsing the area tree XML
  101. */
  102. public void parse(Source src, AreaTreeModel treeModel, FOUserAgent userAgent)
  103. throws TransformerException {
  104. Transformer transformer = tFactory.newTransformer();
  105. transformer.setErrorListener(new DefaultErrorListener(log));
  106. SAXResult res = new SAXResult(getContentHandler(treeModel, userAgent));
  107. transformer.transform(src, res);
  108. }
  109. /**
  110. * Creates a new ContentHandler instance that you can send the area tree XML to. The parsed
  111. * pages are added to the AreaTreeModel instance you pass in as a parameter.
  112. * @param treeModel the AreaTreeModel that the parsed pages are added to
  113. * @param userAgent the user agent
  114. * @return the ContentHandler instance to receive the SAX stream from the area tree XML
  115. */
  116. public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) {
  117. ElementMappingRegistry elementMappingRegistry
  118. = userAgent.getFactory().getElementMappingRegistry();
  119. return new Handler(treeModel, userAgent, elementMappingRegistry);
  120. }
  121. private static class Handler extends DefaultHandler {
  122. private Map makers = new java.util.HashMap();
  123. private AreaTreeModel treeModel;
  124. private FOUserAgent userAgent;
  125. private ElementMappingRegistry elementMappingRegistry;
  126. private Attributes lastAttributes;
  127. private CharBuffer content = CharBuffer.allocate(64);
  128. private boolean ignoreCharacters = true;
  129. private PageViewport currentPageViewport;
  130. private Map pageViewportsByKey = new java.util.HashMap();
  131. // set of "ID firsts" that have already been assigned to a PV:
  132. private Set idFirstsAssigned = new java.util.HashSet();
  133. private Stack areaStack = new Stack();
  134. private boolean firstFlow;
  135. private Stack delegateStack = new Stack();
  136. private ContentHandler delegate;
  137. private DOMImplementation domImplementation;
  138. private Locator locator;
  139. private StructureTreeBuilder structureTreeBuilder;
  140. private ContentHandler structureTreeBuilderWrapper;
  141. private Attributes pageSequenceAttributes;
  142. private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {
  143. private StructureTreeBuilderWrapper()
  144. throws SAXException {
  145. super(structureTreeBuilder.getHandlerForNextPageSequence());
  146. }
  147. public void endDocument() throws SAXException {
  148. super.endDocument();
  149. startAreaTreeElement("pageSequence", pageSequenceAttributes);
  150. pageSequenceAttributes = null;
  151. }
  152. }
  153. public Handler(AreaTreeModel treeModel, FOUserAgent userAgent,
  154. ElementMappingRegistry elementMappingRegistry) {
  155. this.treeModel = treeModel;
  156. this.userAgent = userAgent;
  157. this.elementMappingRegistry = elementMappingRegistry;
  158. makers.put("areaTree", new AreaTreeMaker());
  159. makers.put("page", new PageMaker());
  160. makers.put("pageSequence", new PageSequenceMaker());
  161. makers.put("title", new TitleMaker());
  162. makers.put("pageViewport", new PageViewportMaker());
  163. makers.put("regionViewport", new RegionViewportMaker());
  164. makers.put("regionBefore", new RegionBeforeMaker());
  165. makers.put("regionAfter", new RegionAfterMaker());
  166. makers.put("regionStart", new RegionStartMaker());
  167. makers.put("regionEnd", new RegionEndMaker());
  168. makers.put("regionBody", new RegionBodyMaker());
  169. makers.put("flow", new FlowMaker());
  170. makers.put("mainReference", new MainReferenceMaker());
  171. makers.put("span", new SpanMaker());
  172. makers.put("footnote", new FootnoteMaker());
  173. makers.put("beforeFloat", new BeforeFloatMaker());
  174. makers.put("block", new BlockMaker());
  175. makers.put("lineArea", new LineAreaMaker());
  176. makers.put("inline", new InlineMaker());
  177. makers.put("inlineparent", new InlineParentMaker());
  178. makers.put("inlineblockparent", new InlineBlockParentMaker());
  179. makers.put("text", new TextMaker());
  180. makers.put("word", new WordMaker());
  181. makers.put("space", new SpaceMaker());
  182. makers.put("leader", new LeaderMaker());
  183. makers.put("viewport", new ViewportMaker());
  184. makers.put("image", new ImageMaker());
  185. makers.put("foreignObject", new ForeignObjectMaker());
  186. makers.put("bookmarkTree", new BookmarkTreeMaker());
  187. makers.put("bookmark", new BookmarkMaker());
  188. makers.put("destination", new DestinationMaker());
  189. if (userAgent.isAccessibilityEnabled()) {
  190. structureTreeBuilder = new StructureTreeBuilder(tFactory);
  191. userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
  192. }
  193. }
  194. private Area findAreaType(Class clazz) {
  195. if (areaStack.size() > 0) {
  196. int pos = areaStack.size() - 1;
  197. Object obj = null;
  198. while (pos >= 0 && !(clazz.isInstance(obj = areaStack.get(pos)))) {
  199. pos--;
  200. }
  201. if (pos >= 0) {
  202. return (Area)obj;
  203. }
  204. }
  205. return null;
  206. }
  207. private RegionViewport getCurrentRegionViewport() {
  208. return (RegionViewport)findAreaType(RegionViewport.class);
  209. }
  210. private BodyRegion getCurrentBodyRegion() {
  211. return (BodyRegion)findAreaType(BodyRegion.class);
  212. }
  213. private BlockParent getCurrentBlockParent() {
  214. return (BlockParent)findAreaType(BlockParent.class);
  215. }
  216. private AbstractTextArea getCurrentText() {
  217. return (AbstractTextArea)findAreaType(AbstractTextArea.class);
  218. }
  219. private Viewport getCurrentViewport() {
  220. return (Viewport)findAreaType(Viewport.class);
  221. }
  222. /** {@inheritDoc} */
  223. public void setDocumentLocator(Locator locator) {
  224. this.locator = locator;
  225. }
  226. private Locator getLocator() {
  227. return this.locator;
  228. }
  229. /** {@inheritDoc} */
  230. public void startElement(String uri, String localName, String qName, Attributes attributes)
  231. throws SAXException {
  232. if (delegate != null) {
  233. delegateStack.push(qName);
  234. delegate.startElement(uri, localName, qName, attributes);
  235. } else if (domImplementation != null) {
  236. //domImplementation is set so we need to start a new DOM building sub-process
  237. TransformerHandler handler;
  238. try {
  239. handler = tFactory.newTransformerHandler();
  240. } catch (TransformerConfigurationException e) {
  241. throw new SAXException("Error creating a new TransformerHandler", e);
  242. }
  243. Document doc = domImplementation.createDocument(uri, qName, null);
  244. //It's easier to work with an empty document, so remove the root element
  245. doc.removeChild(doc.getDocumentElement());
  246. handler.setResult(new DOMResult(doc));
  247. Area parent = (Area)areaStack.peek();
  248. ((ForeignObject)parent).setDocument(doc);
  249. //activate delegate for nested foreign document
  250. domImplementation = null; //Not needed anymore now
  251. this.delegate = handler;
  252. delegateStack.push(qName);
  253. delegate.startDocument();
  254. delegate.startElement(uri, localName, qName, attributes);
  255. } else {
  256. boolean handled = true;
  257. if ("".equals(uri)) {
  258. if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) {
  259. structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
  260. pageSequenceAttributes = new AttributesImpl(attributes);
  261. } else if (localName.equals("structureTree")) {
  262. if (userAgent.isAccessibilityEnabled()) {
  263. delegate = structureTreeBuilderWrapper;
  264. } else {
  265. /* Delegate to a handler that does nothing */
  266. delegate = new DefaultHandler();
  267. }
  268. delegateStack.push(qName);
  269. delegate.startDocument();
  270. delegate.startElement(uri, localName, qName, attributes);
  271. } else {
  272. if (pageSequenceAttributes != null) {
  273. /*
  274. * This means that no structure-element tag was
  275. * found in the XML, otherwise a
  276. * StructureTreeBuilderWrapper object would have
  277. * been created, which would have reset the
  278. * pageSequenceAttributes field.
  279. */
  280. AccessibilityEventProducer.Provider
  281. .get(userAgent.getEventBroadcaster())
  282. .noStructureTreeInXML(this);
  283. }
  284. handled = startAreaTreeElement(localName, attributes);
  285. }
  286. } else {
  287. ContentHandlerFactoryRegistry registry
  288. = userAgent.getFactory().getContentHandlerFactoryRegistry();
  289. ContentHandlerFactory factory = registry.getFactory(uri);
  290. if (factory != null) {
  291. delegate = factory.createContentHandler();
  292. delegateStack.push(qName);
  293. delegate.startDocument();
  294. delegate.startElement(uri, localName, qName, attributes);
  295. } else {
  296. handled = false;
  297. }
  298. }
  299. if (!handled) {
  300. if (uri == null || uri.length() == 0) {
  301. throw new SAXException("Unhandled element " + localName
  302. + " in namespace: " + uri);
  303. } else {
  304. log.warn("Unhandled element " + localName
  305. + " in namespace: " + uri);
  306. }
  307. }
  308. }
  309. }
  310. private boolean startAreaTreeElement(String localName, Attributes attributes)
  311. throws SAXException {
  312. lastAttributes = new AttributesImpl(attributes);
  313. Maker maker = (Maker)makers.get(localName);
  314. content.clear();
  315. ignoreCharacters = true;
  316. if (maker != null) {
  317. ignoreCharacters = maker.ignoreCharacters();
  318. maker.startElement(attributes);
  319. } else if ("extension-attachments".equals(localName)) {
  320. //TODO implement me
  321. } else {
  322. return false;
  323. }
  324. return true;
  325. }
  326. /** {@inheritDoc} */
  327. public void endElement(String uri, String localName, String qName) throws SAXException {
  328. if (delegate != null) {
  329. delegate.endElement(uri, localName, qName);
  330. delegateStack.pop();
  331. if (delegateStack.size() == 0) {
  332. delegate.endDocument();
  333. if (delegate instanceof ContentHandlerFactory.ObjectSource) {
  334. Object obj = ((ContentHandlerFactory.ObjectSource)delegate).getObject();
  335. handleExternallyGeneratedObject(obj);
  336. }
  337. delegate = null; //Sub-document is processed, return to normal processing
  338. }
  339. } else {
  340. if ("".equals(uri)) {
  341. Maker maker = (Maker)makers.get(localName);
  342. if (maker != null) {
  343. maker.endElement();
  344. content.clear();
  345. }
  346. ignoreCharacters = true;
  347. } else {
  348. //log.debug("Ignoring " + localName + " in namespace: " + uri);
  349. }
  350. }
  351. }
  352. // ============== Maker classes for the area tree objects =============
  353. private static interface Maker {
  354. void startElement(Attributes attributes) throws SAXException;
  355. void endElement();
  356. boolean ignoreCharacters();
  357. }
  358. private abstract class AbstractMaker implements Maker {
  359. public void startElement(Attributes attributes) throws SAXException {
  360. //nop
  361. }
  362. public void endElement() {
  363. //nop
  364. }
  365. public boolean ignoreCharacters() {
  366. return true;
  367. }
  368. }
  369. private class AreaTreeMaker extends AbstractMaker {
  370. public void startElement(Attributes attributes) {
  371. // In case the Handler is reused:
  372. idFirstsAssigned.clear();
  373. }
  374. }
  375. private class PageSequenceMaker extends AbstractMaker {
  376. public void startElement(Attributes attributes) {
  377. PageSequence pageSequence = new PageSequence(null);
  378. String lang = attributes.getValue("language");
  379. pageSequence.setLanguage(lang);
  380. String country = attributes.getValue("country");
  381. pageSequence.setCountry(country);
  382. transferForeignObjects(attributes, pageSequence);
  383. areaStack.push(pageSequence);
  384. }
  385. }
  386. private class TitleMaker extends AbstractMaker {
  387. public void startElement(Attributes attributes) {
  388. LineArea line = new LineArea();
  389. transferForeignObjects(attributes, line);
  390. areaStack.push(line);
  391. }
  392. public void endElement() {
  393. LineArea line = (LineArea)areaStack.pop();
  394. PageSequence pageSequence = (PageSequence)areaStack.peek();
  395. pageSequence.setTitle(line);
  396. }
  397. }
  398. private class PageViewportMaker extends AbstractMaker {
  399. public void startElement(Attributes attributes) {
  400. if (!areaStack.isEmpty()) {
  401. PageSequence pageSequence = (PageSequence)areaStack.peek();
  402. treeModel.startPageSequence(pageSequence);
  403. areaStack.pop();
  404. }
  405. if (currentPageViewport != null) {
  406. throw new IllegalStateException("currentPageViewport must be null");
  407. }
  408. Rectangle viewArea = XMLUtil.getAttributeAsRectangle(attributes, "bounds");
  409. int pageNumber = XMLUtil.getAttributeAsInt(attributes, "nr", -1);
  410. String key = attributes.getValue("key");
  411. String pageNumberString = attributes.getValue("formatted-nr");
  412. String pageMaster = attributes.getValue("simple-page-master-name");
  413. boolean blank = XMLUtil.getAttributeAsBoolean(attributes, "blank", false);
  414. currentPageViewport = new PageViewport(viewArea,
  415. pageNumber, pageNumberString,
  416. pageMaster, blank);
  417. transferForeignObjects(attributes, currentPageViewport);
  418. currentPageViewport.setKey(key);
  419. pageViewportsByKey.put(key, currentPageViewport);
  420. }
  421. }
  422. private class PageMaker extends AbstractMaker {
  423. public void startElement(Attributes attributes) {
  424. Page p = new Page();
  425. currentPageViewport.setPage(p);
  426. }
  427. public void endElement() {
  428. treeModel.addPage(currentPageViewport);
  429. currentPageViewport = null;
  430. }
  431. }
  432. private class RegionViewportMaker extends AbstractMaker {
  433. public void startElement(Attributes attributes) {
  434. RegionViewport rv = getCurrentRegionViewport();
  435. if (rv != null) {
  436. throw new IllegalStateException("Current RegionViewport must be null");
  437. }
  438. Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "rect");
  439. rv = new RegionViewport(viewArea);
  440. transferForeignObjects(attributes, rv);
  441. rv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
  442. setAreaAttributes(attributes, rv);
  443. setTraits(attributes, rv, SUBSET_COMMON);
  444. setTraits(attributes, rv, SUBSET_BOX);
  445. setTraits(attributes, rv, SUBSET_COLOR);
  446. areaStack.push(rv);
  447. }
  448. public void endElement() {
  449. assertObjectOfClass(areaStack.pop(), RegionViewport.class);
  450. }
  451. }
  452. private class RegionBeforeMaker extends AbstractMaker {
  453. public void startElement(Attributes attributes) {
  454. pushNewRegionReference(attributes, Constants.FO_REGION_BEFORE);
  455. }
  456. public void endElement() {
  457. assertObjectOfClass(areaStack.pop(), RegionReference.class);
  458. }
  459. }
  460. private class RegionAfterMaker extends AbstractMaker {
  461. public void startElement(Attributes attributes) {
  462. pushNewRegionReference(attributes, Constants.FO_REGION_AFTER);
  463. }
  464. public void endElement() {
  465. assertObjectOfClass(areaStack.pop(), RegionReference.class);
  466. }
  467. }
  468. private class RegionStartMaker extends AbstractMaker {
  469. public void startElement(Attributes attributes) {
  470. pushNewRegionReference(attributes, Constants.FO_REGION_START);
  471. }
  472. public void endElement() {
  473. assertObjectOfClass(areaStack.pop(), RegionReference.class);
  474. }
  475. }
  476. private class RegionEndMaker extends AbstractMaker {
  477. public void startElement(Attributes attributes) {
  478. pushNewRegionReference(attributes, Constants.FO_REGION_END);
  479. }
  480. public void endElement() {
  481. assertObjectOfClass(areaStack.pop(), RegionReference.class);
  482. }
  483. }
  484. private class RegionBodyMaker extends AbstractMaker {
  485. public void startElement(Attributes attributes) {
  486. BodyRegion body = getCurrentBodyRegion();
  487. if (body != null) {
  488. throw new IllegalStateException("Current BodyRegion must be null");
  489. }
  490. String regionName = attributes.getValue("name");
  491. int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1);
  492. int columnGap = XMLUtil.getAttributeAsInt(attributes, "columnGap", 0);
  493. RegionViewport rv = getCurrentRegionViewport();
  494. body = new BodyRegion(Constants.FO_REGION_BODY,
  495. regionName, rv, columnCount, columnGap);
  496. transferForeignObjects(attributes, body);
  497. body.setCTM(getAttributeAsCTM(attributes, "ctm"));
  498. setAreaAttributes(attributes, body);
  499. setTraits(attributes, body, SUBSET_BORDER_PADDING);
  500. rv.setRegionReference(body);
  501. currentPageViewport.getPage().setRegionViewport(
  502. Constants.FO_REGION_BODY, rv);
  503. areaStack.push(body);
  504. }
  505. public void endElement() {
  506. assertObjectOfClass(areaStack.pop(), BodyRegion.class);
  507. }
  508. }
  509. private class FlowMaker extends AbstractMaker {
  510. public void startElement(Attributes attributes) {
  511. BodyRegion body = getCurrentBodyRegion();
  512. if (!firstFlow) {
  513. body.getMainReference().getCurrentSpan().moveToNextFlow();
  514. } else {
  515. firstFlow = false;
  516. }
  517. NormalFlow flow = body.getMainReference().getCurrentSpan().getCurrentFlow();
  518. transferForeignObjects(attributes, flow);
  519. setAreaAttributes(attributes, flow);
  520. areaStack.push(flow);
  521. }
  522. public void endElement() {
  523. assertObjectOfClass(areaStack.pop(), NormalFlow.class);
  524. }
  525. }
  526. private class MainReferenceMaker extends AbstractMaker {
  527. public void startElement(Attributes attributes) {
  528. //mainReference is created by the BodyRegion
  529. MainReference mr = getCurrentBodyRegion().getMainReference();
  530. transferForeignObjects(attributes, mr);
  531. setAreaAttributes(attributes, mr);
  532. }
  533. }
  534. private class SpanMaker extends AbstractMaker {
  535. public void startElement(Attributes attributes) {
  536. int ipd = XMLUtil.getAttributeAsInt(attributes, "ipd", 0);
  537. int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1);
  538. BodyRegion body = getCurrentBodyRegion();
  539. Span span = new Span(columnCount,
  540. body.getColumnGap(), ipd);
  541. transferForeignObjects(attributes, span);
  542. setAreaAttributes(attributes, span);
  543. body.getMainReference().getSpans().add(span);
  544. firstFlow = true;
  545. }
  546. }
  547. private class FootnoteMaker extends AbstractMaker {
  548. public void startElement(Attributes attributes) {
  549. Footnote fn = getCurrentBodyRegion().getFootnote();
  550. transferForeignObjects(attributes, fn);
  551. fn.setTop(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
  552. areaStack.push(fn);
  553. }
  554. public void endElement() {
  555. assertObjectOfClass(areaStack.pop(), Footnote.class);
  556. }
  557. }
  558. private class BeforeFloatMaker extends AbstractMaker {
  559. public void startElement(Attributes attributes) {
  560. BeforeFloat bf = getCurrentBodyRegion().getBeforeFloat();
  561. transferForeignObjects(attributes, bf);
  562. areaStack.push(bf);
  563. }
  564. public void endElement() {
  565. assertObjectOfClass(areaStack.pop(), BeforeFloat.class);
  566. }
  567. }
  568. private class BlockMaker extends AbstractMaker {
  569. public void startElement(Attributes attributes) {
  570. boolean isViewport = XMLUtil.getAttributeAsBoolean(attributes,
  571. "is-viewport-area", false);
  572. Block block;
  573. if (isViewport) {
  574. BlockViewport bv = new BlockViewport();
  575. bv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
  576. bv.setCTM(getAttributeAsCTM(attributes, "ctm"));
  577. if (bv.getPositioning() != BlockViewport.RELATIVE) {
  578. bv.setXOffset(
  579. XMLUtil.getAttributeAsInt(attributes, "left-position", 0));
  580. bv.setYOffset(
  581. XMLUtil.getAttributeAsInt(attributes, "top-position", 0));
  582. }
  583. block = bv;
  584. } else {
  585. block = new Block();
  586. }
  587. String positioning = attributes.getValue("positioning");
  588. if ("absolute".equalsIgnoreCase(positioning)) {
  589. block.setPositioning(Block.ABSOLUTE);
  590. } else if ("fixed".equalsIgnoreCase(positioning)) {
  591. block.setPositioning(Block.FIXED);
  592. } else if ("relative".equalsIgnoreCase(positioning)) {
  593. block.setPositioning(Block.RELATIVE);
  594. } else {
  595. block.setPositioning(Block.STACK);
  596. }
  597. if (attributes.getValue("left-offset") != null) {
  598. block.setXOffset(XMLUtil.getAttributeAsInt(attributes, "left-offset", 0));
  599. }
  600. if (attributes.getValue("top-offset") != null) {
  601. block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
  602. }
  603. transferForeignObjects(attributes, block);
  604. setAreaAttributes(attributes, block);
  605. setTraits(attributes, block, SUBSET_COMMON);
  606. setTraits(attributes, block, SUBSET_BOX);
  607. setTraits(attributes, block, SUBSET_COLOR);
  608. Area parent = (Area)areaStack.peek();
  609. //BlockParent parent = getCurrentBlockParent();
  610. parent.addChildArea(block);
  611. areaStack.push(block);
  612. }
  613. public void endElement() {
  614. assertObjectOfClass(areaStack.pop(), Block.class);
  615. }
  616. }
  617. private class LineAreaMaker extends AbstractMaker {
  618. public void startElement(Attributes attributes) {
  619. LineArea line = new LineArea();
  620. setAreaAttributes(attributes, line);
  621. setTraits(attributes, line, SUBSET_COMMON);
  622. setTraits(attributes, line, SUBSET_BOX);
  623. setTraits(attributes, line, SUBSET_COLOR);
  624. BlockParent parent = getCurrentBlockParent();
  625. parent.addChildArea(line);
  626. areaStack.push(line);
  627. }
  628. public void endElement() {
  629. assertObjectOfClass(areaStack.pop(), LineArea.class);
  630. }
  631. }
  632. // Maker for "generic" inline areas
  633. private class InlineMaker extends AbstractMaker {
  634. public void startElement(Attributes attributes) {
  635. InlineArea inl = new InlineArea();
  636. transferForeignObjects(attributes, inl);
  637. inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  638. setAreaAttributes(attributes, inl);
  639. setTraits(attributes, inl, SUBSET_COMMON);
  640. setTraits(attributes, inl, SUBSET_BOX);
  641. setTraits(attributes, inl, SUBSET_COLOR);
  642. Area parent = (Area)areaStack.peek();
  643. parent.addChildArea(inl);
  644. areaStack.push(inl);
  645. }
  646. public void endElement() {
  647. assertObjectOfClass(areaStack.pop(), InlineArea.class);
  648. }
  649. }
  650. private class InlineParentMaker extends AbstractMaker {
  651. public void startElement(Attributes attributes) {
  652. InlineParent ip = new InlineParent();
  653. transferForeignObjects(attributes, ip);
  654. ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  655. setAreaAttributes(attributes, ip);
  656. setTraits(attributes, ip, SUBSET_COMMON);
  657. setTraits(attributes, ip, SUBSET_BOX);
  658. setTraits(attributes, ip, SUBSET_COLOR);
  659. setTraits(attributes, ip, SUBSET_LINK);
  660. setPtr(ip, attributes);
  661. Area parent = (Area)areaStack.peek();
  662. parent.addChildArea(ip);
  663. areaStack.push(ip);
  664. }
  665. public void endElement() {
  666. assertObjectOfClass(areaStack.pop(), InlineParent.class);
  667. }
  668. }
  669. private class InlineBlockParentMaker extends AbstractMaker {
  670. public void startElement(Attributes attributes) {
  671. InlineBlockParent ibp = new InlineBlockParent();
  672. transferForeignObjects(attributes, ibp);
  673. ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  674. setAreaAttributes(attributes, ibp);
  675. setTraits(attributes, ibp, SUBSET_COMMON);
  676. setTraits(attributes, ibp, SUBSET_BOX);
  677. setTraits(attributes, ibp, SUBSET_COLOR);
  678. Area parent = (Area)areaStack.peek();
  679. parent.addChildArea(ibp);
  680. areaStack.push(ibp);
  681. }
  682. public void endElement() {
  683. assertObjectOfClass(areaStack.pop(), InlineBlockParent.class);
  684. }
  685. }
  686. private class TextMaker extends AbstractMaker {
  687. public void startElement(Attributes attributes) {
  688. if (getCurrentText() != null) {
  689. throw new IllegalStateException("Current Text must be null");
  690. }
  691. TextArea text = new TextArea();
  692. setAreaAttributes(attributes, text);
  693. setTraits(attributes, text, SUBSET_COMMON);
  694. setTraits(attributes, text, SUBSET_BOX);
  695. setTraits(attributes, text, SUBSET_COLOR);
  696. setTraits(attributes, text, SUBSET_FONT);
  697. text.setBaselineOffset(XMLUtil.getAttributeAsInt(attributes, "baseline", 0));
  698. text.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  699. text.setTextLetterSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
  700. "tlsadjust", 0));
  701. text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
  702. "twsadjust", 0));
  703. setPtr(text, attributes);
  704. Area parent = (Area)areaStack.peek();
  705. parent.addChildArea(text);
  706. areaStack.push(text);
  707. }
  708. public void endElement() {
  709. assertObjectOfClass(areaStack.pop(), TextArea.class);
  710. }
  711. }
  712. private class WordMaker extends AbstractMaker {
  713. public void endElement() {
  714. int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0);
  715. int[] letterAdjust
  716. = ConversionUtils.toIntArray(
  717. lastAttributes.getValue("letter-adjust"), "\\s");
  718. content.flip();
  719. WordArea word = new WordArea(content.toString().trim(), offset, letterAdjust);
  720. AbstractTextArea text = getCurrentText();
  721. word.setParentArea(text);
  722. text.addChildArea(word);
  723. }
  724. public boolean ignoreCharacters() {
  725. return false;
  726. }
  727. }
  728. private class SpaceMaker extends AbstractMaker {
  729. public void endElement() {
  730. int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0);
  731. //TODO the isAdjustable parameter is currently not used/implemented
  732. if (content.position() > 0) {
  733. content.flip();
  734. boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true);
  735. SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable);
  736. AbstractTextArea text = getCurrentText();
  737. space.setParentArea(text);
  738. text.addChildArea(space);
  739. } else {
  740. Space space = new Space();
  741. setAreaAttributes(lastAttributes, space);
  742. setTraits(lastAttributes, space, SUBSET_COMMON);
  743. setTraits(lastAttributes, space, SUBSET_BOX);
  744. setTraits(lastAttributes, space, SUBSET_COLOR);
  745. space.setOffset(offset);
  746. Area parent = (Area)areaStack.peek();
  747. parent.addChildArea(space);
  748. }
  749. }
  750. public boolean ignoreCharacters() {
  751. return false;
  752. }
  753. }
  754. private class LeaderMaker extends AbstractMaker {
  755. public void startElement(Attributes attributes) {
  756. Leader leader = new Leader();
  757. transferForeignObjects(attributes, leader);
  758. setAreaAttributes(attributes, leader);
  759. setTraits(attributes, leader, SUBSET_COMMON);
  760. setTraits(attributes, leader, SUBSET_BOX);
  761. setTraits(attributes, leader, SUBSET_COLOR);
  762. setTraits(attributes, leader, SUBSET_FONT);
  763. leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  764. String ruleStyle = attributes.getValue("ruleStyle");
  765. if (ruleStyle != null) {
  766. leader.setRuleStyle(ruleStyle);
  767. }
  768. leader.setRuleThickness(
  769. XMLUtil.getAttributeAsInt(attributes, "ruleThickness", 0));
  770. Area parent = (Area)areaStack.peek();
  771. parent.addChildArea(leader);
  772. }
  773. }
  774. private class ViewportMaker extends AbstractMaker {
  775. public void startElement(Attributes attributes) {
  776. Viewport viewport = new Viewport(null);
  777. transferForeignObjects(attributes, viewport);
  778. setAreaAttributes(attributes, viewport);
  779. setTraits(attributes, viewport, SUBSET_COMMON);
  780. setTraits(attributes, viewport, SUBSET_BOX);
  781. setTraits(attributes, viewport, SUBSET_COLOR);
  782. viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
  783. viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
  784. viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
  785. setPtr(viewport, attributes);
  786. Area parent = (Area)areaStack.peek();
  787. parent.addChildArea(viewport);
  788. areaStack.push(viewport);
  789. }
  790. public void endElement() {
  791. assertObjectOfClass(areaStack.pop(), Viewport.class);
  792. }
  793. }
  794. private class ImageMaker extends AbstractMaker {
  795. public void startElement(Attributes attributes) {
  796. String url = attributes.getValue("url");
  797. Image image = new Image(url);
  798. transferForeignObjects(attributes, image);
  799. setAreaAttributes(attributes, image);
  800. setTraits(attributes, image, SUBSET_COMMON);
  801. setPtr(image, attributes);
  802. getCurrentViewport().setContent(image);
  803. }
  804. }
  805. private class ForeignObjectMaker extends AbstractMaker {
  806. public void startElement(Attributes attributes) throws SAXException {
  807. String ns = attributes.getValue("ns");
  808. domImplementation
  809. = elementMappingRegistry.getDOMImplementationForNamespace(ns);
  810. if (domImplementation == null) {
  811. throw new SAXException("No DOMImplementation could be"
  812. + " identified to handle namespace: " + ns);
  813. }
  814. ForeignObject foreign = new ForeignObject(ns);
  815. transferForeignObjects(attributes, foreign);
  816. setAreaAttributes(attributes, foreign);
  817. setTraits(attributes, foreign, SUBSET_COMMON);
  818. getCurrentViewport().setContent(foreign);
  819. areaStack.push(foreign);
  820. }
  821. public void endElement() {
  822. assertObjectOfClass(areaStack.pop(), ForeignObject.class);
  823. }
  824. }
  825. private class BookmarkTreeMaker extends AbstractMaker {
  826. public void startElement(Attributes attributes) {
  827. BookmarkData bm = new BookmarkData();
  828. areaStack.push(bm);
  829. }
  830. public void endElement() {
  831. Object tos = areaStack.pop();
  832. assertObjectOfClass(tos, BookmarkData.class);
  833. treeModel.handleOffDocumentItem((BookmarkData) tos);
  834. // as long as the bookmark tree comes after the last PageViewport in the
  835. // area tree XML, we don't have to worry about resolved/unresolved. The
  836. // only resolution needed is the mapping of the pvKey to the PV instance.
  837. }
  838. }
  839. private class BookmarkMaker extends AbstractMaker {
  840. public void startElement(Attributes attributes) {
  841. String title = attributes.getValue("title");
  842. boolean showChildren = XMLUtil.getAttributeAsBoolean(
  843. attributes, "show-children", false);
  844. String[] linkdata
  845. = InternalLink.parseXMLAttribute(attributes.getValue("internal-link"));
  846. PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]);
  847. BookmarkData bm = new BookmarkData(title, showChildren, pv, linkdata[1]);
  848. Object tos = areaStack.peek();
  849. if (tos instanceof BookmarkData) {
  850. BookmarkData parent = (BookmarkData) tos;
  851. parent.addSubData(bm);
  852. }
  853. areaStack.push(bm);
  854. }
  855. public void endElement() {
  856. assertObjectOfClass(areaStack.pop(), BookmarkData.class);
  857. }
  858. }
  859. private class DestinationMaker extends AbstractMaker {
  860. public void startElement(Attributes attributes) {
  861. String[] linkdata
  862. = InternalLink.parseXMLAttribute(lastAttributes.getValue("internal-link"));
  863. PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]);
  864. DestinationData dest = new DestinationData(linkdata[1]);
  865. List pages = new java.util.ArrayList();
  866. pages.add(pv);
  867. dest.resolveIDRef(linkdata[1], pages);
  868. areaStack.push(dest);
  869. }
  870. public void endElement() {
  871. Object tos = areaStack.pop();
  872. assertObjectOfClass(tos, DestinationData.class);
  873. treeModel.handleOffDocumentItem((DestinationData) tos);
  874. }
  875. }
  876. // ====================================================================
  877. private void pushNewRegionReference(Attributes attributes, int side) {
  878. String regionName = attributes.getValue("name");
  879. RegionViewport rv = getCurrentRegionViewport();
  880. RegionReference reg = new RegionReference(side,
  881. regionName, rv);
  882. transferForeignObjects(attributes, reg);
  883. reg.setCTM(getAttributeAsCTM(attributes, "ctm"));
  884. setAreaAttributes(attributes, reg);
  885. setTraits(attributes, reg, SUBSET_BORDER_PADDING);
  886. rv.setRegionReference(reg);
  887. currentPageViewport.getPage().setRegionViewport(
  888. side, rv);
  889. areaStack.push(reg);
  890. }
  891. private void assertObjectOfClass(Object obj, Class clazz) {
  892. if (!clazz.isInstance(obj)) {
  893. throw new IllegalStateException("Object is not an instance of "
  894. + clazz.getName() + " but of " + obj.getClass().getName());
  895. }
  896. }
  897. /**
  898. * Handles objects created by "sub-parsers" that implement the ObjectSource interface.
  899. * An example of object handled here are ExtensionAttachments.
  900. * @param obj the Object to be handled.
  901. */
  902. protected void handleExternallyGeneratedObject(Object obj) {
  903. if (areaStack.size() == 0 && obj instanceof ExtensionAttachment) {
  904. ExtensionAttachment attachment = (ExtensionAttachment)obj;
  905. if (this.currentPageViewport == null) {
  906. this.treeModel.handleOffDocumentItem(
  907. new OffDocumentExtensionAttachment(attachment));
  908. } else {
  909. this.currentPageViewport.addExtensionAttachment(attachment);
  910. }
  911. } else {
  912. Object o = areaStack.peek();
  913. if (o instanceof AreaTreeObject && obj instanceof ExtensionAttachment) {
  914. AreaTreeObject ato = (AreaTreeObject)o;
  915. ExtensionAttachment attachment = (ExtensionAttachment)obj;
  916. ato.addExtensionAttachment(attachment);
  917. } else {
  918. log.warn("Don't know how to handle externally generated object: " + obj);
  919. }
  920. }
  921. }
  922. private void setAreaAttributes(Attributes attributes, Area area) {
  923. area.setIPD(Integer.parseInt(attributes.getValue("ipd")));
  924. area.setBPD(Integer.parseInt(attributes.getValue("bpd")));
  925. }
  926. private static final Object[] SUBSET_COMMON = new Object[] {
  927. Trait.PROD_ID};
  928. private static final Object[] SUBSET_LINK = new Object[] {
  929. Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK};
  930. private static final Object[] SUBSET_COLOR = new Object[] {
  931. Trait.BACKGROUND, Trait.COLOR};
  932. private static final Object[] SUBSET_FONT = new Object[] {
  933. Trait.FONT, Trait.FONT_SIZE, Trait.BLINK,
  934. Trait.OVERLINE, Trait.OVERLINE_COLOR,
  935. Trait.LINETHROUGH, Trait.LINETHROUGH_COLOR,
  936. Trait.UNDERLINE, Trait.UNDERLINE_COLOR};
  937. private static final Object[] SUBSET_BOX = new Object[] {
  938. Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END,
  939. Trait.SPACE_BEFORE, Trait.SPACE_AFTER, Trait.SPACE_START, Trait.SPACE_END,
  940. Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END,
  941. Trait.START_INDENT, Trait.END_INDENT,
  942. Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA};
  943. private static final Object[] SUBSET_BORDER_PADDING = new Object[] {
  944. Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END,
  945. Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END};
  946. private void setTraits(Attributes attributes, Area area, Object[] traitSubset) {
  947. for (int i = traitSubset.length; --i >= 0;) {
  948. Object trait = traitSubset[i];
  949. String traitName = Trait.getTraitName(trait);
  950. String value = attributes.getValue(traitName);
  951. if (value != null) {
  952. Class cl = Trait.getTraitClass(trait);
  953. if (cl == Integer.class) {
  954. area.addTrait(trait, new Integer(value));
  955. } else if (cl == Boolean.class) {
  956. area.addTrait(trait, Boolean.valueOf(value));
  957. } else if (cl == String.class) {
  958. area.addTrait(trait, value);
  959. if (trait == Trait.PROD_ID
  960. && !idFirstsAssigned.contains(value)
  961. && currentPageViewport != null) {
  962. currentPageViewport.setFirstWithID(value);
  963. idFirstsAssigned.add(value);
  964. }
  965. } else if (cl == Color.class) {
  966. try {
  967. area.addTrait(trait, ColorUtil.parseColorString(this.userAgent, value));
  968. } catch (PropertyException e) {
  969. throw new IllegalArgumentException(e.getMessage());
  970. }
  971. } else if (cl == InternalLink.class) {
  972. area.addTrait(trait, new InternalLink(value));
  973. } else if (cl == Trait.ExternalLink.class) {
  974. area.addTrait(trait, Trait.ExternalLink.makeFromTraitValue(value));
  975. } else if (cl == Background.class) {
  976. Background bkg = new Background();
  977. try {
  978. Color col = ColorUtil.parseColorString(
  979. this.userAgent, attributes.getValue("bkg-color"));
  980. bkg.setColor(col);
  981. } catch (PropertyException e) {
  982. throw new IllegalArgumentException(e.getMessage());
  983. }
  984. String uri = attributes.getValue("bkg-img");
  985. if (uri != null) {
  986. bkg.setURL(uri);
  987. try {
  988. ImageManager manager = userAgent.getFactory().getImageManager();
  989. ImageSessionContext sessionContext
  990. = userAgent.getImageSessionContext();
  991. ImageInfo info = manager.getImageInfo(uri, sessionContext);
  992. bkg.setImageInfo(info);
  993. } catch (ImageException e) {
  994. ResourceEventProducer eventProducer
  995. = ResourceEventProducer.Provider.get(
  996. this.userAgent.getEventBroadcaster());
  997. eventProducer.imageError(this, uri, e, getLocator());
  998. } catch (FileNotFoundException fnfe) {
  999. ResourceEventProducer eventProducer
  1000. = ResourceEventProducer.Provider.get(
  1001. this.userAgent.getEventBroadcaster());
  1002. eventProducer.imageNotFound(this, uri, fnfe, getLocator());
  1003. } catch (IOException ioe) {
  1004. ResourceEventProducer eventProducer
  1005. = ResourceEventProducer.Provider.get(
  1006. this.userAgent.getEventBroadcaster());
  1007. eventProducer.imageIOError(this, uri, ioe, getLocator());
  1008. }
  1009. String repeat = attributes.getValue("bkg-repeat");
  1010. if (repeat != null) {
  1011. bkg.setRepeat(repeat);
  1012. }
  1013. bkg.setHoriz(XMLUtil.getAttributeAsInt(attributes,
  1014. "bkg-horz-offset", 0));
  1015. bkg.setVertical(XMLUtil.getAttributeAsInt(attributes,
  1016. "bkg-vert-offset", 0));
  1017. }
  1018. area.addTrait(trait, bkg);
  1019. } else if (cl == BorderProps.class) {
  1020. area.addTrait(trait, BorderProps.valueOf(this.userAgent, value));
  1021. }
  1022. } else {
  1023. if (trait == Trait.FONT) {
  1024. String fontName = attributes.getValue("font-name");
  1025. if (fontName != null) {
  1026. String fontStyle = attributes.getValue("font-style");
  1027. int fontWeight = XMLUtil.getAttributeAsInt(
  1028. attributes, "font-weight", Font.WEIGHT_NORMAL);
  1029. area.addTrait(trait,
  1030. FontInfo.createFontKey(fontName, fontStyle, fontWeight));
  1031. }
  1032. }
  1033. }
  1034. }
  1035. }
  1036. private static CTM getAttributeAsCTM(Attributes attributes, String name) {
  1037. String s = attributes.getValue(name).trim();
  1038. if (s.startsWith("[") && s.endsWith("]")) {
  1039. s = s.substring(1, s.length() - 1);
  1040. double[] values = ConversionUtils.toDoubleArray(s, "\\s");
  1041. if (values.length != 6) {
  1042. throw new IllegalArgumentException("CTM must consist of 6 double values!");
  1043. }
  1044. return new CTM(values[0], values[1], values[2], values[3], values[4], values[5]);
  1045. } else {
  1046. throw new IllegalArgumentException("CTM must be surrounded by square brackets!");
  1047. }
  1048. }
  1049. private static void transferForeignObjects(Attributes atts, AreaTreeObject ato) {
  1050. for (int i = 0, c = atts.getLength(); i < c; i++) {
  1051. String ns = atts.getURI(i);
  1052. if (ns.length() > 0) {
  1053. if (XMLConstants.XMLNS_NAMESPACE_URI.equals(ns)) {
  1054. continue;
  1055. }
  1056. QName qname = new QName(ns, atts.getQName(i));
  1057. ato.setForeignAttribute(qname, atts.getValue(i));
  1058. }
  1059. }
  1060. }
  1061. private void setPtr(Area area, Attributes attributes) {
  1062. String ptr = attributes.getValue("ptr");
  1063. if (ptr != null) {
  1064. area.addTrait(Trait.PTR, ptr);
  1065. }
  1066. }
  1067. /** {@inheritDoc} */
  1068. public void characters(char[] ch, int start, int length) throws SAXException {
  1069. if (delegate != null) {
  1070. delegate.characters(ch, start, length);
  1071. } else if (!ignoreCharacters) {
  1072. int maxLength = this.content.capacity() - this.content.position();
  1073. if (maxLength < length) {
  1074. // allocate a larger buffer and transfer content
  1075. CharBuffer newContent
  1076. = CharBuffer.allocate(this.content.position() + length);
  1077. this.content.flip();
  1078. newContent.put(this.content);
  1079. this.content = newContent;
  1080. }
  1081. // make sure the full capacity is used
  1082. this.content.limit(this.content.capacity());
  1083. // add characters to the buffer
  1084. this.content.put(ch, start, length);
  1085. // decrease the limit, if necessary
  1086. if (this.content.position() < this.content.limit()) {
  1087. this.content.limit(this.content.position());
  1088. }
  1089. }
  1090. }
  1091. }
  1092. }