Skip to content

Commit 6c9a7b2

Browse files
author
Artyom Yanchevsky
committed
Support 'background-size' style
DEVSIX-1708
1 parent d1466b8 commit 6c9a7b2

File tree

310 files changed

+187
-122
lines changed

Some content is hidden

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

310 files changed

+187
-122
lines changed

src/main/java/com/itextpdf/html2pdf/css/apply/util/BackgroundApplierUtil.java

Lines changed: 110 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ This file is part of the iText (R) project.
5757
import com.itextpdf.layout.property.BackgroundImage;
5858
import com.itextpdf.layout.property.BackgroundPosition;
5959
import com.itextpdf.layout.property.BackgroundRepeat;
60+
import com.itextpdf.layout.property.BackgroundSize;
6061
import com.itextpdf.layout.property.BlendMode;
6162
import com.itextpdf.layout.property.Property;
6263
import com.itextpdf.layout.property.UnitValue;
@@ -99,34 +100,44 @@ public static void applyBackground(Map<String, String> cssProps, ProcessorContex
99100

100101
final String backgroundImagesStr = cssProps.get(CssConstants.BACKGROUND_IMAGE);
101102
final String backgroundRepeatStr = cssProps.get(CssConstants.BACKGROUND_REPEAT);
103+
final String backgroundSizeStr = cssProps.get(CssConstants.BACKGROUND_SIZE);
102104
final String backgroundPositionXStr = cssProps.get(CssConstants.BACKGROUND_POSITION_X);
103105
final String backgroundPositionYStr = cssProps.get(CssConstants.BACKGROUND_POSITION_Y);
104106
final String backgroundBlendModeStr = cssProps.get(CssConstants.BACKGROUND_BLEND_MODE);
105107

106108
final List<BackgroundImage> backgroundImagesList = new ArrayList<>();
107109
final List<String> backgroundImagesArray = CssUtils.splitStringWithComma(backgroundImagesStr);
108110
final List<String> backgroundRepeatArray = CssUtils.splitStringWithComma(backgroundRepeatStr);
111+
final List<List<String>> backgroundSizeArray = backgroundSizeStr == null ? null
112+
: CssUtils.extractShorthandProperties(backgroundSizeStr);
109113
final List<String> backgroundPositionXArray = CssUtils.splitStringWithComma(backgroundPositionXStr);
110114
final List<String> backgroundPositionYArray = CssUtils.splitStringWithComma(backgroundPositionYStr);
111115
final List<String> backgroundBlendModeArray = CssUtils.splitStringWithComma(backgroundBlendModeStr);
116+
117+
final String fontSize = cssProps.get(CssConstants.FONT_SIZE);
118+
final float em = fontSize == null ? 0 : CssUtils.parseAbsoluteLength(fontSize);
119+
final float rem = context.getCssContext().getRootFontSize();
120+
112121
for (int i = 0; i < backgroundImagesArray.size(); ++i) {
113122
final String backgroundImage = backgroundImagesArray.get(i);
114123
if (backgroundImage == null || CssConstants.NONE.equals(backgroundImage)) {
115124
continue;
116125
}
117-
118-
final String fontSize = cssProps.get(CssConstants.FONT_SIZE);
119-
final float em = fontSize == null ? 0 : CssUtils.parseAbsoluteLength(fontSize);
120-
final float rem = context.getCssContext().getRootFontSize();
121126
final BackgroundPosition position =
122127
applyBackgroundPosition(backgroundPositionXArray, backgroundPositionYArray, i, em, rem);
123128
final BlendMode blendMode = applyBackgroundBlendMode(backgroundBlendModeArray, i);
124-
129+
boolean imageApplied = false;
125130
if (CssGradientUtil.isCssLinearGradientValue(backgroundImage)) {
126-
applyLinearGradient(backgroundImage, backgroundImagesList, blendMode, position, em, rem);
131+
imageApplied = applyLinearGradient(backgroundImage, backgroundImagesList, blendMode, position, em, rem);
127132
} else {
128133
final BackgroundRepeat repeat = applyBackgroundRepeat(backgroundRepeatArray, i);
129-
applyBackgroundImage(context, backgroundImage, backgroundImagesList, repeat, blendMode, position);
134+
final PdfXObject image = context.getResourceResolver().retrieveImageExtended(
135+
CssUtils.extractUrl(backgroundImage));
136+
imageApplied = applyBackgroundImage(image, backgroundImagesList, repeat, blendMode, position);
137+
}
138+
if (imageApplied) {
139+
applyBackgroundSize(backgroundSizeArray, em, rem, i,
140+
backgroundImagesList.get(backgroundImagesList.size() - 1));
130141
}
131142
}
132143
if (!backgroundImagesList.isEmpty()) {
@@ -184,11 +195,11 @@ private static BackgroundPosition applyBackgroundPosition(List<String> backgroun
184195
List<String> backgroundPositionYArray,
185196
int i, float em, float rem) {
186197
final BackgroundPosition position = new BackgroundPosition();
187-
final int indexX = getBackgroundSidePropertyIndex(backgroundPositionXArray, i);
198+
final int indexX = getBackgroundSidePropertyIndex(backgroundPositionXArray.size(), i);
188199
if (indexX != -1) {
189200
applyBackgroundPositionX(position, backgroundPositionXArray.get(indexX), em, rem);
190201
}
191-
final int indexY = getBackgroundSidePropertyIndex(backgroundPositionYArray, i);
202+
final int indexY = getBackgroundSidePropertyIndex(backgroundPositionYArray.size(), i);
192203
if (indexY != -1) {
193204
applyBackgroundPositionY(position, backgroundPositionYArray.get(indexY), em, rem);
194205
}
@@ -238,7 +249,7 @@ private static void applyBackgroundPositionY(BackgroundPosition position, String
238249
}
239250

240251
private static BackgroundRepeat applyBackgroundRepeat(List<String> backgroundRepeatArray, int iteration) {
241-
final int index = getBackgroundSidePropertyIndex(backgroundRepeatArray, iteration);
252+
final int index = getBackgroundSidePropertyIndex(backgroundRepeatArray.size(), iteration);
242253
if (index != -1) {
243254
final boolean repeatX = CssConstants.REPEAT.equals(backgroundRepeatArray.get(index)) ||
244255
CssConstants.REPEAT_X.equals(backgroundRepeatArray.get(index));
@@ -249,13 +260,9 @@ private static BackgroundRepeat applyBackgroundRepeat(List<String> backgroundRep
249260
return new BackgroundRepeat();
250261
}
251262

252-
private static int getBackgroundSidePropertyIndex(final List<String> backgroundPropertyArray, final int iteration) {
253-
if (!backgroundPropertyArray.isEmpty()) {
254-
if (backgroundPropertyArray.size() > iteration) {
255-
return iteration;
256-
} else {
257-
return 0;
258-
}
263+
private static int getBackgroundSidePropertyIndex(final int propertiesNumber, final int iteration) {
264+
if (propertiesNumber > 0) {
265+
return iteration % propertiesNumber;
259266
}
260267
return -1;
261268
}
@@ -270,39 +277,93 @@ private static void applyBackgroundColor(final String backgroundColorStr, final
270277
}
271278
}
272279

273-
private static void applyBackgroundImage(ProcessorContext context, String backgroundImage,
274-
List<BackgroundImage> backgroundImagesList, BackgroundRepeat repeat,
275-
BlendMode backgroundBlendMode, BackgroundPosition position) {
276-
final PdfXObject image = context.getResourceResolver().retrieveImageExtended(
277-
CssUtils.extractUrl(backgroundImage));
278-
if (image != null) {
279-
if (image instanceof PdfImageXObject) {
280-
backgroundImagesList
281-
.add(new HtmlBackgroundImage((PdfImageXObject) image, repeat, position, backgroundBlendMode));
282-
} else if (image instanceof PdfFormXObject) {
283-
backgroundImagesList
284-
.add(new HtmlBackgroundImage((PdfFormXObject) image, repeat, position, backgroundBlendMode));
285-
} else {
286-
throw new IllegalStateException();
287-
}
280+
private static boolean applyBackgroundImage(PdfXObject image, List<BackgroundImage> backgroundImagesList,
281+
BackgroundRepeat repeat, BlendMode backgroundBlendMode, BackgroundPosition position) {
282+
if (image == null) {
283+
return false;
284+
}
285+
if (image instanceof PdfImageXObject) {
286+
backgroundImagesList.add(new HtmlBackgroundImage((PdfImageXObject) image, repeat, position,
287+
backgroundBlendMode));
288+
return true;
289+
} else if (image instanceof PdfFormXObject) {
290+
backgroundImagesList.add(new HtmlBackgroundImage((PdfFormXObject) image, repeat, position,
291+
backgroundBlendMode));
292+
return true;
293+
} else {
294+
throw new IllegalStateException();
288295
}
289296
}
290297

291-
private static void applyLinearGradient(String backgroundImage, List<BackgroundImage> backgroundImagesList,
292-
BlendMode blendMode, BackgroundPosition position, float em, float rem) {
298+
private static boolean applyLinearGradient(String image, List<BackgroundImage> backgroundImagesList,
299+
BlendMode blendMode, BackgroundPosition position, float em, float rem) {
293300
try {
294301
StrategyBasedLinearGradientBuilder gradientBuilder =
295-
CssGradientUtil.parseCssLinearGradient(backgroundImage, em, rem);
302+
CssGradientUtil.parseCssLinearGradient(image, em, rem);
296303
if (gradientBuilder != null) {
297304
backgroundImagesList.add(new BackgroundImage.Builder().setLinearGradientBuilder(gradientBuilder)
298305
.setBackgroundBlendMode(blendMode).setBackgroundPosition(position).build());
306+
return true;
299307
}
300308
} catch (StyledXMLParserException e) {
301-
LOGGER.warn(MessageFormatUtil.format(
302-
LogMessageConstant.INVALID_GRADIENT_DECLARATION, backgroundImage));
309+
LOGGER.warn(MessageFormatUtil.format(LogMessageConstant.INVALID_GRADIENT_DECLARATION, image));
310+
}
311+
return false;
312+
}
313+
314+
private static void applyBackgroundSize(List<List<String>> backgroundProperties, float em, float rem,
315+
int imageIndex, BackgroundImage image) {
316+
if (backgroundProperties == null || backgroundProperties.isEmpty()) {
317+
return;
318+
}
319+
if (image.getForm() != null && (image.getImageHeight() == 0f || image.getImageWidth() == 0f)) {
320+
return;
321+
}
322+
List<String> backgroundSizeValues = backgroundProperties
323+
.get(getBackgroundSidePropertyIndex(backgroundProperties.size(), imageIndex));
324+
if (backgroundSizeValues.size() == 2 && CommonCssConstants.AUTO.equals(backgroundSizeValues.get(1))) {
325+
backgroundSizeValues.remove(1);
326+
}
327+
if (backgroundSizeValues.size() == 1) {
328+
String widthValue = backgroundSizeValues.get(0);
329+
applyBackgroundWidth(widthValue, image, em, rem);
330+
}
331+
if (backgroundSizeValues.size() == 2) {
332+
applyBackgroundWidthHeight(backgroundSizeValues, image, em, rem);
303333
}
304334
}
305335

336+
private static void applyBackgroundWidth(final String widthValue, final BackgroundImage image,
337+
final float em, final float rem) {
338+
if (CommonCssConstants.BACKGROUND_SIZE_VALUES.contains(widthValue)) {
339+
if (widthValue.equals(CommonCssConstants.CONTAIN)) {
340+
image.getBackgroundSize().setBackgroundSizeToContain();
341+
}
342+
if (widthValue.equals(CommonCssConstants.COVER)) {
343+
image.getBackgroundSize().setBackgroundSizeToCover();
344+
}
345+
return;
346+
}
347+
image.getBackgroundSize().setBackgroundSizeToValues(CssUtils.parseLengthValueToPt(widthValue, em, rem), null);
348+
}
349+
350+
private static void applyBackgroundWidthHeight(final List<String> backgroundSizeValues,
351+
final BackgroundImage image, final float em, final float rem) {
352+
String widthValue = backgroundSizeValues.get(0);
353+
if (CommonCssConstants.BACKGROUND_SIZE_VALUES.contains(widthValue)) {
354+
if (widthValue.equals(CommonCssConstants.AUTO)) {
355+
UnitValue height = CssUtils.parseLengthValueToPt(backgroundSizeValues.get(1), em, rem);
356+
if (height != null) {
357+
image.getBackgroundSize().setBackgroundSizeToValues(null, height);
358+
}
359+
}
360+
return;
361+
}
362+
image.getBackgroundSize().setBackgroundSizeToValues(
363+
CssUtils.parseLengthValueToPt(backgroundSizeValues.get(0), em, rem),
364+
CssUtils.parseLengthValueToPt(backgroundSizeValues.get(1), em, rem));
365+
}
366+
306367
/**
307368
* Implementation of the Image class when used in the context of HTML to PDF conversion.
308369
*/
@@ -327,7 +388,7 @@ private static class HtmlBackgroundImage extends BackgroundImage {
327388
*/
328389
public HtmlBackgroundImage(PdfImageXObject xObject,
329390
BackgroundRepeat repeat, BackgroundPosition position, BlendMode blendMode) {
330-
super(xObject, repeat, position, null, blendMode);
391+
super(xObject, repeat, position, new BackgroundSize(), null, blendMode);
331392
dimensionMultiplier = PX_TO_PT_MULTIPLIER;
332393
}
333394

@@ -341,7 +402,17 @@ public HtmlBackgroundImage(PdfImageXObject xObject,
341402
*/
342403
public HtmlBackgroundImage(PdfFormXObject xObject,
343404
BackgroundRepeat repeat, BackgroundPosition position, BlendMode blendMode) {
344-
super(xObject, repeat, position, null, blendMode);
405+
super(xObject, repeat, position, new BackgroundSize(), null, blendMode);
406+
}
407+
408+
@Override
409+
public float getImageWidth() {
410+
return (float) (image.getWidth() * dimensionMultiplier);
411+
}
412+
413+
@Override
414+
public float getImageHeight() {
415+
return (float) (image.getHeight() * dimensionMultiplier);
345416
}
346417

347418
@Override

src/test/java/com/itextpdf/html2pdf/css/BackgroundTest.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ public static void beforeClass() {
7070
}
7171

7272
@Test
73-
@Ignore("DEVSIX-1708")
7473
public void backgroundSizeTest01() throws IOException, InterruptedException {
7574
HtmlConverter.convertToPdf(new File(sourceFolder + "backgroundsize01.html"),
7675
new File(destinationFolder + "backgroundsize01.pdf"));
@@ -80,13 +79,13 @@ public void backgroundSizeTest01() throws IOException, InterruptedException {
8079
}
8180

8281
@Test
83-
// TODO DEVSIX-1708 support background-size
82+
// TODO DEVSIX-4370 support background repeat for linear-gradient
8483
public void backgroundAttachmentMarginRoot1Test() throws IOException, InterruptedException {
8584
convertToPdfAndCompare("backgroundAttachmentMarginRoot1", sourceFolder, destinationFolder);
8685
}
8786

8887
@Test
89-
// TODO DEVSIX-1708 support background-size
88+
// TODO DEVSIX-4370 support background repeat for linear-gradient
9089
public void backgroundAttachmentMarginRoot2Test() throws IOException, InterruptedException {
9190
convertToPdfAndCompare("backgroundAttachmentMarginRoot2", sourceFolder, destinationFolder);
9291
}
@@ -121,6 +120,16 @@ public void backgroundSoloImageTest() throws IOException, InterruptedException {
121120
convertToPdfAndCompare("background_solo_image", sourceFolder, destinationFolder);
122121
}
123122

123+
@Test
124+
public void backgroundImageWithoutFixedWidthTest() throws IOException, InterruptedException {
125+
convertToPdfAndCompare("backgroundImageWithoutFixedSize", sourceFolder, destinationFolder);
126+
}
127+
128+
@Test
129+
public void backgroundImageCoverSizeTest() throws IOException, InterruptedException {
130+
convertToPdfAndCompare("backgroundImageCoverSize", sourceFolder, destinationFolder);
131+
}
132+
124133
@Test
125134
@LogMessages(messages = {
126135
@LogMessage(messageTemplate = com.itextpdf.styledxmlparser.LogMessageConstant.ONLY_THE_LAST_BACKGROUND_CAN_INCLUDE_BACKGROUND_COLOR)

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/Background334Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ This file is part of the iText (R) project.
2626
import com.itextpdf.test.annotations.LogMessage;
2727
import com.itextpdf.test.annotations.LogMessages;
2828

29-
// TODO DEVSIX-1708 support background size
3029
public class Background334Test extends W3CCssTest {
3130
@Override
3231
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundImageCoverZoomed1Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundImageCoverZoomed1Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize003Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize003Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize007Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize007Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize008Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize008Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize009Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize009Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize010Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize010Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

src/test/java/com/itextpdf/html2pdf/css/w3c/css_backgrounds/BackgroundSize011Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ This file is part of the iText (R) project.
2424

2525
import com.itextpdf.html2pdf.css.w3c.W3CCssTest;
2626

27-
// TODO DEVSIX-1708 support background-size
2827
public class BackgroundSize011Test extends W3CCssTest {
2928
@Override
3029
protected String getHtmlFileName() {

0 commit comments

Comments
 (0)