Skip to content

Commit

Permalink
#482 #483 #491 Make word breaker testable and start writing tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
danfickle committed May 27, 2020
1 parent b885384 commit 430edfb
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ void copyTo(AppBreakOpportunity other) {
other.isSoftHyphenBreak = isSoftHyphenBreak;
}
}

public static LineBreakResult doBreakText(
LayoutContext c,
LineBreakContext context,
Expand All @@ -402,8 +402,22 @@ public static LineBreakResult doBreakText(
? style.getFloatPropertyProportionalWidth(CSSName.LETTER_SPACING, 0, c)
: 0f;

ToIntFunction<String> measurer = (str) ->
c.getTextRenderer().getWidth(c.getFontContext(), font, str);

String currentString = context.getStartSubstring();
FSTextBreaker iterator = lineBreaker.getBreaker(currentString, c.getSharedContext());
FSTextBreaker lineIterator = lineBreaker.getBreaker(currentString, c.getSharedContext());

return doBreakTextWords(currentString, context, avail, lineIterator, letterSpacing, measurer);
}

static LineBreakResult doBreakTextWords(
String currentString,
LineBreakContext context,
int avail,
FSTextBreaker iterator,
float letterSpacing,
ToIntFunction<String> measurer) {

int lastWrap = 0;

Expand All @@ -423,13 +437,12 @@ public static LineBreakResult doBreakText(
String subString = currentString.substring(current.left, current.right);
float extraSpacing = (current.right - current.left) * letterSpacing;

int normalSplitWidth = (int) (c.getTextRenderer().getWidth(
c.getFontContext(), font, subString) + extraSpacing);

int normalSplitWidth = (int) (measurer.applyAsInt(subString) + extraSpacing);

if (currentString.charAt(current.right - 1) == SOFT_HYPHEN) {
current.isSoftHyphenBreak = true;
int withTrailingHyphenSplitWidth = (int) (c.getTextRenderer().getWidth(
c.getFontContext(), font, subString + '-') +
int withTrailingHyphenSplitWidth = (int)
(measurer.applyAsInt(subString + '-') +
extraSpacing + letterSpacing);
current.withHyphenGraphicsLength = current.graphicsLength + withTrailingHyphenSplitWidth;

Expand Down Expand Up @@ -458,8 +471,8 @@ public static LineBreakResult doBreakText(
current.copyTo(prev);
current.right = currentString.length();
float extraSpacing = (current.right - current.left) * letterSpacing;
int splitWidth = (int) (c.getTextRenderer().getWidth(
c.getFontContext(), font, currentString.substring(current.left)) + extraSpacing);
int splitWidth = (int) (measurer.applyAsInt(
currentString.substring(current.left)) + extraSpacing);
current.graphicsLength += splitWidth;
nextUnfittableSplitWidth = splitWidth;
}
Expand Down Expand Up @@ -500,8 +513,7 @@ public static LineBreakResult doBreakText(
} else if (current.left == currentString.length()) {
String text = context.getCalculatedSubstring();
float extraSpacing = text.length() * letterSpacing;
context.setWidth((int) (c.getTextRenderer().getWidth(
c.getFontContext(), font, text) + extraSpacing));
context.setWidth((int) (measurer.applyAsInt(text) + extraSpacing));
} else {
context.setWidth(current.graphicsLength);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public boolean isEndsOnSoftHyphen() {
}

public void setEndsOnSoftHyphen(boolean b) {
this._endsOnSoftHyphen = true;
this._endsOnSoftHyphen = b;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,72 +1,15 @@
package com.openhtmltopdf.layout;

import java.util.function.ToIntFunction;

import org.junit.Test;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;

import com.openhtmltopdf.extend.FSTextBreaker;
import static com.openhtmltopdf.layout.BreakerTestSupport.*;

public class BreakerTest {
private static class SimpleCharBreaker implements FSTextBreaker {
private String text;
private int pos;

@Override
public int next() {
return pos > text.length() ? -1 : pos++;
}

@Override
public void setText(String newText) {
this.text = newText;
this.pos = 0;
}
}

private static class SimpleLineBreaker implements FSTextBreaker {
private String text;
private int position;

@Override
public int next() {
int ret = text.indexOf(' ', this.position);
this.position = ret < 0 ? -1 : ret + 1;
return ret;
}

@Override
public void setText(String newText) {
this.text = newText;
this.position = 0;
}
}

private FSTextBreaker createLine(String line) {
SimpleLineBreaker breaker = new SimpleLineBreaker();
breaker.setText(line);
return breaker;
}

private FSTextBreaker createChar(String line) {
FSTextBreaker breaker = new SimpleCharBreaker();
breaker.setText(line);
return breaker;
}

private final ToIntFunction<String> MEASURER = (str) -> str.length();
private final ToIntFunction<String> MEASURER3 = (str) -> str.length() * 3;

private LineBreakContext createContext(String str) {
LineBreakContext ctx = new LineBreakContext();
ctx.setMaster(str);
return ctx;
}

@Test
public void testCharacterBreakerSingleChar() {
String whole = "A";
Expand Down Expand Up @@ -108,8 +51,8 @@ public void testCharacterBreakerUntilWord() {

assertFalse(context.isUnbreakable());
assertFalse(context.isNeedsNewLine());
assertThat(context.getWidth(), equalTo(4));
assertThat(context.getEnd(), equalTo(4));
assertThat(context.getWidth(), equalTo(5));
assertThat(context.getEnd(), equalTo(5));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.openhtmltopdf.layout;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;

import java.util.Arrays;
import java.util.EnumSet;
import java.util.function.ToIntFunction;

import com.openhtmltopdf.extend.FSTextBreaker;

public class BreakerTestSupport {
enum ContextIs {
UNBREAKABLE,
NEEDS_NEW_LINE,
FINISHED_IN_CHAR_BREAKING_MODE,
FINISHED,
ENDS_ON_NL,
/**
* This should really be called ENDS_ON_VISIBLE_SOFT_HYPHEN.
*/
ENDS_ON_SOFT_HYPHEN,
ENDS_ON_WORD_BREAK
}

static void assertContextIs(LineBreakContext context, ContextIs... trues) {
EnumSet<ContextIs> truthy = trues.length > 0 ?
EnumSet.copyOf(Arrays.asList(trues)) :
EnumSet.noneOf(ContextIs.class);
boolean desired;

desired = truthy.contains(ContextIs.UNBREAKABLE);
assertThat(context.isUnbreakable(), equalTo(desired));

desired = truthy.contains(ContextIs.NEEDS_NEW_LINE);
assertThat(context.isNeedsNewLine(), equalTo(desired));

desired = truthy.contains(ContextIs.FINISHED_IN_CHAR_BREAKING_MODE);
assertThat(context.isFinishedInCharBreakingMode(), equalTo(desired));

desired = truthy.contains(ContextIs.FINISHED);
assertThat(context.isFinished(), equalTo(desired));

desired = truthy.contains(ContextIs.ENDS_ON_NL);
assertThat(context.isEndsOnNL(), equalTo(desired));

desired = truthy.contains(ContextIs.ENDS_ON_SOFT_HYPHEN);
assertThat(context.isEndsOnSoftHyphen(), equalTo(desired));

desired = truthy.contains(ContextIs.ENDS_ON_WORD_BREAK);
assertThat(context.isEndsOnWordBreak(), equalTo(desired));
}

private static class SimpleCharBreaker implements FSTextBreaker {
private String text;
private int pos;

@Override
public int next() {
return pos > text.length() ? -1 : pos++;
}

@Override
public void setText(String newText) {
this.text = newText;
this.pos = 0;
}
}

private static class SimpleLineBreaker implements FSTextBreaker {
private String text;
private int position;

@Override
public int next() {
if (this.position == -1) {
return -1;
}

int ret = text.indexOf(' ', this.position);
int softHyphen = text.indexOf('\u00ad', this.position);

if (softHyphen != -1 && (softHyphen < ret || ret == -1)) {
ret = softHyphen;
}

this.position = ret < 0 ? -1 : ret + 1;
return this.position;
}

@Override
public void setText(String newText) {
this.text = newText;
this.position = 0;
}
}

static FSTextBreaker createLine(String line) {
SimpleLineBreaker breaker = new SimpleLineBreaker();
breaker.setText(line);
return breaker;
}

static FSTextBreaker createChar(String line) {
FSTextBreaker breaker = new SimpleCharBreaker();
breaker.setText(line);
return breaker;
}

static LineBreakContext createContext(String str) {
LineBreakContext ctx = new LineBreakContext();
ctx.setMaster(str);
return ctx;
}

static final ToIntFunction<String> MEASURER = (str) -> str.length();
static final ToIntFunction<String> MEASURER3 = (str) -> str.length() * 3;
static final ToIntFunction<String> MEASURER_WITH_ZERO_WIDTH_SOFT_HYPHEN = (str) -> {
long softHyphenCount = str.chars().filter(ch -> ch == Breaker.SOFT_HYPHEN).count();
return (int) (str.length() - softHyphenCount);
};
}
Loading

0 comments on commit 430edfb

Please sign in to comment.