diff --git a/itext.tests/itext.layout.tests/itext/layout/HyphenateLayoutTest.cs b/itext.tests/itext.layout.tests/itext/layout/HyphenateLayoutTest.cs index 30b4e263d5..8255647b54 100644 --- a/itext.tests/itext.layout.tests/itext/layout/HyphenateLayoutTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/HyphenateLayoutTest.cs @@ -244,5 +244,20 @@ public virtual void HyphenSymbolTest01() { NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, destinationFolder , "diff")); } + + [NUnit.Framework.Test] + public virtual void WordsBreakingWordSoftHyphenTest() { + String outFileName = destinationFolder + "wordsBreakingWordSoftHyphenTest.pdf"; + String cmpFileName = sourceFolder + "cmp_wordsBreakingWordSoftHyphenTest.pdf"; + String SOFT_HYPHEN = "\u00AD"; + String text = "Soft hyphen at the mid" + SOFT_HYPHEN + "dle,\nhyphen at the end: abcdef" + SOFT_HYPHEN + "ghijklmnopqrst\n" + + SOFT_HYPHEN + "hyphen at the beginning."; + using (Document document = new Document(new PdfDocument(new PdfWriter(outFileName)))) { + document.Add(new Paragraph(text).SetWidth(150).SetBorder(new SolidBorder(1)).SetHyphenation(new HyphenationConfig + (1, 1))); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, destinationFolder + )); + } } } diff --git a/itext.tests/itext.layout.tests/itext/layout/font/selectorstrategy/BestMatchFontSelectorStrategyTest.cs b/itext.tests/itext.layout.tests/itext/layout/font/selectorstrategy/BestMatchFontSelectorStrategyTest.cs index c703652c74..b0d393c8bd 100644 --- a/itext.tests/itext.layout.tests/itext/layout/font/selectorstrategy/BestMatchFontSelectorStrategyTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/font/selectorstrategy/BestMatchFontSelectorStrategyTest.cs @@ -36,8 +36,8 @@ public virtual void TwoDiacriticsInRowTest() { IList> result = strategy.GetGlyphLines("L with accent: \u004f\u0301\u0302 abc"); NUnit.Framework.Assert.AreEqual(3, result.Count); NUnit.Framework.Assert.AreEqual("L with accent: ", result[0].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual("\u004f\u0301\u0302", result[1].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual(" abc", result[2].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("\u004f\u0301\u0302 ", result[1].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("abc", result[2].GetFirst().ToString()); // Diacritics and symbol were separated, but the font is the same NUnit.Framework.Assert.AreEqual(result[0].GetSecond(), result[2].GetSecond()); } @@ -49,8 +49,8 @@ public virtual void OneDiacriticTest() { IList> result = strategy.GetGlyphLines("L with accent: \u004f\u0302 abc"); NUnit.Framework.Assert.AreEqual(3, result.Count); NUnit.Framework.Assert.AreEqual("L with accent: ", result[0].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual("\u004f\u0302", result[1].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual(" abc", result[2].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("\u004f\u0302 ", result[1].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("abc", result[2].GetFirst().ToString()); NUnit.Framework.Assert.AreNotEqual(result[0].GetSecond(), result[1].GetSecond()); } @@ -75,8 +75,8 @@ public virtual void DiacriticFontDoesnotContainPreviousSymbolTest() { NUnit.Framework.Assert.AreEqual(6, result.Count); NUnit.Framework.Assert.AreEqual("Ми", result[0].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("\u0301", result[1].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual("ръ", result[2].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual(" (mír", result[3].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("ръ (", result[2].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("mír", result[3].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("ə", result[4].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual(")", result[5].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual(result[0].GetSecond(), result[2].GetSecond()); @@ -100,8 +100,8 @@ public virtual void SurrogatePairsTest() { IList> result = strategy.GetGlyphLines("text \uD800\uDF10\uD800\uDF00\uD800\uDF11 text" ); NUnit.Framework.Assert.AreEqual(3, result.Count); - NUnit.Framework.Assert.AreEqual("text", result[0].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual(" \uD800\uDF10\uD800\uDF00\uD800\uDF11 ", result[1].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("text ", result[0].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("\uD800\uDF10\uD800\uDF00\uD800\uDF11 ", result[1].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("text", result[2].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual(result[0].GetSecond(), result[2].GetSecond()); } @@ -122,13 +122,21 @@ public virtual void ThreeFontWithSpacesTest() { IFontSelectorStrategy strategy = FontSelectorTestsUtil.CreateStrategyWithLimitedThreeFonts(new BestMatchFontSelectorStrategy.BestMatchFontSelectorStrategyFactory ()); IList> result = strategy.GetGlyphLines(" axadefa "); - NUnit.Framework.Assert.AreEqual(6, result.Count); + NUnit.Framework.Assert.AreEqual(5, result.Count); NUnit.Framework.Assert.AreEqual(" a", result[0].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("x", result[1].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("a", result[2].GetFirst().ToString()); NUnit.Framework.Assert.AreEqual("def", result[3].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual("a", result[4].GetFirst().ToString()); - NUnit.Framework.Assert.AreEqual(" ", result[5].GetFirst().ToString()); + NUnit.Framework.Assert.AreEqual("a ", result[4].GetFirst().ToString()); + } + + [NUnit.Framework.Test] + public virtual void WindowsLineEndingsTest() { + IFontSelectorStrategy strategy = FontSelectorTestsUtil.CreateStrategyWithFreeSans(new BestMatchFontSelectorStrategy.BestMatchFontSelectorStrategyFactory + ()); + IList> result = strategy.GetGlyphLines("Hello\r\n World!\r\n "); + NUnit.Framework.Assert.AreEqual(1, result.Count); + NUnit.Framework.Assert.AreEqual("Hello\r\n World!\r\n ", result[0].GetFirst().ToString()); } } } diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_checkThreeFontsInOneLineWithUnicodeRange.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_checkThreeFontsInOneLineWithUnicodeRange.pdf index c436675d64..2403a4cbb2 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_checkThreeFontsInOneLineWithUnicodeRange.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_checkThreeFontsInOneLineWithUnicodeRange.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup.pdf index 4ed5f7f8cf..03676c4a35 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup2.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup2.pdf index 3606e69da7..d325f64b4d 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup2.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup2.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup3.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup3.pdf index fbe7d8afa0..e4ebbb8797 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup3.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinGroup3.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinWithUnicodeRange.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinWithUnicodeRange.pdf index b4ccf49431..4d31ceda72 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinWithUnicodeRange.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_cyrillicAndLatinWithUnicodeRange.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_duplicateFontWithUnicodeRange.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_duplicateFontWithUnicodeRange.pdf index d28b1a7a4b..89fed9a2a5 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_duplicateFontWithUnicodeRange.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/FontSelectorTest/cmp_duplicateFontWithUnicodeRange.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/HyphenateLayoutTest/cmp_wordsBreakingWordSoftHyphenTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/HyphenateLayoutTest/cmp_wordsBreakingWordSoftHyphenTest.pdf new file mode 100644 index 0000000000..9007d8a9c5 Binary files /dev/null and b/itext.tests/itext.layout.tests/resources/itext/layout/HyphenateLayoutTest/cmp_wordsBreakingWordSoftHyphenTest.pdf differ diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_notAsciiCharTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_notAsciiCharTest.pdf index b743463bab..3a5f0bc2f3 100644 Binary files a/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_notAsciiCharTest.pdf and b/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_notAsciiCharTest.pdf differ diff --git a/itext/itext.layout/itext/layout/font/selectorstrategy/AbstractFontSelectorStrategy.cs b/itext/itext.layout/itext/layout/font/selectorstrategy/AbstractFontSelectorStrategy.cs index 0aaf3db995..5fbb7aa1f4 100644 --- a/itext/itext.layout/itext/layout/font/selectorstrategy/AbstractFontSelectorStrategy.cs +++ b/itext/itext.layout/itext/layout/font/selectorstrategy/AbstractFontSelectorStrategy.cs @@ -109,7 +109,8 @@ public virtual IList> GetGlyphLines(String text) { if (codePoint > 0xFFFF) { i++; } - if (IsCurrentFontCheckRequired() && (i != indexDiacritic - 1)) { + if (IsCurrentFontCheckRequired() && (i != indexDiacritic - 1) && !iText.IO.Util.TextUtil.IsWhitespaceOrNonPrintable + (codePoint)) { if (currentFont != MatchFont(codePoint, fontSelector, fontProvider, additionalFonts)) { breakRequested = true; } @@ -191,8 +192,7 @@ protected internal virtual PdfFont MatchFont(int codePoint, FontSelector fontSel foreach (FontInfo fontInfo in fontSelector.GetFonts()) { if (fontInfo.GetFontUnicodeRange().Contains(codePoint)) { PdfFont temptFont = GetPdfFont(fontInfo, fontProvider, additionalFonts); - Glyph glyph = temptFont.GetGlyph(codePoint); - if (null != glyph && 0 != glyph.GetCode()) { + if (temptFont.ContainsGlyph(codePoint)) { matchedFont = temptFont; break; } diff --git a/itext/itext.layout/itext/layout/renderer/TextRenderer.cs b/itext/itext.layout/itext/layout/renderer/TextRenderer.cs index 92f205661e..8ffb0eb18e 100644 --- a/itext/itext.layout/itext/layout/renderer/TextRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/TextRenderer.cs @@ -466,9 +466,13 @@ public override LayoutResult Layout(LayoutContext layoutContext) { for (int i = hyph.Length() - 1; i >= 0; i--) { String pre = hyph.GetPreHyphenText(i); String pos = hyph.GetPostHyphenText(i); - float currentHyphenationChoicePreTextWidth = GetGlyphLineWidth(ConvertToGlyphLine(text.ToUnicodeString(currentTextPos - , wordBounds[0]) + pre + hyphenationConfig.GetHyphenSymbol()), fontSize.GetValue(), hScale, characterSpacing - , wordSpacing); + char hyphen = hyphenationConfig.GetHyphenSymbol(); + String glyphLine = text.ToUnicodeString(currentTextPos, wordBounds[0]) + pre; + if (font.ContainsGlyph(hyphen)) { + glyphLine += hyphen; + } + float currentHyphenationChoicePreTextWidth = GetGlyphLineWidth(ConvertToGlyphLine(glyphLine), fontSize.GetValue + (), hScale, characterSpacing, wordSpacing); if (currentLineWidth + currentHyphenationChoicePreTextWidth + italicSkewAddition + boldSimulationAddition <= layoutBox.GetWidth()) { hyphenationApplied = true; @@ -476,10 +480,12 @@ public override LayoutResult Layout(LayoutContext layoutContext) { line.SetStart(currentTextPos); } line.SetEnd(Math.Max(line.GetEnd(), wordBounds[0] + pre.Length)); - GlyphLine lineCopy = line.Copy(line.GetStart(), line.GetEnd()); - lineCopy.Add(font.GetGlyph(hyphenationConfig.GetHyphenSymbol())); - lineCopy.SetEnd(lineCopy.GetEnd() + 1); - line = lineCopy; + if (font.ContainsGlyph(hyphen)) { + GlyphLine lineCopy = line.Copy(line.GetStart(), line.GetEnd()); + lineCopy.Add(font.GetGlyph(hyphen)); + lineCopy.SetEnd(lineCopy.GetEnd() + 1); + line = lineCopy; + } // TODO DEVSIX-7010 recalculate line properties in case of word hyphenation. // These values are based on whole word. Recalculate properly based on hyphenated part. currentLineAscender = Math.Max(currentLineAscender, nonBreakablePartMaxAscender); diff --git a/port-hash b/port-hash index 94e18e2fbf..f07d944028 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -238107cd5532d937fc246b97f60c8f1599786f9d +d7b7288459c53470547f639cf5386cb2636c2eca