/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: XMLRenderer.java 1805173 2017-08-16 10:50:04Z ssteiner $ */

package org.apache.fop.render.xml;

// Java
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import org.apache.xmlgraphics.util.QName;
import org.apache.xmlgraphics.util.XMLizable;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Area;
import org.apache.fop.area.AreaTreeObject;
import org.apache.fop.area.BeforeFloat;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockViewport;
import org.apache.fop.area.BodyRegion;
import org.apache.fop.area.BookmarkData;
import org.apache.fop.area.CTM;
import org.apache.fop.area.DestinationData;
import org.apache.fop.area.Footnote;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.MainReference;
import org.apache.fop.area.NormalFlow;
import org.apache.fop.area.OffDocumentExtensionAttachment;
import org.apache.fop.area.OffDocumentItem;
import org.apache.fop.area.PageSequence;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionReference;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Span;
import org.apache.fop.area.Trait;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
import org.apache.fop.area.inline.Container;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.XMLHandler;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.LanguageTags;
import org.apache.fop.util.XMLUtil;

Renderer that renders areas to XML for debugging purposes. This creates an xml that contains the information of the area tree. It does not output any state or derived information. The output can be used to build a new area tree which can be rendered to any renderer.
/** * Renderer that renders areas to XML for debugging purposes. * This creates an xml that contains the information of the area * tree. It does not output any state or derived information. * The output can be used to build a new area tree which can be * rendered to any renderer. */
public class XMLRenderer extends AbstractXMLRenderer {
Area Tree (AT) version, used to express an @version attribute in the root element of the AT document, the initial value of which is set to '2.0' to signify that something preceded it (but didn't happen to be marked as such), and that this version is not necessarily backwards compatible with the unmarked (<2.0) version.
/** * Area Tree (AT) version, used to express an @version attribute * in the root element of the AT document, the initial value of which * is set to '2.0' to signify that something preceded it (but didn't * happen to be marked as such), and that this version is not necessarily * backwards compatible with the unmarked (&lt;2.0) version. */
public static final String VERSION = "2.0";
XML MIME type
/** XML MIME type */
public static final String XML_MIME_TYPE = MimeConstants.MIME_FOP_AREA_TREE; private boolean startedSequence; private boolean compactFormat;
If not null, the XMLRenderer will mimic another renderer by using its font setup.
/** If not null, the XMLRenderer will mimic another renderer by using its font setup. */
protected Renderer mimic;
Params:
  • userAgent – the user agent that contains configuration details. This cannot be null.
/** * @param userAgent the user agent that contains configuration details. This cannot be null. */
public XMLRenderer(FOUserAgent userAgent) { super(userAgent); context = new RendererContext(this, XML_MIME_TYPE); XMLHandler xmlHandler = new XMLXMLHandler(); userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler); Boolean b = (Boolean)userAgent.getRendererOptions().get("compact-format"); if (b != null) { setCompactFormat(b); } }
Call this method to make the XMLRenderer mimic a different renderer by using its font setup. This is useful when working with the intermediate format parser.
Params:
  • renderer – the renderer to mimic
/** * Call this method to make the XMLRenderer mimic a different renderer by using its font * setup. This is useful when working with the intermediate format parser. * @param renderer the renderer to mimic */
public void mimicRenderer(Renderer renderer) { this.mimic = renderer; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void setupFontInfo(FontInfo inFontInfo) throws FOPException { if (mimic != null) { mimic.setupFontInfo(inFontInfo); } else { super.setupFontInfo(inFontInfo); } }
Controls whether to create a more compact format which omit certain attributes.
Params:
  • compact – true to activate the compact format
/** * Controls whether to create a more compact format which omit certain attributes. * @param compact true to activate the compact format */
public void setCompactFormat(boolean compact) { this.compactFormat = compact; } private boolean isDetailedFormat() { return !this.compactFormat; }
Adds the general Area attributes.
Params:
  • area – Area to extract attributes from
/** * Adds the general Area attributes. * @param area Area to extract attributes from */
protected void addAreaAttributes(Area area) { addAttribute("ipd", area.getIPD()); addAttribute("bpd", area.getBPD()); maybeAddLevelAttribute(area); if (isDetailedFormat()) { if (area.getIPD() != 0) { addAttribute("ipda", area.getAllocIPD()); } if (area.getBPD() != 0) { addAttribute("bpda", area.getAllocBPD()); } addAttribute("bap", area.getBorderAndPaddingWidthStart() + " " + area.getBorderAndPaddingWidthEnd() + " " + area.getBorderAndPaddingWidthBefore() + " " + area.getBorderAndPaddingWidthAfter()); } }
Adds attributes from traits of an Area.
Params:
  • area – Area to extract traits from
/** * Adds attributes from traits of an Area. * @param area Area to extract traits from */
protected void addTraitAttributes(Area area) { Map traitMap = area.getTraits(); if (traitMap != null) { for (Object o : traitMap.entrySet()) { Map.Entry traitEntry = (Map.Entry) o; Object key = traitEntry.getKey(); String name = Trait.getTraitName(key); Class clazz = Trait.getTraitClass(key); if ("break-before".equals(name) || "break-after".equals(name)) { continue; } Object value = traitEntry.getValue(); if (((Integer) key).intValue() == Trait.FONT) { FontTriplet triplet = (FontTriplet) value; addAttribute("font-name", triplet.getName()); addAttribute("font-style", triplet.getStyle()); addAttribute("font-weight", triplet.getWeight()); } else if (clazz.equals(InternalLink.class)) { InternalLink iLink = (InternalLink) value; addAttribute(name, iLink.xmlAttribute()); } else if (clazz.equals(Background.class)) { Background bkg = (Background) value; //TODO Remove the following line (makes changes in the test checks necessary) addAttribute(name, bkg.toString()); if (bkg.getColor() != null) { addAttribute("bkg-color", ColorUtil.colorToString(bkg.getColor())); } if (bkg.getURL() != null) { addAttribute("bkg-img", bkg.getURL()); String repString; int repeat = bkg.getRepeat(); switch (repeat) { case Constants.EN_REPEAT: repString = "repeat"; break; case Constants.EN_REPEATX: repString = "repeat-x"; break; case Constants.EN_REPEATY: repString = "repeat-y"; break; case Constants.EN_NOREPEAT: repString = "no-repeat"; break; default: throw new IllegalStateException( "Illegal value for repeat encountered: " + repeat); } addAttribute("bkg-repeat", repString); addAttribute("bkg-horz-offset", bkg.getHoriz()); addAttribute("bkg-vert-offset", bkg.getVertical()); } } else if (clazz.equals(Color.class)) { Color c = (Color) value; addAttribute(name, ColorUtil.colorToString(c)); } else if (((Integer) key).intValue() == Trait.START_INDENT || ((Integer) key).intValue() == Trait.END_INDENT) { if ((Integer) value != 0) { addAttribute(name, value.toString()); } } else { addAttribute(name, value.toString()); } } } transferForeignObjects(area); } private void transferForeignObjects(AreaTreeObject ato) { Map prefixes = new java.util.HashMap(); Iterator iter = ato.getForeignAttributes().entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); QName qname = (QName)entry.getKey(); prefixes.put(qname.getPrefix(), qname.getNamespaceURI()); addAttribute(qname, (String)entry.getValue()); } //Namespace declarations iter = prefixes.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); String qn = "xmlns:" + (String)entry.getKey(); atts.addAttribute("", (String)entry.getKey(), qn, CDATA, (String)entry.getValue()); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void processOffDocumentItem(OffDocumentItem oDI) { if (oDI instanceof BookmarkData) { renderBookmarkTree((BookmarkData) oDI); } else if (oDI instanceof DestinationData) { renderDestination((DestinationData) oDI); } else if (oDI instanceof OffDocumentExtensionAttachment) { ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)oDI).getAttachment(); if (extensionAttachments == null) { extensionAttachments = new java.util.ArrayList(); } extensionAttachments.add(attachment); } else { String warn = "Ignoring OffDocumentItem: " + oDI; log.warn(warn); } }
Renders a BookmarkTree object
Params:
  • bookmarkRoot – the BookmarkData object representing the top of the tree
/** * Renders a BookmarkTree object * @param bookmarkRoot the BookmarkData object representing the top of the tree */
@Override protected void renderBookmarkTree(BookmarkData bookmarkRoot) { if (bookmarkRoot.getWhenToProcess() == OffDocumentItem.END_OF_DOC) { endPageSequence(); } /* If this kind of handling is also necessary for other renderers, then better add endPageSequence to the Renderer interface and call it explicitly from model.endDocument() */ startElement("bookmarkTree"); for (int i = 0; i < bookmarkRoot.getCount(); i++) { renderBookmarkItem(bookmarkRoot.getSubData(i)); } endElement("bookmarkTree"); } private void renderBookmarkItem(BookmarkData bm) { atts.clear(); addAttribute("title", bm.getBookmarkTitle()); addAttribute("show-children", String.valueOf(bm.showChildItems())); PageViewport pv = bm.getPageViewport(); String pvKey = pv == null ? null : pv.getKey(); addAttribute("internal-link", InternalLink.makeXMLAttribute(pvKey, bm.getIDRef())); startElement("bookmark", atts); for (int i = 0; i < bm.getCount(); i++) { renderBookmarkItem(bm.getSubData(i)); } endElement("bookmark"); }
Renders a DestinationData object (named destination)
Params:
  • destination – the destination object
/** * Renders a DestinationData object (named destination) * @param destination the destination object */
protected void renderDestination(DestinationData destination) { if (destination.getWhenToProcess() == OffDocumentItem.END_OF_DOC) { endPageSequence(); } atts.clear(); PageViewport pv = destination.getPageViewport(); String pvKey = pv == null ? null : pv.getKey(); addAttribute("internal-link", InternalLink.makeXMLAttribute(pvKey, destination.getIDRef())); startElement("destination", atts); endElement("destination"); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void startRenderer(OutputStream outputStream) throws IOException { log.debug("Rendering areas to Area Tree XML"); if (this.handler == null) { SAXTransformerFactory factory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); try { TransformerHandler transformerHandler = factory.newTransformerHandler(); this.handler = transformerHandler; StreamResult res = new StreamResult(outputStream); transformerHandler.setResult(res); } catch (TransformerConfigurationException tce) { throw new RuntimeException(tce.getMessage()); } this.out = outputStream; } try { handler.startDocument(); } catch (SAXException saxe) { handleSAXException(saxe); } if (userAgent.getProducer() != null) { comment("Produced by " + userAgent.getProducer()); } atts.clear(); addAttribute("version", VERSION); startElement("areaTree", atts); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void stopRenderer() throws IOException { endPageSequence(); endElement("areaTree"); try { handler.endDocument(); } catch (SAXException saxe) { handleSAXException(saxe); } if (this.out != null) { this.out.flush(); } log.debug("Written out Area Tree XML"); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void renderPage(PageViewport page) throws IOException, FOPException { atts.clear(); addAttribute("bounds", page.getViewArea()); addAttribute("key", page.getKey()); addAttribute("nr", page.getPageNumber()); addAttribute("formatted-nr", page.getPageNumberString()); if (page.getSimplePageMasterName() != null) { addAttribute("simple-page-master-name", page.getSimplePageMasterName()); } if (page.isBlank()) { addAttribute("blank", "true"); } transferForeignObjects(page); startElement("pageViewport", atts); startElement("page"); handlePageExtensionAttachments(page); super.renderPage(page); endElement("page"); endElement("pageViewport"); }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void handleExtensionAttachments(List attachments) { if (attachments != null && attachments.size() > 0) { startElement("extension-attachments"); for (Object attachment1 : attachments) { ExtensionAttachment attachment = (ExtensionAttachment) attachment1; if (attachment instanceof XMLizable) { try { ((XMLizable) attachment).toSAX(this.handler); } catch (SAXException e) { log.error("Error while serializing Extension Attachment", e); } } else { String warn = "Ignoring non-XMLizable ExtensionAttachment: " + attachment; log.warn(warn); } } endElement("extension-attachments"); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void startPageSequence(PageSequence pageSequence) { handleDocumentExtensionAttachments(); endPageSequence(); // move this before handleDocumentExtensionAttachments() ? startedSequence = true; atts.clear(); Locale locale = pageSequence.getLocale(); if (locale != null) { addAttribute(new QName(XMLConstants.XML_NS_URI, "xml:lang"), LanguageTags.toLanguageTag(locale)); } transferForeignObjects(pageSequence); startElement("pageSequence", atts); handleExtensionAttachments(pageSequence.getExtensionAttachments()); LineArea seqTitle = pageSequence.getTitle(); if (seqTitle != null) { startElement("title"); List children = seqTitle.getInlineAreas(); for (Object aChildren : children) { InlineArea inline = (InlineArea) aChildren; renderInlineArea(inline); } endElement("title"); } }
Tells the renderer to finish the current PageSequence
/** * Tells the renderer to finish the current PageSequence */
public void endPageSequence() { if (startedSequence) { endElement("pageSequence"); } startedSequence = false; }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderRegionViewport(RegionViewport port) { if (port != null) { atts.clear(); addAreaAttributes(port); addTraitAttributes(port); addAttribute("rect", port.getViewArea()); if (port.hasClip()) { addAttribute("clipped", "true"); } startElement("regionViewport", atts); RegionReference region = port.getRegionReference(); atts.clear(); addAreaAttributes(region); addTraitAttributes(region); addAttribute("name", region.getRegionName()); addAttribute("ctm", region.getCTM().toString()); if (region.getRegionClass() == FO_REGION_BEFORE) { startElement("regionBefore", atts); renderRegion(region); endElement("regionBefore"); } else if (region.getRegionClass() == FO_REGION_START) { startElement("regionStart", atts); renderRegion(region); endElement("regionStart"); } else if (region.getRegionClass() == FO_REGION_BODY) { assert (region instanceof BodyRegion); BodyRegion body = (BodyRegion) region; if (body.getColumnCount() != 1) { addAttribute("columnGap", body.getColumnGap()); addAttribute("columnCount", body.getColumnCount()); } startElement("regionBody", atts); renderBodyRegion(body); endElement("regionBody"); } else if (region.getRegionClass() == FO_REGION_END) { startElement("regionEnd", atts); renderRegion(region); endElement("regionEnd"); } else if (region.getRegionClass() == FO_REGION_AFTER) { startElement("regionAfter", atts); renderRegion(region); endElement("regionAfter"); } endElement("regionViewport"); } } @Override protected void startVParea(CTM ctm, Rectangle clippingRect) { //only necessary for graphical output }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void endVParea() { //only necessary for graphical output }
{@inheritDoc}
/** {@inheritDoc} */
protected void startLayer(String layer) { //only necessary for graphical output }
{@inheritDoc}
/** {@inheritDoc} */
protected void endLayer() { //only necessary for graphical output }
{@inheritDoc} org.apache.fop.area.inline.InlineArea)
/** * {@inheritDoc} * org.apache.fop.area.inline.InlineArea) */
@Override protected void renderInlineAreaBackAndBorders(InlineArea area) { //only necessary for graphical output }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderBeforeFloat(BeforeFloat bf) { startElement("beforeFloat"); super.renderBeforeFloat(bf); endElement("beforeFloat"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderFootnote(Footnote footnote) { atts.clear(); addAttribute("top-offset", footnote.getTop()); startElement("footnote", atts); super.renderFootnote(footnote); endElement("footnote"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderMainReference(MainReference mr) { atts.clear(); addAreaAttributes(mr); addTraitAttributes(mr); if (mr.getColumnCount() != 1) { addAttribute("columnGap", mr.getColumnGap()); } startElement("mainReference", atts); Span span = null; List spans = mr.getSpans(); for (Object span1 : spans) { span = (Span) span1; atts.clear(); if (span.getColumnCount() != 1) { addAttribute("columnCount", span.getColumnCount()); } addAreaAttributes(span); addTraitAttributes(span); startElement("span", atts); for (int c = 0; c < span.getColumnCount(); c++) { NormalFlow flow = span.getNormalFlow(c); renderFlow(flow); } endElement("span"); } endElement("mainReference"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderFlow(NormalFlow flow) { // the normal flow reference area contains stacked blocks atts.clear(); addAreaAttributes(flow); addTraitAttributes(flow); startElement("flow", atts); super.renderFlow(flow); endElement("flow"); }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void renderReferenceArea(Block block) { handleBlockTraits(block); List children = block.getChildAreas(); if (children != null) { renderBlocks(block, children); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void renderBlock(Block block) { atts.clear(); addAreaAttributes(block); addTraitAttributes(block); int positioning = block.getPositioning(); if (block instanceof BlockViewport) { BlockViewport bvp = (BlockViewport)block; boolean abspos = false; if (bvp.getPositioning() == Block.ABSOLUTE || bvp.getPositioning() == Block.FIXED) { abspos = true; } if (abspos) { addAttribute("left-position", bvp.getXOffset()); addAttribute("top-position", bvp.getYOffset()); } addAttribute("ctm", bvp.getCTM().toString()); if (bvp.hasClip()) { addAttribute("clipped", "true"); } } else { if (block.getXOffset() != 0) { addAttribute("left-offset", block.getXOffset()); } if (block.getYOffset() != 0) { addAttribute("top-offset", block.getYOffset()); } } switch (positioning) { case Block.RELATIVE: addAttribute("positioning", "relative"); break; case Block.ABSOLUTE: addAttribute("positioning", "absolute"); break; case Block.FIXED: addAttribute("positioning", "fixed"); break; default: //nop } startElement("block", atts); super.renderBlock(block); endElement("block"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderLineArea(LineArea line) { atts.clear(); addAreaAttributes(line); addTraitAttributes(line); startElement("lineArea", atts); super.renderLineArea(line); endElement("lineArea"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderInlineArea(InlineArea inlineArea) { atts.clear(); if (inlineArea.getClass() == InlineArea.class) { // Generic inline area. This is implemented to allow the 0x0 "dummy" // area generated by fo:wrapper to pass its id. addAreaAttributes(inlineArea); addTraitAttributes(inlineArea); startElement("inline", atts); endElement("inline"); } else { super.renderInlineArea(inlineArea); // calls specific renderers for Text, Space, Viewport, etc. etc. } }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderInlineViewport(InlineViewport viewport) { atts.clear(); addAreaAttributes(viewport); addTraitAttributes(viewport); addAttribute("offset", viewport.getBlockProgressionOffset()); addAttribute("pos", viewport.getContentPosition()); if (viewport.hasClip()) { addAttribute("clip", "true"); } startElement("viewport", atts); super.renderInlineViewport(viewport); endElement("viewport"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override public void renderImage(Image image, Rectangle2D pos) { atts.clear(); addAreaAttributes(image); addTraitAttributes(image); addAttribute("url", image.getURL()); //addAttribute("pos", pos); startElement("image", atts); endElement("image"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override public void renderContainer(Container cont) { startElement("container"); super.renderContainer(cont); endElement("container"); }
Renders an fo:foreing-object.
Params:
  • fo – the foreign object
  • pos – the position of the foreign object
See Also:
/** * Renders an fo:foreing-object. * @param fo the foreign object * @param pos the position of the foreign object * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) */
@Override public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { atts.clear(); addAreaAttributes(fo); addTraitAttributes(fo); String ns = fo.getNameSpace(); addAttribute("ns", ns); startElement("foreignObject", atts); Document doc = fo.getDocument(); context.setProperty(XMLXMLHandler.HANDLER, handler); renderXML(context, doc, ns); endElement("foreignObject"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderInlineSpace(Space space) { atts.clear(); addAreaAttributes(space); addTraitAttributes(space); addAttribute("offset", space.getBlockProgressionOffset()); startElement("space", atts); endElement("space"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderText(TextArea text) { atts.clear(); if (text.getTextWordSpaceAdjust() != 0) { addAttribute("twsadjust", text.getTextWordSpaceAdjust()); } if (text.getTextLetterSpaceAdjust() != 0) { addAttribute("tlsadjust", text.getTextLetterSpaceAdjust()); } addAttribute("offset", text.getBlockProgressionOffset()); addAttribute("baseline", text.getBaselineOffset()); addAreaAttributes(text); addTraitAttributes(text); startElement("text", atts); super.renderText(text); endElement("text"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderWord(WordArea word) { atts.clear(); int offset = word.getBlockProgressionOffset(); if (offset != 0) { addAttribute("offset", offset); } int[] letterAdjust = word.getLetterAdjustArray(); if (letterAdjust != null) { StringBuffer sb = new StringBuffer(64); boolean nonZeroFound = false; for (int i = 0, c = letterAdjust.length; i < c; i++) { if (i > 0) { sb.append(' '); } sb.append(letterAdjust[i]); nonZeroFound |= (letterAdjust[i] != 0); } if (nonZeroFound) { addAttribute("letter-adjust", sb.toString()); } } maybeAddLevelAttribute(word); maybeAddPositionAdjustAttribute(word); String text = word.getWord(); maybeAddReversedAttribute(word, text); startElement("word", atts); characters(text); endElement("word"); super.renderWord(word); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderSpace(SpaceArea space) { atts.clear(); int offset = space.getBlockProgressionOffset(); if (offset != 0) { addAttribute("offset", offset); } maybeAddLevelAttribute(space); if (!space.isAdjustable()) { addAttribute("adj", "false"); //default is true } startElement("space", atts); characters(space.getSpace()); endElement("space"); super.renderSpace(space); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderInlineParent(InlineParent ip) { atts.clear(); addAreaAttributes(ip); addTraitAttributes(ip); addAttribute("offset", ip.getBlockProgressionOffset()); startElement("inlineparent", atts); super.renderInlineParent(ip); endElement("inlineparent"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderInlineBlockParent(InlineBlockParent ibp) { atts.clear(); addAreaAttributes(ibp); addTraitAttributes(ibp); addAttribute("offset", ibp.getBlockProgressionOffset()); startElement("inlineblockparent", atts); super.renderInlineBlockParent(ibp); endElement("inlineblockparent"); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected void renderLeader(Leader area) { atts.clear(); addAreaAttributes(area); addTraitAttributes(area); addAttribute("offset", area.getBlockProgressionOffset()); addAttribute("ruleStyle", area.getRuleStyleAsString()); addAttribute("ruleThickness", area.getRuleThickness()); startElement("leader", atts); endElement("leader"); super.renderLeader(area); }
{@inheritDoc}
/** {@inheritDoc} */
public String getMimeType() { return XML_MIME_TYPE; } private void maybeAddLevelAttribute(Area a) { int level = a.getBidiLevel(); if (level >= 0) { addAttribute("level", level); } } private void maybeAddPositionAdjustAttribute(WordArea w) { int[][] adjustments = w.getGlyphPositionAdjustments(); if (adjustments != null) { addAttribute("position-adjust", XMLUtil.encodePositionAdjustments(adjustments)); } } private void maybeAddReversedAttribute(WordArea w, String text) { if (w.isReversed() && (text.length() > 1)) { addAttribute("reversed", "true"); } } }