Hopefully handle the building and using of RichTextRuns correctly. Should include proper handling of the +1 length in the styles (Bug 39177), and shared character/paragraph styles (Bugs 39547 and 38544)

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@413912 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2006-06-13 14:57:34 +00:00
parent 01f4fd56fe
commit 6f7e6cba29
2 changed files with 150 additions and 39 deletions

View File

@ -20,6 +20,7 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Vector;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.record.StyleTextPropAtom.TextPropCollection; import org.apache.poi.hslf.record.StyleTextPropAtom.TextPropCollection;
@ -92,51 +93,149 @@ public class TextRun
cStyles = _styleAtom.getCharacterStyles(); cStyles = _styleAtom.getCharacterStyles();
} }
_rtRuns = new RichTextRun[cStyles.size()];
// Handle case of no current style, with a default // Handle case of no current style, with a default
if(_rtRuns.length == 0) { if(pStyles.size() == 0 || cStyles.size() == 0) {
_rtRuns = new RichTextRun[1]; _rtRuns = new RichTextRun[1];
_rtRuns[0] = new RichTextRun(this, 0, runRawText.length()); _rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
} else { } else {
// Build up Rich Text Runs, one for each character style block // Build up Rich Text Runs, one for each
// TODO: Handle case of shared character styles // character/paragraph style pair
Vector rtrs = new Vector();
int pos = 0; int pos = 0;
int curP = 0; int curP = 0;
int pLenRemain = ((TextPropCollection)pStyles.get(curP)).getCharactersCovered(); int curC = 0;
int pLenRemain = -1;
int cLenRemain = -1;
// Build one for each character style // Build one for each run with the same style
for(int i=0; i<_rtRuns.length; i++) { while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
// Get the Props to use // Get the Props to use
TextPropCollection pProps = (TextPropCollection)pStyles.get(curP); TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
TextPropCollection cProps = (TextPropCollection)cStyles.get(i); TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
// Get the length to extend over int pLen = pProps.getCharactersCovered();
// (Last run is often 1 char shorter than the cProp claims) int cLen = cProps.getCharactersCovered();
int len = cProps.getCharactersCovered();
if(len+pos > runRawText.length()) {
len = runRawText.length()-pos;
}
// Build the rich text run // Handle new pass
// TODO: Tell the RichTextRun if the styles are shared boolean freshSet = false;
_rtRuns[i] = new RichTextRun(this, pos, len, pProps, cProps, false, false); if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
pos += len; if(pLenRemain == -1) { pLenRemain = pLen; }
if(cLenRemain == -1) { cLenRemain = cLen; }
// See if we need to move onto the next paragraph style // So we know how to build the eventual run
pLenRemain -= len; int runLen = -1;
if(pLenRemain == 0) { boolean pShared = false;
boolean cShared = false;
// Same size, new styles - neither shared
if(pLen == cLen && freshSet) {
runLen = cLen;
pShared = false;
cShared = false;
curP++; curP++;
if(curP < pStyles.size()) { curC++;
pLenRemain = ((TextPropCollection)pStyles.get(curP)).getCharactersCovered(); pLenRemain = -1;
cLenRemain = -1;
} else {
// Some sharing
// See if we are already in a shared block
if(pLenRemain < pLen) {
// Existing shared p block
pShared = true;
// Do we end with the c block, or either side of it?
if(pLenRemain == cLenRemain) {
// We end at the same time
cShared = false;
runLen = pLenRemain;
curP++;
curC++;
pLenRemain = -1;
cLenRemain = -1;
} else if(pLenRemain < cLenRemain) {
// We end before the c block
cShared = true;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
} else {
// We end after the c block
cShared = false;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
}
} else if(cLenRemain < cLen) {
// Existing shared c block
cShared = true;
// Do we end with the p block, or either side of it?
if(pLenRemain == cLenRemain) {
// We end at the same time
pShared = false;
runLen = cLenRemain;
curP++;
curC++;
pLenRemain = -1;
cLenRemain = -1;
} else if(cLenRemain < pLenRemain) {
// We end before the p block
pShared = true;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
} else {
// We end after the p block
pShared = false;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
}
} else {
// Start of a shared block
if(pLenRemain < cLenRemain) {
// Shared c block
pShared = false;
cShared = true;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
} else {
// Shared p block
pShared = true;
cShared = false;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
}
} }
} }
if(pLenRemain < 0) {
System.err.println("Paragraph style ran out before character style did! Short by " + (0-pLenRemain) + " characters."); // Wind on
System.err.println("Calling RichTextRun functions is likely to break things - see Bug #38544"); int prevPos = pos;
pos += runLen;
// Adjust for end-of-run extra 1 length
if(pos > runRawText.length()) {
runLen--;
} }
// Save
RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
rtrs.add(rtr);
} }
// Build the array
_rtRuns = new RichTextRun[rtrs.size()];
rtrs.copyInto(_rtRuns);
} }
} }
@ -212,21 +311,31 @@ public class TextRun
ensureStyleAtomPresent(); ensureStyleAtomPresent();
// Update the text length for its Paragraph and Character stylings // Update the text length for its Paragraph and Character stylings
// If it's shared:
// * calculate the new length based on the run's old text
// * this should leave in any +1's for the end of block if needed
// If it isn't shared:
// * reset the length, to the new string's length
// * add on +1 if the last block
// The last run needs its stylings to be 1 longer than the raw
// text is. This is to define the stylings that any new text
// that is added will inherit
TextPropCollection pCol = run._getRawParagraphStyle(); TextPropCollection pCol = run._getRawParagraphStyle();
TextPropCollection cCol = run._getRawCharacterStyle(); TextPropCollection cCol = run._getRawCharacterStyle();
// Character style covers the new run int newSize = s.length();
cCol.updateTextSize(s.length());
// Paragraph might cover other runs to, so remove old size and add new one
pCol.updateTextSize( pCol.getCharactersCovered() - run.getLength() + s.length());
// If we were dealing with the last RichTextRun in the set, then
// we need to tell the Character TextPropCollections a size 1 bigger
// than it really is
// (The Paragraph one will keep the extra 1 length from before)
// This extra style length is used to indicate that new text in
// the paragraph should go into this set of styling
if(runID == _rtRuns.length-1) { if(runID == _rtRuns.length-1) {
cCol.updateTextSize( cCol.getCharactersCovered() + 1 ); newSize++;
}
if(run._isParagraphStyleShared()) {
pCol.updateTextSize( pCol.getCharactersCovered() - run.getLength() + s.length() );
} else {
pCol.updateTextSize(newSize);
}
if(run._isCharacterStyleShared()) {
cCol.updateTextSize( cCol.getCharactersCovered() - run.getLength() + s.length() );
} else {
cCol.updateTextSize(newSize);
} }
// Build up the new text // Build up the new text

View File

@ -82,6 +82,8 @@ public class RichTextRun
length = len; length = len;
paragraphStyle = pStyle; paragraphStyle = pStyle;
characterStyle = cStyle; characterStyle = cStyle;
sharingParagraphStyle = pShared;
sharingCharacterStyle = cShared;
} }
/** /**