Skip to content

Commit

Permalink
For #25 - Add method to builder to specify a custom line breaker. [ci…
Browse files Browse the repository at this point in the history
… skip]

See also implementation of line breaker using ICU4J in rtl-support
module.
  • Loading branch information
danfickle committed Jun 28, 2016
1 parent d2a0b90 commit f138331
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 79 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CHANGELOG

head - 0.0.1-RC5-SNAPSHOT
========
+ [Add method to builder to specify a custom line breaker](https://github.com/danfickle/openhtmltopdf/issues/25) Thanks @Magotchi

0.0.1-RC4
========
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.openhtmltopdf.extend;

/**
* Represents a text breaker, such as those on line break opportunities.
* Implementations usually wrap a BreakIterator of some kind.
* Will be reused many times during a run.
*/
public interface FSTextBreaker {
public int next();
public void setText(String newText);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@
*/
package com.openhtmltopdf.layout;

import java.text.BreakIterator;

import com.openhtmltopdf.css.constants.IdentValue;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.render.FSFont;

/**
Expand Down Expand Up @@ -109,7 +108,7 @@ private static void doBreakText(LayoutContext c,
boolean tryToBreakAnywhere) {
FSFont font = style.getFSFont(c);
String currentString = context.getStartSubstring();
BreakIterator iterator = getWordStream(currentString);
FSTextBreaker iterator = getLineBreakStream(currentString, c.getSharedContext());
int left = 0;
int right = tryToBreakAnywhere ? 1 : iterator.next();
int lastWrap = 0;
Expand Down Expand Up @@ -174,11 +173,9 @@ private static void doBreakText(LayoutContext c,
return;
}

public static BreakIterator getWordStream(String s) {
BreakIterator i = new UrlAwareLineBreakIterator();
public static FSTextBreaker getLineBreakStream(String s, SharedContext shared) {
FSTextBreaker i = shared.getLineBreaker();
i.setText(s);
return i;
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.text.BreakIterator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.w3c.dom.Document;
Expand All @@ -36,6 +38,7 @@
import com.openhtmltopdf.css.style.EmptyStyle;
import com.openhtmltopdf.css.value.FontSpecification;
import com.openhtmltopdf.extend.FSCanvas;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.extend.FontContext;
import com.openhtmltopdf.extend.FontResolver;
import com.openhtmltopdf.extend.NamespaceHandler;
Expand Down Expand Up @@ -126,6 +129,7 @@ public class SharedContext {
private boolean defaultPageSizeIsInches;

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

public SharedContext() {
}
Expand Down Expand Up @@ -634,6 +638,14 @@ public void setDefaultPageSize(Float pageWidth, Float pageHeight, boolean isInch
this.defaultPageSizeIsInches = isInches;
}

public FSTextBreaker getLineBreaker() {
return lineBreaker;
}

public void setLineBreaker(FSTextBreaker breaker) {
this.lineBreaker = breaker;
}

/**
* This registers the shared context with a thread local so it
* can be used anywhere. It should be matched with a call to
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
package com.openhtmltopdf.layout;

import java.text.BreakIterator;
import java.text.CharacterIterator;
import com.openhtmltopdf.extend.FSTextBreaker;


/**
* BreakIterator implementation that improves line breaking for URLs. Break points are supported
* before path fragments.
*/
public class UrlAwareLineBreakIterator extends BreakIterator {
public class UrlAwareLineBreakIterator implements FSTextBreaker {

private static final String BREAKING_CHARS = ".,:;!?- \n\r\t/";

private BreakIterator delegate = BreakIterator.getLineInstance();
private final BreakIterator delegate;
private String text;
private Range currentRange;


public int preceding(int offset) {
throw new UnsupportedOperationException("Not yet implemented");
}


public int last() {
throw new UnsupportedOperationException("Not yet implemented");
public UrlAwareLineBreakIterator(BreakIterator breaker) {
delegate = breaker;
}


public int previous() {
throw new UnsupportedOperationException("Not yet implemented");
}



@Override
public int next() {
checkNotAheadOfDelegate();

Expand Down Expand Up @@ -103,42 +92,7 @@ private boolean advanceDelegate() {
return next == BreakIterator.DONE;
}


public int next(int n) {
throw new UnsupportedOperationException("Not yet implemented");
}


public boolean isBoundary(int offset) {
throw new UnsupportedOperationException("Not yet implemented");
}


public int following(int offset) {
throw new UnsupportedOperationException("Not yet implemented");
}


public int first() {
throw new UnsupportedOperationException("Not yet implemented");
}


public void setText(CharacterIterator newText) {
throw new UnsupportedOperationException("Not yet implemented");
}


public int current() {
throw new UnsupportedOperationException("Not yet implemented");
}


public CharacterIterator getText() {
return delegate.getText();
}


@Override
public void setText(String newText) {
delegate.setText(newText);
text = newText;
Expand All @@ -148,56 +102,46 @@ public void setText(String newText) {

private static class Range {

int start;
int stop;

private final int start;
private final int stop;

public Range(int start, int stop) {
this.start = start;
this.stop = Math.max(start, stop);
}


public Range(int referencePoint, int startOffset, int stopOffset) {
this(referencePoint + startOffset, referencePoint + stopOffset);
}


public Range withStart(int start) {
return new Range(start, stop);
}


public Range withStop(int stop) {
return new Range(start, stop);
}


public Range incrementStart() {
int newStart = start + 1;
return new Range(newStart, Math.max(newStart, stop));
}


public Range decrementStop() {
int newStop = stop + -1;
return new Range(Math.min(start, newStop), newStop);
}


public int getStart() {
return start;
}


public int getStop() {
return stop;
}


public String toString() {
return "[" + start + ", " + stop + ")";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.openhtmltopdf.css.extend.ContentFunction;
import com.openhtmltopdf.css.parser.FSFunction;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.layout.Breaker;
import com.openhtmltopdf.layout.LayoutContext;
import com.openhtmltopdf.layout.Styleable;
Expand Down Expand Up @@ -247,7 +248,7 @@ private int calcMinWidthFromWordLength(
int lastWord = 0;

String text = getText(trimLeadingSpace);
BreakIterator breakIterator = Breaker.getWordStream(text);
FSTextBreaker breakIterator = Breaker.getLineBreakStream(text, c.getSharedContext());

// Breaker should be used
while ( (current = breakIterator.next()) != BreakIterator.DONE) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.openhtmltopdf.layout;

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

import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.layout.UrlAwareLineBreakIterator;

import junit.framework.TestCase;
Expand Down Expand Up @@ -107,7 +109,7 @@ public void testNext_IncompleteUrl() throws Exception {


private void assertBreaksCorrectly(String input, String[] segments) {
BreakIterator iterator = new UrlAwareLineBreakIterator();
FSTextBreaker iterator = new UrlAwareLineBreakIterator(BreakIterator.getLineInstance(Locale.US));
iterator.setText(input);

int segmentIndex = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.openhtmltopdf.context.StyleReference;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.extend.FSCache;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.extend.FSUriResolver;
import com.openhtmltopdf.extend.HttpStreamFactory;
import com.openhtmltopdf.extend.NamespaceHandler;
Expand All @@ -76,7 +77,6 @@
import com.openhtmltopdf.resource.XMLResource;
import com.openhtmltopdf.simple.extend.XhtmlNamespaceHandler;
import com.openhtmltopdf.util.Configuration;
import com.openhtmltopdf.util.ThreadCtx;
import com.openhtmltopdf.util.XRLog;

public class PdfBoxRenderer {
Expand Down Expand Up @@ -178,13 +178,14 @@ public PdfBoxRenderer(float dotsPerPoint, int dotsPerPixel, boolean useSubsets,

/**
* Do not use this method. It is constantly changing as options are added to the builder.
* @param lineBreaker
*/
public PdfBoxRenderer(boolean textDirection, boolean testMode,
boolean useSubsets, HttpStreamFactory httpStreamFactory,
BidiSplitterFactory splitterFactory, BidiReorderer reorderer, String html,
Document document, String baseUri, String uri, File file,
OutputStream os, FSUriResolver _resolver, FSCache _cache, SVGDrawer svgImpl,
Float pageWidth, Float pageHeight, boolean isPageSizeInches, float pdfVersion, String replacementText) {
Float pageWidth, Float pageHeight, boolean isPageSizeInches, float pdfVersion, String replacementText, FSTextBreaker lineBreaker) {

_pdfDoc = new PDDocument();
_pdfDoc.setVersion(pdfVersion);
Expand Down Expand Up @@ -244,6 +245,10 @@ public PdfBoxRenderer(boolean textDirection, boolean testMode,
this._outputDevice.setBidiReorderer(_reorderer);
}

if (lineBreaker != null) {
_sharedContext.setLineBreaker(lineBreaker);
}

this._defaultTextDirection = textDirection ? BidiSplitter.RTL : BidiSplitter.LTR;

if (html != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import com.openhtmltopdf.bidi.BidiReorderer;
import com.openhtmltopdf.bidi.BidiSplitterFactory;
import com.openhtmltopdf.extend.FSCache;
import com.openhtmltopdf.extend.FSTextBreaker;
import com.openhtmltopdf.extend.FSUriResolver;
import com.openhtmltopdf.extend.HttpStreamFactory;
import com.openhtmltopdf.extend.SVGDrawer;
import com.openhtmltopdf.swing.NaiveUserAgent;

public class PdfRendererBuilder
{
Expand Down Expand Up @@ -42,6 +42,7 @@ public static enum PageSizeUnits { MM, INCHES };
private boolean _isPageSizeInches;
private float _pdfVersion = 1.7f;
private String _replacementText;
private FSTextBreaker _lineBreaker;

/**
* Run the XHTML/XML to PDF conversion and output to an output stream set by toStream.
Expand All @@ -67,7 +68,8 @@ public void run() throws Exception {
public PdfBoxRenderer buildPdfRenderer() {
return new PdfBoxRenderer(_textDirection, _testMode, _useSubsets, _httpStreamFactory, _splitter, _reorderer,
_html, _document, _baseUri, _uri, _file, _os, _resolver, _cache, _svgImpl,
_pageWidth, _pageHeight, _isPageSizeInches, _pdfVersion, _replacementText);
_pageWidth, _pageHeight, _isPageSizeInches, _pdfVersion, _replacementText,
_lineBreaker);
}

/**
Expand Down Expand Up @@ -256,4 +258,19 @@ public PdfRendererBuilder useReplacementText(String replacement) {
this._replacementText = replacement;
return this;
}

/**
* Specify the line breaker. By default a Java default BreakIterator line instance is used
* with US locale. Additionally, this is wrapped with UrlAwareLineBreakIterator to also
* break before the forward slash (/) character so that long URIs can be broken on to multiple lines.
*
* You may want to use a BreakIterator with a different locale (wrapped by UrlAwareLineBreakIterator or not)
* or a more advanced BreakIterator from icu4j (see the rtl-support module for an example).
* @param breaker
* @return
*/
public PdfRendererBuilder useLineBreaker(FSTextBreaker breaker) {
this._lineBreaker = breaker;
return this;
}
}
Loading

0 comments on commit f138331

Please sign in to comment.