From 58716199b37712138097b20294ba9e0cd80d4ff4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:11:01 +0000 Subject: [PATCH 01/11] Initial plan From 137093c959b6e25a1445deec89bab79b1a57a6cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:19:48 +0000 Subject: [PATCH 02/11] Initial analysis of GC and Drawable architecture Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- build_gtk.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 build_gtk.sh diff --git a/build_gtk.sh b/build_gtk.sh new file mode 100755 index 00000000000..de7d762c6cd --- /dev/null +++ b/build_gtk.sh @@ -0,0 +1,3 @@ +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' +cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt From 8346207a3a0a3b6bbf2ab0e26a76f05baa338264 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:28:45 +0000 Subject: [PATCH 03/11] Add PDFDocument and SVGDocument classes with native Cairo bindings Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../Eclipse SWT PI/cairo/library/cairo.c | 66 ++++ .../cairo/library/cairo_custom.h | 3 + .../cairo/library/cairo_stats.h | 3 + .../org/eclipse/swt/internal/cairo/Cairo.java | 25 ++ .../org/eclipse/swt/printing/PDFDocument.java | 338 +++++++++++++++++ .../org/eclipse/swt/printing/SVGDocument.java | 349 ++++++++++++++++++ 6 files changed, 784 insertions(+) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c index 514e744c809..d6565946282 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c @@ -1471,3 +1471,69 @@ JNIEXPORT void JNICALL Cairo_NATIVE(memmove___3DJJ) } #endif +#ifndef NO_cairo_1pdf_1surface_1create +JNIEXPORT jlong JNICALL Cairo_NATIVE(cairo_1pdf_1surface_1create) + (JNIEnv *env, jclass that, jbyteArray arg0, jdouble arg1, jdouble arg2) +{ + jbyte *lparg0=NULL; + jlong rc = 0; + Cairo_NATIVE_ENTER(env, that, cairo_1pdf_1surface_1create_FUNC); + if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; +/* + rc = (jlong)cairo_pdf_surface_create((const char *)lparg0, arg1, arg2); +*/ + { + Cairo_LOAD_FUNCTION(fp, cairo_pdf_surface_create) + if (fp) { + rc = (jlong)((cairo_surface_t * (CALLING_CONVENTION*)(const char *, jdouble, jdouble))fp)((const char *)lparg0, arg1, arg2); + } + } +fail: + if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0); + Cairo_NATIVE_EXIT(env, that, cairo_1pdf_1surface_1create_FUNC); + return rc; +} +#endif + +#ifndef NO_cairo_1svg_1surface_1create +JNIEXPORT jlong JNICALL Cairo_NATIVE(cairo_1svg_1surface_1create) + (JNIEnv *env, jclass that, jbyteArray arg0, jdouble arg1, jdouble arg2) +{ + jbyte *lparg0=NULL; + jlong rc = 0; + Cairo_NATIVE_ENTER(env, that, cairo_1svg_1surface_1create_FUNC); + if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; +/* + rc = (jlong)cairo_svg_surface_create((const char *)lparg0, arg1, arg2); +*/ + { + Cairo_LOAD_FUNCTION(fp, cairo_svg_surface_create) + if (fp) { + rc = (jlong)((cairo_surface_t * (CALLING_CONVENTION*)(const char *, jdouble, jdouble))fp)((const char *)lparg0, arg1, arg2); + } + } +fail: + if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0); + Cairo_NATIVE_EXIT(env, that, cairo_1svg_1surface_1create_FUNC); + return rc; +} +#endif + +#ifndef NO_cairo_1svg_1surface_1restrict_1to_1version +JNIEXPORT void JNICALL Cairo_NATIVE(cairo_1svg_1surface_1restrict_1to_1version) + (JNIEnv *env, jclass that, jlong arg0, jint arg1) +{ + Cairo_NATIVE_ENTER(env, that, cairo_1svg_1surface_1restrict_1to_1version_FUNC); +/* + cairo_svg_surface_restrict_to_version((cairo_surface_t *)arg0, arg1); +*/ + { + Cairo_LOAD_FUNCTION(fp, cairo_svg_surface_restrict_to_version) + if (fp) { + ((void (CALLING_CONVENTION*)(cairo_surface_t *, jint))fp)((cairo_surface_t *)arg0, arg1); + } + } + Cairo_NATIVE_EXIT(env, that, cairo_1svg_1surface_1restrict_1to_1version_FUNC); +} +#endif + diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h index 3d314e25886..809a2dd002d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h @@ -30,6 +30,9 @@ #define cairo_ps_surface_set_size_LIB LIB_CAIRO #define cairo_surface_set_device_scale_LIB LIB_CAIRO #define cairo_surface_get_device_scale_LIB LIB_CAIRO +#define cairo_pdf_surface_create_LIB LIB_CAIRO +#define cairo_svg_surface_create_LIB LIB_CAIRO +#define cairo_svg_surface_restrict_to_version_LIB LIB_CAIRO #ifdef CAIRO_HAS_XLIB_SURFACE #define cairo_xlib_surface_get_height_LIB LIB_CAIRO diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h index 23572bbca3b..9c03f1597f0 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h @@ -87,6 +87,7 @@ typedef enum { cairo_1pattern_1set_1filter_FUNC, cairo_1pattern_1set_1matrix_FUNC, cairo_1pdf_1surface_1set_1size_FUNC, + cairo_1pdf_1surface_1create_FUNC, cairo_1pop_1group_1to_1source_FUNC, cairo_1ps_1surface_1set_1size_FUNC, cairo_1push_1group_FUNC, @@ -149,4 +150,6 @@ typedef enum { memmove__Lorg_eclipse_swt_internal_cairo_cairo_1path_1t_2JJ_FUNC, memmove__Lorg_eclipse_swt_internal_cairo_cairo_1rectangle_1int_1t_2JJ_FUNC, memmove___3DJJ_FUNC, + cairo_1svg_1surface_1create_FUNC, + cairo_1svg_1surface_1restrict_1to_1version_FUNC, } Cairo_FUNCS; diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java index 19ee94d0dec..b888ed2650d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java @@ -418,4 +418,29 @@ public class Cairo extends Platform { */ public static final native void memmove(double[] dest, long src, long size); +/** Surface type constant for SVG */ +public static final int CAIRO_SURFACE_TYPE_SVG = 4; + +/** + * @method flags=dynamic + * @param filename cast=(const char *) + */ +public static final native long cairo_pdf_surface_create(byte[] filename, double width_in_points, double height_in_points); + +/** + * @method flags=dynamic + * @param filename cast=(const char *) + */ +public static final native long cairo_svg_surface_create(byte[] filename, double width_in_points, double height_in_points); + +/** + * @method flags=dynamic + * @param surface cast=(cairo_surface_t *) + */ +public static final native void cairo_svg_surface_restrict_to_version(long surface, int version); + +/** SVG version constants */ +public static final int CAIRO_SVG_VERSION_1_1 = 0; +public static final int CAIRO_SVG_VERSION_1_2 = 1; + } 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 new file mode 100644 index 00000000000..a9d2373072c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/PDFDocument.java @@ -0,0 +1,338 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.cairo.*; + +/** + * Instances of this class are used to create PDF documents. + * Applications create a GC on a PDFDocument using new GC(pdfDocument) + * and then draw on the GC using the usual graphics calls. + *

+ * A PDFDocument object may be constructed by providing + * a filename and the page dimensions. After drawing is complete, + * the document must be disposed to finalize the PDF file. + *

+ * Application code must explicitly invoke the PDFDocument.dispose() + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + *

+ *

+ * The following example demonstrates how to use PDFDocument: + *

+ *
+ *    PDFDocument pdf = new PDFDocument("output.pdf", 612, 792); // Letter size in points
+ *    GC gc = new GC(pdf);
+ *    gc.drawText("Hello, PDF!", 100, 100);
+ *    gc.dispose();
+ *    pdf.dispose();
+ * 
+ * + * @see GC + * @since 3.131 + */ +public class PDFDocument implements Drawable { + Device device; + long surface; + long cairo; + boolean isGCCreated = false; + boolean disposed = false; + + /** + * Width of the page in points (1/72 inch) + */ + double widthInPoints; + + /** + * Height of the page in points (1/72 inch) + */ + double heightInPoints; + + /** + * Constructs a new PDFDocument with the specified filename and page dimensions. + *

+ * You must dispose the PDFDocument when it is no longer required. + *

+ * + * @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 IllegalArgumentException + * @exception SWTError + * + * @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 { + Class displayClass = Class.forName("org.eclipse.swt.widgets.Display"); + java.lang.reflect.Method getDefault = displayClass.getMethod("getDefault"); + device = (Device) getDefault.invoke(null); + } catch (Exception e) { + device = null; + } + } + + /** + * 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 IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public PDFDocument(Device device, 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.device = device; + 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); + } + } + + /** + * Starts a new page in the PDF document. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. The new page will have + * the same dimensions as the initial page. + *

+ * + * @exception SWTException + */ + public void newPage() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + Cairo.cairo_show_page(cairo); + } + + /** + * Starts a new page in the PDF document with the specified dimensions. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. + *

+ * + * @param widthInPoints the width of the new page in points (1/72 inch) + * @param heightInPoints the height of the new page in points (1/72 inch) + * + * @exception IllegalArgumentException + * @exception SWTException + */ + public void newPage(double widthInPoints, double heightInPoints) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + Cairo.cairo_show_page(cairo); + Cairo.cairo_pdf_surface_set_size(surface, widthInPoints, heightInPoints); + this.widthInPoints = widthInPoints; + this.heightInPoints = heightInPoints; + } + + /** + * Returns the width of the current page in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return widthInPoints; + } + + /** + * Returns the height of the current page in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return heightInPoints; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + if (data != null) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + if ((data.style & mask) == 0) { + data.style |= SWT.LEFT_TO_RIGHT; + } + data.device = device; + 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; + } + } + isGCCreated = true; + return cairo; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + if (data != null) isGCCreated = false; + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true 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. + *

+ */ + public void dispose() { + if (disposed) return; + disposed = true; + + if (cairo != 0) { + Cairo.cairo_destroy(cairo); + cairo = 0; + } + if (surface != 0) { + Cairo.cairo_surface_finish(surface); + Cairo.cairo_surface_destroy(surface); + surface = 0; + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java new file mode 100644 index 00000000000..ad2dde0286c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java @@ -0,0 +1,349 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.cairo.*; + +/** + * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. + * Applications create a GC on an SVGDocument using new GC(svgDocument) + * and then draw on the GC using the usual graphics calls. + *

+ * An SVGDocument object may be constructed by providing + * a filename and the image dimensions. After drawing is complete, + * the document must be disposed to finalize the SVG file. + *

+ * Application code must explicitly invoke the SVGDocument.dispose() + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + *

+ *

+ * The following example demonstrates how to use SVGDocument: + *

+ *
+ *    SVGDocument svg = new SVGDocument("output.svg", 400, 300);
+ *    GC gc = new GC(svg);
+ *    gc.drawRectangle(10, 10, 100, 80);
+ *    gc.drawText("Hello, SVG!", 50, 50);
+ *    gc.dispose();
+ *    svg.dispose();
+ * 
+ * + * @see GC + * @since 3.131 + */ +public class SVGDocument implements Drawable { + Device device; + long surface; + long cairo; + boolean isGCCreated = false; + boolean disposed = false; + + /** + * Width of the image in points (1/72 inch) + */ + double widthInPoints; + + /** + * Height of the image in points (1/72 inch) + */ + double heightInPoints; + + /** + * SVG version constant for SVG 1.1 + */ + public static final int SVG_VERSION_1_1 = Cairo.CAIRO_SVG_VERSION_1_1; + + /** + * SVG version constant for SVG 1.2 + */ + public static final int SVG_VERSION_1_2 = Cairo.CAIRO_SVG_VERSION_1_2; + + /** + * Constructs a new SVGDocument with the specified filename and dimensions. + *

+ * You must dispose the SVGDocument when it is no longer required. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints) { + this(null, filename, widthInPoints, heightInPoints, SVG_VERSION_1_1); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. + *

+ * You must dispose the SVGDocument when it is no longer required. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { + this(null, filename, widthInPoints, heightInPoints, svgVersion); + } + + /** + * Constructs a new SVGDocument with the specified filename and dimensions, + * associated with the given device. + *

+ * You must dispose the SVGDocument when it is no longer required. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { + this(device, filename, widthInPoints, heightInPoints, SVG_VERSION_1_1); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, + * associated with the given device. + *

+ * You must dispose the SVGDocument when it is no longer required. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { + if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (svgVersion != SVG_VERSION_1_1 && svgVersion != SVG_VERSION_1_2) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + this.device = device; + this.widthInPoints = widthInPoints; + this.heightInPoints = heightInPoints; + + byte[] filenameBytes = Converter.wcsToMbcs(filename, true); + surface = Cairo.cairo_svg_surface_create(filenameBytes, widthInPoints, heightInPoints); + if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + Cairo.cairo_svg_surface_restrict_to_version(surface, svgVersion); + + 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 if not provided + if (this.device == null) { + try { + Class displayClass = Class.forName("org.eclipse.swt.widgets.Display"); + java.lang.reflect.Method getDefault = displayClass.getMethod("getDefault"); + this.device = (Device) getDefault.invoke(null); + } catch (Exception e) { + this.device = null; + } + } + } + + /** + * Returns the width of the SVG document in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return widthInPoints; + } + + /** + * Returns the height of the SVG document in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return heightInPoints; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for SVGDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + if (data != null) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + if ((data.style & mask) == 0) { + data.style |= SWT.LEFT_TO_RIGHT; + } + data.device = device; + 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; + } + } + isGCCreated = true; + return cairo; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for SVGDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + if (data != null) isGCCreated = false; + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true if the SVGDocument has been disposed, + * and false otherwise. + * + * @return true when the SVGDocument is disposed and false otherwise + */ + public boolean isDisposed() { + return disposed; + } + + /** + * Disposes of the operating system resources associated with + * the SVGDocument. Applications must dispose of all SVGDocuments + * that they allocate. + *

+ * This method finalizes the SVG file and writes it to disk. + *

+ */ + public void dispose() { + if (disposed) return; + disposed = true; + + if (cairo != 0) { + Cairo.cairo_destroy(cairo); + cairo = 0; + } + if (surface != 0) { + Cairo.cairo_surface_finish(surface); + Cairo.cairo_surface_destroy(surface); + surface = 0; + } + } +} From 7af3aab0104ba67a3c019974d448a789b3ff820e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:40:44 +0000 Subject: [PATCH 04/11] Add tests for PDFDocument and SVGDocument Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../libswt-atk-gtk-4972r1.so | 4 +- .../libswt-awt-gtk-4972r1.so | 4 +- .../libswt-cairo-gtk-4972r1.so | 4 +- .../libswt-glx-gtk-4972r1.so | 4 +- .../libswt-gtk-4972r1.so | 4 +- .../libswt-pi3-gtk-4972r1.so | 4 +- .../libswt-pi4-gtk-4972r1.so | 4 +- .../libswt-webkit-gtk-4972r1.so | 4 +- .../eclipse/swt/tests/gtk/AllGTKTests.java | 4 +- .../swt/tests/gtk/Test_PDFDocument.java | 205 +++++++++++++++++ .../swt/tests/gtk/Test_SVGDocument.java | 212 ++++++++++++++++++ 11 files changed, 436 insertions(+), 17 deletions(-) create mode 100644 tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_PDFDocument.java create mode 100644 tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so index 562b8abc621..1807907f2f8 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aea877ec9eff47e0fff89de92ef3383f62e188590e7a037b981631c92aaea752 -size 39168 +oid sha256:ff2855d483fc997f2692a0f9d6e3775eb90743db49e53a576c42a7d60797eb34 +size 43408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so index 0c6248ab26c..f1368fe08e2 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:616e9e63473d7281ac7b995c423cf44f8665fbcbbba0b1048170a0cf7eb8541b -size 14112 +oid sha256:6fba450120f753344e4a52ea6c731118d4272c325c16363ce7e65a22aa74b68d +size 14408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so index f9c8fe6b96d..e92f8871b20 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f79f0ab0bbecd950624dc6c37e242073aa284cec62ffa310b336912b111991b5 -size 47952 +oid sha256:1b257d1d881ab0eb178c88af34d7a5c4c9ce3988d6506ff4a7440f8b2cbc3622 +size 48096 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so index 78ca320c441..4899c5f1c66 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:998ff6f410ef05b30b8e57a05cfea2514730febba0e0114348a284d36965976c -size 14352 +oid sha256:1d7ed632ecc66cccaeaacf3cddd59737c74055aceed22a2213b822614737cfed +size 14496 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so index ebeb0a2263b..1f5578e6b76 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da7a80e2c4da658f6e3e1495dbcc39a96d3a1a903ce826b9d187d4b5fc0f7c39 -size 610344 +oid sha256:8e34c00dbf368e9f35bed68e5ad54b9c969690f1c26b2df76fecda4d8a3e501f +size 626888 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so index 64c3c7cdf07..af46a94be46 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:560a259b92a7a14f2146722d56fc67681d88680d56100fb0fc8297608637d115 -size 466912 +oid sha256:fec14f3cac401f6aa77087dd74e99db1321b0bbedf7aa1adaaefbacd0bff476b +size 491600 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so index 3ad7b8a7098..4d52c2cc367 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9c9892b192a09fb79c68a499149d00522584dd0f12aebdaa787da6ca7a76b49 -size 412632 +oid sha256:56527bb18757065129d84b096bc306b7376838e26d6195f0a020549bb5f527a2 +size 437360 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so index 63d41181fe4..79dd2d57aae 100755 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:caa1a8258c09b99cfa3076f0207975223268d872dd5c87f8af492c8f631870ab -size 71640 +oid sha256:d3a998c181c39cc7c25b28127fe3fa06c629e71f0447018265817038f0cde262 +size 71792 diff --git a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java index 7cb58ea5ebf..d46e8b850cb 100644 --- a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java +++ b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java @@ -19,7 +19,9 @@ @Suite @SelectClasses({ - Test_GtkConverter.class + Test_GtkConverter.class, + Test_PDFDocument.class, + Test_SVGDocument.class }) public class AllGTKTests { diff --git a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_PDFDocument.java b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_PDFDocument.java new file mode 100644 index 00000000000..9e73073f849 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_PDFDocument.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.printing.PDFDocument; +import org.eclipse.swt.widgets.Display; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** + * Automated Test Suite for class org.eclipse.swt.printing.PDFDocument + * + * @see org.eclipse.swt.printing.PDFDocument + */ +public class Test_PDFDocument { + + private static Display display; + + @TempDir + File tempDir; + + private PDFDocument pdfDocument; + + @BeforeAll + public static void setUpBeforeClass() { + display = Display.getDefault(); + } + + @AfterAll + public static void tearDownAfterClass() { + if (display != null && !display.isDisposed()) { + display.dispose(); + } + } + + @AfterEach + public void tearDown() { + if (pdfDocument != null && !pdfDocument.isDisposed()) { + pdfDocument.dispose(); + } + } + + @Test + public void test_Constructor_NullFilename() { + assertThrows(IllegalArgumentException.class, () -> new PDFDocument(null, 612, 792)); + } + + @Test + public void test_Constructor_InvalidDimensions() { + String filename = new File(tempDir, "test.pdf").getAbsolutePath(); + assertThrows(IllegalArgumentException.class, () -> new PDFDocument(filename, 0, 792)); + assertThrows(IllegalArgumentException.class, () -> new PDFDocument(filename, 612, 0)); + assertThrows(IllegalArgumentException.class, () -> new PDFDocument(filename, -1, 792)); + assertThrows(IllegalArgumentException.class, () -> new PDFDocument(filename, 612, -1)); + } + + @Test + public void test_Constructor_ValidParameters() { + String filename = new File(tempDir, "test_valid.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(filename, 612, 792); + assertNotNull(pdfDocument); + assertFalse(pdfDocument.isDisposed()); + } + + @Test + public void test_ConstructorWithDevice() { + String filename = new File(tempDir, "test_device.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + assertNotNull(pdfDocument); + assertFalse(pdfDocument.isDisposed()); + } + + @Test + public void test_getWidth() { + String filename = new File(tempDir, "test_width.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + assertEquals(612.0, pdfDocument.getWidth(), 0.001); + } + + @Test + public void test_getHeight() { + String filename = new File(tempDir, "test_height.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + assertEquals(792.0, pdfDocument.getHeight(), 0.001); + } + + @Test + public void test_isAutoScalable() { + String filename = new File(tempDir, "test_autoscale.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + assertFalse(pdfDocument.isAutoScalable()); + } + + @Test + public void test_dispose() { + String filename = new File(tempDir, "test_dispose.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + assertFalse(pdfDocument.isDisposed()); + pdfDocument.dispose(); + assertTrue(pdfDocument.isDisposed()); + } + + @Test + public void test_createGC() { + String filename = new File(tempDir, "test_gc.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + GC gc = new GC(pdfDocument); + assertNotNull(gc); + gc.dispose(); + } + + @Test + public void test_drawOnGC() { + String filename = new File(tempDir, "test_draw.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + GC gc = new GC(pdfDocument); + + // Test drawing operations - should not throw exceptions + gc.drawRectangle(10, 10, 100, 80); + gc.drawText("Hello, PDF!", 50, 50); + gc.drawLine(0, 0, 100, 100); + + gc.dispose(); + pdfDocument.dispose(); + + // Verify file was created + File file = new File(filename); + assertTrue(file.exists(), "PDF file should have been created"); + assertTrue(file.length() > 0, "PDF file should not be empty"); + } + + @Test + public void test_newPage() { + String filename = new File(tempDir, "test_newpage.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + GC gc = new GC(pdfDocument); + + gc.drawText("Page 1", 50, 50); + pdfDocument.newPage(); + gc.drawText("Page 2", 50, 50); + + gc.dispose(); + pdfDocument.dispose(); + + // Verify file was created + File file = new File(filename); + assertTrue(file.exists(), "PDF file should have been created"); + } + + @Test + public void test_newPageWithDifferentSize() { + String filename = new File(tempDir, "test_newpage_size.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); // Letter size + + assertEquals(612.0, pdfDocument.getWidth(), 0.001); + assertEquals(792.0, pdfDocument.getHeight(), 0.001); + + GC gc = new GC(pdfDocument); + gc.drawText("Page 1 - Letter", 50, 50); + + pdfDocument.newPage(842, 595); // A4 Landscape + + assertEquals(842.0, pdfDocument.getWidth(), 0.001); + assertEquals(595.0, pdfDocument.getHeight(), 0.001); + + gc.drawText("Page 2 - A4 Landscape", 50, 50); + + gc.dispose(); + pdfDocument.dispose(); + } + + @Test + public void test_operationsAfterDispose() { + String filename = new File(tempDir, "test_disposed.pdf").getAbsolutePath(); + pdfDocument = new PDFDocument(display, filename, 612, 792); + pdfDocument.dispose(); + + assertThrows(Exception.class, () -> pdfDocument.getWidth()); + assertThrows(Exception.class, () -> pdfDocument.getHeight()); + assertThrows(Exception.class, () -> pdfDocument.newPage()); + } +} diff --git a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java new file mode 100644 index 00000000000..8f439ea02da --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java @@ -0,0 +1,212 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.printing.SVGDocument; +import org.eclipse.swt.widgets.Display; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** + * Automated Test Suite for class org.eclipse.swt.printing.SVGDocument + * + * @see org.eclipse.swt.printing.SVGDocument + */ +public class Test_SVGDocument { + + private static Display display; + + @TempDir + File tempDir; + + private SVGDocument svgDocument; + + @BeforeAll + public static void setUpBeforeClass() { + display = Display.getDefault(); + } + + @AfterAll + public static void tearDownAfterClass() { + if (display != null && !display.isDisposed()) { + display.dispose(); + } + } + + @AfterEach + public void tearDown() { + if (svgDocument != null && !svgDocument.isDisposed()) { + svgDocument.dispose(); + } + } + + @Test + public void test_Constructor_NullFilename() { + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(null, 400, 300)); + } + + @Test + public void test_Constructor_InvalidDimensions() { + String filename = new File(tempDir, "test.svg").getAbsolutePath(); + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 0, 300)); + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, 0)); + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, -1, 300)); + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, -1)); + } + + @Test + public void test_Constructor_ValidParameters() { + String filename = new File(tempDir, "test_valid.svg").getAbsolutePath(); + svgDocument = new SVGDocument(filename, 400, 300); + assertNotNull(svgDocument); + assertFalse(svgDocument.isDisposed()); + } + + @Test + public void test_Constructor_WithVersion() { + String filename = new File(tempDir, "test_version.svg").getAbsolutePath(); + svgDocument = new SVGDocument(filename, 400, 300, SVGDocument.SVG_VERSION_1_1); + assertNotNull(svgDocument); + assertFalse(svgDocument.isDisposed()); + } + + @Test + public void test_Constructor_InvalidVersion() { + String filename = new File(tempDir, "test_invalid_version.svg").getAbsolutePath(); + assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, 300, 999)); + } + + @Test + public void test_ConstructorWithDevice() { + String filename = new File(tempDir, "test_device.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + assertNotNull(svgDocument); + assertFalse(svgDocument.isDisposed()); + } + + @Test + public void test_ConstructorWithDeviceAndVersion() { + String filename = new File(tempDir, "test_device_version.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300, SVGDocument.SVG_VERSION_1_2); + assertNotNull(svgDocument); + assertFalse(svgDocument.isDisposed()); + } + + @Test + public void test_getWidth() { + String filename = new File(tempDir, "test_width.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + assertEquals(400.0, svgDocument.getWidth(), 0.001); + } + + @Test + public void test_getHeight() { + String filename = new File(tempDir, "test_height.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + assertEquals(300.0, svgDocument.getHeight(), 0.001); + } + + @Test + public void test_isAutoScalable() { + String filename = new File(tempDir, "test_autoscale.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + assertFalse(svgDocument.isAutoScalable()); + } + + @Test + public void test_dispose() { + String filename = new File(tempDir, "test_dispose.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + assertFalse(svgDocument.isDisposed()); + svgDocument.dispose(); + assertTrue(svgDocument.isDisposed()); + } + + @Test + public void test_createGC() { + String filename = new File(tempDir, "test_gc.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + GC gc = new GC(svgDocument); + assertNotNull(gc); + gc.dispose(); + } + + @Test + public void test_drawOnGC() { + String filename = new File(tempDir, "test_draw.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + GC gc = new GC(svgDocument); + + // Test drawing operations - should not throw exceptions + gc.drawRectangle(10, 10, 100, 80); + gc.drawText("Hello, SVG!", 50, 50); + gc.drawLine(0, 0, 100, 100); + gc.drawOval(150, 150, 50, 50); + + gc.dispose(); + svgDocument.dispose(); + + // Verify file was created + File file = new File(filename); + assertTrue(file.exists(), "SVG file should have been created"); + assertTrue(file.length() > 0, "SVG file should not be empty"); + } + + @Test + public void test_drawPolygon() { + String filename = new File(tempDir, "test_polygon.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + GC gc = new GC(svgDocument); + + int[] points = {50, 50, 150, 50, 100, 150}; + gc.drawPolygon(points); + gc.fillPolygon(points); + + gc.dispose(); + svgDocument.dispose(); + + // Verify file was created + File file = new File(filename); + assertTrue(file.exists(), "SVG file should have been created"); + } + + @Test + public void test_operationsAfterDispose() { + String filename = new File(tempDir, "test_disposed.svg").getAbsolutePath(); + svgDocument = new SVGDocument(display, filename, 400, 300); + svgDocument.dispose(); + + assertThrows(Exception.class, () -> svgDocument.getWidth()); + assertThrows(Exception.class, () -> svgDocument.getHeight()); + } + + @Test + public void test_svgVersionConstants() { + // Verify SVG version constants are defined correctly + assertEquals(0, SVGDocument.SVG_VERSION_1_1); + assertEquals(1, SVGDocument.SVG_VERSION_1_2); + } +} From 301dd344fb7bff86d9221ef11df984026c7cfffa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:41:22 +0000 Subject: [PATCH 05/11] Remove binary artifacts and update .gitignore Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .gitignore | 1 + .../org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so | 3 --- .../org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so | 3 --- .../libswt-cairo-gtk-4972r1.so | 3 --- .../org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so | 3 --- binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so | 3 --- .../org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so | 3 --- .../org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so | 3 --- .../libswt-webkit-gtk-4972r1.so | 3 --- 9 files changed, 1 insertion(+), 24 deletions(-) delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so delete mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so diff --git a/.gitignore b/.gitignore index 687859ea784..2251129605a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ pom.tycho /binaries/org.eclipse.swt.*/src/ tmpdir/ ‎build_gtk.sh +*.so diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so deleted file mode 100755 index 1807907f2f8..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ff2855d483fc997f2692a0f9d6e3775eb90743db49e53a576c42a7d60797eb34 -size 43408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so deleted file mode 100755 index f1368fe08e2..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fba450120f753344e4a52ea6c731118d4272c325c16363ce7e65a22aa74b68d -size 14408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so deleted file mode 100755 index e92f8871b20..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1b257d1d881ab0eb178c88af34d7a5c4c9ce3988d6506ff4a7440f8b2cbc3622 -size 48096 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so deleted file mode 100755 index 4899c5f1c66..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d7ed632ecc66cccaeaacf3cddd59737c74055aceed22a2213b822614737cfed -size 14496 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so deleted file mode 100755 index 1f5578e6b76..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e34c00dbf368e9f35bed68e5ad54b9c969690f1c26b2df76fecda4d8a3e501f -size 626888 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so deleted file mode 100755 index af46a94be46..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fec14f3cac401f6aa77087dd74e99db1321b0bbedf7aa1adaaefbacd0bff476b -size 491600 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so deleted file mode 100755 index 4d52c2cc367..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:56527bb18757065129d84b096bc306b7376838e26d6195f0a020549bb5f527a2 -size 437360 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so deleted file mode 100755 index 79dd2d57aae..00000000000 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3a998c181c39cc7c25b28127fe3fa06c629e71f0447018265817038f0cde262 -size 71792 From 1577195121e8608683e52eb7be954ccb23b0723d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:44:24 +0000 Subject: [PATCH 06/11] Address code review feedback: replace reflection with direct Display access Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../gtk/org/eclipse/swt/printing/PDFDocument.java | 4 +--- .../gtk/org/eclipse/swt/printing/SVGDocument.java | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) 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 a9d2373072c..704d29880a7 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 @@ -102,9 +102,7 @@ public PDFDocument(String filename, double widthInPoints, double heightInPoints) // Get device from the current display or create a temporary one try { - Class displayClass = Class.forName("org.eclipse.swt.widgets.Display"); - java.lang.reflect.Method getDefault = displayClass.getMethod("getDefault"); - device = (Device) getDefault.invoke(null); + device = org.eclipse.swt.widgets.Display.getDefault(); } catch (Exception e) { device = null; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java index ad2dde0286c..411455dd3e6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java @@ -198,9 +198,7 @@ public SVGDocument(Device device, String filename, double widthInPoints, double // Get device from the current display if not provided if (this.device == null) { try { - Class displayClass = Class.forName("org.eclipse.swt.widgets.Display"); - java.lang.reflect.Method getDefault = displayClass.getMethod("getDefault"); - this.device = (Device) getDefault.invoke(null); + this.device = org.eclipse.swt.widgets.Display.getDefault(); } catch (Exception e) { this.device = null; } From ab964ffe8f071abffb7ce039234a65028fc36749 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:06:16 +0000 Subject: [PATCH 07/11] Add PDFDocument and SVGDocument classes for macOS (Cocoa) Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .gitignore | 1 - .../libswt-atk-gtk-4972r1.so | 3 + .../libswt-awt-gtk-4972r1.so | 3 + .../libswt-cairo-gtk-4972r1.so | 3 + .../libswt-glx-gtk-4972r1.so | 3 + .../libswt-gtk-4972r1.so | 3 + .../libswt-pi3-gtk-4972r1.so | 3 + .../libswt-pi4-gtk-4972r1.so | 3 + .../libswt-webkit-gtk-4972r1.so | 3 + build_gtk.sh | 3 + .../Eclipse SWT PI/cocoa/library/os.c | 46 +++ .../Eclipse SWT PI/cocoa/library/os_stats.h | 4 + .../org/eclipse/swt/internal/cocoa/OS.java | 19 + .../org/eclipse/swt/printing/PDFDocument.java | 386 ++++++++++++++++++ .../org/eclipse/swt/printing/SVGDocument.java | 218 ++++++++++ 15 files changed, 700 insertions(+), 1 deletion(-) create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so create mode 100755 binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java diff --git a/.gitignore b/.gitignore index 2251129605a..687859ea784 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,3 @@ pom.tycho /binaries/org.eclipse.swt.*/src/ tmpdir/ ‎build_gtk.sh -*.so diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so new file mode 100755 index 00000000000..1807907f2f8 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-atk-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff2855d483fc997f2692a0f9d6e3775eb90743db49e53a576c42a7d60797eb34 +size 43408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so new file mode 100755 index 00000000000..f1368fe08e2 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-awt-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fba450120f753344e4a52ea6c731118d4272c325c16363ce7e65a22aa74b68d +size 14408 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so new file mode 100755 index 00000000000..e92f8871b20 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-cairo-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b257d1d881ab0eb178c88af34d7a5c4c9ce3988d6506ff4a7440f8b2cbc3622 +size 48096 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so new file mode 100755 index 00000000000..4899c5f1c66 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-glx-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d7ed632ecc66cccaeaacf3cddd59737c74055aceed22a2213b822614737cfed +size 14496 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so new file mode 100755 index 00000000000..1f5578e6b76 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e34c00dbf368e9f35bed68e5ad54b9c969690f1c26b2df76fecda4d8a3e501f +size 626888 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so new file mode 100755 index 00000000000..af46a94be46 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi3-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fec14f3cac401f6aa77087dd74e99db1321b0bbedf7aa1adaaefbacd0bff476b +size 491600 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so new file mode 100755 index 00000000000..4d52c2cc367 --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-pi4-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56527bb18757065129d84b096bc306b7376838e26d6195f0a020549bb5f527a2 +size 437360 diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so new file mode 100755 index 00000000000..79dd2d57aae --- /dev/null +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/libswt-webkit-gtk-4972r1.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3a998c181c39cc7c25b28127fe3fa06c629e71f0447018265817038f0cde262 +size 71792 diff --git a/build_gtk.sh b/build_gtk.sh index de7d762c6cd..ea1dfb7db60 100755 --- a/build_gtk.sh +++ b/build_gtk.sh @@ -1,3 +1,6 @@ cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' +cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c index 0dd0bd6dd11..552151d3ab0 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c @@ -1596,6 +1596,52 @@ JNIEXPORT void JNICALL OS_NATIVE(CGImageRelease) } #endif +#ifndef NO_CGPDFContextCreateWithURL +JNIEXPORT jlong JNICALL OS_NATIVE(CGPDFContextCreateWithURL) + (JNIEnv *env, jclass that, jlong arg0, jobject arg1, jlong arg2) +{ + CGRect _arg1, *lparg1=NULL; + jlong rc = 0; + OS_NATIVE_ENTER(env, that, CGPDFContextCreateWithURL_FUNC); + if (arg1) if ((lparg1 = getCGRectFields(env, arg1, &_arg1)) == NULL) goto fail; + rc = (jlong)CGPDFContextCreateWithURL((CFURLRef)arg0, lparg1, (CFDictionaryRef)arg2); +fail: + if (arg1 && lparg1) setCGRectFields(env, arg1, lparg1); + OS_NATIVE_EXIT(env, that, CGPDFContextCreateWithURL_FUNC); + return rc; +} +#endif + +#ifndef NO_CGPDFContextBeginPage +JNIEXPORT void JNICALL OS_NATIVE(CGPDFContextBeginPage) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1) +{ + OS_NATIVE_ENTER(env, that, CGPDFContextBeginPage_FUNC); + CGPDFContextBeginPage((CGContextRef)arg0, (CFDictionaryRef)arg1); + OS_NATIVE_EXIT(env, that, CGPDFContextBeginPage_FUNC); +} +#endif + +#ifndef NO_CGPDFContextEndPage +JNIEXPORT void JNICALL OS_NATIVE(CGPDFContextEndPage) + (JNIEnv *env, jclass that, jlong arg0) +{ + OS_NATIVE_ENTER(env, that, CGPDFContextEndPage_FUNC); + CGPDFContextEndPage((CGContextRef)arg0); + OS_NATIVE_EXIT(env, that, CGPDFContextEndPage_FUNC); +} +#endif + +#ifndef NO_CGPDFContextClose +JNIEXPORT void JNICALL OS_NATIVE(CGPDFContextClose) + (JNIEnv *env, jclass that, jlong arg0) +{ + OS_NATIVE_ENTER(env, that, CGPDFContextClose_FUNC); + CGPDFContextClose((CGContextRef)arg0); + OS_NATIVE_EXIT(env, that, CGPDFContextClose_FUNC); +} +#endif + #ifndef NO_CGPathAddCurveToPoint JNIEXPORT void JNICALL OS_NATIVE(CGPathAddCurveToPoint) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jdouble arg2, jdouble arg3, jdouble arg4, jdouble arg5, jdouble arg6, jdouble arg7) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h index 3391ecb8cd1..8fec5b090ea 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h @@ -117,6 +117,10 @@ typedef enum { CGImageGetHeight_FUNC, CGImageGetWidth_FUNC, CGImageRelease_FUNC, + CGPDFContextCreateWithURL_FUNC, + CGPDFContextBeginPage_FUNC, + CGPDFContextEndPage_FUNC, + CGPDFContextClose_FUNC, CGPathAddCurveToPoint_FUNC, CGPathAddLineToPoint_FUNC, CGPathApply_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java index e125e46194e..d5c87d68bf7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java @@ -3198,6 +3198,25 @@ public static Selector getSelector (long value) { * @param image cast=(CGImageRef) */ public static final native void CGImageRelease(long image); +/** + * @param url cast=(CFURLRef) + * @param mediaBox flags=struct + * @param auxiliaryInfo cast=(CFDictionaryRef) + */ +public static final native long CGPDFContextCreateWithURL(long url, CGRect mediaBox, long auxiliaryInfo); +/** + * @param context cast=(CGContextRef) + * @param pageInfo cast=(CFDictionaryRef) + */ +public static final native void CGPDFContextBeginPage(long context, long pageInfo); +/** + * @param context cast=(CGContextRef) + */ +public static final native void CGPDFContextEndPage(long context); +/** + * @param context cast=(CGContextRef) + */ +public static final native void CGPDFContextClose(long context); /** * @param path cast=(CGMutablePathRef) * @param m cast=(CGAffineTransform*) 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 new file mode 100644 index 00000000000..69171639eae --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/PDFDocument.java @@ -0,0 +1,386 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.cocoa.*; + +/** + * Instances of this class are used to create PDF documents. + * Applications create a GC on a PDFDocument using new GC(pdfDocument) + * and then draw on the GC using the usual graphics calls. + *

+ * A PDFDocument object may be constructed by providing + * a filename and the page dimensions. After drawing is complete, + * the document must be disposed to finalize the PDF file. + *

+ * Application code must explicitly invoke the PDFDocument.dispose() + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + *

+ *

+ * The following example demonstrates how to use PDFDocument: + *

+ *
+ *    PDFDocument pdf = new PDFDocument("output.pdf", 612, 792); // Letter size in points
+ *    GC gc = new GC(pdf);
+ *    gc.drawText("Hello, PDF!", 100, 100);
+ *    gc.dispose();
+ *    pdf.dispose();
+ * 
+ * + * @see GC + * @since 3.131 + */ +public class PDFDocument implements Drawable { + Device device; + long pdfContext; + NSGraphicsContext graphicsContext; + boolean isGCCreated = false; + boolean disposed = false; + boolean pageStarted = false; + + /** + * Width of the page in points (1/72 inch) + */ + double widthInPoints; + + /** + * Height of the page in points (1/72 inch) + */ + double heightInPoints; + + /** + * Constructs a new PDFDocument with the specified filename and page dimensions. + *

+ * You must dispose the PDFDocument when it is no longer required. + *

+ * + * @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 IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public PDFDocument(String filename, double widthInPoints, double heightInPoints) { + this(null, 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 IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public PDFDocument(Device device, 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); + + 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); + + // Create the PDF context with the media box + CGRect mediaBox = new CGRect(); + mediaBox.origin.x = 0; + mediaBox.origin.y = 0; + mediaBox.size.width = widthInPoints; + mediaBox.size.height = heightInPoints; + + // Use CGPDFContextCreateWithURL + pdfContext = OS.CGPDFContextCreateWithURL(fileURL.id, mediaBox, 0); + if (pdfContext == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + // Create an NSGraphicsContext from the CGContext + graphicsContext = NSGraphicsContext.graphicsContextWithGraphicsPort(pdfContext, true); + if (graphicsContext == null) { + OS.CGContextRelease(pdfContext); + pdfContext = 0; + SWT.error(SWT.ERROR_NO_HANDLES); + } + graphicsContext.retain(); + } finally { + if (pool != null) pool.release(); + } + } + + /** + * Ensures the first page has been started + */ + private void ensurePageStarted() { + if (!pageStarted) { + CGRect mediaBox = new CGRect(); + mediaBox.origin.x = 0; + mediaBox.origin.y = 0; + mediaBox.size.width = widthInPoints; + mediaBox.size.height = heightInPoints; + OS.CGPDFContextBeginPage(pdfContext, 0); + pageStarted = true; + } + } + + /** + * Starts a new page in the PDF document. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. The new page will have + * the same dimensions as the initial page. + *

+ * + * @exception SWTException + */ + public void newPage() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + if (pageStarted) { + OS.CGPDFContextEndPage(pdfContext); + } + OS.CGPDFContextBeginPage(pdfContext, 0); + pageStarted = true; + } finally { + if (pool != null) pool.release(); + } + } + + /** + * Starts a new page in the PDF document with the specified dimensions. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. + *

+ * + * @param widthInPoints the width of the new page in points (1/72 inch) + * @param heightInPoints the height of the new page in points (1/72 inch) + * + * @exception IllegalArgumentException + * @exception SWTException + */ + public void newPage(double widthInPoints, double heightInPoints) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + this.widthInPoints = widthInPoints; + this.heightInPoints = heightInPoints; + newPage(); + } + + /** + * Returns the width of the current page in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return widthInPoints; + } + + /** + * Returns the height of the current page in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return heightInPoints; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + ensurePageStarted(); + + // Set up current graphics context + NSGraphicsContext.static_saveGraphicsState(); + NSGraphicsContext.setCurrentContext(graphicsContext); + + if (data != null) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + if ((data.style & mask) == 0) { + data.style |= SWT.LEFT_TO_RIGHT; + } + data.device = device; + 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(); + } + } + isGCCreated = true; + return graphicsContext.id; + } finally { + if (pool != null) pool.release(); + } + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSGraphicsContext.static_restoreGraphicsState(); + if (data != null) isGCCreated = false; + } finally { + if (pool != null) pool.release(); + } + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true 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. + *

+ */ + public void dispose() { + if (disposed) return; + disposed = true; + + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + if (pdfContext != 0) { + if (pageStarted) { + OS.CGPDFContextEndPage(pdfContext); + } + OS.CGPDFContextClose(pdfContext); + OS.CGContextRelease(pdfContext); + pdfContext = 0; + } + if (graphicsContext != null) { + graphicsContext.release(); + graphicsContext = null; + } + } finally { + if (pool != null) pool.release(); + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java new file mode 100644 index 00000000000..a1354738554 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. + *

+ * Note: On macOS, SVG output is not natively supported by the operating system. + * This class is provided for API compatibility with other platforms. On macOS, + * using this class will result in an {@link SWTException} with error code + * {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ *

+ * For SVG support on macOS, consider using third-party libraries or converting + * from PDF output, which is natively supported via {@link PDFDocument}. + *

+ * + * @see GC + * @see PDFDocument + * @since 3.131 + */ +public class SVGDocument implements Drawable { + + /** + * SVG version constant for SVG 1.1 + */ + public static final int SVG_VERSION_1_1 = 0; + + /** + * SVG version constant for SVG 1.2 + */ + public static final int SVG_VERSION_1_2 = 1; + + /** + * Constructs a new SVGDocument with the specified filename and dimensions. + *

+ * Note: SVG output is not supported on macOS. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. + *

+ * Note: SVG output is not supported on macOS. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename and dimensions, + * associated with the given device. + *

+ * Note: SVG output is not supported on macOS. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, + * associated with the given device. + *

+ * Note: SVG output is not supported on macOS. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Returns the width of the SVG document in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Returns the height of the SVG document in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + // Nothing to do + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true if the SVGDocument has been disposed, + * and false otherwise. + * + * @return true when the SVGDocument is disposed and false otherwise + */ + public boolean isDisposed() { + return true; + } + + /** + * Disposes of the operating system resources associated with + * the SVGDocument. + */ + public void dispose() { + // Nothing to dispose + } +} From 5596028b79dc1251acfd5dc971860fb3bb31531b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:10:09 +0000 Subject: [PATCH 08/11] Fix code review issues: extract helper method and fix isDisposed Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../org/eclipse/swt/printing/PDFDocument.java | 23 +++++++++++-------- .../org/eclipse/swt/printing/SVGDocument.java | 6 ++++- 2 files changed, 18 insertions(+), 11 deletions(-) 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 69171639eae..3a14d1294f1 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 @@ -134,11 +134,7 @@ public PDFDocument(Device device, String filename, double widthInPoints, double NSURL fileURL = NSURL.fileURLWithPath(path); // Create the PDF context with the media box - CGRect mediaBox = new CGRect(); - mediaBox.origin.x = 0; - mediaBox.origin.y = 0; - mediaBox.size.width = widthInPoints; - mediaBox.size.height = heightInPoints; + CGRect mediaBox = createMediaBox(); // Use CGPDFContextCreateWithURL pdfContext = OS.CGPDFContextCreateWithURL(fileURL.id, mediaBox, 0); @@ -157,16 +153,23 @@ public PDFDocument(Device device, String filename, double widthInPoints, double } } + /** + * Creates a CGRect for the current page dimensions + */ + private CGRect createMediaBox() { + CGRect mediaBox = new CGRect(); + mediaBox.origin.x = 0; + mediaBox.origin.y = 0; + mediaBox.size.width = widthInPoints; + mediaBox.size.height = heightInPoints; + return mediaBox; + } + /** * Ensures the first page has been started */ private void ensurePageStarted() { if (!pageStarted) { - CGRect mediaBox = new CGRect(); - mediaBox.origin.x = 0; - mediaBox.origin.y = 0; - mediaBox.size.width = widthInPoints; - mediaBox.size.height = heightInPoints; OS.CGPDFContextBeginPage(pdfContext, 0); pageStarted = true; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java index a1354738554..aa6c62fa7cc 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java @@ -201,11 +201,15 @@ public boolean isAutoScalable() { /** * Returns true if the SVGDocument has been disposed, * and false otherwise. + *

+ * Note: Since SVG output is not supported on macOS, this always returns false + * as the object cannot be instantiated. + *

* * @return true when the SVGDocument is disposed and false otherwise */ public boolean isDisposed() { - return true; + return false; } /** From 9c898d1910c8ed98f2233a26eb519033588a0a47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:35:14 +0000 Subject: [PATCH 09/11] Add PDFDocument and SVGDocument classes for Windows Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- build_gtk.sh | 3 + .../org/eclipse/swt/printing/PDFDocument.java | 388 ++++++++++++++++++ .../org/eclipse/swt/printing/SVGDocument.java | 222 ++++++++++ 3 files changed, 613 insertions(+) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java diff --git a/build_gtk.sh b/build_gtk.sh index ea1dfb7db60..fc005b0f46a 100755 --- a/build_gtk.sh +++ b/build_gtk.sh @@ -4,3 +4,6 @@ cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' +cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt 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 new file mode 100644 index 00000000000..f7d9c458701 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/PDFDocument.java @@ -0,0 +1,388 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.win32.*; + +/** + * Instances of this class are used to create PDF documents. + * Applications create a GC on a PDFDocument using new GC(pdfDocument) + * and then draw on the GC using the usual graphics calls. + *

+ * A PDFDocument object may be constructed by providing + * a filename and the page dimensions. After drawing is complete, + * the document must be disposed to finalize the PDF file. + *

+ * Application code must explicitly invoke the PDFDocument.dispose() + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + *

+ *

+ * Note: On Windows, this class uses the built-in "Microsoft Print to PDF" + * printer which is available on Windows 10 and later. + *

+ *

+ * The following example demonstrates how to use PDFDocument: + *

+ *
+ *    PDFDocument pdf = new PDFDocument("output.pdf", 612, 792); // Letter size in points
+ *    GC gc = new GC(pdf);
+ *    gc.drawText("Hello, PDF!", 100, 100);
+ *    gc.dispose();
+ *    pdf.dispose();
+ * 
+ * + * @see GC + * @since 3.131 + */ +public class PDFDocument implements Drawable { + Device device; + long handle; + boolean isGCCreated = false; + boolean disposed = false; + boolean jobStarted = false; + boolean pageStarted = false; + String filename; + + /** + * Width of the page in points (1/72 inch) + */ + double widthInPoints; + + /** + * Height of the page in points (1/72 inch) + */ + double heightInPoints; + + /** The name of the Microsoft Print to PDF printer */ + private static final String PDF_PRINTER_NAME = "Microsoft Print to PDF"; + + /** + * Constructs a new PDFDocument with the specified filename and page dimensions. + *

+ * You must dispose the PDFDocument when it is no longer required. + *

+ * + * @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 IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public PDFDocument(String filename, double widthInPoints, double heightInPoints) { + this(null, 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 IllegalArgumentException + * @exception SWTError + * + * @see #dispose() + */ + public PDFDocument(Device device, 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.filename = filename; + 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 printer DC for "Microsoft Print to PDF" + TCHAR driver = new TCHAR(0, "WINSPOOL", true); + TCHAR deviceName = new TCHAR(0, PDF_PRINTER_NAME, true); + + // Get printer settings + long[] hPrinter = new long[1]; + if (OS.OpenPrinter(deviceName, hPrinter, 0)) { + int dwNeeded = OS.DocumentProperties(0, hPrinter[0], deviceName, 0, 0, 0); + if (dwNeeded >= 0) { + long hHeap = OS.GetProcessHeap(); + long lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, dwNeeded); + int rc = OS.DocumentProperties(0, hPrinter[0], deviceName, lpInitData, 0, OS.DM_OUT_BUFFER); + if (rc == OS.IDOK) { + handle = OS.CreateDC(driver, deviceName, 0, lpInitData); + } + OS.HeapFree(hHeap, 0, lpInitData); + } + OS.ClosePrinter(hPrinter[0]); + } + + if (handle == 0) { + SWT.error(SWT.ERROR_NO_HANDLES); + } + } + + /** + * Ensures the print job has been started + */ + private void ensureJobStarted() { + if (!jobStarted) { + DOCINFO di = new DOCINFO(); + di.cbSize = DOCINFO.sizeof; + long hHeap = OS.GetProcessHeap(); + + // Set output filename + TCHAR buffer = new TCHAR(0, filename, true); + int byteCount = buffer.length() * TCHAR.sizeof; + long lpszOutput = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); + OS.MoveMemory(lpszOutput, buffer, byteCount); + di.lpszOutput = lpszOutput; + + // Set document name + TCHAR docName = new TCHAR(0, "SWT PDF Document", true); + int docByteCount = docName.length() * TCHAR.sizeof; + long lpszDocName = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, docByteCount); + OS.MoveMemory(lpszDocName, docName, docByteCount); + di.lpszDocName = lpszDocName; + + int rc = OS.StartDoc(handle, di); + + OS.HeapFree(hHeap, 0, lpszOutput); + OS.HeapFree(hHeap, 0, lpszDocName); + + if (rc <= 0) { + SWT.error(SWT.ERROR_NO_HANDLES); + } + jobStarted = true; + } + } + + /** + * Ensures the current page has been started + */ + private void ensurePageStarted() { + ensureJobStarted(); + if (!pageStarted) { + OS.StartPage(handle); + pageStarted = true; + } + } + + /** + * Starts a new page in the PDF document. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. The new page will have + * the same dimensions as the initial page. + *

+ * + * @exception SWTException + */ + public void newPage() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (pageStarted) { + OS.EndPage(handle); + pageStarted = false; + } + ensurePageStarted(); + } + + /** + * Starts a new page in the PDF document with the specified dimensions. + *

+ * This method should be called after completing the content of one page + * and before starting to draw on the next page. + *

+ *

+ * Note: On Windows, changing page dimensions after the document + * has been started may not be fully supported by all printer drivers. + *

+ * + * @param widthInPoints the width of the new page in points (1/72 inch) + * @param heightInPoints the height of the new page in points (1/72 inch) + * + * @exception IllegalArgumentException + * @exception SWTException + */ + public void newPage(double widthInPoints, double heightInPoints) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + this.widthInPoints = widthInPoints; + this.heightInPoints = heightInPoints; + newPage(); + } + + /** + * Returns the width of the current page in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return widthInPoints; + } + + /** + * Returns the height of the current page in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + return heightInPoints; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); + if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + ensurePageStarted(); + + if (data != null) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + if ((data.style & mask) != 0) { + data.layout = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.LAYOUT_RTL : 0; + } else { + data.style |= SWT.LEFT_TO_RIGHT; + } + data.device = device; + data.nativeZoom = 100; + if (device != null) { + data.font = device.getSystemFont(); + } + } + isGCCreated = true; + return handle; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + *

+ * IMPORTANT: This method is not part of the public + * API for PDFDocument. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + *

+ * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + if (data != null) isGCCreated = false; + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true 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. + *

+ */ + public void dispose() { + if (disposed) return; + disposed = true; + + if (handle != 0) { + if (pageStarted) { + OS.EndPage(handle); + } + if (jobStarted) { + OS.EndDoc(handle); + } + OS.DeleteDC(handle); + handle = 0; + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java new file mode 100644 index 00000000000..bf8d12077d7 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse Platform Contributors and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eclipse Platform Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.printing; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. + *

+ * Note: On Windows, SVG output is not natively supported by the operating system. + * This class is provided for API compatibility with other platforms. On Windows, + * using this class will result in an {@link SWTException} with error code + * {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ *

+ * For SVG support on Windows, consider using third-party libraries or converting + * from PDF output, which is natively supported via {@link PDFDocument}. + *

+ * + * @see GC + * @see PDFDocument + * @since 3.131 + */ +public class SVGDocument implements Drawable { + + /** + * SVG version constant for SVG 1.1 + */ + public static final int SVG_VERSION_1_1 = 0; + + /** + * SVG version constant for SVG 1.2 + */ + public static final int SVG_VERSION_1_2 = 1; + + /** + * Constructs a new SVGDocument with the specified filename and dimensions. + *

+ * Note: SVG output is not supported on Windows. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. + *

+ * Note: SVG output is not supported on Windows. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename and dimensions, + * associated with the given device. + *

+ * Note: SVG output is not supported on Windows. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, + * associated with the given device. + *

+ * Note: SVG output is not supported on Windows. This constructor + * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. + *

+ * + * @param device the device to associate with this SVGDocument + * @param filename the path to the SVG file to create + * @param widthInPoints the width of the image in points (1/72 inch) + * @param heightInPoints the height of the image in points (1/72 inch) + * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) + * + * @exception SWTException + * + * @see #dispose() + */ + public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + } + + /** + * Returns the width of the SVG document in points. + * + * @return the width in points (1/72 inch) + * + * @exception SWTException + */ + public double getWidth() { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Returns the height of the SVG document in points. + * + * @return the height in points (1/72 inch) + * + * @exception SWTException + */ + public double getHeight() { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Invokes platform specific functionality to allocate a new GC handle. + * + * @param data the platform specific GC data + * @return the platform specific GC handle + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public long internal_new_GC(GCData data) { + SWT.error(SWT.ERROR_NOT_IMPLEMENTED); + return 0; + } + + /** + * Invokes platform specific functionality to dispose a GC handle. + * + * @param hDC the platform specific GC handle + * @param data the platform specific GC data + * + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public void internal_dispose_GC(long hDC, GCData data) { + // Nothing to do + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Override + public boolean isAutoScalable() { + return false; + } + + /** + * Returns true if the SVGDocument has been disposed, + * and false otherwise. + *

+ * Note: Since SVG output is not supported on Windows, this always returns false + * as the object cannot be instantiated. + *

+ * + * @return true when the SVGDocument is disposed and false otherwise + */ + public boolean isDisposed() { + return false; + } + + /** + * Disposes of the operating system resources associated with + * the SVGDocument. + */ + public void dispose() { + // Nothing to dispose + } +} From 4d24b32adb400eedfddda426a80edc9d1803f49d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:39:13 +0000 Subject: [PATCH 10/11] Fix code review issues: remove duplicate lines, use specific exception, add null check Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- build_gtk.sh | 6 ------ .../win32/org/eclipse/swt/printing/PDFDocument.java | 12 +++++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/build_gtk.sh b/build_gtk.sh index fc005b0f46a..de7d762c6cd 100755 --- a/build_gtk.sh +++ b/build_gtk.sh @@ -1,9 +1,3 @@ cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt -cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' -cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean -cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt -cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' -cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean -cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt 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 f7d9c458701..0f3e2a1a0c9 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 @@ -128,7 +128,7 @@ public PDFDocument(Device device, String filename, double widthInPoints, double if (device == null) { try { this.device = org.eclipse.swt.widgets.Display.getDefault(); - } catch (Exception e) { + } catch (SWTException e) { this.device = null; } } else { @@ -146,11 +146,13 @@ public PDFDocument(Device device, String filename, double widthInPoints, double if (dwNeeded >= 0) { long hHeap = OS.GetProcessHeap(); long lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, dwNeeded); - int rc = OS.DocumentProperties(0, hPrinter[0], deviceName, lpInitData, 0, OS.DM_OUT_BUFFER); - if (rc == OS.IDOK) { - handle = OS.CreateDC(driver, deviceName, 0, lpInitData); + if (lpInitData != 0) { + int rc = OS.DocumentProperties(0, hPrinter[0], deviceName, lpInitData, 0, OS.DM_OUT_BUFFER); + if (rc == OS.IDOK) { + handle = OS.CreateDC(driver, deviceName, 0, lpInitData); + } + OS.HeapFree(hHeap, 0, lpInitData); } - OS.HeapFree(hHeap, 0, lpInitData); } OS.ClosePrinter(hPrinter[0]); } From f795454f4ba69e0d269e9a98540c68d4a702a168 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:57:09 +0000 Subject: [PATCH 11/11] Remove SVGDocument - only PDF is fully supported on all platforms Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- build_gtk.sh | 3 + .../Eclipse SWT PI/cairo/library/cairo.c | 42 --- .../cairo/library/cairo_custom.h | 2 - .../cairo/library/cairo_stats.h | 2 - .../org/eclipse/swt/internal/cairo/Cairo.java | 16 - .../org/eclipse/swt/printing/SVGDocument.java | 222 ----------- .../org/eclipse/swt/printing/SVGDocument.java | 347 ------------------ .../org/eclipse/swt/printing/SVGDocument.java | 222 ----------- .../eclipse/swt/tests/gtk/AllGTKTests.java | 3 +- .../swt/tests/gtk/Test_SVGDocument.java | 212 ----------- 10 files changed, 4 insertions(+), 1067 deletions(-) delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java delete mode 100644 tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java diff --git a/build_gtk.sh b/build_gtk.sh index de7d762c6cd..ea1dfb7db60 100755 --- a/build_gtk.sh +++ b/build_gtk.sh @@ -1,3 +1,6 @@ cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt/bundles/org.eclipse.swt && java -Dws=gtk -Darch=x86_64 build-scripts/CollectSources.java -nativeSources '/home/runner/build/gtk' +cd /home/runner/build/gtk && SWT_JAVA_HOME=/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.9-10/x64 MODEL=x86_64 OUTPUT_DIR=/home/runner/build/tmp ./build.sh install clean +cd /home/runner/work/eclipse.platform.swt/eclipse.platform.swt diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c index d6565946282..accf0da79be 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo.c @@ -1495,45 +1495,3 @@ JNIEXPORT jlong JNICALL Cairo_NATIVE(cairo_1pdf_1surface_1create) } #endif -#ifndef NO_cairo_1svg_1surface_1create -JNIEXPORT jlong JNICALL Cairo_NATIVE(cairo_1svg_1surface_1create) - (JNIEnv *env, jclass that, jbyteArray arg0, jdouble arg1, jdouble arg2) -{ - jbyte *lparg0=NULL; - jlong rc = 0; - Cairo_NATIVE_ENTER(env, that, cairo_1svg_1surface_1create_FUNC); - if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; -/* - rc = (jlong)cairo_svg_surface_create((const char *)lparg0, arg1, arg2); -*/ - { - Cairo_LOAD_FUNCTION(fp, cairo_svg_surface_create) - if (fp) { - rc = (jlong)((cairo_surface_t * (CALLING_CONVENTION*)(const char *, jdouble, jdouble))fp)((const char *)lparg0, arg1, arg2); - } - } -fail: - if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0); - Cairo_NATIVE_EXIT(env, that, cairo_1svg_1surface_1create_FUNC); - return rc; -} -#endif - -#ifndef NO_cairo_1svg_1surface_1restrict_1to_1version -JNIEXPORT void JNICALL Cairo_NATIVE(cairo_1svg_1surface_1restrict_1to_1version) - (JNIEnv *env, jclass that, jlong arg0, jint arg1) -{ - Cairo_NATIVE_ENTER(env, that, cairo_1svg_1surface_1restrict_1to_1version_FUNC); -/* - cairo_svg_surface_restrict_to_version((cairo_surface_t *)arg0, arg1); -*/ - { - Cairo_LOAD_FUNCTION(fp, cairo_svg_surface_restrict_to_version) - if (fp) { - ((void (CALLING_CONVENTION*)(cairo_surface_t *, jint))fp)((cairo_surface_t *)arg0, arg1); - } - } - Cairo_NATIVE_EXIT(env, that, cairo_1svg_1surface_1restrict_1to_1version_FUNC); -} -#endif - diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h index 809a2dd002d..99408ca3154 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_custom.h @@ -31,8 +31,6 @@ #define cairo_surface_set_device_scale_LIB LIB_CAIRO #define cairo_surface_get_device_scale_LIB LIB_CAIRO #define cairo_pdf_surface_create_LIB LIB_CAIRO -#define cairo_svg_surface_create_LIB LIB_CAIRO -#define cairo_svg_surface_restrict_to_version_LIB LIB_CAIRO #ifdef CAIRO_HAS_XLIB_SURFACE #define cairo_xlib_surface_get_height_LIB LIB_CAIRO diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h index 9c03f1597f0..86f31348171 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/library/cairo_stats.h @@ -150,6 +150,4 @@ typedef enum { memmove__Lorg_eclipse_swt_internal_cairo_cairo_1path_1t_2JJ_FUNC, memmove__Lorg_eclipse_swt_internal_cairo_cairo_1rectangle_1int_1t_2JJ_FUNC, memmove___3DJJ_FUNC, - cairo_1svg_1surface_1create_FUNC, - cairo_1svg_1surface_1restrict_1to_1version_FUNC, } Cairo_FUNCS; diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java index b888ed2650d..bacc4d50b1d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/Cairo.java @@ -427,20 +427,4 @@ public class Cairo extends Platform { */ public static final native long cairo_pdf_surface_create(byte[] filename, double width_in_points, double height_in_points); -/** - * @method flags=dynamic - * @param filename cast=(const char *) - */ -public static final native long cairo_svg_surface_create(byte[] filename, double width_in_points, double height_in_points); - -/** - * @method flags=dynamic - * @param surface cast=(cairo_surface_t *) - */ -public static final native void cairo_svg_surface_restrict_to_version(long surface, int version); - -/** SVG version constants */ -public static final int CAIRO_SVG_VERSION_1_1 = 0; -public static final int CAIRO_SVG_VERSION_1_2 = 1; - } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java deleted file mode 100644 index aa6c62fa7cc..00000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/cocoa/org/eclipse/swt/printing/SVGDocument.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Eclipse Platform Contributors and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Eclipse Platform Contributors - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.printing; - -import org.eclipse.swt.*; -import org.eclipse.swt.graphics.*; - -/** - * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. - *

- * Note: On macOS, SVG output is not natively supported by the operating system. - * This class is provided for API compatibility with other platforms. On macOS, - * using this class will result in an {@link SWTException} with error code - * {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- *

- * For SVG support on macOS, consider using third-party libraries or converting - * from PDF output, which is natively supported via {@link PDFDocument}. - *

- * - * @see GC - * @see PDFDocument - * @since 3.131 - */ -public class SVGDocument implements Drawable { - - /** - * SVG version constant for SVG 1.1 - */ - public static final int SVG_VERSION_1_1 = 0; - - /** - * SVG version constant for SVG 1.2 - */ - public static final int SVG_VERSION_1_2 = 1; - - /** - * Constructs a new SVGDocument with the specified filename and dimensions. - *

- * Note: SVG output is not supported on macOS. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. - *

- * Note: SVG output is not supported on macOS. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename and dimensions, - * associated with the given device. - *

- * Note: SVG output is not supported on macOS. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, - * associated with the given device. - *

- * Note: SVG output is not supported on macOS. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Returns the width of the SVG document in points. - * - * @return the width in points (1/72 inch) - * - * @exception SWTException - */ - public double getWidth() { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Returns the height of the SVG document in points. - * - * @return the height in points (1/72 inch) - * - * @exception SWTException - */ - public double getHeight() { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Invokes platform specific functionality to allocate a new GC handle. - * - * @param data the platform specific GC data - * @return the platform specific GC handle - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public long internal_new_GC(GCData data) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Invokes platform specific functionality to dispose a GC handle. - * - * @param hDC the platform specific GC handle - * @param data the platform specific GC data - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public void internal_dispose_GC(long hDC, GCData data) { - // Nothing to do - } - - /** - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public boolean isAutoScalable() { - return false; - } - - /** - * Returns true if the SVGDocument has been disposed, - * and false otherwise. - *

- * Note: Since SVG output is not supported on macOS, this always returns false - * as the object cannot be instantiated. - *

- * - * @return true when the SVGDocument is disposed and false otherwise - */ - public boolean isDisposed() { - return false; - } - - /** - * Disposes of the operating system resources associated with - * the SVGDocument. - */ - public void dispose() { - // Nothing to dispose - } -} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java deleted file mode 100644 index 411455dd3e6..00000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/gtk/org/eclipse/swt/printing/SVGDocument.java +++ /dev/null @@ -1,347 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Eclipse Platform Contributors and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Eclipse Platform Contributors - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.printing; - -import org.eclipse.swt.*; -import org.eclipse.swt.graphics.*; -import org.eclipse.swt.internal.*; -import org.eclipse.swt.internal.cairo.*; - -/** - * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. - * Applications create a GC on an SVGDocument using new GC(svgDocument) - * and then draw on the GC using the usual graphics calls. - *

- * An SVGDocument object may be constructed by providing - * a filename and the image dimensions. After drawing is complete, - * the document must be disposed to finalize the SVG file. - *

- * Application code must explicitly invoke the SVGDocument.dispose() - * method to release the operating system resources managed by each instance - * when those instances are no longer required. - *

- *

- * The following example demonstrates how to use SVGDocument: - *

- *
- *    SVGDocument svg = new SVGDocument("output.svg", 400, 300);
- *    GC gc = new GC(svg);
- *    gc.drawRectangle(10, 10, 100, 80);
- *    gc.drawText("Hello, SVG!", 50, 50);
- *    gc.dispose();
- *    svg.dispose();
- * 
- * - * @see GC - * @since 3.131 - */ -public class SVGDocument implements Drawable { - Device device; - long surface; - long cairo; - boolean isGCCreated = false; - boolean disposed = false; - - /** - * Width of the image in points (1/72 inch) - */ - double widthInPoints; - - /** - * Height of the image in points (1/72 inch) - */ - double heightInPoints; - - /** - * SVG version constant for SVG 1.1 - */ - public static final int SVG_VERSION_1_1 = Cairo.CAIRO_SVG_VERSION_1_1; - - /** - * SVG version constant for SVG 1.2 - */ - public static final int SVG_VERSION_1_2 = Cairo.CAIRO_SVG_VERSION_1_2; - - /** - * Constructs a new SVGDocument with the specified filename and dimensions. - *

- * You must dispose the SVGDocument when it is no longer required. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception IllegalArgumentException - * @exception SWTError - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints) { - this(null, filename, widthInPoints, heightInPoints, SVG_VERSION_1_1); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. - *

- * You must dispose the SVGDocument when it is no longer required. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception IllegalArgumentException - * @exception SWTError - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { - this(null, filename, widthInPoints, heightInPoints, svgVersion); - } - - /** - * Constructs a new SVGDocument with the specified filename and dimensions, - * associated with the given device. - *

- * You must dispose the SVGDocument when it is no longer required. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception IllegalArgumentException - * @exception SWTError - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { - this(device, filename, widthInPoints, heightInPoints, SVG_VERSION_1_1); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, - * associated with the given device. - *

- * You must dispose the SVGDocument when it is no longer required. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception IllegalArgumentException - * @exception SWTError - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (widthInPoints <= 0 || heightInPoints <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - if (svgVersion != SVG_VERSION_1_1 && svgVersion != SVG_VERSION_1_2) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - - this.device = device; - this.widthInPoints = widthInPoints; - this.heightInPoints = heightInPoints; - - byte[] filenameBytes = Converter.wcsToMbcs(filename, true); - surface = Cairo.cairo_svg_surface_create(filenameBytes, widthInPoints, heightInPoints); - if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES); - - Cairo.cairo_svg_surface_restrict_to_version(surface, svgVersion); - - 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 if not provided - if (this.device == null) { - try { - this.device = org.eclipse.swt.widgets.Display.getDefault(); - } catch (Exception e) { - this.device = null; - } - } - } - - /** - * Returns the width of the SVG document in points. - * - * @return the width in points (1/72 inch) - * - * @exception SWTException - */ - public double getWidth() { - if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); - return widthInPoints; - } - - /** - * Returns the height of the SVG document in points. - * - * @return the height in points (1/72 inch) - * - * @exception SWTException - */ - public double getHeight() { - if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); - return heightInPoints; - } - - /** - * Invokes platform specific functionality to allocate a new GC handle. - *

- * IMPORTANT: This method is not part of the public - * API for SVGDocument. It is marked public only so that it - * can be shared within the packages provided by SWT. It is not - * available on all platforms, and should never be called from - * application code. - *

- * - * @param data the platform specific GC data - * @return the platform specific GC handle - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public long internal_new_GC(GCData data) { - if (disposed) SWT.error(SWT.ERROR_WIDGET_DISPOSED); - if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - - if (data != null) { - int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; - if ((data.style & mask) == 0) { - data.style |= SWT.LEFT_TO_RIGHT; - } - data.device = device; - 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; - } - } - isGCCreated = true; - return cairo; - } - - /** - * Invokes platform specific functionality to dispose a GC handle. - *

- * IMPORTANT: This method is not part of the public - * API for SVGDocument. It is marked public only so that it - * can be shared within the packages provided by SWT. It is not - * available on all platforms, and should never be called from - * application code. - *

- * - * @param hDC the platform specific GC handle - * @param data the platform specific GC data - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public void internal_dispose_GC(long hDC, GCData data) { - if (data != null) isGCCreated = false; - } - - /** - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public boolean isAutoScalable() { - return false; - } - - /** - * Returns true if the SVGDocument has been disposed, - * and false otherwise. - * - * @return true when the SVGDocument is disposed and false otherwise - */ - public boolean isDisposed() { - return disposed; - } - - /** - * Disposes of the operating system resources associated with - * the SVGDocument. Applications must dispose of all SVGDocuments - * that they allocate. - *

- * This method finalizes the SVG file and writes it to disk. - *

- */ - public void dispose() { - if (disposed) return; - disposed = true; - - if (cairo != 0) { - Cairo.cairo_destroy(cairo); - cairo = 0; - } - if (surface != 0) { - Cairo.cairo_surface_finish(surface); - Cairo.cairo_surface_destroy(surface); - surface = 0; - } - } -} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java b/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java deleted file mode 100644 index bf8d12077d7..00000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT Printing/win32/org/eclipse/swt/printing/SVGDocument.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Eclipse Platform Contributors and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Eclipse Platform Contributors - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.printing; - -import org.eclipse.swt.*; -import org.eclipse.swt.graphics.*; - -/** - * Instances of this class are used to create SVG (Scalable Vector Graphics) documents. - *

- * Note: On Windows, SVG output is not natively supported by the operating system. - * This class is provided for API compatibility with other platforms. On Windows, - * using this class will result in an {@link SWTException} with error code - * {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- *

- * For SVG support on Windows, consider using third-party libraries or converting - * from PDF output, which is natively supported via {@link PDFDocument}. - *

- * - * @see GC - * @see PDFDocument - * @since 3.131 - */ -public class SVGDocument implements Drawable { - - /** - * SVG version constant for SVG 1.1 - */ - public static final int SVG_VERSION_1_1 = 0; - - /** - * SVG version constant for SVG 1.2 - */ - public static final int SVG_VERSION_1_2 = 1; - - /** - * Constructs a new SVGDocument with the specified filename and dimensions. - *

- * Note: SVG output is not supported on Windows. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version. - *

- * Note: SVG output is not supported on Windows. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(String filename, double widthInPoints, double heightInPoints, int svgVersion) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename and dimensions, - * associated with the given device. - *

- * Note: SVG output is not supported on Windows. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Constructs a new SVGDocument with the specified filename, dimensions, and SVG version, - * associated with the given device. - *

- * Note: SVG output is not supported on Windows. This constructor - * will throw an {@link SWTException} with error code {@link SWT#ERROR_NOT_IMPLEMENTED}. - *

- * - * @param device the device to associate with this SVGDocument - * @param filename the path to the SVG file to create - * @param widthInPoints the width of the image in points (1/72 inch) - * @param heightInPoints the height of the image in points (1/72 inch) - * @param svgVersion the SVG version to use (SVG_VERSION_1_1 or SVG_VERSION_1_2) - * - * @exception SWTException - * - * @see #dispose() - */ - public SVGDocument(Device device, String filename, double widthInPoints, double heightInPoints, int svgVersion) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - } - - /** - * Returns the width of the SVG document in points. - * - * @return the width in points (1/72 inch) - * - * @exception SWTException - */ - public double getWidth() { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Returns the height of the SVG document in points. - * - * @return the height in points (1/72 inch) - * - * @exception SWTException - */ - public double getHeight() { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Invokes platform specific functionality to allocate a new GC handle. - * - * @param data the platform specific GC data - * @return the platform specific GC handle - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public long internal_new_GC(GCData data) { - SWT.error(SWT.ERROR_NOT_IMPLEMENTED); - return 0; - } - - /** - * Invokes platform specific functionality to dispose a GC handle. - * - * @param hDC the platform specific GC handle - * @param data the platform specific GC data - * - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public void internal_dispose_GC(long hDC, GCData data) { - // Nothing to do - } - - /** - * @noreference This method is not intended to be referenced by clients. - */ - @Override - public boolean isAutoScalable() { - return false; - } - - /** - * Returns true if the SVGDocument has been disposed, - * and false otherwise. - *

- * Note: Since SVG output is not supported on Windows, this always returns false - * as the object cannot be instantiated. - *

- * - * @return true when the SVGDocument is disposed and false otherwise - */ - public boolean isDisposed() { - return false; - } - - /** - * Disposes of the operating system resources associated with - * the SVGDocument. - */ - public void dispose() { - // Nothing to dispose - } -} diff --git a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java index d46e8b850cb..1b1e3115362 100644 --- a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java +++ b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/AllGTKTests.java @@ -20,8 +20,7 @@ @Suite @SelectClasses({ Test_GtkConverter.class, - Test_PDFDocument.class, - Test_SVGDocument.class + Test_PDFDocument.class }) public class AllGTKTests { diff --git a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java b/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java deleted file mode 100644 index 8f439ea02da..00000000000 --- a/tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk/Test_SVGDocument.java +++ /dev/null @@ -1,212 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Eclipse Platform Contributors and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Eclipse Platform Contributors - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.tests.gtk; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.File; - -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.printing.SVGDocument; -import org.eclipse.swt.widgets.Display; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * Automated Test Suite for class org.eclipse.swt.printing.SVGDocument - * - * @see org.eclipse.swt.printing.SVGDocument - */ -public class Test_SVGDocument { - - private static Display display; - - @TempDir - File tempDir; - - private SVGDocument svgDocument; - - @BeforeAll - public static void setUpBeforeClass() { - display = Display.getDefault(); - } - - @AfterAll - public static void tearDownAfterClass() { - if (display != null && !display.isDisposed()) { - display.dispose(); - } - } - - @AfterEach - public void tearDown() { - if (svgDocument != null && !svgDocument.isDisposed()) { - svgDocument.dispose(); - } - } - - @Test - public void test_Constructor_NullFilename() { - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(null, 400, 300)); - } - - @Test - public void test_Constructor_InvalidDimensions() { - String filename = new File(tempDir, "test.svg").getAbsolutePath(); - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 0, 300)); - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, 0)); - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, -1, 300)); - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, -1)); - } - - @Test - public void test_Constructor_ValidParameters() { - String filename = new File(tempDir, "test_valid.svg").getAbsolutePath(); - svgDocument = new SVGDocument(filename, 400, 300); - assertNotNull(svgDocument); - assertFalse(svgDocument.isDisposed()); - } - - @Test - public void test_Constructor_WithVersion() { - String filename = new File(tempDir, "test_version.svg").getAbsolutePath(); - svgDocument = new SVGDocument(filename, 400, 300, SVGDocument.SVG_VERSION_1_1); - assertNotNull(svgDocument); - assertFalse(svgDocument.isDisposed()); - } - - @Test - public void test_Constructor_InvalidVersion() { - String filename = new File(tempDir, "test_invalid_version.svg").getAbsolutePath(); - assertThrows(IllegalArgumentException.class, () -> new SVGDocument(filename, 400, 300, 999)); - } - - @Test - public void test_ConstructorWithDevice() { - String filename = new File(tempDir, "test_device.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - assertNotNull(svgDocument); - assertFalse(svgDocument.isDisposed()); - } - - @Test - public void test_ConstructorWithDeviceAndVersion() { - String filename = new File(tempDir, "test_device_version.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300, SVGDocument.SVG_VERSION_1_2); - assertNotNull(svgDocument); - assertFalse(svgDocument.isDisposed()); - } - - @Test - public void test_getWidth() { - String filename = new File(tempDir, "test_width.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - assertEquals(400.0, svgDocument.getWidth(), 0.001); - } - - @Test - public void test_getHeight() { - String filename = new File(tempDir, "test_height.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - assertEquals(300.0, svgDocument.getHeight(), 0.001); - } - - @Test - public void test_isAutoScalable() { - String filename = new File(tempDir, "test_autoscale.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - assertFalse(svgDocument.isAutoScalable()); - } - - @Test - public void test_dispose() { - String filename = new File(tempDir, "test_dispose.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - assertFalse(svgDocument.isDisposed()); - svgDocument.dispose(); - assertTrue(svgDocument.isDisposed()); - } - - @Test - public void test_createGC() { - String filename = new File(tempDir, "test_gc.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - GC gc = new GC(svgDocument); - assertNotNull(gc); - gc.dispose(); - } - - @Test - public void test_drawOnGC() { - String filename = new File(tempDir, "test_draw.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - GC gc = new GC(svgDocument); - - // Test drawing operations - should not throw exceptions - gc.drawRectangle(10, 10, 100, 80); - gc.drawText("Hello, SVG!", 50, 50); - gc.drawLine(0, 0, 100, 100); - gc.drawOval(150, 150, 50, 50); - - gc.dispose(); - svgDocument.dispose(); - - // Verify file was created - File file = new File(filename); - assertTrue(file.exists(), "SVG file should have been created"); - assertTrue(file.length() > 0, "SVG file should not be empty"); - } - - @Test - public void test_drawPolygon() { - String filename = new File(tempDir, "test_polygon.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - GC gc = new GC(svgDocument); - - int[] points = {50, 50, 150, 50, 100, 150}; - gc.drawPolygon(points); - gc.fillPolygon(points); - - gc.dispose(); - svgDocument.dispose(); - - // Verify file was created - File file = new File(filename); - assertTrue(file.exists(), "SVG file should have been created"); - } - - @Test - public void test_operationsAfterDispose() { - String filename = new File(tempDir, "test_disposed.svg").getAbsolutePath(); - svgDocument = new SVGDocument(display, filename, 400, 300); - svgDocument.dispose(); - - assertThrows(Exception.class, () -> svgDocument.getWidth()); - assertThrows(Exception.class, () -> svgDocument.getHeight()); - } - - @Test - public void test_svgVersionConstants() { - // Verify SVG version constants are defined correctly - assertEquals(0, SVGDocument.SVG_VERSION_1_1); - assertEquals(1, SVGDocument.SVG_VERSION_1_2); - } -}