001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: FObjMixed.java 439511 2006-09-02 00:52:38Z adelmelle $ */
019:
020: package org.apache.fop.fo;
021:
022: import org.xml.sax.Locator;
023:
024: import org.apache.fop.apps.FOPException;
025:
026: /**
027: * Base class for representation of mixed content formatting objects
028: * (i.e., those that can contain both child FO's and text nodes/PCDATA).
029: * It should not be instantiated directly.
030: */
031: public abstract class FObjMixed extends FObj {
032:
033: /** Represents accumulated, pending FO text. See flushText(). */
034: protected FOText ft = null;
035:
036: /** Used for white-space handling; start CharIterator at node ... */
037: protected FONode currentTextNode;
038:
039: /** Used in creating pointers between subsequent FOText nodes
040: * in the same Block (for handling text-transform) */
041: protected FOText lastFOTextProcessed = null;
042:
043: /**
044: * @param parent FONode that is the parent of this object
045: */
046: protected FObjMixed(FONode parent) {
047: super (parent);
048: }
049:
050: /** @see org.apache.fop.fo.FONode */
051: protected void addCharacters(char[] data, int start, int end,
052: PropertyList pList, Locator locator) throws FOPException {
053: if (ft == null) {
054: ft = new FOText(this );
055: ft.setLocator(locator);
056: if (!inMarker()) {
057: ft.bind(pList);
058: }
059: }
060: ft.addCharacters(data, start, end, null, null);
061: }
062:
063: /** @see org.apache.fop.fo.FONode#endOfNode() */
064: protected void endOfNode() throws FOPException {
065: flushText();
066: if (!inMarker() || getNameId() == FO_MARKER) {
067: getFOEventHandler().whiteSpaceHandler.handleWhiteSpace(
068: this , currentTextNode);
069: }
070: super .endOfNode();
071: }
072:
073: /**
074: * Handles white-space for the node that is passed in,
075: * starting at its current text-node
076: * (used by RetrieveMarker to trigger 'end-of-node' white-space
077: * handling)
078: * @param fobj the node for which to handle white-space
079: */
080: protected static void handleWhiteSpaceFor(FObjMixed fobj) {
081: fobj.getFOEventHandler().getXMLWhiteSpaceHandler()
082: .handleWhiteSpace(fobj, fobj.currentTextNode);
083: }
084:
085: /**
086: * Adds accumulated text as one FOText instance, unless
087: * the one instance's char array contains more than
088: * Short.MAX_VALUE characters. In the latter case the
089: * instance is split up into more manageable chunks.
090: *
091: * @throws FOPException if there is a problem during processing
092: */
093: protected void flushText() throws FOPException {
094: if (ft != null) {
095: FOText lft = ft;
096: /* make sure nested calls to itself have no effect */
097: ft = null;
098: FOText tmpText;
099: int indexStart = 0;
100: int indexEnd = (lft.ca.length > Short.MAX_VALUE ? Short.MAX_VALUE
101: : lft.ca.length) - 1;
102: int charCount = 0;
103: short tmpSize;
104: while (charCount < lft.ca.length) {
105: tmpSize = (short) (indexEnd - indexStart + 1);
106: charCount += tmpSize;
107: tmpText = (FOText) lft.clone(this , false);
108: tmpText.ca = new char[tmpSize];
109: tmpText.startIndex = 0;
110: tmpText.endIndex = tmpSize;
111: System.arraycopy(lft.ca, indexStart, tmpText.ca, 0,
112: indexEnd - indexStart + 1);
113: if (getNameId() == FO_BLOCK) {
114: tmpText
115: .createBlockPointers((org.apache.fop.fo.flow.Block) this );
116: this .lastFOTextProcessed = tmpText;
117: } else if (getNameId() != FO_MARKER
118: && getNameId() != FO_TITLE
119: && getNameId() != FO_BOOKMARK_TITLE) {
120: FONode fo = parent;
121: int foNameId = fo.getNameId();
122: while (foNameId != FO_BLOCK
123: && foNameId != FO_MARKER
124: && foNameId != FO_TITLE
125: && foNameId != FO_BOOKMARK_TITLE
126: && foNameId != FO_PAGE_SEQUENCE) {
127: fo = fo.getParent();
128: foNameId = fo.getNameId();
129: }
130: if (foNameId == FO_BLOCK) {
131: tmpText
132: .createBlockPointers((org.apache.fop.fo.flow.Block) fo);
133: ((FObjMixed) fo).lastFOTextProcessed = tmpText;
134: } else if (foNameId == FO_PAGE_SEQUENCE) {
135: log.error("Could not create block pointers."
136: + " FOText w/o Block ancestor.");
137: }
138: }
139: tmpText.endOfNode();
140: addChildNode(tmpText);
141: indexStart = indexEnd + 1;
142: indexEnd = (((lft.ca.length - charCount) < Short.MAX_VALUE) ? lft.ca.length
143: : charCount + Short.MAX_VALUE) - 1;
144: }
145: }
146: }
147:
148: /**
149: * @see org.apache.fop.fo.FONode#addChildNode(FONode)
150: */
151: protected void addChildNode(FONode child) throws FOPException {
152: flushText();
153: if (!inMarker() || getNameId() == FO_MARKER) {
154: if (child instanceof FOText
155: || child.getNameId() == FO_CHARACTER) {
156: if (currentTextNode == null) {
157: currentTextNode = child;
158: }
159: } else {
160: // handle white-space for all text up to here
161: getFOEventHandler().whiteSpaceHandler.handleWhiteSpace(
162: this , currentTextNode, child);
163: currentTextNode = null;
164: }
165: }
166: super .addChildNode(child);
167: }
168:
169: /**
170: * @return iterator for this object
171: */
172: public CharIterator charIterator() {
173: return new RecursiveCharIterator(this);
174: }
175: }
|