diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java index ce7d51ae1d1..6a0b6d1c473 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java @@ -43,14 +43,15 @@ * * @see GC * @since 3.133 + * + * @noreference This class is provisional API and subject to change. It is being made available to gather early feedback. The API or behavior may change in future releases as the implementation evolves based on user feedback. */ -public class PDFDocument implements Drawable { - Device device; +public final class PDFDocument extends Device { long pdfContext; NSGraphicsContext graphicsContext; boolean isGCCreated = false; - boolean disposed = false; boolean pageStarted = false; + String filename; /** * Width of the page in points (1/72 inch) @@ -62,6 +63,16 @@ public class PDFDocument implements Drawable { */ double heightInPoints; + /** + * Internal data class to pass PDF document parameters through + * the Device constructor. + */ + static class PDFDocumentData extends DeviceData { + String filename; + double widthInPoints; + double heightInPoints; + } + /** * Constructs a new PDFDocument with the specified filename and page dimensions. *
@@ -83,52 +94,38 @@ public class PDFDocument implements Drawable { * @see #dispose() */ public PDFDocument(String filename, double widthInPoints, double heightInPoints) { - this(null, filename, widthInPoints, heightInPoints); + super(checkData(filename, widthInPoints, heightInPoints)); } /** - * Constructs a new PDFDocument with the specified filename and page dimensions, - * associated with the given device. - *
- * You must dispose the PDFDocument when it is no longer required. - *
- * - * @param device the device to associate with this PDFDocument - * @param filename the path to the PDF file to create - * @param widthInPoints the width of each page in points (1/72 inch) - * @param heightInPoints the height of each page in points (1/72 inch) - * - * @exception IllegalArgumentExceptioninit.
+ *
+ * @param data the DeviceData which describes the receiver
+ */
+ @Override
+ protected void create(DeviceData data) {
+ PDFDocumentData pdfData = (PDFDocumentData) data;
+ this.filename = pdfData.filename;
+ this.widthInPoints = pdfData.widthInPoints;
+ this.heightInPoints = pdfData.heightInPoints;
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
- this.widthInPoints = widthInPoints;
- this.heightInPoints = heightInPoints;
-
- // Get device from the current display if not provided
- if (device == null) {
- try {
- this.device = org.eclipse.swt.widgets.Display.getDefault();
- } catch (Exception e) {
- this.device = null;
- }
- } else {
- this.device = device;
- }
-
// Create CFURL from the filename
NSString path = NSString.stringWith(filename);
NSURL fileURL = NSURL.fileURLWithPath(path);
@@ -184,11 +181,11 @@ private void ensurePageStarted() {
*
*
* @exception SWTException
@@ -273,7 +303,7 @@ public double getHeight() {
*/
@Override
public long internal_new_GC(GCData data) {
- if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ checkDevice();
if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = null;
@@ -290,18 +320,16 @@ public long internal_new_GC(GCData data) {
if ((data.style & mask) == 0) {
data.style |= SWT.LEFT_TO_RIGHT;
}
- data.device = device;
+ data.device = this;
data.flippedContext = graphicsContext;
data.restoreContext = true;
NSSize size = new NSSize();
size.width = widthInPoints;
size.height = heightInPoints;
data.size = size;
- if (device != null) {
- data.background = device.getSystemColor(SWT.COLOR_WHITE).handle;
- data.foreground = device.getSystemColor(SWT.COLOR_BLACK).handle;
- data.font = device.getSystemFont();
- }
+ data.background = getSystemColor(SWT.COLOR_WHITE).handle;
+ data.foreground = getSystemColor(SWT.COLOR_BLACK).handle;
+ data.font = getSystemFont();
}
isGCCreated = true;
return graphicsContext.id;
@@ -350,27 +378,12 @@ public boolean isAutoScalable() {
}
/**
- * Returns true if the PDFDocument has been disposed,
- * and false otherwise.
- *
- * @return true when the PDFDocument is disposed and false otherwise
+ * Destroys the PDF document handle.
+ * This method is called internally by the dispose
+ * mechanism of the Device class.
*/
- public boolean isDisposed() {
- return disposed;
- }
-
- /**
- * Disposes of the operating system resources associated with
- * the PDFDocument. Applications must dispose of all PDFDocuments
- * that they allocate.
- *
- * This method finalizes the PDF file and writes it to disk. - *
- */ - public void dispose() { - if (disposed) return; - disposed = true; - + @Override + protected void destroy() { NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java index 9c76c25187b..a219df6c420 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java @@ -44,13 +44,14 @@ * * @see GC * @since 3.133 + * + * @noreference This class is provisional API and subject to change. It is being made available to gather early feedback. The API or behavior may change in future releases as the implementation evolves based on user feedback. */ -public class PDFDocument implements Drawable { - Device device; +public final class PDFDocument extends Device { long surface; long cairo; boolean isGCCreated = false; - boolean disposed = false; + String filename; /** * Width of the page in points (1/72 inch) @@ -62,6 +63,16 @@ public class PDFDocument implements Drawable { */ double heightInPoints; + /** + * Internal data class to pass PDF document parameters through + * the Device constructor. + */ + static class PDFDocumentData extends DeviceData { + String filename; + double widthInPoints; + double heightInPoints; + } + /** * Constructs a new PDFDocument with the specified filename and page dimensions. *@@ -83,60 +94,34 @@ public class PDFDocument implements Drawable { * @see #dispose() */ public PDFDocument(String filename, double widthInPoints, double heightInPoints) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - - this.widthInPoints = widthInPoints; - this.heightInPoints = heightInPoints; - - byte[] filenameBytes = Converter.wcsToMbcs(filename, true); - surface = Cairo.cairo_pdf_surface_create(filenameBytes, widthInPoints, heightInPoints); - if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES); - - cairo = Cairo.cairo_create(surface); - if (cairo == 0) { - Cairo.cairo_surface_destroy(surface); - surface = 0; - SWT.error(SWT.ERROR_NO_HANDLES); - } - - // Get device from the current display or create a temporary one - try { - device = org.eclipse.swt.widgets.Display.getDefault(); - } catch (Exception e) { - device = null; - } + super(checkData(filename, widthInPoints, heightInPoints)); } /** - * Constructs a new PDFDocument with the specified filename and page dimensions, - * associated with the given device. - *
- * You must dispose the PDFDocument when it is no longer required. - *
- * - * @param device the device to associate with this PDFDocument - * @param filename the path to the PDF file to create - * @param widthInPoints the width of each page in points (1/72 inch) - * @param heightInPoints the height of each page in points (1/72 inch) - * - * @exception IllegalArgumentExceptioninit.
+ *
+ * @param data the DeviceData which describes the receiver
+ */
+ @Override
+ protected void create(DeviceData data) {
+ PDFDocumentData pdfData = (PDFDocumentData) data;
+ this.filename = pdfData.filename;
+ this.widthInPoints = pdfData.widthInPoints;
+ this.heightInPoints = pdfData.heightInPoints;
byte[] filenameBytes = Converter.wcsToMbcs(filename, true);
surface = Cairo.cairo_pdf_surface_create(filenameBytes, widthInPoints, heightInPoints);
@@ -159,11 +144,11 @@ public PDFDocument(Device device, String filename, double widthInPoints, double
*
*
* @exception SWTException
@@ -239,7 +257,7 @@ public double getHeight() {
*/
@Override
public long internal_new_GC(GCData data) {
- if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ checkDevice();
if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (data != null) {
@@ -247,27 +265,13 @@ public long internal_new_GC(GCData data) {
if ((data.style & mask) == 0) {
data.style |= SWT.LEFT_TO_RIGHT;
}
- data.device = device;
+ data.device = this;
data.cairo = cairo;
data.width = (int) widthInPoints;
data.height = (int) heightInPoints;
- if (device != null) {
- data.foregroundRGBA = device.getSystemColor(SWT.COLOR_BLACK).handle;
- data.backgroundRGBA = device.getSystemColor(SWT.COLOR_WHITE).handle;
- data.font = device.getSystemFont();
- } else {
- // Fallback: create default colors manually using GdkRGBA values
- data.foregroundRGBA = new org.eclipse.swt.internal.gtk.GdkRGBA();
- data.foregroundRGBA.red = 0;
- data.foregroundRGBA.green = 0;
- data.foregroundRGBA.blue = 0;
- data.foregroundRGBA.alpha = 1;
- data.backgroundRGBA = new org.eclipse.swt.internal.gtk.GdkRGBA();
- data.backgroundRGBA.red = 1;
- data.backgroundRGBA.green = 1;
- data.backgroundRGBA.blue = 1;
- data.backgroundRGBA.alpha = 1;
- }
+ data.foregroundRGBA = getSystemColor(SWT.COLOR_BLACK).handle;
+ data.backgroundRGBA = getSystemColor(SWT.COLOR_WHITE).handle;
+ data.font = getSystemFont();
}
isGCCreated = true;
return cairo;
@@ -302,27 +306,12 @@ public boolean isAutoScalable() {
}
/**
- * Returns true if the PDFDocument has been disposed,
- * and false otherwise.
- *
- * @return true when the PDFDocument is disposed and false otherwise
+ * Destroys the PDF document handle.
+ * This method is called internally by the dispose
+ * mechanism of the Device class.
*/
- public boolean isDisposed() {
- return disposed;
- }
-
- /**
- * Disposes of the operating system resources associated with
- * the PDFDocument. Applications must dispose of all PDFDocuments
- * that they allocate.
- *
- * This method finalizes the PDF file and writes it to disk. - *
- */ - public void dispose() { - if (disposed) return; - disposed = true; - + @Override + protected void destroy() { if (cairo != 0) { Cairo.cairo_destroy(cairo); cairo = 0; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java index db15aa658f9..1766f3923c7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java @@ -47,114 +47,135 @@ * * @see GC * @since 3.133 + * + * @noreference This class is provisional API and subject to change. It is being made available to gather early feedback. The API or behavior may change in future releases as the implementation evolves based on user feedback. */ -public class PDFDocument implements Drawable { - Device device; +public final class PDFDocument extends Device { long handle; boolean isGCCreated = false; - boolean disposed = false; boolean jobStarted = false; boolean pageStarted = false; String filename; /** - * Width of the page in device-independent units + * Preferred width of the page in points (1/72 inch) */ - double width; + double preferredWidthInPoints; /** - * Height of the page in device-independent units + * Preferred height of the page in points (1/72 inch) */ - double height; + double preferredHeightInPoints; /** - * Width of the page in points (1/72 inch) + * Actual width of the page in points (1/72 inch) */ - double widthInPoints; + double actualWidthInPoints; /** - * Height of the page in points (1/72 inch) + * Actual height of the page in points (1/72 inch) */ - double heightInPoints; + double actualHeightInPoints; /** The name of the Microsoft Print to PDF printer */ private static final String PDF_PRINTER_NAME = "Microsoft Print to PDF"; - + + /** Points per inch - the standard PDF coordinate system uses 72 points per inch */ + private static final double POINTS_PER_INCH = 72.0; + + /** + * Internal data class to pass PDF document parameters through + * the Device constructor. + */ + static class PDFDocumentData extends DeviceData { + String filename; + double widthInPoints; + double heightInPoints; + } + /** Helper class to represent a paper size with orientation */ private static class PaperSize { int paperSizeConstant; int orientation; - double widthInInches; - double heightInInches; - + double widthInPoints; + double heightInPoints; + PaperSize(int paperSize, int orientation, double width, double height) { this.paperSizeConstant = paperSize; this.orientation = orientation; - this.widthInInches = width; - this.heightInInches = height; + this.widthInPoints = width; + this.heightInPoints = height; } } /** - * Finds the best matching standard paper size for the given dimensions. + * Finds the best matching standard paper size for the given dimensions in points. * Tries both portrait and landscape orientations and selects the one that * minimizes wasted space while ensuring the content fits. + * The returned paper size will always be >= the requested size. */ - private static PaperSize findBestPaperSize(double widthInInches, double heightInInches) { - // Common paper sizes (width x height in inches, portrait orientation) + private static PaperSize findBestPaperSize(double widthInPoints, double heightInPoints) { + // Common paper sizes (width x height in points, portrait orientation) + // 1 inch = 72 points int[][] standardSizes = { - {OS.DMPAPER_LETTER, 850, 1100}, // 8.5 x 11 - {OS.DMPAPER_LEGAL, 850, 1400}, // 8.5 x 14 - {OS.DMPAPER_A4, 827, 1169}, // 8.27 x 11.69 - {OS.DMPAPER_TABLOID, 1100, 1700}, // 11 x 17 - {OS.DMPAPER_A3, 1169, 1654}, // 11.69 x 16.54 - {OS.DMPAPER_EXECUTIVE, 725, 1050}, // 7.25 x 10.5 - {OS.DMPAPER_A5, 583, 827}, // 5.83 x 8.27 + {OS.DMPAPER_LETTER, 612, 792}, // 8.5 x 11 inches + {OS.DMPAPER_LEGAL, 612, 1008}, // 8.5 x 14 inches + {OS.DMPAPER_A4, 595, 842}, // 8.27 x 11.69 inches (210 x 297 mm) + {OS.DMPAPER_TABLOID, 792, 1224}, // 11 x 17 inches + {OS.DMPAPER_A3, 842, 1191}, // 11.69 x 16.54 inches (297 x 420 mm) + {OS.DMPAPER_EXECUTIVE, 522, 756}, // 7.25 x 10.5 inches + {OS.DMPAPER_A5, 420, 595}, // 5.83 x 8.27 inches (148 x 210 mm) }; - + PaperSize bestMatch = null; double minWaste = Double.MAX_VALUE; - + for (int[] size : standardSizes) { - double paperWidth = size[1] / 100.0; - double paperHeight = size[2] / 100.0; - + double paperWidth = size[1]; + double paperHeight = size[2]; + // Try portrait orientation - if (widthInInches <= paperWidth && heightInInches <= paperHeight) { - double waste = (paperWidth * paperHeight) - (widthInInches * heightInInches); + if (widthInPoints <= paperWidth && heightInPoints <= paperHeight) { + double waste = (paperWidth * paperHeight) - (widthInPoints * heightInPoints); if (waste < minWaste) { minWaste = waste; bestMatch = new PaperSize(size[0], OS.DMORIENT_PORTRAIT, paperWidth, paperHeight); } } - + // Try landscape orientation (swap width and height) - if (widthInInches <= paperHeight && heightInInches <= paperWidth) { - double waste = (paperHeight * paperWidth) - (widthInInches * heightInInches); + if (widthInPoints <= paperHeight && heightInPoints <= paperWidth) { + double waste = (paperHeight * paperWidth) - (widthInPoints * heightInPoints); if (waste < minWaste) { minWaste = waste; bestMatch = new PaperSize(size[0], OS.DMORIENT_LANDSCAPE, paperHeight, paperWidth); } } } - - // Default to Letter if no match found + + // Error if requested size exceeds the largest available standard paper size if (bestMatch == null) { - bestMatch = new PaperSize(OS.DMPAPER_LETTER, OS.DMORIENT_PORTRAIT, 8.5, 11.0); + SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [Requested page size exceeds maximum supported size]"); } - + return bestMatch; } /** - * Constructs a new PDFDocument with the specified filename and page dimensions. + * Constructs a new PDFDocument with the specified filename and preferred page dimensions. + *+ * The dimensions specify the preferred page size in points (1/72 inch). On Windows, + * the Microsoft Print to PDF driver only supports standard paper sizes, so the actual + * page size may be larger than requested. Use {@link #getBounds()} to query the actual + * page dimensions after construction. + *
** You must dispose the PDFDocument when it is no longer required. *
* * @param filename the path to the PDF file to create - * @param width the width of each page in device-independent units - * @param height the height of each page in device-independent units + * @param widthInPoints the preferred width of each page in points (1/72 inch) + * @param heightInPoints the preferred height of each page in points (1/72 inch) * * @exception IllegalArgumentException- * You must dispose the PDFDocument when it is no longer required. - *
- * - * @param device the device to associate with this PDFDocument - * @param filename the path to the PDF file to create - * @param width the width of each page in device-independent units - * @param height the height of each page in device-independent units - * - * @exception IllegalArgumentExceptioninit.
+ *
+ * @param data the DeviceData which describes the receiver
+ */
+ @Override
+ protected void create(DeviceData data) {
+ PDFDocumentData pdfData = (PDFDocumentData) data;
+ this.filename = pdfData.filename;
+ this.preferredWidthInPoints = pdfData.widthInPoints;
+ this.preferredHeightInPoints = pdfData.heightInPoints;
+
+ // Find the best matching standard paper size for the requested dimensions
+ PaperSize bestMatch = findBestPaperSize(preferredWidthInPoints, preferredHeightInPoints);
+ this.actualWidthInPoints = bestMatch.widthInPoints;
+ this.actualHeightInPoints = bestMatch.heightInPoints;
// Create printer DC for "Microsoft Print to PDF"
TCHAR driver = new TCHAR(0, "WINSPOOL", true);
@@ -257,7 +252,7 @@ public PDFDocument(Device device, String filename, double width, double height)
}
if (handle == 0) {
- SWT.error(SWT.ERROR_NO_HANDLES);
+ SWT.error(SWT.ERROR_NO_HANDLES, null, " [Failed to create device context for '" + PDF_PRINTER_NAME + "'. Ensure the printer is installed and enabled.]");
}
}
@@ -290,7 +285,8 @@ private void ensureJobStarted() {
OS.HeapFree(hHeap, 0, lpszDocName);
if (rc <= 0) {
- SWT.error(SWT.ERROR_NO_HANDLES);
+ int lastError = OS.GetLastError();
+ SWT.error(SWT.ERROR_NO_HANDLES, null, " [StartDoc failed for '" + PDF_PRINTER_NAME + "' (rc=" + rc + ", lastError=" + lastError + ")]");
}
jobStarted = true;
}
@@ -302,7 +298,11 @@ private void ensureJobStarted() {
private void ensurePageStarted() {
ensureJobStarted();
if (!pageStarted) {
- OS.StartPage(handle);
+ int rc = OS.StartPage(handle);
+ if (rc <= 0) {
+ int lastError = OS.GetLastError();
+ SWT.error(SWT.ERROR_NO_HANDLES, null, " [StartPage failed (rc=" + rc + ", lastError=" + lastError + ")]");
+ }
pageStarted = true;
}
}
@@ -316,11 +316,11 @@ private void ensurePageStarted() {
*
*
* @exception SWTException + * On Windows, this may be larger than the preferred width specified + * in the constructor due to standard paper size constraints. + *
* - * @return the width in points (1/72 inch) + * @return the actual width in points (1/72 inch) * * @exception SWTException+ * On Windows, this may be larger than the preferred height specified + * in the constructor due to standard paper size constraints. + *
* - * @return the height in points (1/72 inch) + * @return the actual height in points (1/72 inch) * * @exception SWTException+ * On Windows, this returns the actual page size which may be larger + * than the preferred size specified in the constructor. + *
+ * + * @return the bounding rectangle + * + * @exception SWTException+ * On Windows, the printable area may be smaller than the page bounds + * due to printer margins. + *
+ * + * @return the client area + * + * @exception SWTExceptiontrue if the PDFDocument has been disposed,
- * and false otherwise.
- *
- * @return true when the PDFDocument is disposed and false otherwise
- */
- public boolean isDisposed() {
- return disposed;
- }
-
- /**
- * Disposes of the operating system resources associated with
- * the PDFDocument. Applications must dispose of all PDFDocuments
- * that they allocate.
- * - * This method finalizes the PDF file and writes it to disk. - *
+ * Destroys the PDF document handle. + * This method is called internally by the dispose + * mechanism of theDevice class.
*/
- public void dispose() {
- if (disposed) return;
- disposed = true;
-
+ @Override
+ protected void destroy() {
if (handle != 0) {
if (pageStarted) {
OS.EndPage(handle);