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.

AreaTreeParser.java 52KB

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