Skip to content

Commit ef19e7b

Browse files
ars18wrwiText-CI
authored andcommitted
Process RTL on lists.
Set the LEFT symbol alignment as the default one for rtl tables. Fix tag processing of list item renderers. Update some cmps. DEVSIX-2433
1 parent 8941ee3 commit ef19e7b

File tree

52 files changed

+91
-29
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+91
-29
lines changed

layout/src/main/java/com/itextpdf/layout/renderer/ListItemRenderer.java

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,16 @@ This file is part of the iText (R) project.
4444
package com.itextpdf.layout.renderer;
4545

4646
import com.itextpdf.io.LogMessageConstant;
47+
import com.itextpdf.kernel.colors.ColorConstants;
4748
import com.itextpdf.kernel.font.PdfFont;
49+
import com.itextpdf.kernel.geom.Line;
4850
import com.itextpdf.kernel.pdf.tagging.StandardRoles;
51+
import com.itextpdf.layout.borders.SolidBorder;
4952
import com.itextpdf.layout.element.ListItem;
5053
import com.itextpdf.layout.element.Paragraph;
5154
import com.itextpdf.layout.layout.LayoutContext;
5255
import com.itextpdf.layout.layout.LayoutResult;
56+
import com.itextpdf.layout.property.BaseDirection;
5357
import com.itextpdf.layout.property.ListSymbolAlignment;
5458
import com.itextpdf.layout.property.ListSymbolPosition;
5559
import com.itextpdf.layout.property.Property;
@@ -133,19 +137,33 @@ public void draw(DrawContext drawContext) {
133137

134138
// It will be null in case of overflow (only the "split" part will contain symbol renderer.
135139
if (symbolRenderer != null && !symbolAddedInside) {
140+
boolean isRtl = BaseDirection.RIGHT_TO_LEFT.equals(this.<BaseDirection>getProperty(Property.BASE_DIRECTION));
136141
symbolRenderer.setParent(this);
137-
float x = occupiedArea.getBBox().getX();
142+
float x = isRtl ? occupiedArea.getBBox().getRight() : occupiedArea.getBBox().getLeft();
138143
ListSymbolPosition symbolPosition = (ListSymbolPosition) ListRenderer.getListItemOrListProperty(this, parent, Property.LIST_SYMBOL_POSITION);
139144
if (symbolPosition != ListSymbolPosition.DEFAULT) {
140145
Float symbolIndent = this.getPropertyAsFloat(Property.LIST_SYMBOL_INDENT);
141-
x -= symbolAreaWidth + (float) (symbolIndent == null ? 0 : symbolIndent);
146+
if (isRtl) {
147+
x += (symbolAreaWidth + (float) (symbolIndent == null ? 0 : symbolIndent));
148+
} else {
149+
x -= (symbolAreaWidth + (float) (symbolIndent == null ? 0 : symbolIndent));
150+
}
142151
if (symbolPosition == ListSymbolPosition.OUTSIDE) {
143-
UnitValue marginLeftUV = this.getPropertyAsUnitValue(Property.MARGIN_LEFT);
144-
if (!marginLeftUV.isPointValue()) {
145-
Logger logger = LoggerFactory.getLogger(ListItemRenderer.class);
146-
logger.error(MessageFormatUtil.format(LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property.MARGIN_LEFT));
152+
if (isRtl) {
153+
UnitValue marginRightUV = this.getPropertyAsUnitValue(Property.MARGIN_RIGHT);
154+
if (!marginRightUV.isPointValue()) {
155+
Logger logger = LoggerFactory.getLogger(ListItemRenderer.class);
156+
logger.error(MessageFormatUtil.format(LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property.MARGIN_RIGHT));
157+
}
158+
x -= marginRightUV.getValue();
159+
} else {
160+
UnitValue marginLeftUV = this.getPropertyAsUnitValue(Property.MARGIN_LEFT);
161+
if (!marginLeftUV.isPointValue()) {
162+
Logger logger = LoggerFactory.getLogger(ListItemRenderer.class);
163+
logger.error(MessageFormatUtil.format(LogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED, Property.MARGIN_LEFT));
164+
}
165+
x += marginLeftUV.getValue();
147166
}
148-
x += marginLeftUV.getValue();
149167
}
150168
}
151169
applyMargins(occupiedArea.getBBox(), false);
@@ -161,8 +179,8 @@ public void draw(DrawContext drawContext) {
161179
}
162180
}
163181
if (yLine != null) {
164-
if (symbolRenderer instanceof TextRenderer) {
165-
((TextRenderer) symbolRenderer).moveYLineTo((float) yLine);
182+
if (symbolRenderer instanceof LineRenderer) {
183+
symbolRenderer.move(0, (float) yLine - ((LineRenderer) symbolRenderer).getYLine());
166184
} else {
167185
symbolRenderer.move(0, (float) yLine - symbolRenderer.getOccupiedArea().getBBox().getY());
168186
}
@@ -182,12 +200,26 @@ public void draw(DrawContext drawContext) {
182200
applyMargins(occupiedArea.getBBox(), true);
183201

184202
ListSymbolAlignment listSymbolAlignment = (ListSymbolAlignment)parent.<ListSymbolAlignment>getProperty(Property.LIST_SYMBOL_ALIGNMENT,
185-
ListSymbolAlignment.RIGHT);
186-
float xPosition = x - symbolRenderer.getOccupiedArea().getBBox().getX();
203+
isRtl ? ListSymbolAlignment.LEFT : ListSymbolAlignment.RIGHT);
204+
float dxPosition = x - symbolRenderer.getOccupiedArea().getBBox().getX();
187205
if (listSymbolAlignment == ListSymbolAlignment.RIGHT) {
188-
xPosition += symbolAreaWidth - symbolRenderer.getOccupiedArea().getBBox().getWidth();
206+
if (!isRtl) {
207+
dxPosition += symbolAreaWidth - symbolRenderer.getOccupiedArea().getBBox().getWidth();
208+
}
209+
} else if (listSymbolAlignment == ListSymbolAlignment.LEFT) {
210+
if (isRtl) {
211+
dxPosition -= (symbolAreaWidth - symbolRenderer.getOccupiedArea().getBBox().getWidth());
212+
}
213+
}
214+
if (symbolRenderer instanceof LineRenderer) {
215+
if (isRtl) {
216+
symbolRenderer.move(dxPosition - symbolRenderer.getOccupiedArea().getBBox().getWidth(), 0);
217+
} else {
218+
symbolRenderer.move(dxPosition, 0);
219+
}
220+
} else {
221+
symbolRenderer.move(dxPosition, 0);
189222
}
190-
symbolRenderer.move(xPosition, 0);
191223

192224
if (symbolRenderer.getOccupiedArea().getBBox().getRight() > parent.getOccupiedArea().getBBox().getLeft()) {
193225
beginElementOpacityApplying(drawContext);
@@ -234,13 +266,24 @@ private void applyListSymbolPosition() {
234266
if (symbolRenderer != null) {
235267
ListSymbolPosition symbolPosition = (ListSymbolPosition) ListRenderer.getListItemOrListProperty(this, parent, Property.LIST_SYMBOL_POSITION);
236268
if (symbolPosition == ListSymbolPosition.INSIDE) {
269+
boolean isRtl = BaseDirection.RIGHT_TO_LEFT.equals(this.<BaseDirection>getProperty(Property.BASE_DIRECTION));
237270
if (childRenderers.size() > 0 && childRenderers.get(0) instanceof ParagraphRenderer) {
238271
ParagraphRenderer paragraphRenderer = (ParagraphRenderer) childRenderers.get(0);
239272
Float symbolIndent = this.getPropertyAsFloat(Property.LIST_SYMBOL_INDENT);
240-
if (symbolIndent != null) {
241-
symbolRenderer.setProperty(Property.MARGIN_RIGHT, UnitValue.createPointValue((float) symbolIndent));
242-
}
243-
paragraphRenderer.childRenderers.add(0, symbolRenderer);
273+
274+
if (symbolRenderer instanceof LineRenderer) {
275+
if (symbolIndent != null) {
276+
symbolRenderer.getChildRenderers().get(1).setProperty(isRtl ? Property.MARGIN_LEFT : Property.MARGIN_RIGHT, UnitValue.createPointValue((float) symbolIndent));
277+
}
278+
for (IRenderer childRenderer: symbolRenderer.getChildRenderers()) {
279+
paragraphRenderer.childRenderers.add(0, childRenderer);
280+
}
281+
} else {
282+
if (symbolIndent != null) {
283+
symbolRenderer.setProperty(isRtl ? Property.MARGIN_LEFT : Property.MARGIN_RIGHT, UnitValue.createPointValue((float) symbolIndent));
284+
}
285+
paragraphRenderer.childRenderers.add(0, symbolRenderer);
286+
}
244287
symbolAddedInside = true;
245288
} else if (childRenderers.size() > 0 && childRenderers.get(0) instanceof ImageRenderer) {
246289
Paragraph p = new Paragraph();
@@ -272,7 +315,12 @@ private void applyListSymbolPosition() {
272315
}
273316

274317
private boolean isListSymbolEmpty(IRenderer listSymbolRenderer) {
275-
return listSymbolRenderer instanceof TextRenderer && ((TextRenderer) listSymbolRenderer).getText().toString().length() == 0;
318+
if (listSymbolRenderer instanceof TextRenderer) {
319+
return ((TextRenderer) listSymbolRenderer).getText().toString().length() == 0;
320+
} else if (listSymbolRenderer instanceof LineRenderer) {
321+
return ((TextRenderer) listSymbolRenderer.getChildRenderers().get(1)).getText().toString().length() == 0;
322+
}
323+
return false;
276324
}
277325

278326
private float[] calculateAscenderDescender() {

layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ This file is part of the iText (R) project.
6262
import com.itextpdf.layout.layout.LayoutResult;
6363
import com.itextpdf.layout.minmaxwidth.MinMaxWidth;
6464
import com.itextpdf.layout.minmaxwidth.MinMaxWidthUtils;
65+
import com.itextpdf.layout.property.BaseDirection;
6566
import com.itextpdf.layout.property.IListSymbolFactory;
6667
import com.itextpdf.layout.property.ListNumberingType;
6768
import com.itextpdf.layout.property.ListSymbolPosition;
@@ -149,7 +150,7 @@ static Object getListItemOrListProperty(IRenderer listItem, IRenderer list, int
149150
private IRenderer createListSymbolRenderer(int index, IRenderer renderer) {
150151
Object defaultListSymbol = getListItemOrListProperty(renderer, this, Property.LIST_SYMBOL);
151152
if (defaultListSymbol instanceof Text) {
152-
return new TextRenderer((Text) defaultListSymbol);
153+
return surroundTextBullet(new TextRenderer((Text) defaultListSymbol));
153154
} else if (defaultListSymbol instanceof Image) {
154155
return new ImageRenderer((Image) defaultListSymbol);
155156
} else if (defaultListSymbol instanceof ListNumberingType) {
@@ -224,16 +225,29 @@ public void draw(DrawContext drawContext) {
224225
} else {
225226
textRenderer = new TextRenderer(textElement);
226227
}
227-
return textRenderer;
228+
return surroundTextBullet(textRenderer);
228229
} else if (defaultListSymbol instanceof IListSymbolFactory) {
229-
return ((IListSymbolFactory) defaultListSymbol).createSymbol(index, this, renderer).createRendererSubTree();
230+
return surroundTextBullet(((IListSymbolFactory) defaultListSymbol).createSymbol(index, this, renderer).createRendererSubTree());
230231
} else if (defaultListSymbol == null) {
231232
return null;
232233
} else {
233234
throw new IllegalStateException();
234235
}
235236
}
236237

238+
239+
// Wrap the bullet with a line because the direction (f.e. RTL) is processed on the LineRenderer level.
240+
private LineRenderer surroundTextBullet(IRenderer bulletRenderer) {
241+
LineRenderer lineRenderer = new LineRenderer();
242+
Text zeroWidthJoiner = new Text("\u200D");
243+
zeroWidthJoiner.getAccessibilityProperties().setRole(StandardRoles.ARTIFACT);
244+
TextRenderer zeroWidthJoinerRenderer = new TextRenderer(zeroWidthJoiner);
245+
lineRenderer.addChild(zeroWidthJoinerRenderer);
246+
lineRenderer.addChild(bulletRenderer);
247+
lineRenderer.addChild(zeroWidthJoinerRenderer);
248+
return lineRenderer;
249+
}
250+
237251
/**
238252
* <p>
239253
* Corrects split and overflow renderers when {@link com.itextpdf.layout.property.Property#FORCED_PLACEMENT} is applied.
@@ -306,17 +320,13 @@ private LayoutResult initializeListSymbols(LayoutContext layoutContext) {
306320
childRenderers.get(i).setParent(this);
307321
listItemNum = (childRenderers.get(i).<Integer>getProperty(Property.LIST_SYMBOL_ORDINAL_VALUE) != null) ? (int) childRenderers.get(i).<Integer>getProperty(Property.LIST_SYMBOL_ORDINAL_VALUE) : listItemNum;
308322
IRenderer currentSymbolRenderer = makeListSymbolRenderer(listItemNum, childRenderers.get(i));
323+
if (BaseDirection.RIGHT_TO_LEFT.equals(this.<BaseDirection>getProperty(Property.BASE_DIRECTION))) {
324+
currentSymbolRenderer.setProperty(Property.BASE_DIRECTION, BaseDirection.RIGHT_TO_LEFT);
325+
}
309326
LayoutResult listSymbolLayoutResult = null;
310327
if (currentSymbolRenderer != null) {
311328
++listItemNum;
312329
currentSymbolRenderer.setParent(childRenderers.get(i));
313-
// Workaround for the case when font is specified as string
314-
if (currentSymbolRenderer instanceof AbstractRenderer
315-
// TODO remove check for String type before 7.2
316-
&& (currentSymbolRenderer.<Object>getProperty(Property.FONT) instanceof String[] || currentSymbolRenderer.<Object>getProperty(Property.FONT) instanceof String)) {
317-
PdfFont actualPdfFont = ((AbstractRenderer) currentSymbolRenderer).resolveFirstPdfFont();
318-
currentSymbolRenderer.setProperty(Property.FONT, actualPdfFont);
319-
}
320330
listSymbolLayoutResult = currentSymbolRenderer.layout(layoutContext);
321331
currentSymbolRenderer.setParent(null);
322332
}
@@ -364,7 +374,11 @@ private LayoutResult initializeListSymbols(LayoutContext layoutContext) {
364374
if (symbolRenderer != null) {
365375
LayoutTaggingHelper taggingHelper = this.<LayoutTaggingHelper>getProperty(Property.TAGGING_HELPER);
366376
if (taggingHelper != null) {
367-
taggingHelper.setRoleHint(symbolRenderer, StandardRoles.LBL);
377+
if (symbolRenderer instanceof LineRenderer) {
378+
taggingHelper.setRoleHint(symbolRenderer.getChildRenderers().get(1), StandardRoles.LBL);
379+
} else {
380+
taggingHelper.setRoleHint(symbolRenderer, StandardRoles.LBL);
381+
}
368382
}
369383
}
370384
}
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)