diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java
index 365065171..732e266bf 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java
@@ -1491,6 +1491,9 @@ public final class CSSName implements Comparable {
new PrimitivePropertyBuilders.BoxSizing()
);
+ /**
+ * The maximum number of inserted shadow pages to insert for cut-off content.
+ */
public final static CSSName FS_MAX_OVERFLOW_PAGES =
addProperty(
"-fs-max-overflow-pages",
@@ -1499,6 +1502,19 @@ public final class CSSName implements Comparable {
NOT_INHERITED,
new PrimitivePropertyBuilders.FSMaxOverflowPages()
);
+
+ /**
+ * Whether cut-off content to the right (default) of the page or left
+ * of the page should be inserted as shadow pages.
+ */
+ public final static CSSName FS_OVERFLOW_PAGES_DIRECTION =
+ addProperty(
+ "-fs-overflow-pages-direction",
+ PRIMITIVE,
+ "ltr",
+ NOT_INHERITED,
+ new PrimitivePropertyBuilders.FSOverflowPagesDirection()
+ );
/**
diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java
index 2cf48613a..ba978927e 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java
@@ -1855,4 +1855,14 @@ protected boolean isNegativeValuesAllowed() {
return false;
}
}
+
+ public static class FSOverflowPagesDirection extends SingleIdent {
+ private static final BitSet ALLOWED = setFor(new IdentValue[] { IdentValue.LTR, IdentValue.RTL });
+
+ @Override
+ protected BitSet getAllowed() {
+ return ALLOWED;
+ }
+ }
+
}
diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/PageBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/PageBox.java
index 6b1f6ebac..a2b208062 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/PageBox.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/PageBox.java
@@ -26,8 +26,6 @@
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
-import java.util.Locale;
-
import org.w3c.dom.Element;
import org.w3c.dom.css.CSSPrimitiveValue;
@@ -276,11 +274,14 @@ public Rectangle getDocumentCoordinatesContentBounds(CssContext c) {
/**
* Get the shadow page (a page inserted to carry cut off content) content area of the layed out document.
* For example: If a page one is 100 units high and 150 wide and has a margin of 10 then this will return a
- * rect(130, 0, 130, 80) for the first shadow page and a rect(260, 0, 130, 80) for the second shadow page.
+ * rect(130, 0, 130, 80) for the first shadow page and a rect(260, 0, 130, 80) for the second shadow page
+ * assuming cut-off direction is LTR.
+ *
+ * For RTL the rects would be rect(-130, 0, 130, 80) and rect(-260, 0, 130, 80).
*/
public Rectangle getDocumentCoordinatesContentBoundsForInsertedPage(CssContext c, int shadowPageNumber) {
return new Rectangle(
- getContentWidth(c) * (shadowPageNumber + 1),
+ getContentWidth(c) * (shadowPageNumber + 1) * (getCutOffPageDirection() == IdentValue.LTR ? 1 : -1),
getPaintingTop(),
getContentWidth(c),
getContentHeight(c));
@@ -300,6 +301,14 @@ public int getMaxInsertedPages() {
return getStyle().fsMaxOverflowPages();
}
+ /**
+ * @return Either ltr (should insert cut-off content to the right of the page) or
+ * rtl (should insert cut-off content to the left of the page).
+ */
+ public IdentValue getCutOffPageDirection() {
+ return getStyle().getIdent(CSSName.FS_OVERFLOW_PAGES_DIRECTION);
+ }
+
public Rectangle getPagedViewClippingBounds(CssContext cssCtx, int additionalClearance) {
Rectangle result = new Rectangle(
additionalClearance +
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java
index adbbd568b..7b9a908e9 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java
@@ -24,6 +24,7 @@
import com.openhtmltopdf.bidi.BidiSplitterFactory;
import com.openhtmltopdf.bidi.SimpleBidiReorderer;
import com.openhtmltopdf.context.StyleReference;
+import com.openhtmltopdf.css.constants.IdentValue;
import com.openhtmltopdf.css.style.CalculatedStyle;
import com.openhtmltopdf.extend.*;
import com.openhtmltopdf.layout.BoxBuilder;
@@ -610,7 +611,7 @@ private void writePDFFast(List pages, RenderingContext c, Rectangle2D f
if (!pageOperations.shadowPages().isEmpty()) {
// TODO.
- int translateX = (int) (firstPageSize.getWidth() * _outputDevice.getDotsPerPoint());
+ int translateX = (int) (firstPageSize.getWidth() * _outputDevice.getDotsPerPoint()) * (currentPage.getCutOffPageDirection() == IdentValue.LTR ? 1 : -1);
for (DisplayListPageContainer shadowPage : pageOperations.shadowPages()) {
PDPage shadowPdPage = new PDPage(new PDRectangle((float) firstPageSize.getWidth(), (float) firstPageSize.getHeight()));
PDPageContentStream shadowCs = new PDPageContentStream(doc, shadowPdPage, AppendMode.APPEND, !_testMode);