Skip to content

Commit

Permalink
For #28 - Add method to builder to set character break iterator.
Browse files Browse the repository at this point in the history
  • Loading branch information
danfickle committed Jun 30, 2016
1 parent f1597aa commit 6523242
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ public static void breakFirstLetter(LayoutContext c, LineBreakContext context,
private static int getFirstLetterEnd(String text, int start) {
boolean letterFound = false;
int end = text.length();
char currentChar;
for ( int i = start; i < end; i++ ) {
currentChar = text.charAt(i);
int currentChar;
for ( int i = start; i < end; ) {
currentChar = text.codePointAt(i);
if (!TextUtil.isFirstLetterSeparatorChar(currentChar)) {
if (letterFound) {
return i;
} else {
letterFound = true;
}
}
i += Character.charCount(currentChar);
}
return end;
}
Expand Down Expand Up @@ -106,11 +107,15 @@ public static void breakText(LayoutContext c,
private static void doBreakText(LayoutContext c,
LineBreakContext context, int avail, CalculatedStyle style,
boolean tryToBreakAnywhere) {
FSFont font = style.getFSFont(c);

FSFont font = style.getFSFont(c);
String currentString = context.getStartSubstring();
FSTextBreaker iterator = getLineBreakStream(currentString, c.getSharedContext());
FSTextBreaker iterator = tryToBreakAnywhere ?
getCharacterBreakStream(currentString, c.getSharedContext()) :
getLineBreakStream(currentString, c.getSharedContext());

int left = 0;
int right = tryToBreakAnywhere ? 1 : iterator.next();
int right = iterator.next();
int lastWrap = 0;
int graphicsLength = 0;
int lastGraphicsLength = 0;
Expand All @@ -121,12 +126,7 @@ private static void doBreakText(LayoutContext c,
c.getFontContext(), font, currentString.substring(left, right));
lastWrap = left;
left = right;
if ( tryToBreakAnywhere ) {
right = ( right + 1 ) % currentString.length();
}
else { // break relies on BreakIterator
right = iterator.next();
}
right = iterator.next();
}

if (graphicsLength <= avail) {
Expand Down Expand Up @@ -173,6 +173,12 @@ private static void doBreakText(LayoutContext c,
return;
}

public static FSTextBreaker getCharacterBreakStream(String currentString, SharedContext sharedContext) {
FSTextBreaker i = sharedContext.getCharacterBreaker();
i.setText(currentString);
return i;
}

public static FSTextBreaker getLineBreakStream(String s, SharedContext shared) {
FSTextBreaker i = shared.getLineBreaker();
i.setText(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public class SharedContext {

private String replacementText = "#";
private FSTextBreaker lineBreaker = new UrlAwareLineBreakIterator(BreakIterator.getLineInstance(Locale.US));
private FSTextBreaker characterBreaker = new TextUtil.DefaultCharacterBreaker(BreakIterator.getCharacterInstance(Locale.US));

private FSTextTransformer _unicodeToLowerTransformer = new TextUtil.DefaultToLowerTransformer(Locale.US);
private FSTextTransformer _unicodeToUpperTransformer = new TextUtil.DefaultToUpperTransformer(Locale.US);
Expand Down Expand Up @@ -650,6 +651,15 @@ public FSTextBreaker getLineBreaker() {
public void setLineBreaker(FSTextBreaker breaker) {
this.lineBreaker = breaker;
}

public FSTextBreaker getCharacterBreaker() {
return characterBreaker;
}

public void setCharacterBreaker(FSTextBreaker breaker) {
this.characterBreaker = breaker;
}


/**
* This registers the shared context with a thread local so it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,35 @@
*/
package com.openhtmltopdf.layout;

import java.text.BreakIterator;
import java.util.Locale;

import com.openhtmltopdf.css.constants.CSSName;
import com.openhtmltopdf.css.constants.IdentValue;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.extend.FSTextTransformer;
import com.openhtmltopdf.util.ThreadCtx;
import com.openhtmltopdf.util.Uu;


/**
* Description of the Class
*
* @author empty
*/
public class TextUtil {
public static class DefaultCharacterBreaker implements FSTextBreaker {
private final BreakIterator iter;

public DefaultCharacterBreaker(BreakIterator iter) {
this.iter = iter;
}

@Override
public int next() {
return iter.next();
}

@Override
public void setText(String newText) {
iter.setText(newText);
}
}

public static class DefaultToUpperTransformer implements FSTextTransformer {
private final Locale lc;

Expand Down Expand Up @@ -95,81 +108,36 @@ public String transform(String in) {

public static String transformText( String text, CalculatedStyle style ) {
IdentValue transform = style.getIdent( CSSName.TEXT_TRANSFORM );
IdentValue fontVariant = style.getIdent( CSSName.FONT_VARIANT );

SharedContext ctx = ThreadCtx.get().sharedContext();

if ( transform == IdentValue.LOWERCASE ) {
text = ctx.getUnicodeToLowerTransformer().transform(text);
}
if ( transform == IdentValue.UPPERCASE ) {
if ( transform == IdentValue.UPPERCASE ||
fontVariant == IdentValue.SMALL_CAPS ) {
text = ctx.getUnicodeToUpperTransformer().transform(text);
}
if ( transform == IdentValue.CAPITALIZE ) {
text = ctx.getUnicodeToTitleTransformer().transform(text);
}
IdentValue fontVariant = style.getIdent( CSSName.FONT_VARIANT );
if ( fontVariant == IdentValue.SMALL_CAPS ) {
text = ctx.getUnicodeToUpperTransformer().transform(text);
}
return text;
}

/**
* Description of the Method
*
* @param text PARAM
* @param style
* @return Returns
*/
public static String transformFirstLetterText( String text, CalculatedStyle style ) {
if (text.length() > 0) {
IdentValue transform = style.getIdent( CSSName.TEXT_TRANSFORM );
IdentValue fontVariant = style.getIdent( CSSName.FONT_VARIANT );
char currentChar;
for ( int i = 0, end = text.length(); i < end; i++ ) {
currentChar = text.charAt(i);
if ( !isFirstLetterSeparatorChar( currentChar ) ) {
if ( transform == IdentValue.LOWERCASE ) {
currentChar = Character.toLowerCase( currentChar );
text = replaceChar( text, currentChar, i );
} else if ( transform == IdentValue.UPPERCASE || transform == IdentValue.CAPITALIZE || fontVariant == IdentValue.SMALL_CAPS ) {
currentChar = Character.toUpperCase( currentChar );
text = replaceChar( text, currentChar, i );
}
break;
}
}
}
return text;
}

/**
* Replace character at the specified index by another.
*
* @param text Source text
* @param newChar Replacement character
* @return Returns the new text
*/
public static String replaceChar( String text, char newChar, int index ) {
int textLength = text.length();
StringBuilder b = new StringBuilder(textLength);
for (int i = 0; i < textLength; i++) {
if (i == index) {
b.append(newChar);
} else {
b.append(text.charAt(i));
}
}
return b.toString();
public static String transformFirstLetterText( String text, CalculatedStyle style ) {
return transformText(text, style);
}

/**
* Description of the Method
*
* @param c PARAM
* @return Returns
* According to the CSS spec the first letter includes certain punctuation immediately
* preceding or following the actual first letter.
* @param currentChar
* @return
*/
public static boolean isFirstLetterSeparatorChar( char c ) {
switch (Character.getType(c)) {
public static boolean isFirstLetterSeparatorChar( int currentChar ) {
switch (Character.getType(currentChar)) {
case Character.START_PUNCTUATION:
case Character.END_PUNCTUATION:
case Character.INITIAL_QUOTE_PUNCTUATION:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.openhtmltopdf.layout;

import java.util.Locale;

import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;

import com.openhtmltopdf.extend.FSTextTransformer;

public class TextTransformersTest {
@Test
public void testSimpleToUpperTransform() {
FSTextTransformer tr = new TextUtil.DefaultToUpperTransformer(Locale.US);
Assert.assertThat(tr.transform("this is a Test"), equalTo("THIS IS A TEST"));
}

@Test
public void testSimpleToLowerTransform() {
FSTextTransformer tr = new TextUtil.DefaultToLowerTransformer(Locale.US);
Assert.assertThat(tr.transform("THIS IS a TEST"), equalTo("this is a test"));
}

@Test
public void testSimpleToTitleTransform() {
FSTextTransformer tr = new TextUtil.DefaultToTitleTransformer();
Assert.assertThat(tr.transform("this iS a teST"), equalTo("This IS A TeST"));
}

@Test
public void testPunctuationUnchanged() {
FSTextTransformer[] trs = new FSTextTransformer[] {
new TextUtil.DefaultToUpperTransformer(Locale.US),
new TextUtil.DefaultToLowerTransformer(Locale.US),
new TextUtil.DefaultToTitleTransformer() };

for (FSTextTransformer tr : trs) {
Assert.assertThat(tr.transform("!@#$%^&&*()_-+=?/><,.~`"), equalTo("!@#$%^&&*()_-+=?/><,.~`"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,23 @@ static class UnicodeImplementation {
final BidiReorderer reorderer;
final BidiSplitterFactory splitterFactory;
final FSTextBreaker lineBreaker;
final FSTextBreaker charBreaker;
final FSTextTransformer toLowerTransformer;
final FSTextTransformer toUpperTransformer;
final FSTextTransformer toTitleTransformer;
final boolean textDirection;

UnicodeImplementation(BidiReorderer reorderer, BidiSplitterFactory splitterFactory,
FSTextBreaker lineBreaker, FSTextTransformer toLower, FSTextTransformer toUpper,
FSTextTransformer toTitle, boolean textDirection) {
FSTextTransformer toTitle, boolean textDirection, FSTextBreaker charBreaker) {
this.reorderer = reorderer;
this.splitterFactory = splitterFactory;
this.lineBreaker = lineBreaker;
this.toLowerTransformer = toLower;
this.toUpperTransformer = toUpper;
this.toTitleTransformer = toTitle;
this.textDirection = textDirection;
this.charBreaker = charBreaker;
}
}

Expand Down Expand Up @@ -297,6 +299,10 @@ static class BaseDocument {
_sharedContext.setLineBreaker(unicode.lineBreaker);
}

if (unicode.charBreaker != null) {
_sharedContext.setCharacterBreaker(unicode.charBreaker);
}

if (unicode.toLowerTransformer != null) {
_sharedContext.setUnicodeToLowerTransformer(unicode.toLowerTransformer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ public static enum PageSizeUnits { MM, INCHES };
private float _pdfVersion = 1.7f;
private String _replacementText;
private FSTextBreaker _lineBreaker;
private FSTextBreaker _charBreaker;
private FSTextTransformer _unicodeToUpperTransformer;
private FSTextTransformer _unicodeToLowerTransformer;
private FSTextTransformer _unicodeToTitleTransformer;


/**
* Run the XHTML/XML to PDF conversion and output to an output stream set by toStream.
Expand All @@ -74,7 +76,7 @@ public void run() throws Exception {
*/
public PdfBoxRenderer buildPdfRenderer() {
UnicodeImplementation unicode = new UnicodeImplementation(_reorderer, _splitter, _lineBreaker,
_unicodeToLowerTransformer, _unicodeToUpperTransformer, _unicodeToTitleTransformer, _textDirection);
_unicodeToLowerTransformer, _unicodeToUpperTransformer, _unicodeToTitleTransformer, _textDirection, _charBreaker);

PageDimensions pageSize = new PageDimensions(_pageWidth, _pageHeight, _isPageSizeInches);

Expand Down Expand Up @@ -285,6 +287,18 @@ public PdfRendererBuilder useUnicodeLineBreaker(FSTextBreaker breaker) {
return this;
}

/**
* Specify the character breaker. By default a break iterator character instance is used with
* US locale. Currently this is used when <code>word-wrap: break-word</code> is in
* effect.
* @param breaker
* @return
*/
public PdfRendererBuilder useUnicodeCharacterBreaker(FSTextBreaker breaker) {
this._charBreaker = breaker;
return this;
}

/**
* Specify a transformer to use to upper case strings.
* By default <code>String::toUpperCase(Locale.US)</code> is used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,22 @@ public void setText(String newText) {
this.breaker.setText(newText);
}
}

public static class ICUCharacterBreaker implements FSTextBreaker {
private final BreakIterator breaker;

public ICUCharacterBreaker(Locale locale) {
this.breaker = BreakIterator.getCharacterInstance(locale);
}

@Override
public int next() {
return this.breaker.next();
}

@Override
public void setText(String newText) {
this.breaker.setText(newText);
}
}
}

0 comments on commit 6523242

Please sign in to comment.