1 17 18 19 20 package org.apache.fop.area; 21 22 import java.awt.Color ; 23 import java.awt.geom.Rectangle2D ; 24 import java.util.List ; 25 import java.util.Map ; 26 import java.util.Stack ; 27 import java.util.StringTokenizer ; 28 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 38 import org.apache.commons.logging.Log; 39 import org.apache.commons.logging.LogFactory; 40 import org.apache.fop.apps.FOUserAgent; 41 import org.apache.fop.area.Trait.Background; 42 import org.apache.fop.area.inline.AbstractTextArea; 43 import org.apache.fop.area.inline.Character; 44 import org.apache.fop.area.inline.ForeignObject; 45 import org.apache.fop.area.inline.Image; 46 import org.apache.fop.area.inline.InlineBlockParent; 47 import org.apache.fop.area.inline.InlineParent; 48 import org.apache.fop.area.inline.Leader; 49 import org.apache.fop.area.inline.Space; 50 import org.apache.fop.area.inline.SpaceArea; 51 import org.apache.fop.area.inline.TextArea; 52 import org.apache.fop.area.inline.Viewport; 53 import org.apache.fop.area.inline.WordArea; 54 import org.apache.fop.fo.Constants; 55 import org.apache.fop.fo.ElementMappingRegistry; 56 import org.apache.fop.fo.expr.PropertyException; 57 import org.apache.fop.fo.extensions.ExtensionAttachment; 58 import org.apache.fop.fonts.Font; 59 import org.apache.fop.fonts.FontInfo; 60 import org.apache.fop.image.FopImage; 61 import org.apache.fop.image.ImageFactory; 62 import org.apache.fop.traits.BorderProps; 63 import org.apache.fop.util.ColorUtil; 64 import org.apache.fop.util.ContentHandlerFactory; 65 import org.apache.fop.util.ContentHandlerFactoryRegistry; 66 import org.apache.fop.util.DefaultErrorListener; 67 import org.apache.fop.util.QName; 68 import org.w3c.dom.DOMImplementation ; 69 import org.w3c.dom.Document ; 70 import org.xml.sax.Attributes ; 71 import org.xml.sax.ContentHandler ; 72 import org.xml.sax.SAXException ; 73 import org.xml.sax.helpers.DefaultHandler ; 74 75 79 public class AreaTreeParser { 80 81 82 protected static Log log = LogFactory.getLog(AreaTreeParser.class); 83 84 private static SAXTransformerFactory tFactory 85 = (SAXTransformerFactory )SAXTransformerFactory.newInstance(); 86 87 95 public void parse(Source src, AreaTreeModel treeModel, FOUserAgent userAgent) 96 throws TransformerException { 97 Transformer transformer = tFactory.newTransformer(); 98 transformer.setErrorListener(new DefaultErrorListener(log)); 99 100 SAXResult res = new SAXResult (getContentHandler(treeModel, userAgent)); 101 102 transformer.transform(src, res); 103 } 104 105 112 public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) { 113 ElementMappingRegistry elementMappingRegistry 114 = userAgent.getFactory().getElementMappingRegistry(); 115 return new Handler (treeModel, userAgent, elementMappingRegistry); 116 } 117 118 private static class Handler extends DefaultHandler { 119 120 private Map makers = new java.util.HashMap (); 121 122 private AreaTreeModel treeModel; 123 private FOUserAgent userAgent; 124 private ElementMappingRegistry elementMappingRegistry; 125 126 private Attributes lastAttributes; 127 private StringBuffer content = new StringBuffer (); 128 129 private PageViewport currentPageViewport; 130 private Stack areaStack = new Stack (); 131 private boolean firstFlow; 132 private boolean pendingStartPageSequence; 133 134 private Stack delegateStack = new Stack (); 135 private ContentHandler delegate; 136 private DOMImplementation domImplementation; 137 138 139 public Handler(AreaTreeModel treeModel, FOUserAgent userAgent, 140 ElementMappingRegistry elementMappingRegistry) { 141 this.treeModel = treeModel; 142 this.userAgent = userAgent; 143 this.elementMappingRegistry = elementMappingRegistry; 144 makers.put("areaTree", new AreaTreeMaker()); 145 makers.put("page", new PageMaker()); 146 makers.put("pageSequence", new PageSequenceMaker()); 147 makers.put("title", new TitleMaker()); 148 makers.put("pageViewport", new PageViewportMaker()); 149 makers.put("regionViewport", new RegionViewportMaker()); 150 makers.put("regionBefore", new RegionBeforeMaker()); 151 makers.put("regionAfter", new RegionAfterMaker()); 152 makers.put("regionStart", new RegionStartMaker()); 153 makers.put("regionEnd", new RegionEndMaker()); 154 makers.put("regionBody", new RegionBodyMaker()); 155 makers.put("flow", new FlowMaker()); 156 makers.put("mainReference", new MainReferenceMaker()); 157 makers.put("span", new SpanMaker()); 158 makers.put("footnote", new FootnoteMaker()); 159 makers.put("beforeFloat", new BeforeFloatMaker()); 160 makers.put("block", new BlockMaker()); 161 makers.put("lineArea", new LineAreaMaker()); 162 makers.put("inlineparent", new InlineParentMaker()); 163 makers.put("inlineblockparent", new InlineBlockParentMaker()); 164 makers.put("text", new TextMaker()); 165 makers.put("word", new WordMaker()); 166 makers.put("space", new SpaceMaker()); 167 makers.put("char", new CharMaker()); 168 makers.put("leader", new LeaderMaker()); 169 makers.put("viewport", new ViewportMaker()); 170 makers.put("image", new ImageMaker()); 171 makers.put("foreignObject", new ForeignObjectMaker()); 172 } 173 174 private static Rectangle2D parseRect(String rect) { 175 StringTokenizer tokenizer = new StringTokenizer (rect, " "); 176 return new Rectangle2D.Double ( 177 Double.parseDouble(tokenizer.nextToken()), 178 Double.parseDouble(tokenizer.nextToken()), 179 Double.parseDouble(tokenizer.nextToken()), 180 Double.parseDouble(tokenizer.nextToken())); 181 } 182 183 private Area findAreaType(Class clazz) { 184 if (areaStack.size() > 0) { 185 int pos = areaStack.size() - 1; 186 Object obj = null; 187 while (pos >= 0 && !(clazz.isInstance(obj = areaStack.get(pos)))) { 188 pos--; 189 } 190 if (pos >= 0) { 191 return (Area)obj; 192 } 193 } 194 return null; 195 } 196 197 private RegionViewport getCurrentRegionViewport() { 198 return (RegionViewport)findAreaType(RegionViewport.class); 199 } 200 201 private BodyRegion getCurrentBodyRegion() { 202 return (BodyRegion)findAreaType(BodyRegion.class); 203 } 204 205 private BlockParent getCurrentBlockParent() { 206 return (BlockParent)findAreaType(BlockParent.class); 207 } 208 209 private AbstractTextArea getCurrentText() { 210 return (AbstractTextArea)findAreaType(AbstractTextArea.class); 211 } 212 213 private Viewport getCurrentViewport() { 214 return (Viewport)findAreaType(Viewport.class); 215 } 216 217 218 public void startElement(String uri, String localName, String qName, Attributes attributes) 219 throws SAXException { 220 if (delegate != null) { 221 delegateStack.push(qName); 222 delegate.startElement(uri, localName, qName, attributes); 223 } else if (domImplementation != null) { 224 TransformerHandler handler; 226 try { 227 handler = tFactory.newTransformerHandler(); 228 } catch (TransformerConfigurationException e) { 229 throw new SAXException ("Error creating a new TransformerHandler", e); 230 } 231 Document doc = domImplementation.createDocument(uri, qName, null); 232 doc.removeChild(doc.getDocumentElement()); 234 handler.setResult(new DOMResult (doc)); 235 Area parent = (Area)areaStack.peek(); 236 ((ForeignObject)parent).setDocument(doc); 237 238 domImplementation = null; this.delegate = handler; 241 delegateStack.push(qName); 242 delegate.startDocument(); 243 delegate.startElement(uri, localName, qName, attributes); 244 } else { 245 lastAttributes = attributes; 246 boolean handled = true; 247 if ("".equals(uri)) { 248 Maker maker = (Maker)makers.get(localName); 249 if (maker != null) { 250 maker.startElement(attributes); 251 } else if ("extension-attachments".equals(localName)) { 252 } else { 254 handled = false; 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 281 282 public void endElement(String uri, String localName, String qName) throws SAXException { 283 if (delegate != null) { 284 delegate.endElement(uri, localName, qName); 285 delegateStack.pop(); 286 if (delegateStack.size() == 0) { 287 delegate.endDocument(); 288 if (delegate instanceof ContentHandlerFactory.ObjectSource) { 289 Object obj = ((ContentHandlerFactory.ObjectSource)delegate).getObject(); 290 handleExternallyGeneratedObject(obj); 291 } 292 delegate = null; } 294 } else { 295 if ("".equals(uri)) { 296 Maker maker = (Maker)makers.get(localName); 297 if (maker != null) { 298 maker.endElement(); 299 } 300 } else { 301 } 303 content.setLength(0); } 305 } 306 307 309 private static interface Maker { 310 void startElement(Attributes attributes) throws SAXException ; 311 void endElement(); 312 } 313 314 private abstract class AbstractMaker implements Maker { 315 316 public void startElement(Attributes attributes) throws SAXException { 317 } 319 320 public void endElement() { 321 } 323 } 324 325 private class AreaTreeMaker extends AbstractMaker { 326 } 328 329 private class PageSequenceMaker extends AbstractMaker { 330 331 public void startElement(Attributes attributes) { 332 pendingStartPageSequence = true; 333 } 335 } 336 337 private class TitleMaker extends AbstractMaker { 338 339 public void startElement(Attributes attributes) { 340 LineArea line = new LineArea(); 341 transferForeignObjects(attributes, line); 342 areaStack.push(line); 343 } 344 345 public void endElement() { 346 LineArea line = (LineArea)areaStack.pop(); 347 treeModel.startPageSequence(line); 348 pendingStartPageSequence = false; 349 } 350 351 352 } 353 354 private class PageViewportMaker extends AbstractMaker { 355 356 public void startElement(Attributes attributes) { 357 if (pendingStartPageSequence) { 358 treeModel.startPageSequence(null); 359 pendingStartPageSequence = false; 360 } 361 if (currentPageViewport != null) { 362 throw new IllegalStateException ("currentPageViewport must be null"); 363 } 364 Rectangle2D viewArea = parseRect(attributes.getValue("bounds")); 365 int pageNumber = getAttributeAsInteger(attributes, "nr", -1); 366 String key = attributes.getValue("key"); 367 String pageNumberString = attributes.getValue("formatted-nr"); 368 String pageMaster = attributes.getValue("simple-page-master-name"); 369 boolean blank = getAttributeAsBoolean(attributes, "blank", false); 370 currentPageViewport = new PageViewport(viewArea, 371 pageNumber, pageNumberString, 372 pageMaster, blank); 373 transferForeignObjects(attributes, currentPageViewport); 374 currentPageViewport.setKey(key); 375 } 376 377 } 378 379 private class PageMaker extends AbstractMaker { 380 381 public void startElement(Attributes attributes) { 382 Page p = new Page(); 383 currentPageViewport.setPage(p); 384 } 385 386 public void endElement() { 387 treeModel.addPage(currentPageViewport); 388 currentPageViewport = null; 389 } 390 } 391 392 private class RegionViewportMaker extends AbstractMaker { 393 394 public void startElement(Attributes attributes) { 395 RegionViewport rv = getCurrentRegionViewport(); 396 if (rv != null) { 397 throw new IllegalStateException ("Current RegionViewport must be null"); 398 } 399 Rectangle2D viewArea = parseRect(attributes.getValue("rect")); 400 rv = new RegionViewport(viewArea); 401 transferForeignObjects(attributes, rv); 402 rv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); 403 setAreaAttributes(attributes, rv); 404 setTraits(attributes, rv, SUBSET_COMMON); 405 setTraits(attributes, rv, SUBSET_BOX); 406 setTraits(attributes, rv, SUBSET_COLOR); 407 areaStack.push(rv); 408 } 409 410 public void endElement() { 411 assertObjectOfClass(areaStack.pop(), RegionViewport.class); 412 } 413 } 414 415 private class RegionBeforeMaker extends AbstractMaker { 416 417 public void startElement(Attributes attributes) { 418 pushNewRegionReference(attributes, Constants.FO_REGION_BEFORE); 419 } 420 421 public void endElement() { 422 assertObjectOfClass(areaStack.pop(), RegionReference.class); 423 } 424 } 425 426 private class RegionAfterMaker extends AbstractMaker { 427 428 public void startElement(Attributes attributes) { 429 pushNewRegionReference(attributes, Constants.FO_REGION_AFTER); 430 } 431 432 public void endElement() { 433 assertObjectOfClass(areaStack.pop(), RegionReference.class); 434 } 435 } 436 437 private class RegionStartMaker extends AbstractMaker { 438 439 public void startElement(Attributes attributes) { 440 pushNewRegionReference(attributes, Constants.FO_REGION_START); 441 } 442 443 public void endElement() { 444 assertObjectOfClass(areaStack.pop(), RegionReference.class); 445 } 446 } 447 448 private class RegionEndMaker extends AbstractMaker { 449 450 public void startElement(Attributes attributes) { 451 pushNewRegionReference(attributes, Constants.FO_REGION_END); 452 } 453 454 public void endElement() { 455 assertObjectOfClass(areaStack.pop(), RegionReference.class); 456 } 457 } 458 459 private class RegionBodyMaker extends AbstractMaker { 460 461 public void startElement(Attributes attributes) { 462 BodyRegion body = getCurrentBodyRegion(); 463 if (body != null) { 464 throw new IllegalStateException ("Current BodyRegion must be null"); 465 } 466 String regionName = attributes.getValue("name"); 467 int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); 468 int columnGap = getAttributeAsInteger(attributes, "columnGap", 0); 469 RegionViewport rv = getCurrentRegionViewport(); 470 body = new BodyRegion(Constants.FO_REGION_BODY, 471 regionName, rv, columnCount, columnGap); 472 transferForeignObjects(attributes, body); 473 body.setCTM(getAttributeAsCTM(attributes, "ctm")); 474 setAreaAttributes(attributes, body); 475 rv.setRegionReference(body); 476 currentPageViewport.getPage().setRegionViewport( 477 Constants.FO_REGION_BODY, rv); 478 areaStack.push(body); 479 } 480 481 public void endElement() { 482 assertObjectOfClass(areaStack.pop(), BodyRegion.class); 483 } 484 } 485 486 private class FlowMaker extends AbstractMaker { 487 488 public void startElement(Attributes attributes) { 489 BodyRegion body = getCurrentBodyRegion(); 490 if (!firstFlow) { 491 body.getMainReference().getCurrentSpan().moveToNextFlow(); 492 } else { 493 firstFlow = false; 494 } 495 NormalFlow flow = body.getMainReference().getCurrentSpan().getCurrentFlow(); 496 transferForeignObjects(attributes, flow); 497 setAreaAttributes(attributes, flow); 498 areaStack.push(flow); 499 } 500 501 public void endElement() { 502 assertObjectOfClass(areaStack.pop(), NormalFlow.class); 503 } 504 } 505 506 private class MainReferenceMaker extends AbstractMaker { 507 508 public void startElement(Attributes attributes) { 509 MainReference mr = getCurrentBodyRegion().getMainReference(); 511 transferForeignObjects(attributes, mr); 512 setAreaAttributes(attributes, mr); 513 } 514 } 515 516 private class SpanMaker extends AbstractMaker { 517 518 public void startElement(Attributes attributes) { 519 int ipd = getAttributeAsInteger(attributes, "ipd", 0); 520 int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); 521 BodyRegion body = getCurrentBodyRegion(); 522 Span span = new Span(columnCount, 523 body.getColumnGap(), ipd); 524 transferForeignObjects(attributes, span); 525 setAreaAttributes(attributes, span); 526 body.getMainReference().getSpans().add(span); 527 firstFlow = true; 528 } 529 } 530 531 private class FootnoteMaker extends AbstractMaker { 532 533 public void startElement(Attributes attributes) { 534 Footnote fn = getCurrentBodyRegion().getFootnote(); 535 transferForeignObjects(attributes, fn); 536 areaStack.push(fn); 537 } 538 539 public void endElement() { 540 assertObjectOfClass(areaStack.pop(), Footnote.class); 541 } 542 } 543 544 private class BeforeFloatMaker extends AbstractMaker { 545 546 public void startElement(Attributes attributes) { 547 BeforeFloat bf = getCurrentBodyRegion().getBeforeFloat(); 548 transferForeignObjects(attributes, bf); 549 areaStack.push(bf); 550 } 551 552 public void endElement() { 553 assertObjectOfClass(areaStack.pop(), BeforeFloat.class); 554 } 555 } 556 557 private class BlockMaker extends AbstractMaker { 558 559 public void startElement(Attributes attributes) { 560 boolean isViewport = getAttributeAsBoolean(attributes, 561 "is-viewport-area", false); 562 Block block; 563 if (isViewport) { 564 BlockViewport bv = new BlockViewport(); 565 bv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); 566 bv.setCTM(getAttributeAsCTM(attributes, "ctm")); 567 if (bv.getPositioning() != BlockViewport.RELATIVE) { 568 bv.setXOffset( 569 getAttributeAsInteger(attributes, "left-position", 0)); 570 bv.setYOffset( 571 getAttributeAsInteger(attributes, "top-position", 0)); 572 } 573 block = bv; 574 } else { 575 block = new Block(); 576 } 577 String positioning = attributes.getValue("positioning"); 578 if ("absolute".equalsIgnoreCase(positioning)) { 579 block.setPositioning(Block.ABSOLUTE); 580 } else if ("fixed".equalsIgnoreCase(positioning)) { 581 block.setPositioning(Block.FIXED); 582 } else if ("relative".equalsIgnoreCase(positioning)) { 583 block.setPositioning(Block.RELATIVE); 584 } else { 585 block.setPositioning(Block.STACK); 586 } 587 if (attributes.getValue("left-offset") != null) { 588 block.setXOffset(getAttributeAsInteger(attributes, "left-offset", 0)); 589 } 590 if (attributes.getValue("top-offset") != null) { 591 block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0)); 592 } 593 transferForeignObjects(attributes, block); 594 setAreaAttributes(attributes, block); 595 setTraits(attributes, block, SUBSET_COMMON); 596 setTraits(attributes, block, SUBSET_BOX); 597 setTraits(attributes, block, SUBSET_COLOR); 598 Area parent = (Area)areaStack.peek(); 599 parent.addChildArea(block); 601 areaStack.push(block); 602 } 603 604 public void endElement() { 605 assertObjectOfClass(areaStack.pop(), Block.class); 606 } 607 } 608 609 private class LineAreaMaker extends AbstractMaker { 610 611 public void startElement(Attributes attributes) { 612 LineArea line = new LineArea(); 613 setAreaAttributes(attributes, line); 614 setTraits(attributes, line, SUBSET_COMMON); 615 setTraits(attributes, line, SUBSET_BOX); 616 setTraits(attributes, line, SUBSET_COLOR); 617 BlockParent parent = getCurrentBlockParent(); 618 parent.addChildArea(line); 619 areaStack.push(line); 620 } 621 622 public void endElement() { 623 assertObjectOfClass(areaStack.pop(), LineArea.class); 624 } 625 } 626 627 private class InlineParentMaker extends AbstractMaker { 628 629 public void startElement(Attributes attributes) { 630 InlineParent ip = new InlineParent(); 631 transferForeignObjects(attributes, ip); 632 ip.setOffset(getAttributeAsInteger(attributes, "offset", 0)); 633 setAreaAttributes(attributes, ip); 634 setTraits(attributes, ip, SUBSET_COMMON); 635 setTraits(attributes, ip, SUBSET_BOX); 636 setTraits(attributes, ip, SUBSET_COLOR); 637 setTraits(attributes, ip, SUBSET_LINK); 638 Area parent = (Area)areaStack.peek(); 639 parent.addChildArea(ip); 640 areaStack.push(ip); 641 } 642 643 public void endElement() { 644 assertObjectOfClass(areaStack.pop(), InlineParent.class); 645 } 646 } 647 648 private class InlineBlockParentMaker extends AbstractMaker { 649 650 public void startElement(Attributes attributes) { 651 InlineBlockParent ibp = new InlineBlockParent(); 652 transferForeignObjects(attributes, ibp); 653 ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0)); 654 setAreaAttributes(attributes, ibp); 655 setTraits(attributes, ibp, SUBSET_COMMON); 656 setTraits(attributes, ibp, SUBSET_BOX); 657 setTraits(attributes, ibp, SUBSET_COLOR); 658 Area parent = (Area)areaStack.peek(); 659 parent.addChildArea(ibp); 660 areaStack.push(ibp); 661 } 662 663 public void endElement() { 664 assertObjectOfClass(areaStack.pop(), InlineBlockParent.class); 665 } 666 } 667 668 private class TextMaker extends AbstractMaker { 669 670 public void startElement(Attributes attributes) { 671 if (getCurrentText() != null) { 672 throw new IllegalStateException ("Current Text must be null"); 673 } 674 TextArea text = new TextArea(); 675 setAreaAttributes(attributes, text); 676 setTraits(attributes, text, SUBSET_COMMON); 677 setTraits(attributes, text, SUBSET_BOX); 678 setTraits(attributes, text, SUBSET_COLOR); 679 setTraits(attributes, text, SUBSET_FONT); 680 text.setBaselineOffset(getAttributeAsInteger(attributes, "baseline", 0)); 681 text.setOffset(getAttributeAsInteger(attributes, "offset", 0)); 682 text.setTextLetterSpaceAdjust(getAttributeAsInteger(attributes, 683 "tlsadjust", 0)); 684 text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes, 685 "twsadjust", 0)); 686 Area parent = (Area)areaStack.peek(); 687 parent.addChildArea(text); 688 areaStack.push(text); 689 } 690 691 public void endElement() { 692 assertObjectOfClass(areaStack.pop(), TextArea.class); 693 } 694 } 695 696 private class WordMaker extends AbstractMaker { 697 698 private int[] toIntArray(String s) { 699 if (s == null || s.length() == 0) { 700 return null; 701 } 702 StringTokenizer tokenizer = new StringTokenizer (s, " "); 703 List values = new java.util.ArrayList (); 704 while (tokenizer.hasMoreTokens()) { 705 values.add(new Integer (tokenizer.nextToken())); 706 } 707 int[] res = new int[values.size()]; 708 for (int i = 0, c = res.length; i < c; i++) { 709 res[i] = ((Integer )values.get(i)).intValue(); 710 } 711 return res; 712 } 713 714 public void endElement() { 715 int offset = getAttributeAsInteger(lastAttributes, "offset", 0); 716 int[] letterAdjust = toIntArray(lastAttributes.getValue("letter-adjust")); 717 String txt = content.toString(); 718 WordArea word = new WordArea(txt, offset, letterAdjust); 719 AbstractTextArea text = getCurrentText(); 720 word.setParentArea(text); 721 text.addChildArea(word); 722 } 723 } 724 725 private class SpaceMaker extends AbstractMaker { 726 727 public void endElement() { 728 int offset = getAttributeAsInteger(lastAttributes, "offset", 0); 729 String txt = content.toString(); 730 if (txt.length() > 0) { 732 boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true); 733 SpaceArea space = new SpaceArea(txt.charAt(0), offset, adjustable); 734 AbstractTextArea text = getCurrentText(); 735 space.setParentArea(text); 736 text.addChildArea(space); 737 } else { 738 Space space = new Space(); 739 setAreaAttributes(lastAttributes, space); 740 setTraits(lastAttributes, space, SUBSET_COMMON); 741 setTraits(lastAttributes, space, SUBSET_BOX); 742 setTraits(lastAttributes, space, SUBSET_COLOR); 743 space.setOffset(offset); 744 Area parent = (Area)areaStack.peek(); 745 parent.addChildArea(space); 746 } 747 } 748 } 749 750 private class CharMaker extends AbstractMaker { 751 752 public void endElement() { 753 String txt = content.toString(); 754 Character ch = new Character (txt.charAt(0)); 755 transferForeignObjects(lastAttributes, ch); 756 setAreaAttributes(lastAttributes, ch); 757 setTraits(lastAttributes, ch, SUBSET_COMMON); 758 setTraits(lastAttributes, ch, SUBSET_BOX); 759 setTraits(lastAttributes, ch, SUBSET_COLOR); 760 setTraits(lastAttributes, ch, SUBSET_FONT); 761 ch.setOffset(getAttributeAsInteger(lastAttributes, "offset", 0)); 762 ch.setBaselineOffset(getAttributeAsInteger(lastAttributes, "baseline", 0)); 763 Area parent = (Area)areaStack.peek(); 764 parent.addChildArea(ch); 765 } 766 } 767 768 private class LeaderMaker extends AbstractMaker { 769 770 public void startElement(Attributes attributes) { 771 Leader leader = new Leader(); 772 transferForeignObjects(attributes, leader); 773 setAreaAttributes(attributes, leader); 774 setTraits(attributes, leader, SUBSET_COMMON); 775 setTraits(attributes, leader, SUBSET_BOX); 776 setTraits(attributes, leader, SUBSET_COLOR); 777 setTraits(attributes, leader, SUBSET_FONT); 778 leader.setOffset(getAttributeAsInteger(attributes, "offset", 0)); 779 String ruleStyle = attributes.getValue("ruleStyle"); 780 if (ruleStyle != null) { 781 leader.setRuleStyle(ruleStyle); 782 } 783 leader.setRuleThickness( 784 getAttributeAsInteger(attributes, "ruleThickness", 0)); 785 Area parent = (Area)areaStack.peek(); 786 parent.addChildArea(leader); 787 } 788 789 public void endElement() { 790 } 791 } 792 793 private class ViewportMaker extends AbstractMaker { 794 795 public void startElement(Attributes attributes) { 796 Viewport viewport = new Viewport(null); 797 transferForeignObjects(attributes, viewport); 798 setAreaAttributes(attributes, viewport); 799 setTraits(attributes, viewport, SUBSET_COMMON); 800 setTraits(attributes, viewport, SUBSET_BOX); 801 setTraits(attributes, viewport, SUBSET_COLOR); 802 viewport.setContentPosition(getAttributeAsRectangle2D(attributes, "pos")); 803 viewport.setClip(getAttributeAsBoolean(attributes, "clip", false)); 804 viewport.setOffset(getAttributeAsInteger(attributes, "offset", 0)); 805 Area parent = (Area)areaStack.peek(); 806 parent.addChildArea(viewport); 807 areaStack.push(viewport); 808 } 809 810 public void endElement() { 811 assertObjectOfClass(areaStack.pop(), Viewport.class); 812 } 813 } 814 815 private class ImageMaker extends AbstractMaker { 816 817 public void startElement(Attributes attributes) { 818 String url = attributes.getValue("url"); 819 Image image = new Image(url); 820 transferForeignObjects(attributes, image); 821 setAreaAttributes(attributes, image); 822 setTraits(attributes, image, SUBSET_COMMON); 823 getCurrentViewport().setContent(image); 824 } 825 } 826 827 private class ForeignObjectMaker extends AbstractMaker { 828 829 public void startElement(Attributes attributes) throws SAXException { 830 String ns = attributes.getValue("ns"); 831 domImplementation 832 = elementMappingRegistry.getDOMImplementationForNamespace(ns); 833 if (domImplementation == null) { 834 throw new SAXException ("No DOMImplementation could be" 835 + " identified to handle namespace: " + ns); 836 } 837 ForeignObject foreign = new ForeignObject(ns); 838 transferForeignObjects(attributes, foreign); 839 setAreaAttributes(attributes, foreign); 840 setTraits(attributes, foreign, SUBSET_COMMON); 841 getCurrentViewport().setContent(foreign); 842 areaStack.push(foreign); 843 } 844 845 public void endElement() { 846 assertObjectOfClass(areaStack.pop(), ForeignObject.class); 847 } 848 } 849 850 852 853 private void pushNewRegionReference(Attributes attributes, int side) { 854 String regionName = attributes.getValue("name"); 855 RegionViewport rv = getCurrentRegionViewport(); 856 RegionReference reg = new RegionReference(side, 857 regionName, rv); 858 transferForeignObjects(attributes, reg); 859 reg.setCTM(getAttributeAsCTM(attributes, "ctm")); 860 setAreaAttributes(attributes, reg); 861 rv.setRegionReference(reg); 862 currentPageViewport.getPage().setRegionViewport( 863 side, rv); 864 areaStack.push(reg); 865 } 866 867 private void assertObjectOfClass(Object obj, Class clazz) { 868 if (!clazz.isInstance(obj)) { 869 throw new IllegalStateException ("Object is not an instance of " 870 + clazz.getName() + " but of " + obj.getClass().getName()); 871 } 872 } 873 874 879 protected void handleExternallyGeneratedObject(Object obj) { 880 if (areaStack.size() == 0 && obj instanceof ExtensionAttachment) { 881 ExtensionAttachment attachment = (ExtensionAttachment)obj; 882 if (this.currentPageViewport == null) { 883 this.treeModel.handleOffDocumentItem( 884 new OffDocumentExtensionAttachment(attachment)); 885 } else { 886 this.currentPageViewport.addExtensionAttachment(attachment); 887 } 888 } else { 889 log.warn("Don't know how to handle externally generated object: " + obj); 890 } 891 } 892 893 private void setAreaAttributes(Attributes attributes, Area area) { 894 area.setIPD(Integer.parseInt(attributes.getValue("ipd"))); 895 area.setBPD(Integer.parseInt(attributes.getValue("bpd"))); 896 } 897 898 private static final Object [] SUBSET_COMMON = new Object [] { 899 Trait.PROD_ID}; 900 private static final Object [] SUBSET_LINK = new Object [] { 901 Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK}; 902 private static final Object [] SUBSET_COLOR = new Object [] { 903 Trait.BACKGROUND, Trait.COLOR}; 904 private static final Object [] SUBSET_FONT = new Object [] { 905 Trait.FONT, Trait.FONT_SIZE, Trait.BLINK, 906 Trait.OVERLINE, Trait.OVERLINE_COLOR, 907 Trait.LINETHROUGH, Trait.LINETHROUGH_COLOR, 908 Trait.UNDERLINE, Trait.UNDERLINE_COLOR}; 909 private static final Object [] SUBSET_BOX = new Object [] { 910 Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END, 911 Trait.SPACE_BEFORE, Trait.SPACE_AFTER, Trait.SPACE_START, Trait.SPACE_END, 912 Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END, 913 Trait.START_INDENT, Trait.END_INDENT, 914 Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA}; 915 916 private void setTraits(Attributes attributes, Area area, Object [] traitSubset) { 917 for (int i = 0, c = traitSubset.length; i < c; i++) { 918 Object trait = traitSubset[i]; 919 String traitName = Trait.getTraitName(trait); 920 String value = attributes.getValue(traitName); 921 if (value != null) { 922 Class cl = Trait.getTraitClass(trait); 923 if (cl == Integer .class) { 924 area.addTrait(trait, new Integer (value)); 925 } else if (cl == Boolean .class) { 926 area.addTrait(trait, Boolean.valueOf(value)); 927 } else if (cl == String .class) { 928 area.addTrait(trait, value); 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 == Background.class) { 936 Background bkg = new Background(); 937 try { 938 Color col = ColorUtil.parseColorString( 939 this.userAgent, attributes.getValue("bkg-color")); 940 bkg.setColor(col); 941 } catch (PropertyException e) { 942 throw new IllegalArgumentException (e.getMessage()); 943 } 944 String url = attributes.getValue("bkg-img"); 945 if (url != null) { 946 bkg.setURL(url); 947 948 ImageFactory fact = userAgent.getFactory().getImageFactory(); 949 FopImage img = fact.getImage(url, userAgent); 950 if (img == null) { 951 log.error("Background image not available: " + url); 952 } else { 953 if (!img.load(FopImage.DIMENSIONS)) { 955 log.error("Cannot read background image dimensions: " 956 + url); 957 } 958 } 959 bkg.setFopImage(img); 960 961 String repeat = attributes.getValue("bkg-repeat"); 962 if (repeat != null) { 963 bkg.setRepeat(repeat); 964 } 965 bkg.setHoriz(getAttributeAsInteger(attributes, 966 "bkg-horz-offset", 0)); 967 bkg.setVertical(getAttributeAsInteger(attributes, 968 "bkg-vert-offset", 0)); 969 } 970 area.addTrait(trait, bkg); 971 } else if (cl == BorderProps.class) { 972 area.addTrait(trait, BorderProps.valueOf(this.userAgent, value)); 973 } 974 } else { 975 if (trait == Trait.FONT) { 976 String fontName = attributes.getValue("font-name"); 977 if (fontName != null) { 978 String fontStyle = attributes.getValue("font-style"); 979 int fontWeight = getAttributeAsInteger( 980 attributes, "font-weight", Font.NORMAL); 981 area.addTrait(trait, 982 FontInfo.createFontKey(fontName, fontStyle, fontWeight)); 983 } 984 } 985 } 986 } 987 } 988 989 private boolean getAttributeAsBoolean(Attributes attributes, String name, 990 boolean defaultValue) { 991 String s = attributes.getValue(name); 992 if (s == null) { 993 return defaultValue; 994 } else { 995 return Boolean.valueOf(s).booleanValue(); 996 } 997 } 998 999 private int getAttributeAsInteger(Attributes attributes, String name, 1000 int defaultValue) { 1001 String s = attributes.getValue(name); 1002 if (s == null) { 1003 return defaultValue; 1004 } else { 1005 return Integer.parseInt(s); 1006 } 1007 } 1008 1009 private CTM getAttributeAsCTM(Attributes attributes, String name) { 1010 String s = attributes.getValue(name).trim(); 1011 if (s.startsWith("[") && s.endsWith("]")) { 1012 s = s.substring(1, s.length() - 1); 1013 StringTokenizer tokenizer = new StringTokenizer (s, " "); 1014 double[] values = new double[] { 1015 Double.parseDouble(tokenizer.nextToken()), 1016 Double.parseDouble(tokenizer.nextToken()), 1017 Double.parseDouble(tokenizer.nextToken()), 1018 Double.parseDouble(tokenizer.nextToken()), 1019 Double.parseDouble(tokenizer.nextToken()), 1020 Double.parseDouble(tokenizer.nextToken())}; 1021 return new CTM(values[0], values[1], values[2], values[3], values[4], values[5]); 1022 } else { 1023 throw new IllegalArgumentException ("CTM must be surrounded by square brackets"); 1024 } 1025 } 1026 1027 private Rectangle2D getAttributeAsRectangle2D(Attributes attributes, String name) { 1028 String s = attributes.getValue(name).trim(); 1029 StringTokenizer tokenizer = new StringTokenizer (s, " "); 1030 double[] values = new double[] { 1031 Double.parseDouble(tokenizer.nextToken()), 1032 Double.parseDouble(tokenizer.nextToken()), 1033 Double.parseDouble(tokenizer.nextToken()), 1034 Double.parseDouble(tokenizer.nextToken())}; 1035 return new Rectangle2D.Double (values[0], values[1], values[2], values[3]); 1036 } 1037 1038 private void transferForeignObjects(Attributes atts, AreaTreeObject ato) { 1039 for (int i = 0, c = atts.getLength(); i < c; i++) { 1040 String ns = atts.getURI(i); 1041 if (ns.length() > 0) { 1042 if ("http://www.w3.org/2000/xmlns/".equals(ns)) { 1043 continue; 1044 } 1045 QName qname = new QName(ns, atts.getQName(i)); 1046 ato.setForeignAttribute(qname, atts.getValue(i)); 1047 } 1048 } 1049 } 1050 1051 1052 public void characters(char[] ch, int start, int length) throws SAXException { 1053 if (delegate != null) { 1054 delegate.characters(ch, start, length); 1055 } else { 1056 content.append(ch, start, length); 1057 } 1058 } 1059 1060 } 1061 1062} 1063 | Popular Tags |