@@ -44,6 +44,7 @@ This file is part of the iText (R) project.
44
44
package com .itextpdf .layout .renderer ;
45
45
46
46
import com .itextpdf .io .LogMessageConstant ;
47
+ import com .itextpdf .io .font .otf .ActualTextIterator ;
47
48
import com .itextpdf .io .font .otf .Glyph ;
48
49
import com .itextpdf .io .font .otf .GlyphLine ;
49
50
import com .itextpdf .io .util .ArrayUtil ;
@@ -448,7 +449,7 @@ && isTextRendererAndRequiresSpecialScriptPreLayoutProcessing(childRenderer)) {
448
449
(childPos , specialScriptLayoutResults , wasParentsHeightClipped , floatsOverflowedToNextLine );
449
450
450
451
curWidth -= getCurWidthSpecialScriptsDecrement (childPos , lastFittingChildRendererData .childIndex ,
451
- lastFittingChildRendererData . childLayoutResult , specialScriptLayoutResults );
452
+ specialScriptLayoutResults );
452
453
453
454
childPos = lastFittingChildRendererData .childIndex ;
454
455
childResult = lastFittingChildRendererData .childLayoutResult ;
@@ -1202,7 +1203,7 @@ private void updateChildrenParent() {
1202
1203
*
1203
1204
* @return total number of trimmed glyphs.
1204
1205
*/
1205
- private int trimFirst () {
1206
+ int trimFirst () {
1206
1207
int totalNumberOfTrimmedGlyphs = 0 ;
1207
1208
for (IRenderer renderer : childRenderers ) {
1208
1209
if (FloatingHelper .isRendererFloating (renderer )) {
@@ -1267,7 +1268,7 @@ static void updateSpecialScriptLayoutResults(Map<Integer, LayoutResult> specialS
1267
1268
}
1268
1269
}
1269
1270
1270
- static float getCurWidthSpecialScriptsDecrement (int childPos , int newChildPos , LayoutResult newLayoutResult ,
1271
+ static float getCurWidthSpecialScriptsDecrement (int childPos , int newChildPos ,
1271
1272
Map <Integer , LayoutResult > specialScriptLayoutResults ) {
1272
1273
float decrement = 0.0f ;
1273
1274
// if childPos == newChildPos, curWidth doesn't include width of the current childRenderer yet, so no decrement is needed
@@ -1277,12 +1278,6 @@ static float getCurWidthSpecialScriptsDecrement(int childPos, int newChildPos, L
1277
1278
decrement += specialScriptLayoutResults .get (i ).getOccupiedArea ().getBBox ().getWidth ();
1278
1279
}
1279
1280
}
1280
-
1281
- // when LayoutResult.NOTHING has artificially been created in getIndexOfRendererWithLastFullyFittingWord,
1282
- // it's occupiedArea isn't 0.0x0.0 as it should be, so we need to subtract it here twice, because it'll be added later
1283
- if (newLayoutResult .getStatus () == LayoutResult .NOTHING ) {
1284
- decrement += specialScriptLayoutResults .get (newChildPos ).getOccupiedArea ().getBBox ().getWidth ();
1285
- }
1286
1281
}
1287
1282
1288
1283
return decrement ;
@@ -1315,6 +1310,7 @@ void specialScriptPreLayoutProcessing(int childPos) {
1315
1310
String sequentialTextContent = info .sequentialTextContent ;
1316
1311
List <Integer > indicesOfFloating = info .indicesOfFloating ;
1317
1312
List <Integer > possibleBreakPointsGlobal = TypographyUtils .getPossibleBreaks (sequentialTextContent );
1313
+
1318
1314
distributePossibleBreakPointsOverSequentialTextRenderers (childPos , numberOfSequentialTextRenderers ,
1319
1315
possibleBreakPointsGlobal , indicesOfFloating );
1320
1316
}
@@ -1345,26 +1341,35 @@ SpecialScriptsContainingTextRendererSequenceInfo getSpecialScriptsContainingText
1345
1341
void distributePossibleBreakPointsOverSequentialTextRenderers (
1346
1342
int childPos , int numberOfSequentialTextRenderers , List <Integer > possibleBreakPointsGlobal ,
1347
1343
List <Integer > indicesOfFloating ) {
1348
- int alreadyProcessedNumberOfGlyphs = 0 ;
1344
+ int alreadyProcessedNumberOfCharsWithinGlyphLines = 0 ;
1349
1345
int indexToBeginWith = 0 ;
1350
1346
for (int i = 0 ; i < numberOfSequentialTextRenderers ; i ++) {
1351
1347
if (!indicesOfFloating .contains (i )) {
1352
1348
TextRenderer childTextRenderer = (TextRenderer ) childRenderers .get (childPos + i );
1353
- int length = childTextRenderer .length ();
1349
+ List <Integer > amountOfCharsBetweenTextStartAndActualTextChunk = new ArrayList <>();
1350
+ List <Integer > glyphLineBasedIndicesOfActualTextChunkEnds = new ArrayList <>();
1351
+
1352
+ fillActualTextChunkRelatedLists (childTextRenderer .getText (),
1353
+ amountOfCharsBetweenTextStartAndActualTextChunk , glyphLineBasedIndicesOfActualTextChunkEnds );
1354
+
1354
1355
List <Integer > possibleBreakPoints = new ArrayList <Integer >();
1355
1356
for (int j = indexToBeginWith ; j < possibleBreakPointsGlobal .size (); j ++) {
1356
- int shiftedBreakPoint = possibleBreakPointsGlobal .get (j ) - alreadyProcessedNumberOfGlyphs ;
1357
- if (shiftedBreakPoint > length ) {
1357
+ int shiftedBreakPoint = possibleBreakPointsGlobal .get (j )
1358
+ - alreadyProcessedNumberOfCharsWithinGlyphLines ;
1359
+ int amountOfCharsBetweenTextStartAndTextEnd = amountOfCharsBetweenTextStartAndActualTextChunk
1360
+ .get (amountOfCharsBetweenTextStartAndActualTextChunk .size () - 1 );
1361
+ if (shiftedBreakPoint > amountOfCharsBetweenTextStartAndTextEnd ) {
1358
1362
indexToBeginWith = j ;
1359
- alreadyProcessedNumberOfGlyphs += length ;
1363
+ alreadyProcessedNumberOfCharsWithinGlyphLines += amountOfCharsBetweenTextStartAndTextEnd ;
1360
1364
break ;
1361
1365
}
1362
- possibleBreakPoints .add (shiftedBreakPoint + childTextRenderer . text . start );
1366
+ possibleBreakPoints .add (shiftedBreakPoint );
1363
1367
}
1364
- if (possibleBreakPoints .isEmpty ()) {
1365
- possibleBreakPoints .add (-1 );
1366
- }
1367
- childTextRenderer .setSpecialScriptsWordBreakPoints (possibleBreakPoints );
1368
+
1369
+ List <Integer > glyphLineBasedPossibleBreakPoints = convertPossibleBreakPointsToGlyphLineBased (
1370
+ possibleBreakPoints , amountOfCharsBetweenTextStartAndActualTextChunk ,
1371
+ glyphLineBasedIndicesOfActualTextChunkEnds );
1372
+ childTextRenderer .setSpecialScriptsWordBreakPoints (glyphLineBasedPossibleBreakPoints );
1368
1373
}
1369
1374
}
1370
1375
}
@@ -1402,9 +1407,9 @@ void distributePossibleBreakPointsOverSequentialTextRenderers(
1402
1407
if (fittingLengthWithTrailingRightSideSpaces > 0 ) {
1403
1408
List <Integer > breakPoints = textRenderer .getSpecialScriptsWordBreakPoints ();
1404
1409
if (breakPoints != null && breakPoints .size () > 0 && breakPoints .get (0 ) != -1 ) {
1405
- int possibleBreakPointPosition =
1406
- textRenderer .findPossibleBreaksSplitPosition (
1407
- fittingLengthWithTrailingRightSideSpaces + textRenderer .text .start , false );
1410
+ int possibleBreakPointPosition = TextRenderer . findPossibleBreaksSplitPosition (
1411
+ textRenderer .getSpecialScriptsWordBreakPoints (),
1412
+ fittingLengthWithTrailingRightSideSpaces + textRenderer .text .start , false );
1408
1413
if (possibleBreakPointPosition > -1 ) {
1409
1414
splitPosition = breakPoints .get (possibleBreakPointPosition ) - amountOfTrailingRightSideSpaces ;
1410
1415
needToSplitRendererContainingLastFullyFittingWord = splitPosition != textRenderer .text .end ;
@@ -1451,7 +1456,8 @@ && isChildFloating(childRenderers.get(analyzedTextRendererIndex - 1))) {
1451
1456
}
1452
1457
}
1453
1458
1454
- updateFloatsOverflowedToNextLine (floatsOverflowedToNextLine , indicesOfFloats , indexOfRendererContainingLastFullyFittingWord );
1459
+ updateFloatsOverflowedToNextLine (floatsOverflowedToNextLine , indicesOfFloats ,
1460
+ indexOfRendererContainingLastFullyFittingWord );
1455
1461
1456
1462
if (returnLayoutResult == null ) {
1457
1463
returnLayoutResult = childPosLayoutResult ;
@@ -1468,9 +1474,7 @@ && isChildFloating(childRenderers.get(analyzedTextRendererIndex - 1))) {
1468
1474
childRenderer .setSpecialScriptFirstNotFittingIndex (-1 );
1469
1475
}
1470
1476
} else {
1471
- LayoutArea occupiedArea = specialScriptLayoutResults .get (indexOfRendererContainingLastFullyFittingWord )
1472
- .getOccupiedArea ();
1473
- returnLayoutResult = new TextLayoutResult (LayoutResult .NOTHING , occupiedArea , null , childRenderer );
1477
+ returnLayoutResult = new TextLayoutResult (LayoutResult .NOTHING , null , null , childRenderer );
1474
1478
}
1475
1479
}
1476
1480
@@ -1560,6 +1564,55 @@ private boolean isInlineBlockChild(IRenderer child) {
1560
1564
return child instanceof BlockRenderer || child instanceof TableRenderer ;
1561
1565
}
1562
1566
1567
+ // ActualTextChunk is either an ActualText or a single independent glyph
1568
+ private static void fillActualTextChunkRelatedLists (
1569
+ GlyphLine glyphLine , List <Integer > amountOfCharsBetweenTextStartAndActualTextChunk ,
1570
+ List <Integer > glyphLineBasedIndicesOfActualTextChunkEnds ) {
1571
+ ActualTextIterator actualTextIterator = new ActualTextIterator (glyphLine );
1572
+
1573
+ int amountOfCharsBetweenTextStartAndCurrentActualTextStartOrGlyph = 0 ;
1574
+ while (actualTextIterator .hasNext ()) {
1575
+ GlyphLine .GlyphLinePart part = actualTextIterator .next ();
1576
+ int amountOfCharsWithinCurrentActualTextOrGlyph = 0 ;
1577
+ if (part .actualText != null ) {
1578
+ amountOfCharsWithinCurrentActualTextOrGlyph = part .actualText .length ();
1579
+ int nextAmountOfChars = amountOfCharsWithinCurrentActualTextOrGlyph
1580
+ + amountOfCharsBetweenTextStartAndCurrentActualTextStartOrGlyph ;
1581
+ amountOfCharsBetweenTextStartAndActualTextChunk .add (nextAmountOfChars );
1582
+ glyphLineBasedIndicesOfActualTextChunkEnds .add (part .end );
1583
+ amountOfCharsBetweenTextStartAndCurrentActualTextStartOrGlyph = nextAmountOfChars ;
1584
+ } else {
1585
+ for (int j = part .start ; j < part .end ; j ++) {
1586
+ char [] chars = glyphLine .get (j ).getChars ();
1587
+ amountOfCharsWithinCurrentActualTextOrGlyph = chars != null ? chars .length : 0 ;
1588
+ int nextAmountOfChars = amountOfCharsWithinCurrentActualTextOrGlyph
1589
+ + amountOfCharsBetweenTextStartAndCurrentActualTextStartOrGlyph ;
1590
+ amountOfCharsBetweenTextStartAndActualTextChunk .add (nextAmountOfChars );
1591
+ glyphLineBasedIndicesOfActualTextChunkEnds .add (j + 1 );
1592
+ amountOfCharsBetweenTextStartAndCurrentActualTextStartOrGlyph = nextAmountOfChars ;
1593
+ }
1594
+ }
1595
+ }
1596
+ }
1597
+
1598
+ private static List <Integer > convertPossibleBreakPointsToGlyphLineBased (
1599
+ List <Integer > possibleBreakPoints , List <Integer > amountOfChars , List <Integer > indices ) {
1600
+ if (possibleBreakPoints .isEmpty ()) {
1601
+ possibleBreakPoints .add (-1 );
1602
+ return possibleBreakPoints ;
1603
+ } else {
1604
+ List <Integer > glyphLineBased = new ArrayList <>();
1605
+
1606
+ for (int j : possibleBreakPoints ) {
1607
+ int found = TextRenderer .findPossibleBreaksSplitPosition (amountOfChars , j , true );
1608
+ if (found >= 0 ) {
1609
+ glyphLineBased .add (indices .get (found ));
1610
+ }
1611
+ }
1612
+ return glyphLineBased ;
1613
+ }
1614
+ }
1615
+
1563
1616
static class RendererGlyph {
1564
1617
public Glyph glyph ;
1565
1618
public TextRenderer renderer ;
0 commit comments