All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.layout.BoxModelRenderProxy Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2007 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */
package com.adobe.xfa.layout;


import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import com.adobe.xfa.Attribute;
import com.adobe.xfa.Element;
import com.adobe.xfa.EnumAttr;
import com.adobe.xfa.STRS;
import com.adobe.xfa.XFA;
import com.adobe.xfa.font.FontInfo;
import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.template.containers.Draw;
import com.adobe.xfa.template.containers.Field;
import com.adobe.xfa.template.containers.Rotate;
import com.adobe.xfa.svg.SVG;
import com.adobe.xfa.svg.SVGNode;
import com.adobe.xfa.svg.SVGTextData;
import com.adobe.xfa.ut.Angle;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.UnitSpan;
import com.adobe.xfa.ut.Margins;
import com.adobe.xfa.ut.StringUtils;


/**
 * This class provides the implementation for box model formatting
 * when rendering from text run definitions.  It was created for Performance 
 * and consistency of rendering.
 * There are two formats in which we can find text run definitions: 
* - Processing instructions
* - SVG
* * The benefit of this class is that the text run definition gives * us the width and height of the caption and content regions, which * avoids the costly process of going through the text engine in order * to obtain this information. * * For details on text caching please refer to the proposals at: * * http://xtg.can.adobe.com/twiki/bin/view//CacheBoilerplateXFAV23Proposal * * http://xtg.can.adobe.com/twiki/bin/view//SVGTextRunsXFAProposal * * @exclude from published api. */ class BoxModelRenderProxy extends BoxModelLayout { public BoxModelRenderProxy(LayoutEnv oEnv) { super(); m_oGfxLayoutEnv = oEnv; m_bHasCaption = false; mbIsProxy = false; } // Override public Rect getCaptionExtent() { return m_oCaptionExtent; } public Rect getContentExtent() { return m_oContentExtent; } public void clear() { m_bHasCaption = false; m_oCaptionExtent = Rect.ZERO; m_oContentExtent = Rect.ZERO; super.clear(); } public boolean allowRenderProxy() { return true; } public boolean hasCaption() { return m_bHasCaption; } public boolean isProxy() { return mbIsProxy; } public void initialize(Element oNode) { // This method gets called only if we're a leaf boxmodel object. // i.e. not called when we've been sub-classed by BoxModelContentImpl //Strategy //Initialize the box model for a text based object (field/draw) //1)Read initial box model settings from node, including //-x,y,anchor //-margins //-border //-caption info //-initialize content (textual in this case) //2)Then format the box model into subregions (content/caption) given these settings. // This will automatically account for min/max ranges //3)Rotate the box model, as appropriate. //4)Record the visual extent of the box model // Proxy box models should only be created for static objects. assert(oNode instanceof Draw); if (! isBoxModelCompatible(oNode)) return; // This will initialize the box model from either SVG definition or PIs checkProxyStatus(oNode); // Read anchorPoint initAnchorPoint(oNode); // Read nominal extent, content and caption margins initMargins(oNode); // Read border margins, content border margins initBorder(oNode); // Format internals based on the info so far //format(oNode); // Once formatted, perform any rotation //initRotatedContentTopLeft(); respectRotation(oNode); // Finally, determine the visual extent. initVisualExtent(oNode); } public void respectRotation(Element oNode) { //Adjust the box model if it is rotated. //Only support rotation on fields+draws, //not subforms with flowing content //Respecting min max must have already occurred. m_bWasRotated = false; m_oRotationAngle = Angle.ZERO; if (oNode instanceof Draw || oNode instanceof Field) { if (oNode.isPropertySpecified(XFA.ROTATETAG, true, 0)) { Rotate oRotate = new Rotate(XFA.ROTATE, oNode.getAttribute(XFA.ROTATETAG).toString()); if (oRotate != null) { Angle oAngle = oRotate.getAngle(); int lAngle = oAngle.degrees(); lAngle = lAngle % 360; if (0 > lAngle) lAngle += 360; oAngle = new Angle(lAngle); m_oRotationAngle = oAngle; Margins oPrevMargins = m_oNEMargins; Margins oPrevBorderMargins = m_oBorderMargins; Margins oPrevWidgetBorderMargins = m_oContentBorderMargins; Margins oPrevWidgetCaptionMargins = m_oCapMargins; Margins oPrevWidgetContentMargins = m_oContMargins; Rect rcPrevNE = getNominalExtent(); CoordPair oNewTL = CoordPair.ZERO_ZERO; CoordPair oNewTR = CoordPair.ZERO_ZERO; //CoordPair oNewBL = new CoordPair(); CoordPair oNewBR = CoordPair.ZERO_ZERO; CoordPair oPrevTL = rcPrevNE.topLeft(); CoordPair oPrevTR = rcPrevNE.topRight(); CoordPair oPrevBL = rcPrevNE.bottomLeft(); CoordPair oPrevBR = rcPrevNE.bottomRight(); Rect rcPrevContentExtent = getContentExtent(); CoordPair oNewContentTL = CoordPair.ZERO_ZERO; CoordPair oNewContentTR = CoordPair.ZERO_ZERO; CoordPair oNewContentBL = CoordPair.ZERO_ZERO; CoordPair oNewContentBR = CoordPair.ZERO_ZERO; CoordPair oPrevContentTL = rcPrevContentExtent.topLeft(); CoordPair oPrevContentTR = rcPrevContentExtent.topRight(); CoordPair oPrevContentBL = rcPrevContentExtent.bottomLeft(); CoordPair oPrevContentBR = rcPrevContentExtent.bottomRight(); Rect rcPrevCaptionExtent = getCaptionExtent(); CoordPair oNewCaptionTL = CoordPair.ZERO_ZERO; CoordPair oNewCaptionTR = CoordPair.ZERO_ZERO; CoordPair oNewCaptionBL = CoordPair.ZERO_ZERO; CoordPair oNewCaptionBR = CoordPair.ZERO_ZERO; CoordPair oPrevCaptionTL = rcPrevCaptionExtent.topLeft(); CoordPair oPrevCaptionTR = rcPrevCaptionExtent.topRight(); CoordPair oPrevCaptionBL = rcPrevCaptionExtent.bottomLeft(); CoordPair oPrevCaptionBR = rcPrevCaptionExtent.bottomRight(); // Required for rotation calcs. CoordPair oNewLocalContentTL = CoordPair.ZERO_ZERO; CoordPair oNewLocalCaptionTL = CoordPair.ZERO_ZERO; CoordPair oLocalAnchor = m_oAnchorPoint.subtract(oPrevTL); CoordPair oContentOrigin = oPrevContentTL; CoordPair oCaptionOrigin = oPrevCaptionTL; switch (lAngle) { case 0: { //nothing to do //Adjust the top left of content extent for text, etc. oNewLocalContentTL = oPrevContentTL.rotatePoint(oLocalAnchor, oAngle); m_oRotatedContentTopLeft = oNewLocalContentTL.subtract(oContentOrigin.rotatePoint(oLocalAnchor, oAngle)); //Adjust the top left of caption extent for text, etc. oNewLocalCaptionTL = oPrevCaptionTL.rotatePoint(oLocalAnchor, oAngle); m_oRotatedCaptionTopLeft = oNewLocalCaptionTL.subtract(oContentOrigin.rotatePoint(oLocalAnchor, oAngle)); return; } case 270: { //1)rotate the 4 corner points 90 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 90 degrees about 'anchor' point oNewTR = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); oNewBR = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //oNewBL = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); oNewTL = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); // Calculation used to adjust to the local top left CoordPair oAdjust = oPrevTL.subtract(oNewTL); oNewContentTR = oPrevContentTL.rotatePoint(oLocalAnchor, oAngle); oNewContentBR = oPrevContentTR.rotatePoint(oLocalAnchor, oAngle); oNewContentBL = oPrevContentBR.rotatePoint(oLocalAnchor, oAngle); oNewContentTL = oPrevContentBL.rotatePoint(oLocalAnchor, oAngle); oNewContentTR = oNewContentTR.add(oAdjust); oNewContentBR = oNewContentBR.add(oAdjust); oNewContentBL = oNewContentBL.add(oAdjust); oNewContentTL = oNewContentTL.add(oAdjust); oNewCaptionTR = oPrevCaptionTL.rotatePoint(oLocalAnchor, oAngle); oNewCaptionBR = oPrevCaptionTR.rotatePoint(oLocalAnchor, oAngle); oNewCaptionBL = oPrevCaptionBR.rotatePoint(oLocalAnchor, oAngle); oNewCaptionTL = oPrevCaptionBL.rotatePoint(oLocalAnchor, oAngle); oNewCaptionTR = oNewCaptionTR.add(oAdjust); oNewCaptionBR = oNewCaptionBR.add(oAdjust); oNewCaptionBL = oNewCaptionBL.add(oAdjust); oNewCaptionTL = oNewCaptionTL.add(oAdjust); m_oNEMargins = new Margins(oPrevMargins.marginBottom(), oPrevMargins.marginLeft(), oPrevMargins.marginTop(), oPrevMargins.marginRight()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft(), oPrevBorderMargins.marginTop(), oPrevBorderMargins.marginRight()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft(), oPrevWidgetBorderMargins.marginTop(), oPrevWidgetBorderMargins.marginRight()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft(), oPrevWidgetCaptionMargins.marginTop(), oPrevWidgetCaptionMargins.marginRight()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft(), oPrevWidgetContentMargins.marginTop(), oPrevWidgetContentMargins.marginRight()); // These calc required for rotation. //Adjust the top left of content extent for text, etc. oNewLocalContentTL = oPrevContentBL.rotatePoint(oLocalAnchor, oAngle); m_oRotatedContentTopLeft = oNewLocalContentTL.subtract(oContentOrigin.rotatePoint(oLocalAnchor, oAngle)); //Adjust the top left of caption extent for text, etc. oNewLocalCaptionTL = oPrevCaptionBL.rotatePoint(oLocalAnchor, oAngle); m_oRotatedCaptionTopLeft = oNewLocalCaptionTL.subtract(oCaptionOrigin.rotatePoint(oLocalAnchor, oAngle)); } break; case 180: { //1)rotate the 4 corner points 180 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 180 degrees about 'anchor' point oNewBR = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); //A //oNewBL = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //B oNewTL = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); //C oNewTR = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); //D // Calculation used to adjust to the local top left CoordPair oAdjust = oPrevTL.subtract(oNewTL); oNewContentBR = oPrevContentTL.rotatePoint(oLocalAnchor, oAngle); //A oNewContentBL = oPrevContentTR.rotatePoint(oLocalAnchor, oAngle); //B oNewContentTL = oPrevContentBR.rotatePoint(oLocalAnchor, oAngle); //C oNewContentTR = oPrevContentBL.rotatePoint(oLocalAnchor, oAngle); //D oNewContentTR = oNewContentTR.add(oAdjust); oNewContentBR = oNewContentBR.add(oAdjust); oNewContentBL = oNewContentBL.add(oAdjust); oNewContentTL = oNewContentTL.add(oAdjust); oNewCaptionBR = oPrevCaptionTL.rotatePoint(oLocalAnchor, oAngle); //A oNewCaptionBL = oPrevCaptionTR.rotatePoint(oLocalAnchor, oAngle); //B oNewCaptionTL = oPrevCaptionBR.rotatePoint(oLocalAnchor, oAngle); //C oNewCaptionTR = oPrevCaptionBL.rotatePoint(oLocalAnchor, oAngle); //D oNewCaptionTR = oNewCaptionTR.add(oAdjust); oNewCaptionBR = oNewCaptionBR.add(oAdjust); oNewCaptionBL = oNewCaptionBL.add(oAdjust); oNewCaptionTL = oNewCaptionTL.add(oAdjust); m_oNEMargins = new Margins(oPrevMargins.marginRight(), oPrevMargins.marginBottom(), oPrevMargins.marginLeft(), oPrevMargins.marginTop()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginRight(), oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft(), oPrevBorderMargins.marginTop()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginRight(), oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft(), oPrevWidgetBorderMargins.marginTop()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginRight(), oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft(), oPrevWidgetCaptionMargins.marginTop()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginRight(), oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft(), oPrevWidgetContentMargins.marginTop()); // These calc required for rotation. //Adjust the top left of content extent for text, etc. oNewLocalContentTL = oPrevContentBR.rotatePoint(oLocalAnchor, oAngle); m_oRotatedContentTopLeft = oNewLocalContentTL.subtract(oContentOrigin.rotatePoint(oLocalAnchor, oAngle)); //Adjust the top left of caption extent for text, etc. oNewLocalCaptionTL = oPrevCaptionBR.rotatePoint(oLocalAnchor, oAngle); m_oRotatedCaptionTopLeft = oNewLocalCaptionTL.subtract(oCaptionOrigin.rotatePoint(oLocalAnchor, oAngle)); } break; case 90: { //1)rotate the 4 corner points 90 degrees about 'm_oAnchorPoint' //2)adjust new anchor point to new orientation //3)flip content margins + border margins //4)for both caption+non caption extents, // rotate the 4 corner points 180 degrees about 'anchor' point //oNewBL = oPrevTL.rotatePoint(m_oAnchorPoint, oAngle); //A oNewTL = oPrevTR.rotatePoint(m_oAnchorPoint, oAngle); //B oNewTR = oPrevBR.rotatePoint(m_oAnchorPoint, oAngle); //C oNewBR = oPrevBL.rotatePoint(m_oAnchorPoint, oAngle); //D // Calculation used to adjust to the local top left CoordPair oAdjust = oPrevTL.subtract(oNewTL); // Rotate the local content coordinates around the local origin. oNewContentBL = oPrevContentTL.rotatePoint(oLocalAnchor, oAngle); //A oNewContentTL = oPrevContentTR.rotatePoint(oLocalAnchor, oAngle); //B oNewContentTR = oPrevContentBR.rotatePoint(oLocalAnchor, oAngle); //C oNewContentBR = oPrevContentBL.rotatePoint(oLocalAnchor, oAngle); //D oNewContentTR = oNewContentTR.add(oAdjust); oNewContentBR = oNewContentBR.add(oAdjust); oNewContentBL = oNewContentBL.add(oAdjust); oNewContentTL = oNewContentTL.add(oAdjust); // Rotate the local caption coordinates around the local origin. oNewCaptionBL = oPrevCaptionTL.rotatePoint(oLocalAnchor, oAngle); //A oNewCaptionTL = oPrevCaptionTR.rotatePoint(oLocalAnchor, oAngle); //B oNewCaptionTR = oPrevCaptionBR.rotatePoint(oLocalAnchor, oAngle); //C oNewCaptionBR = oPrevCaptionBL.rotatePoint(oLocalAnchor, oAngle); //D oNewCaptionTR = oNewCaptionTR.add(oAdjust); oNewCaptionBR = oNewCaptionBR.add(oAdjust); oNewCaptionBL = oNewCaptionBL.add(oAdjust); oNewCaptionTL = oNewCaptionTL.add(oAdjust); m_oNEMargins = new Margins(oPrevMargins.marginTop(), oPrevMargins.marginRight(), oPrevMargins.marginBottom(), oPrevMargins.marginLeft()); m_oBorderMargins = new Margins(oPrevBorderMargins.marginTop(), oPrevBorderMargins.marginRight(), oPrevBorderMargins.marginBottom(), oPrevBorderMargins.marginLeft()); m_oContentBorderMargins = new Margins(oPrevWidgetBorderMargins.marginTop(), oPrevWidgetBorderMargins.marginRight(), oPrevWidgetBorderMargins.marginBottom(), oPrevWidgetBorderMargins.marginLeft()); m_oCapMargins = new Margins(oPrevWidgetCaptionMargins.marginTop(), oPrevWidgetCaptionMargins.marginRight(), oPrevWidgetCaptionMargins.marginBottom(), oPrevWidgetCaptionMargins.marginLeft()); m_oContMargins = new Margins(oPrevWidgetContentMargins.marginTop(), oPrevWidgetContentMargins.marginRight(), oPrevWidgetContentMargins.marginBottom(), oPrevWidgetContentMargins.marginLeft()); // These calc required for rotation. //Adjust the top left of content extent for text, etc. oNewLocalContentTL = oPrevContentTR.rotatePoint(oLocalAnchor, oAngle); m_oRotatedContentTopLeft = oNewLocalContentTL.subtract(oContentOrigin.rotatePoint(oLocalAnchor, oAngle)); //Adjust the top left of caption extent for text, etc. oNewLocalCaptionTL = oPrevCaptionTR.rotatePoint(oLocalAnchor, oAngle); m_oRotatedCaptionTopLeft = oNewLocalCaptionTL.subtract(oCaptionOrigin.rotatePoint(oLocalAnchor, oAngle)); } break; default: { //Only 90 degree increments are handled //Todo: log warning message? assert(false); m_bWasRotated = false; return; } } //Record that rotate occurred (splitting will not be allowed) m_bWasRotated = (0 != lAngle); //Todo: calculate true anchor m_oAnchorType = EnumAttr.TOP_LEFT; m_oAnchorPoint = oNewTL; //Set the new nominal extent UnitSpan oNewWidth = oNewTR.x().subtract(oNewTL.x()); UnitSpan oNewHeight = oNewBR.y().subtract(oNewTR.y()); if (oNewWidth.value() < 0) oNewWidth = oNewWidth.multiply(-1); if (oNewHeight.value() < 0) oNewHeight = oNewHeight.multiply(-1); assert(oNewWidth.gte(UnitSpan.ZERO)); assert(oNewHeight.gte(UnitSpan.ZERO)); m_oNE = m_oNE.width(oNewWidth, false); m_oNE = m_oNE.height(oNewHeight, false); //Set the new caption + non-caption extents m_oCaptionExtent = m_oCaptionExtent.topLeft(oNewCaptionTL); m_oCaptionExtent = m_oCaptionExtent.bottomRight(oNewCaptionBR); m_oCaptionExtent = m_oContentExtent.topLeft(oNewContentTL); m_oCaptionExtent = m_oContentExtent.bottomRight(oNewContentBR); //Todo: flip min/max widths assert(! m_oContentExtent.isDegenerate()); } } } } protected void hasCaption(boolean bHasCaption) { m_bHasCaption = bHasCaption; } protected void checkProxyStatus(Element oNode) { if (! allowRenderProxy()) { mbIsProxy = false; return; } if (oNode.isPropertySpecified(XFA.RENDERASTAG, true, 0)) // Initialize from the embedded SVG fragment initFromSVG(oNode); // We don't expect to find processing instruction text runs // if we're laying out a field. else if (! (oNode instanceof Field)) // Init the content and caption extents based on the text cache PI's. initFromPI(oNode); } protected LayoutEnv m_oGfxLayoutEnv; protected Rect m_oContentExtent = Rect.ZERO; protected Rect m_oCaptionExtent = Rect.ZERO; protected boolean m_bHasCaption; private boolean mbIsProxy; // format override private void initFromPI(Element oNode) { // Retrieve the specified width/height of this object which is stored // in a Processing Instruction (PI). They will be used as the boxmodel // nominal extents. // Proxies do not support notion of growability. They are fixed sized objects. assert(oNode != null); List oPIs = new ArrayList(); oNode.getPI(STRS.BOUNDS, oPIs, true); // If there's no text run PIs, then we're not using the proxy capability. mbIsProxy = (oPIs.size() != 0); if (! mbIsProxy) return; StringBuilder sPIValue = new StringBuilder((String) oPIs.get(0)); StringUtils.trim(sPIValue); StringUtils.trimStart(sPIValue); StringTokenizer sToker = new StringTokenizer(sPIValue.toString()); // Scratch variables String sResult = null; int nResult = 0; // The processing instruction has the following format // // Update the content width sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan moContentW = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Update the content height sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan moContentH = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Update the caption width sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan moCaptionW = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Update the caption height sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan moCaptionH = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Update the rotated content top left sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan oRCTLX = new UnitSpan(UnitSpan.INCHES_72K, nResult); sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan oRCTLY = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Update the rotated caption top left sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan oRCapTLX = new UnitSpan(UnitSpan.INCHES_72K, nResult); sResult = sToker.nextToken(); nResult = StringUtils.safeNumber(sResult); UnitSpan oRCapTLY = new UnitSpan(UnitSpan.INCHES_72K, nResult); // Guard against bad values if (0 > moContentW.value()) moContentW = UnitSpan.ZERO; if (0 > moContentH.value()) moContentH = UnitSpan.ZERO; if (0 > moCaptionW.value()) moCaptionW = UnitSpan.ZERO; if (0 > moCaptionH.value()) moCaptionH = UnitSpan.ZERO; m_oContentExtent = m_oContentExtent.topLeft(new CoordPair(oRCTLX, oRCTLY)); m_oContentExtent = m_oContentExtent.width(moContentW, false); m_oContentExtent = m_oContentExtent.height(moContentH, false); m_oCaptionExtent = m_oCaptionExtent.topLeft(new CoordPair(oRCapTLX, oRCapTLY)); m_oCaptionExtent = m_oCaptionExtent.width(moCaptionW, false); m_oCaptionExtent = m_oCaptionExtent.height(moCaptionH, false); // Set up the nominal extent initWidthHeight(oNode, false); } private void initFromSVG(Element oContainer) { mbIsProxy = true; Element renderAs = oContainer.peekElement(XFA.RENDERASTAG, false, 0); // Todo: some sort of standard error/escape if we hit bad SVG // In that case we ought to revert to a full re-render. SVGNode svg = (SVGNode) renderAs.peekElement(SVG.SVGTAG, false, 0); m_oMinW = svg.getSVGWidth(); m_oMinW = m_oMinW.changeUnits(UnitSpan.INCHES_72K); m_oMinH = svg.getSVGHeight(); m_oMinH = m_oMinH.changeUnits(UnitSpan.INCHES_72K); m_oNE = m_oNE.width(m_oMinW, false); m_oNE = m_oNE.height(m_oMinH, false); m_oMaxW = m_oMinW; m_oMaxH = m_oMinH; int r = 0; // Update the rotated content top left UnitSpan oRCTLX = UnitSpan.ZERO; UnitSpan oRCTLY = UnitSpan.ZERO; SVGNode content = svg.getRegionGroup(false); content.parseTransform(oRCTLX, oRCTLY, r); preProcessGlyphs(content); UnitSpan oContentW = content.getMeasurement(SVG.WIDTHTAG); UnitSpan oContentH = content.getMeasurement(SVG.HEIGHTTAG); // Update the rotated caption top left UnitSpan oRCapTLX = UnitSpan.ZERO; UnitSpan oRCapTLY = UnitSpan.ZERO; UnitSpan oCaptionW = UnitSpan.ZERO; UnitSpan oCaptionH = UnitSpan.ZERO; SVGNode caption = svg.getRegionGroup(true); if (caption == null) { m_bHasCaption = false; } else { m_bHasCaption = true; caption.parseTransform(oRCapTLX, oRCapTLY, r); oCaptionW = caption.getMeasurement(SVG.WIDTHTAG); oCaptionH = caption.getMeasurement(SVG.HEIGHTTAG); preProcessGlyphs(caption); } // Guard against bad values if (0 > oContentW.value()) oContentW = UnitSpan.ZERO; if (0 > oContentH.value()) oContentH = UnitSpan.ZERO; if (0 > oCaptionW.value()) oCaptionW = UnitSpan.ZERO; if (0 > oCaptionH.value()) oCaptionH = UnitSpan.ZERO; m_oContentExtent = m_oContentExtent.topLeft(new CoordPair(oRCTLX, oRCTLY)); m_oContentExtent = m_oContentExtent.width(oContentW, false); m_oContentExtent = m_oContentExtent.height(oContentH, false); m_oContentExtent = m_oCaptionExtent.topLeft(new CoordPair(oRCapTLX, oRCapTLY)); m_oContentExtent = m_oCaptionExtent.width(oCaptionW, false); m_oContentExtent = m_oCaptionExtent.height(oCaptionH, false); } private void preProcessGlyphs(Element group) { for (SVGNode t = (SVGNode)group.getFirstXFAChild(); t != null; t = (SVGNode)t.getNextXFASibling()) { if (t.getClassTag() != SVG.TEXTTAG) continue; String sTextEncoding; boolean bTextBold = false; boolean bTextItalic = false; String sTextTypefaceName = t.getAttribute(SVG.FONTFAMILYTAG).toString(); Attribute boldState = t.peekAttribute(SVG.FONTWEIGHTTAG); if (boldState != null) { bTextBold = (boldState.toString().equals(STRS.BOLD)); } UnitSpan oTextPointSize = t.getMeasurement(SVG.FONTSIZETAG); Attribute fontStyle = t.peekAttribute(SVG.FONTSTYLETAG); if (fontStyle != null) bTextItalic = (fontStyle.toString().equals(STRS.ITALIC)); sTextEncoding = t.getAttribute(SVG.CODEPAGETAG).toString(); // Create a font info, so that we can reconcile the font and // get a proper font instance to render the text. FontInfo oTextFontInfo = new FontInfo(sTextTypefaceName, bTextBold ? FontInfo.WEIGHT_BOLD : FontInfo.WEIGHT_NORMAL, bTextItalic); //int eTextEncoding = FontService.getEncoding(sTextEncoding); FontInstance oTextFontInstance = m_oGfxLayoutEnv.fontService().reconcile(oTextFontInfo, oTextPointSize, 1, 1/*, eEncoding*/); for (SVGNode tspan = (SVGNode)t.getFirstXFAChild(); tspan != null; tspan = (SVGNode)tspan.getNextXFASibling()) { int nGlyphs = 0; if (tspan.getClassTag() != SVG.TSPANTAG && tspan.getClassTag() != SVG.ALTGLYPHTAG) continue; // Default typeface name is that of our parent element String sTypefaceName = sTextTypefaceName; Attribute typeface = tspan.peekAttribute(SVG.FONTFAMILYTAG); if (typeface != null) sTypefaceName = typeface.toString(); // Default Bold state is that of our parent element boolean bBold = bTextBold; Attribute bold = tspan.peekAttribute(SVG.FONTWEIGHTTAG); if (bold != null) bBold = (bold.toString().equals(STRS.BOLD)); // Default point size is that of our parent element UnitSpan oPointSize = oTextPointSize; Attribute pointSize = tspan.peekAttribute(SVG.FONTSIZETAG); if (pointSize != null) oPointSize = tspan.getMeasurement(SVG.FONTSIZETAG); // Default italic state is that of our parent element boolean bItalic = bTextItalic; fontStyle = tspan.peekAttribute(SVG.FONTSTYLETAG); if (fontStyle != null) bItalic = (fontStyle.toString().equals(STRS.ITALIC)); Attribute encoding = tspan.peekAttribute(SVG.CODEPAGETAG); String sEncoding = ""; if (encoding != null) sEncoding = encoding.toString(); FontInstance oFontInstance; // If no attributes have changed from the parent element, // then re-use the font instance we retrieved for it. if (sTypefaceName.equals(sTextTypefaceName) && sEncoding.equals(sTextEncoding) && bBold == bTextBold && bItalic == bTextItalic) { oFontInstance = oTextFontInstance; } else { // Create a font info, so that we can reconcile the font and // get a proper font instance to render the text. FontInfo oFontInfo = new FontInfo(sTypefaceName, bBold ? FontInfo.WEIGHT_BOLD : FontInfo.WEIGHT_NORMAL, bItalic); //int eEncoding = FontService.getEncoding(sEncoding); oFontInstance = m_oGfxLayoutEnv.fontService().reconcile(oFontInfo, oPointSize, 1, 1/*, eEncoding*/); } // // Todo: We shouldn't bail if there's no font! // if (oFontInstance != null) { if (tspan.getClassTag() == SVG.ALTGLYPHTAG) { String sContent = "" /* tspan.getAttribute(SVG.GLYPHREFTAG).toString() */; nGlyphs = (sContent.length() + 1) / 5; int[] pnGlyphs = new int[nGlyphs]; String whitespace = ", "; StringTokenizer sToker = new StringTokenizer(sContent, whitespace); for (int i = 0; i < nGlyphs; i++) { String sID = sToker.nextToken(); int nID = StringUtils.safeNumber(sID, 16); pnGlyphs[i] = nID; oFontInstance.getFontItem().addSubsettedGlyphs(nID, 0 /*, false */); } tspan.storeGlyphs(oFontInstance, pnGlyphs, nGlyphs); } else { SVGTextData text = (SVGTextData) tspan.getProperty(SVG.TEXTDATATAG, 0); if (text == null) continue; String sContent = text.getValue(); for (int i = 0; i < sContent.length(); i++) oFontInstance.getFontItem().addSubsettedGlyphs(0, (int) sContent.charAt(i)/*, true */); tspan.storeText(oFontInstance, sContent); } } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy