Re: Commit: patch 9.2.0898: printing support is lacking
Hisashi T Fujinaka <[email protected]> Sun, 2 Aug 2026 17:35:51 -0700 (PDT)
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <[email protected]> |
I'm seeing:
gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -I/opt/sw/include/gtk-2.=
0 -I/opt/sw/lib/gtk-2.0/include -I/opt/sw/include/pango-1.0 -I/opt/sw/inclu=
de/atk-1.0 -I/opt/sw/include/cairo -I/opt/sw/include/glib-2.0 -I/opt/sw/lib=
/glib-2.0/include -I/opt/sw/include -I/opt/sw/include/freetype2 -I/opt/X11/=
include -MD -I/opt/sw/include -DMACOS_X -g -O2 -D_REENTRANT -U_FORTIFY_SOU=
RCE -D_FORTIFY_SOURCE=3D1 -I/usr/X11/include -I/opt/sw/include/cair=
o -I/opt/sw/include -I/opt/sw/include/freetype2 -I/opt/X11/include -I/opt/=
sw/include/pango-1.0 -I/opt/sw/include/glib-2.0 -I/opt/sw/lib/glib-2.0/incl=
ude -I/opt/sw/include/cairo -I/opt/sw/include -I/opt/sw/include/freetype2 -=
I/opt/X11/include -o objects/hardcopy_pango.o hardcopy_pango.c
hardcopy_pango.c:383:7: error: call to undeclared function 'pango_font_metr=
ics_get_height'; ISO C99 and later do not support implicit function declara=
tions [-Wimplicit-function-declaration]
383 | (pango_font_metrics_get_height(metrics) - (ascent + de=
scent))
| ^
Do I need a newer pango?
On Sun, 2 Aug 2026, Christian Brabandt wrote:
> patch 9.2.0898: printing support is lacking
>
> Commit: https://github.com/vim/vim/commit/f141c19dca84331202ea06f3035c04f=
fc63066d0
> Author: Foxe Chen <[email protected]>
> Date: Sun Aug 2 18:27:01 2026 +0000
>
> patch 9.2.0898: printing support is lacking
>
> Problem: printing support is lacking
> Solution: Improve printing support by making use of pango and cairo
> libraries, use a graphical dialog for :hardcopy in the GTK4 =
ui
> (Foxe Chen).
>
> fixes: #8935
> closes: #20648
>
> Signed-off-by: Foxe Chen <[email protected]>
> Signed-off-by: Christian Brabandt <[email protected]>
>
> diff --git a/Filelist b/Filelist
> index 07853f4c6..7a2f1219b 100644
> --- a/Filelist
> +++ b/Filelist
> @@ -93,6 +93,11 @@ SRC_ALL =3D \
> src/gui.h \
> src/gui_beval.c \
> src/hardcopy.c \
> + src/hardcopy.h \
> + src/hardcopy_pango.c \
> + src/hardcopy_pango.h \
> + src/hardcopy_postscript.c \
> + src/hardcopy_postscript.h \
> src/hashtab.c \
> src/help.c \
> src/highlight.c \
> diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
> index 647e2a622..a9d8f06f5 100644
> --- a/runtime/doc/options.txt
> +++ b/runtime/doc/options.txt
> @@ -1,4 +1,4 @@
> -*options.txt* For Vim version 9.2. Last change: 2026 Jul 29
> +*options.txt* For Vim version 9.2. Last change: 2026 Aug 02
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> @@ -6900,7 +6900,7 @@ A jump table for the options with a short descripti=
on can be found at |Q_op|.
> 'printexpr' 'pexpr' string (default: see below)
> global
> {only available when compiled with the |+printer|
> - and |+postscript| features}
> + and |+postscript| or |+pango| features}
> Expression used to print the PostScript produced with |:hardcopy|.
> See |pexpr-option|.
> This option cannot be set from a |modeline| or in the |sandbox|, for
> diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt
> index 2e8466482..392ad2687 100644
> --- a/runtime/doc/print.txt
> +++ b/runtime/doc/print.txt
> @@ -1,4 +1,4 @@
> -*print.txt* For Vim version 9.2. Last change: 2026 Feb 14
> +*print.txt* For Vim version 9.2. Last change: 2026 Aug 02
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> @@ -13,7 +13,8 @@ Printing *printing*
> 5. PostScript CJK Printing |postscript-cjk-printing|
> 6. PostScript Printing Troubleshooting |postscript-print-trouble|
> 7. PostScript Utilities |postscript-print-util|
> -8. Formfeed Characters |printing-formfeed|
> +8. Pango Printing |pango-printing|
> +9. Formfeed Characters |printing-formfeed|
>
> {only available when compiled with the |+printer| feature}
>
> @@ -33,20 +34,23 @@ Note: If you have problems printing with |:hardcopy|,=
an alternative is to use
> Send [range] lines (default whole file) to the
> printer.
>
> - On MS-Windows a dialog is displayed to allow selection
> - of printer, paper size etc. To skip the dialog, use
> - the [!]. In this case the printer defined by
> - 'printdevice' is used, or, if 'printdevice' is empty,
> - the system default printer.
> + On MS-Windows or GTK4 GUI, a dialog is displayed to
> + allow selection of printer, paper size etc. To skip
> + the dialog, use the [!]. In this case the printer
> + defined by 'printdevice' is used, or, if 'printdevice'
> + is empty, the system default printer. Note that the
> + GTK4 GUI print dialog requires at least GTK 4.14.
>
> - For systems other than MS-Windows, PostScript is
> - written in a temp file and 'printexpr' is used to
> + For systems other than MS-Windows or Pango, PostScript
> + is written in a temp file and 'printexpr' is used to
> actually print it. Then [arguments] can be used by
> 'printexpr' through |v:cmdarg|. Otherwise [arguments]
> is ignored. 'printoptions' can be used to specify
> paper size, duplex, etc.
> Note: If you want PDF, there are tools such as
> - "ps2pdf" that can convert the PostScript to PDF.
> + "ps2pdf" that can convert the PostScript to PDF. If
> + the |+pango| feature is enabled, then emit PDF by
> + setting "format" to "pdf" in 'printoptions'.
>
> :[range]ha[rdcopy][!] >{filename}
> As above, but write the resulting PostScript in file
> @@ -54,7 +58,7 @@ Note: If you have problems printing with |:hardcopy|, a=
n alternative is to use
> Things like "%" are expanded |cmdline-special|
> Careful: An existing file is silently overwritten.
> {only available when compiled with the |+postscript|
> - feature}
> + or |+pango| feature}
> On MS-Windows use the "print to file" feature of the
> printer driver.
>
> @@ -129,7 +133,7 @@ MS-Windows platform.
> *pexpr-option*
> 'printexpr' 'pexpr' String (default: see below)
> global
> -Expression that is evaluated to print the PostScript produced with
> +Expression that is evaluated to print the PostScript or PDF produced wit=
h
> |:hardcopy|.
> The file name to be printed is in |v:fname_in|.
> The arguments to the ":hardcopy" command are in |v:cmdarg|.
> @@ -195,7 +199,8 @@ output. It has the same format as the 'guifont' opti=
on, except that only one
> font may be named, and the special "guifont=3D*" syntax is not available.
>
> In the Win32 GUI version this specifies a font name with its extra attrib=
utes,
> -as with the 'guifont' option.
> +as with the 'guifont' option. When |+pango| is enabled, the format is t=
he
> +same as 'guifont' for the GTK GUI (e.g. "Courier New 10").
>
> For other systems, only ":h11" is recognized, where "11" is the point siz=
e of
> the font. When omitted, the point size is 10.
> @@ -397,6 +402,13 @@ of |:hardcopy|:
> formfeed:y When a form feed character is encountered, continue
> printing of the current line at the beginning of the
> first line on a new page.
> + format:postscript (default)
> + Output format: Postscript
> + format:{name} Output format from this table (only used when compiled
> + with |+pango| feature):
> + {name} meaning ~
> + postscript Generate Postscript
> + pdf Generate Adobe PDF
>
> The item indicated with (default) is used when the item is not present. =
The
> values are not always used, especially when using a dialog to select the
> @@ -436,6 +448,9 @@ There are currently a number of limitations with Post=
Script printing:
> unknown characters. Printing will fail if Vim cannot convert the multi=
byte
> to the 8-bit encoding.
>
> +When using the Pango backend for printing, these limitations are solved.=
See
> +|pango-printing| for more information.
> +
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D
> 4. Custom 8-bit Print Character Encodings *postscript-print-encoding*
> *E618* *E619*
> @@ -717,9 +732,26 @@ There are a couple of points to bear in mind:
> desktop ink jets than for small office laser printers where the paper =
path
> is hidden from view.
>
> +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D
> +8. Pango Printing *pango-printing*
> +
> +If Vim is compiled with |+pango|, then it will render pages using Pango =
(a
> +text handling library), and Cairo (a graphics library). The benefit of =
this
> +is that Unicode is fully supported. Postscript files will still be gene=
rated
> +using Cairo. Additionally, PDF files can be emitted as well, see the
> +"format" key in |popt-option|
> +
> +When using the GTK GUI, |+pango| is always enabled and used. On termina=
l
> +builds of Vim, "--enable-hardcopy-pango" must be passed to the configure
> +options. The linked Cairo library must have the Postscript and PDF backe=
nds
> +enabled.
> +
> + *gtk4-print*
> +When using the GTK4 GUI, |:hardcopy| will use a native graphical print d=
ialog,
> +similar to MS-Windows. See |:hardcopy| for more information.
>
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D
> -8. Formfeed Characters *printing-formfeed*
> +9. Formfeed Characters *printing-formfeed*
>
> By default Vim does not do any special processing of formfeed control
> characters. Setting the 'printoptions' formfeed item will make Vim recog=
nize
> diff --git a/runtime/doc/tags b/runtime/doc/tags
> index 9f59289a8..e83116386 100644
> --- a/runtime/doc/tags
> +++ b/runtime/doc/tags
> @@ -1514,6 +1514,7 @@ $quote eval.txt /*$quote*
> +num64 various.txt /*+num64*
> +ole various.txt /*+ole*
> +packages various.txt /*+packages*
> ++pango various.txt /*+pango*
> +path_extra various.txt /*+path_extra*
> +perl various.txt /*+perl*
> +perl/dyn various.txt /*+perl\/dyn*
> @@ -8262,6 +8263,7 @@ gtk-css gui_x11.txt /*gtk-css*
> gtk-tooltip-colors gui_x11.txt /*gtk-tooltip-colors*
> gtk3-slow gui_x11.txt /*gtk3-slow*
> gtk4-menu-navigation gui_x11.txt /*gtk4-menu-navigation*
> +gtk4-print print.txt /*gtk4-print*
> gtk4-slow gui_x11.txt /*gtk4-slow*
> gu change.txt /*gu*
> gugu change.txt /*gugu*
> @@ -9717,6 +9719,7 @@ page-up intro.txt /*page-up*
> page_down intro.txt /*page_down*
> page_up intro.txt /*page_up*
> pager message.txt /*pager*
> +pango-printing print.txt /*pango-printing*
> papp.vim syntax.txt /*papp.vim*
> paragraph motion.txt /*paragraph*
> partial builtin.txt /*partial*
> diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
> index 0a5ff259c..f0e9acaae 100644
> --- a/runtime/doc/various.txt
> +++ b/runtime/doc/various.txt
> @@ -1,4 +1,4 @@
> -*various.txt* For Vim version 9.2. Last change: 2026 Jul 29
> +*various.txt* For Vim version 9.2. Last change: 2026 Aug 02
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> @@ -482,6 +482,7 @@ m *+perl/dyn* Perl interface |perl-dynamic| |/dyn|
> N *+persistent_undo* Persistent undo |undo-persistence|
> N *+popupwin* Popup windows |popup-window|
> *+postscript* |:hardcopy| writes a PostScript file
> + *+pango* |:hardcopy| uses Pango and Cairo to render pages
> N *+printer* |:hardcopy| command
> H *+profile* |:profile| command
> m *+python* Python 2 interface |python|
> diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
> index 738e95bdb..4db123621 100644
> --- a/runtime/doc/version9.txt
> +++ b/runtime/doc/version9.txt
> @@ -1,4 +1,4 @@
> -*version9.txt* For Vim version 9.2. Last change: 2026 Jul 27
> +*version9.txt* For Vim version 9.2. Last change: 2026 Aug 02
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> @@ -52590,6 +52590,8 @@ GUI ~
> - Added support for the GTK 4 GUI (via patch 9.2.0501). Enable with
> `--enable-gui=3Dgtk4` configure switch at build time.
> - Add support for fullscreen mode in the GTK UI |'go-s'|.
> +- Enable native printing diaglog for the GTK4 UI using pango library, se=
e
> + |pango-printing|.
>
> Popups ~
> ------
> diff --git a/src/Makefile b/src/Makefile
> index a3878d0c8..a8a046da7 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -1417,6 +1417,8 @@ ALL_LIBS =3D \
> $(X_PRE_LIBS) \
> $(X_LIBS) \
> $(WAYLAND_LIBS) \
> + $(CAIRO_LIBS) \
> + $(PANGO_LIBS) \
> $(X_EXTRA_LIBS) \
> $(MZSCHEME_LIBS) \
> $(LIBS) \
> @@ -1543,6 +1545,8 @@ BASIC_SRC =3D \
> gc.c \
> gui_xim.c \
> hardcopy.c \
> + hardcopy_pango.c \
> + hardcopy_postscript.c \
> hashtab.c \
> help.c \
> highlight.c \
> @@ -1729,6 +1733,8 @@ OBJ_COMMON =3D \
> objects/gc.o \
> objects/gui_xim.o \
> objects/hardcopy.o \
> + objects/hardcopy_pango.o \
> + objects/hardcopy_postscript.o \
> objects/hashtab.o \
> objects/help.o \
> objects/highlight.o \
> @@ -3381,6 +3387,12 @@ objects/gc.o: gc.c
> objects/hardcopy.o: hardcopy.c
> $(CCC) -o $@ hardcopy.c
>
> +objects/hardcopy_pango.o: hardcopy_pango.c
> + $(CCC) $(CAIRO_CFLAGS) $(CAIRO_CPPFLAGS) $(PANGO_CFLAGS) $(PANGO_CPPFLA=
GS) -o $@ hardcopy_pango.c
> +
> +objects/hardcopy_postscript.o: hardcopy_postscript.c
> + $(CCC) -o $@ hardcopy_postscript.c
> +
> objects/hashtab.o: hashtab.c
> $(CCC) -o $@ hashtab.c
>
> @@ -4097,7 +4109,17 @@ objects/hardcopy.o: auto/osdef.h hardcopy.c vim.h =
protodef.h auto/config.h featu
> ascii.h keymap.h termdefs.h macros.h option.h beval.h \
> structs.h regexp.h gui.h libvterm/include/vterm.h \
> libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
> - globals.h errors.h version.h
> + globals.h errors.h version.h hardcopy.h hardcopy_pango.h hardcopy_posts=
cript.h
> +objects/hardcopy_pango.o: auto/osdef.h hardcopy_pango.c vim.h protodef.h=
auto/config.h feature.h os_unix.h \
> + ascii.h keymap.h termdefs.h macros.h option.h beval.h \
> + structs.h regexp.h gui.h libvterm/include/vterm.h \
> + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
> + globals.h errors.h hardcopy.h hardcopy_pango.h
> +objects/hardcopy_postscript.o: auto/osdef.h hardcopy_postscript.c vim.h =
protodef.h auto/config.h feature.h os_unix.h \
> + ascii.h keymap.h termdefs.h macros.h option.h beval.h \
> + structs.h regexp.h gui.h libvterm/include/vterm.h \
> + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
> + globals.h errors.h version.h hardcopy.h hardcopy_postscript.h
> objects/hashtab.o: auto/osdef.h hashtab.c vim.h protodef.h auto/config.h =
feature.h os_unix.h \
> ascii.h keymap.h termdefs.h macros.h option.h beval.h \
> structs.h regexp.h gui.h libvterm/include/vterm.h \
> diff --git a/src/auto/configure b/src/auto/configure
> index 8fd4ba3b7..a47cb58d2 100755
> --- a/src/auto/configure
> +++ b/src/auto/configure
> @@ -657,6 +657,12 @@ GUI_LIB_LOC
> GUI_INC_LOC
> NARROW_PROTO
> MOTIF_LIBNAME
> +CAIRO_CPPFLAGS
> +CAIRO_CFLAGS
> +CAIRO_LIBS
> +PANGO_CPPFLAGS
> +PANGO_CFLAGS
> +PANGO_LIBS
> GRESOURCE_OBJ
> GRESOURCE_SRC
> UPDATE_DESKTOP_DATABASE
> @@ -870,6 +876,7 @@ with_gnome_libs
> with_gnome
> enable_icon_cache_update
> enable_desktop_database_update
> +enable_hardcopy_pango
> with_motif_lib
> with_tlib
> enable_largefile
> @@ -1546,6 +1553,7 @@ Optional Features:
> --disable-gtktest Do not try to compile and run a test GTK progra=
m
> --disable-icon-cache-update update disabled
> --disable-desktop-database-update update disabled
> + --enable-hardcopy-pango Use Pango and Cairo for improved hardcopy =
printing. default=3Dyes when GTK GUI enabled
> --disable-largefile omit support for large files
> --disable-canberra Do not use libcanberra.
> --disable-libsodium Do not use libsodium.
> @@ -9241,6 +9249,43 @@ else
> printf "%s
> " "no" >&6; }
> fi
>
> +{ printf "%s
> " "$as_me:${as_lineno-$LINENO}: checking for cairo" >&5
> +printf %s "checking for cairo... " >&6; }
> +have_cairo=3D"no"
> +if "$PKG_CONFIG" --exists 'cairo-ps'; then
> + if "$PKG_CONFIG" --exists 'cairo-pdf'; then
> + have_cairo=3D"yes"
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +printf "%s
> " "yes" >&6; }
> +
> + CAIRO_CFLAGS=3D`$PKG_CONFIG --cflags-only-other cairo-ps cairo-pdf`
> + CAIRO_CPPFLAGS=3D`$PKG_CONFIG --cflags-only-I cairo-ps cairo-pdf`
> + CAIRO_LIBS=3D`$PKG_CONFIG --libs cairo-ps cairo-pdf`
> + else
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +printf "%s
> " "no" >&6; }
> + fi
> +else
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +printf "%s
> " "no" >&6; }
> +fi
> +
> +{ printf "%s
> " "$as_me:${as_lineno-$LINENO}: checking for pango" >&5
> +printf %s "checking for pango... " >&6; }
> +have_pango=3D"no"
> +if "$PKG_CONFIG" --exists 'pango' && "$PKG_CONFIG" --exists 'pangocairo'=
; then
> + have_pango=3D"yes"
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +printf "%s
> " "yes" >&6; }
> +
> + PANGO_CFLAGS=3D`$PKG_CONFIG --cflags-only-other pango pangocairo`
> + PANGO_CPPFLAGS=3D`$PKG_CONFIG --cflags-only-I pango pangocairo`
> + PANGO_LIBS=3D`$PKG_CONFIG --libs pango pangocairo`
> +else
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +printf "%s
> " "no" >&6; }
> +fi
> +
> if test "x$enable_gui" =3D "xgtk4"; then
> with_x=3Dno
> fi
> @@ -11494,6 +11539,58 @@ fi
>
>
>
> +{ printf "%s
> " "$as_me:${as_lineno-$LINENO}: checking --enable-hardcopy-pango argument=
" >&5
> +printf %s "checking --enable-hardcopy-pango argument... " >&6; }
> +# Check whether --enable-hardcopy-pango was given.
> +if test ${enable_hardcopy_pango+y}
> +then :
> + enableval=3D$enable_hardcopy_pango;
> +fi
> +
> +
> +if test "x$have_pango" =3D "xno" || test "x$have_cairo" =3D "xno"; then
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: no, Pango or Cairo not found" >&5
> +printf "%s
> " "no, Pango or Cairo not found" >&6; }
> +else
> + if test "x$GUITYPE" =3D "xGTK" || test "x$GUITYPE" =3D "xGTK4"; then
> + enable_hardcopy_pango=3D"yes"
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: yes, GTK GUI enabled" >&5
> +printf "%s
> " "yes, GTK GUI enabled" >&6; }
> + else
> + if test "$enable_hardcopy_pango" =3D "yes"; then
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +printf "%s
> " "yes" >&6; }
> + else
> + { printf "%s
> " "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +printf "%s
> " "no" >&6; }
> + fi
> + fi
> +fi
> +
> +if test "$enable_hardcopy_pango" =3D "yes"; then
> + cppflags_save=3D$CPPFLAGS
> + cflags_save=3D$CFLAGS
> +
> + printf "%s
> " "#define FEAT_PRINT_PANGO 1" >>confdefs.h
> +
> +
> + CPPFLAGS=3D"$CPPFLAGS $PANGO_CPPFLAGS"
> + CFLAGS=3D"$CFLAGS $PANGO_CFLAGS"
> +
> +
> +
> +
> + CPPFLAGS=3D"$CPPFLAGS $CAIRO_CPPFLAGS"
> + CFLAGS=3D"$CFLAGS $CAIRO_CFLAGS"
> +
> +
> +
> +
> + CPPFLAGS=3D$cppflags_save
> + CFLAGS=3D$cflags_save
> +fi
> +
> +
>
> if test -z "$SKIP_MOTIF"; then
> gui_XXX=3D"/usr/XXX/Motif* /usr/Motif*/XXX /usr/XXX /usr/shlib /usr/X11=
*/XXX /usr/XXX/X11* /usr/dt/XXX /local/Motif*/XXX /local/XXX/Motif* /usr/lo=
cal/Motif*/XXX /usr/local/XXX/Motif* /usr/local/XXX /usr/local/X11*/XXX /us=
r/local/LessTif/Motif*/XXX $MOTIFHOME/XXX"
> diff --git a/src/config.h.in b/src/config.h.in
> index d26bd2078..2dc3b2dec 100644
> --- a/src/config.h.in
> +++ b/src/config.h.in
> @@ -499,6 +499,9 @@
> /* Define if GTK GUI is to be linked against GTK 4 */
> #undef USE_GTK4
>
> +/* Define to use Pango and Cairo for hardcopy printing */
> +#undef FEAT_PRINT_PANGO
> +
> /* Define if we have isinf() */
> #undef HAVE_ISINF
>
> diff --git a/src/config.mk.in b/src/config.mk.in
> index a46a140a7..06a77aed6 100644
> --- a/src/config.mk.in
> +++ b/src/config.mk.in
> @@ -43,6 +43,14 @@ WAYLAND_OBJ =3D @WAYLAND_OBJ@
> WAYLAND_CFLAGS =3D @WAYLAND_CFLAGS@
> WAYLAND_CPPFLAGS =3D @WAYLAND_CPPFLAGS@
>
> +CAIRO_LIBS =3D @CAIRO_LIBS@
> +CAIRO_CFLAGS =3D @CAIRO_CFLAGS@
> +CAIRO_CPPFLAGS =3D @CAIRO_CPPFLAGS@
> +
> +PANGO_LIBS =3D @PANGO_LIBS@
> +PANGO_CFLAGS =3D @PANGO_CFLAGS@
> +PANGO_CPPFLAGS =3D @PANGO_CPPFLAGS@
> +
> XDIFF_OBJS_USED =3D @XDIFF_OBJS_USED@
>
> LUA_LIBS =3D @LUA_LIBS@
> diff --git a/src/configure.ac b/src/configure.ac
> index 654959874..2fdc51637 100644
> --- a/src/configure.ac
> +++ b/src/configure.ac
> @@ -2473,6 +2473,36 @@ else
> AC_MSG_RESULT(no)
> fi
>
> +AC_MSG_CHECKING(for cairo)
> +have_cairo=3D"no"
> +if "$PKG_CONFIG" --exists 'cairo-ps'; then
> + if "$PKG_CONFIG" --exists 'cairo-pdf'; then
> + have_cairo=3D"yes"
> + AC_MSG_RESULT([yes])
> +
> + CAIRO_CFLAGS=3D`$PKG_CONFIG --cflags-only-other cairo-ps cairo-pdf`
> + CAIRO_CPPFLAGS=3D`$PKG_CONFIG --cflags-only-I cairo-ps cairo-pdf`
> + CAIRO_LIBS=3D`$PKG_CONFIG --libs cairo-ps cairo-pdf`
> + else
> + AC_MSG_RESULT(no, pdf backend not enabled)
> + fi
> +else
> + AC_MSG_RESULT(no, postscript backend not enabled)
> +fi
> +
> +AC_MSG_CHECKING(for pango)
> +have_pango=3D"no"
> +if "$PKG_CONFIG" --exists 'pango' && "$PKG_CONFIG" --exists 'pangocairo'=
; then
> + have_pango=3D"yes"
> + AC_MSG_RESULT([yes])
> +
> + PANGO_CFLAGS=3D`$PKG_CONFIG --cflags-only-other pango pangocairo`
> + PANGO_CPPFLAGS=3D`$PKG_CONFIG --cflags-only-I pango pangocairo`
> + PANGO_LIBS=3D`$PKG_CONFIG --libs pango pangocairo`
> +else
> + AC_MSG_RESULT(no)
> +fi
> +
> dnl GTK4 does not use X11 APIs directly, so skip X11 detection entirely.
> dnl This avoids pulling libICE/libSM/libX11/libXt into build dependencies
> dnl for GTK4-only builds, even when --with-x=3Dyes is passed (e.g. by a
> @@ -3121,6 +3151,49 @@ AC_SUBST(GRESOURCE_OBJ)
> AC_SUBST(GTK_UPDATE_ICON_CACHE)
> AC_SUBST(UPDATE_DESKTOP_DATABASE)
>
> +AC_MSG_CHECKING(--enable-hardcopy-pango argument)
> +AC_ARG_ENABLE(hardcopy-pango,
> + [ --enable-hardcopy-pango Use Pango and Cairo for improved hardcop=
y printing. [default=3Dyes when GTK GUI enabled]],
> + ,, enable_hardcopy_pango=3D"no")
> +
> +if test "x$have_pango" =3D "xno" || test "x$have_cairo" =3D "xno"; then
> + AC_MSG_RESULT([no, Pango or Cairo not found])
> +else
> + if test "x$GUITYPE" =3D "xGTK" || test "x$GUITYPE" =3D "xGTK4"; then
> + enable_hardcopy_pango=3D"yes"
> + AC_MSG_RESULT([yes, GTK GUI enabled])
> + else
> + if test "$enable_hardcopy_pango" =3D "yes"; then
> + AC_MSG_RESULT([yes])
> + else
> + AC_MSG_RESULT([no])
> + fi
> + fi
> +fi
> +
> +if test "$enable_hardcopy_pango" =3D "yes"; then
> + cppflags_save=3D$CPPFLAGS
> + cflags_save=3D$CFLAGS
> +
> + AC_DEFINE(FEAT_PRINT_PANGO)
> +
> + CPPFLAGS=3D"$CPPFLAGS $PANGO_CPPFLAGS"
> + CFLAGS=3D"$CFLAGS $PANGO_CFLAGS"
> + AC_SUBST(PANGO_LIBS)
> + AC_SUBST(PANGO_CFLAGS)
> + AC_SUBST(PANGO_CPPFLAGS)
> +
> + CPPFLAGS=3D"$CPPFLAGS $CAIRO_CPPFLAGS"
> + CFLAGS=3D"$CFLAGS $CAIRO_CFLAGS"
> + AC_SUBST(CAIRO_LIBS)
> + AC_SUBST(CAIRO_CFLAGS)
> + AC_SUBST(CAIRO_CPPFLAGS)
> +
> + CPPFLAGS=3D$cppflags_save
> + CFLAGS=3D$cflags_save
> +fi
> +
> +
> dnl Check for Motif include files location.
> dnl The LAST one found is used, this makes the highest version to be used=
,
> dnl e.g. when Motif1.2 and Motif2.0 are both present.
> diff --git a/src/errors.h b/src/errors.h
> index 143e7d7e6..350ffe704 100644
> --- a/src/errors.h
> +++ b/src/errors.h
> @@ -569,7 +569,7 @@ EXTERN char e_font_str_is_not_fixed_width[]
> INIT(=3D N_("E236: Font \"%s\" is not fixed-width"));
> # endif
> #endif
> -#ifdef MSWIN
> +#if defined(MSWIN) || defined(FEAT_PRINT_PANGO)
> EXTERN char e_printer_selection_failed[]
> INIT(=3D N_("E237: Printer selection failed"));
> EXTERN char e_print_error_str[]
> @@ -815,7 +815,7 @@ EXTERN char e_line_number_out_of_range_nr_past_the_en=
d[]
> INIT(=3D "E322: Line number out of range: %ld past the end");
> EXTERN char e_line_count_wrong_in_block_nr[]
> INIT(=3D "E323: Line count wrong in block %ld");
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> EXTERN char e_cant_open_postscript_output_file[]
> INIT(=3D N_("E324: Can't open PostScript output file"));
> #endif
> @@ -915,7 +915,7 @@ EXTERN char e_pattern_uses_more_memory_than_maxmempat=
tern[]
> EXTERN char e_library_call_failed_for_str[]
> INIT(=3D N_("E364: Library call failed for \"%s()\""));
> #endif
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> EXTERN char e_failed_to_print_postscript_file[]
> INIT(=3D N_("E365: Failed to print PostScript file"));
> #endif
> @@ -1568,7 +1568,7 @@ EXTERN char e_using_special_as_number[]
> EXTERN char e_too_many_signs_defined[]
> INIT(=3D N_("E612: Too many signs defined"));
> #endif
> -#if defined(MSWIN) && defined(FEAT_PRINTER)
> +#if defined(FEAT_PRINTER) && (defined(MSWIN) || defined(FEAT_PRINT_PANGO=
))
> EXTERN char e_unknown_printer_font_str[]
> INIT(=3D N_("E613: Unknown printer font: %s"));
> #endif
> diff --git a/src/evalfunc.c b/src/evalfunc.c
> index bad28de7c..74ca2716e 100644
> --- a/src/evalfunc.c
> +++ b/src/evalfunc.c
> @@ -7560,6 +7560,13 @@ f_has(typval_T *argvars, typval_T *rettv)
> 1
> #else
> 0
> +#endif
> + },
> + {"pango",
> +#ifdef FEAT_PRINT_PANGO
> + 1
> +#else
> + 0
> #endif
> },
> {"printer",
> diff --git a/src/evalvars.c b/src/evalvars.c
> index 854cb1fc0..c08a9d6e0 100644
> --- a/src/evalvars.c
> +++ b/src/evalvars.c
> @@ -412,7 +412,7 @@ eval_charconvert(
> return OK;
> }
>
> -#if defined(FEAT_POSTSCRIPT)
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> int
> eval_printexpr(char_u *fname, char_u *args)
> {
> diff --git a/src/feature.h b/src/feature.h
> index 5d5512615..ee7475276 100644
> --- a/src/feature.h
> +++ b/src/feature.h
> @@ -291,17 +291,13 @@
> && !defined(AMIGA)
> # define FEAT_PRINTER
> #endif
> -#if defined(FEAT_PRINTER) && ((defined(MSWIN) && defined(MSWINPS)) \
> - || (!defined(MSWIN) && defined(FEAT_EVAL)))
> +#if defined(FEAT_PRINTER) && !defined(FEAT_PRINT_PANGO) \
> + && ((defined(MSWIN) && defined(MSWINPS)) \
> + || (!defined(MSWIN) && defined(FEAT_EVAL)))
> # define FEAT_POSTSCRIPT
> #endif
> -
> -/*
> - * +gtk_print Native GTK print dialog for :hardcopy (GTK4).
> - * Uses GtkPrintOperation + Pango/Cairo instead of PostScript.
> - */
> -#if defined(FEAT_PRINTER) && defined(FEAT_GUI_GTK) && defined(USE_GTK4)
> -# define FEAT_GUI_GTK_PRINT
> +#if !defined(FEAT_PRINTER) && defined(FEAT_PRINT_PANGO)
> +# undef FEAT_PRINT_PANGO
> #endif
>
> /*
> diff --git a/src/globals.h b/src/globals.h
> index 8e0a37494..305725c3e 100644
> --- a/src/globals.h
> +++ b/src/globals.h
> @@ -1832,8 +1832,9 @@ extern cursorentry_T shape_table[SHAPE_IDX_COUNT];
> # define OPT_PRINT_COLLATE 11
> # define OPT_PRINT_JOBSPLIT 12
> # define OPT_PRINT_FORMFEED 13
> +# define OPT_PRINT_FORMAT 14
>
> -# define OPT_PRINT_NUM_OPTIONS 14
> +# define OPT_PRINT_NUM_OPTIONS 15
>
> EXTERN option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS]
> # ifdef DO_INIT
> @@ -1852,6 +1853,7 @@ EXTERN option_table_T printer_opts[OPT_PRINT_NUM_OP=
TIONS]
> {"collate", FALSE, 0, NULL, 0, FALSE},
> {"jobsplit", FALSE, 0, NULL, 0, FALSE},
> {"formfeed", FALSE, 0, NULL, 0, FALSE},
> + {"format", FALSE, 0, NULL, 0, FALSE},
> }
> # endif
> ;
> diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
> index f5fb4487d..40fa89d89 100644
> --- a/src/gui_gtk4.c
> +++ b/src/gui_gtk4.c
> @@ -5043,322 +5043,188 @@ ex_helpfind(exarg_T *eap UNUSED)
> do_cmdline_cmd((char_u *)"emenu ToolBar.FindHelp");
> }
>
> -
> /*
> * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> - * Printing with GtkPrintOperation
> + * Native print dialog
> * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> */
> -#ifdef FEAT_GUI_GTK_PRINT
>
> -typedef struct
> -{
> - linenr_T first_line; // first line to print (from range)
> - linenr_T last_line; // last line to print (from range)
> - int n_pages; // total number of pages
> - int lines_per_page; // lines that fit on one page
> - PangoFontDescription *font_desc;
> - int do_syntax; // whether to use syntax highlighting
> - double line_height; // line height in points
> - double char_width; // character width in points
> -} print_data_T;
> +#ifdef USE_GTK4_PRINT_DIALOG
> +static GtkPrintDialog *print_dialog =3D NULL;
> +static GtkPrintSettings *print_settings =3D NULL;
> +static GtkPageSetup *page_setup =3D NULL;
> +static GtkPrintSetup *print_setup =3D NULL;
> +static GFile *print_file;
>
> -/*
> - * "begin-print" signal handler.
> - * Calculate pagination based on page size and font metrics.
> - */
> static void
> -print_begin_cb(
> - GtkPrintOperation *op,
> - GtkPrintContext *context,
> - gpointer user_data)
> +print_dialog_cb(GtkPrintDialog *dialog, GAsyncResult *result, gboolean *=
done)
> {
> - print_data_T *pd =3D (print_data_T *)user_data;
> - PangoLayout *layout;
> - PangoFontMetrics *metrics;
> - double page_height;
> - int total_lines;
> -
> - page_height =3D gtk_print_context_get_height(context);
> -
> - // Create a PangoLayout to measure font metrics on the print surface=
.
> - layout =3D gtk_print_context_create_pango_layout(context);
> - pango_layout_set_font_description(layout, pd->font_desc);
> -
> - metrics =3D pango_context_get_metrics(
> - pango_layout_get_context(layout),
> - pd->font_desc, NULL);
> -
> - pd->line_height =3D (double)(pango_font_metrics_get_ascent(metrics)
> - + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE;
> - pd->char_width =3D (double)pango_font_metrics_get_approximate_char_w=
idth(
> - metrics) / PANGO_SCALE;
> -
> - pango_font_metrics_unref(metrics);
> - g_object_unref(layout);
> -
> - if (pd->line_height <=3D 0)
> - pd->line_height =3D 12.0;
> + GError *error =3D NULL;
> + print_setup =3D gtk_print_dialog_setup_finish(dialog, result, &error=
);
>
> - pd->lines_per_page =3D (int)(page_height / pd->line_height);
> - if (pd->lines_per_page <=3D 0)
> - pd->lines_per_page =3D 1;
> -
> - total_lines =3D (int)(pd->last_line - pd->first_line + 1);
> - pd->n_pages =3D (total_lines + pd->lines_per_page - 1) / pd->lines_p=
er_page;
> - if (pd->n_pages <=3D 0)
> - pd->n_pages =3D 1;
> -
> - gtk_print_operation_set_n_pages(op, pd->n_pages);
> + if (print_setup =3D=3D NULL)
> + {
> + semsg(_(e_print_error_str), error->message);
> + g_error_free(error);
> + }
> + *done =3D TRUE;
> }
>
> /*
> - * "draw-page" signal handler.
> - * Render one page of buffer text with optional syntax highlighting.
> + * Return file to write to on success (allocated string), or NULL on fai=
lure
> + * (e.g. user cancelled)
> */
> - static void
> -print_draw_page_cb(
> - GtkPrintOperation *op UNUSED,
> - GtkPrintContext *context,
> - int page_nr,
> - gpointer user_data)
> + char_u *
> +gui_gtk4_print_dialog(
> + prt_settings_T *psettings,
> + char_u *jobname,
> + double *page_width,
> + double *page_height)
> {
> - print_data_T *pd =3D (print_data_T *)user_data;
> - cairo_t *cr;
> - linenr_T lnum;
> - linenr_T first;
> - linenr_T last;
> - double y;
> -
> - cr =3D gtk_print_context_get_cairo_context(context);
> + GtkPrintDialog *dialog =3D gtk_print_dialog_new();
> + gboolean done =3D FALSE;
> + char_u *temp;
>
> - first =3D pd->first_line + (linenr_T)page_nr * pd->lines_per_page;
> - last =3D first + pd->lines_per_page - 1;
> - if (last > pd->last_line)
> - last =3D pd->last_line;
> + gtk_print_dialog_set_title(dialog, (const char *)jobname);
> + gtk_print_dialog_set_modal(dialog, TRUE);
>
> - y =3D 0;
> + print_dialog =3D NULL;
> + print_setup =3D NULL;
>
> - for (lnum =3D first; lnum <=3D last; ++lnum)
> + if (print_settings =3D=3D NULL)
> {
> - char_u *line;
> - PangoLayout *layout;
> - PangoAttrList *attr_list;
> + option_table_T *opt;
>
> - line =3D ml_get(lnum);
> - layout =3D gtk_print_context_create_pango_layout(context);
> - pango_layout_set_font_description(layout, pd->font_desc);
> + print_settings =3D gtk_print_settings_new();
>
> - attr_list =3D pango_attr_list_new();
> -
> -# ifdef FEAT_SYN_HL
> - if (pd->do_syntax && syntax_present(curwin))
> + opt =3D &printer_opts[OPT_PRINT_DUPLEX];
> + if (opt->present)
> {
> - colnr_T col;
> - int prev_syn_id =3D -1;
> - int attr_start =3D 0;
> - long_u prev_fg =3D 0;
> - int prev_bold =3D FALSE;
> - int prev_italic =3D FALSE;
> - int len =3D (int)STRLEN(line);
> -
> - for (col =3D 0; col < len; )
> - {
> - int id;
> - int outputlen;
> - long_u fg_color;
> - int is_bold;
> - int is_italic;
> -
> - if (has_mbyte)
> - {
> - outputlen =3D (*mb_ptr2len)(line + col);
> - if (outputlen < 1)
> - outputlen =3D 1;
> - }
> - else
> - outputlen =3D 1;
> -
> - id =3D syn_get_id(curwin, lnum, col, 1, NULL, FALSE);
> - if (id > 0)
> - id =3D syn_get_final_id(id);
> - else
> - id =3D 0;
> - // syn_get_id may invalidate the line pointer.
> - line =3D ml_get(lnum);
> -
> - fg_color =3D highlight_gui_color_rgb(id, TRUE);
> - is_bold =3D (highlight_has_attr(id, HL_BOLD, 'g') !=3D NULL);
> - is_italic =3D (highlight_has_attr(id, HL_ITALIC, 'g') !=3D NULL);
> -
> - // When attributes change, flush the previous run.
> - if (id !=3D prev_syn_id && col > 0)
> - {
> - if (prev_fg !=3D 0 && prev_fg !=3D (long_u)0xffffffL)
> - {
> - PangoAttribute *a =3D pango_attr_foreground_new(
> - (guint16)(((prev_fg >> 16) & 0xff) * 257),
> - (guint16)(((prev_fg >> 8) & 0xff) * 257),
> - (guint16)((prev_fg & 0xff) * 257));
> - a->start_index =3D attr_start;
> - a->end_index =3D col;
> - pango_attr_list_insert(attr_list, a);
> - }
> - if (prev_bold)
> - {
> - PangoAttribute *a =3D pango_attr_weight_new(
> - PANGO_WEIGHT_BOLD);
> - a->start_index =3D attr_start;
> - a->end_index =3D col;
> - pango_attr_list_insert(attr_list, a);
> - }
> - if (prev_italic)
> - {
> - PangoAttribute *a =3D pango_attr_style_new(
> - PANGO_STYLE_ITALIC);
> - a->start_index =3D attr_start;
> - a->end_index =3D col;
> - pango_attr_list_insert(attr_list, a);
> - }
> - attr_start =3D col;
> - }
> -
> - prev_syn_id =3D id;
> - prev_fg =3D fg_color;
> - prev_bold =3D is_bold;
> - prev_italic =3D is_italic;
> -
> - col +=3D outputlen;
> - }
> + if (STRNICMP(opt->string, "off", 3) =3D=3D 0)
> + gtk_print_settings_set_duplex(print_settings,
> + GTK_PRINT_DUPLEX_SIMPLEX);
> + else if (STRNICMP(opt->string, "short", 5) =3D=3D 0)
> + gtk_print_settings_set_duplex(print_settings,
> + GTK_PRINT_DUPLEX_VERTICAL);
> + else
> + gtk_print_settings_set_duplex(print_settings,
> + GTK_PRINT_DUPLEX_HORIZONTAL);
> + }
>
> - // Flush the last run.
> - if (attr_start < len)
> - {
> - if (prev_fg !=3D 0 && prev_fg !=3D (long_u)0xffffffL)
> - {
> - PangoAttribute *a =3D pango_attr_foreground_new(
> - (guint16)(((prev_fg >> 16) & 0xff) * 257),
> - (guint16)(((prev_fg >> 8) & 0xff) * 257),
> - (guint16)((prev_fg & 0xff) * 257));
> - a->start_index =3D attr_start;
> - a->end_index =3D len;
> - pango_attr_list_insert(attr_list, a);
> - }
> - if (prev_bold)
> - {
> - PangoAttribute *a =3D pango_attr_weight_new(
> - PANGO_WEIGHT_BOLD);
> - a->start_index =3D attr_start;
> - a->end_index =3D len;
> - pango_attr_list_insert(attr_list, a);
> - }
> - if (prev_italic)
> - {
> - PangoAttribute *a =3D pango_attr_style_new(
> - PANGO_STYLE_ITALIC);
> - a->start_index =3D attr_start;
> - a->end_index =3D len;
> - pango_attr_list_insert(attr_list, a);
> - }
> - }
> + opt =3D &printer_opts[OPT_PRINT_PORTRAIT];
> + if (opt->present)
> + {
> + if (*opt->string =3D=3D 'y')
> + gtk_print_settings_set_orientation(print_settings,
> + GTK_PAGE_ORIENTATION_PORTRAIT);
> + else
> + gtk_print_settings_set_orientation(print_settings,
> + GTK_PAGE_ORIENTATION_LANDSCAPE);
> }
> -# endif // FEAT_SYN_HL
>
> - pango_layout_set_attributes(layout, attr_list);
> + opt =3D &printer_opts[OPT_PRINT_PAPER];
> + if (opt->present)
> + {
> + gtk_print_settings_set_paper_size(print_settings,
> + gtk_paper_size_new((const char *)opt->string));
> + }
>
> - // Expand tabs. Use a tab array matching Vim's tabstop.
> + opt =3D &printer_opts[OPT_PRINT_COLLATE];
> + if (opt->present)
> {
> - PangoTabArray *tabs;
> - int tab_width =3D (int)(curbuf->b_p_ts * pd->char_width);
> -
> - if (tab_width <=3D 0)
> - tab_width =3D (int)(8 * pd->char_width);
> - tabs =3D pango_tab_array_new(1, TRUE);
> - pango_tab_array_set_tab(tabs, 0, PANGO_TAB_LEFT, tab_width);
> - pango_layout_set_tabs(layout, tabs);
> - pango_tab_array_free(tabs);
> + if (*opt->string =3D=3D 'y')
> + gtk_print_settings_set_collate(print_settings, TRUE);
> + else
> + gtk_print_settings_set_collate(print_settings, FALSE);
> }
> + }
>
> - pango_layout_set_text(layout, (const char *)line, -1);
> + if (page_setup =3D=3D NULL)
> + page_setup =3D gtk_page_setup_new();
>
> - cairo_move_to(cr, 0, y);
> - pango_cairo_show_layout(cr, layout);
> + gtk_print_dialog_set_print_settings(dialog, print_settings);
> + gtk_print_dialog_set_page_setup(dialog, page_setup);
>
> - pango_attr_list_unref(attr_list);
> - g_object_unref(layout);
> + gtk_print_dialog_setup(dialog, GTK_WINDOW(gui.mainwin), NULL,
> + (GAsyncReadyCallback)print_dialog_cb, &done);
>
> - y +=3D pd->line_height;
> + while (!done)
> + g_main_context_iteration(NULL, TRUE);
> +
> + if (print_setup =3D=3D NULL)
> + {
> + g_object_unref(dialog);
> + g_clear_pointer(&print_setup, gtk_print_setup_unref);
> +
> + psettings->user_abort_msg =3D FALSE;
> + return NULL;
> }
> -}
>
> -/*
> - * Main entry point for GTK4 native printing.
> - * Called from ex_hardcopy() when running in a GTK4 GUI.
> - */
> - void
> -gui_gtk4_hardcopy(exarg_T *eap)
> -{
> - GtkPrintOperation *op;
> - GtkPrintOperationResult res;
> - print_data_T pd;
> - char_u *font_name;
> + g_clear_object(&print_settings);
> + g_clear_object(&page_setup);
> + print_settings =3D g_object_ref(
> + gtk_print_setup_get_print_settings(print_setup));
> + page_setup =3D g_object_ref(gtk_print_setup_get_page_setup(print_set=
up));
>
> - static GtkPrintSettings *settings =3D NULL;
> + {
> + GtkPrintDuplex duplex =3D gtk_print_settings_get_duplex(print_settings)=
;
> + psettings->duplex =3D duplex !=3D GTK_PRINT_DUPLEX_SIMPLEX;
> + }
>
> - CLEAR_FIELD(pd);
> - pd.first_line =3D eap->line1;
> - pd.last_line =3D eap->line2;
> + psettings->has_color =3D gtk_print_settings_get_use_color(print_sett=
ings);
>
> - // Use 'printfont' if set, otherwise fall back to 'guifont'.
> - font_name =3D *p_pfn !=3D NUL ? p_pfn : p_guifont;
> - if (font_name =3D=3D NULL || *font_name =3D=3D NUL)
> - font_name =3D (char_u *)"Monospace 10";
> + *page_width =3D gtk_page_setup_get_paper_width(page_setup,
> + GTK_UNIT_POINTS);
> + *page_height =3D gtk_page_setup_get_paper_height(page_setup,
> + GTK_UNIT_POINTS);
>
> - pd.font_desc =3D pango_font_description_from_string((const char *)fo=
nt_name);
> - if (pd.font_desc =3D=3D NULL)
> + temp =3D vim_tempname('p', FALSE);
> + if (temp =3D=3D NULL)
> {
> - semsg(_(e_unknown_font_str), font_name);
> - return;
> - }
> + emsg(_(e_cant_find_temp_file_for_writing));
> + g_clear_object(&dialog);
> + g_clear_pointer(&print_setup, gtk_print_setup_unref);
>
> - // Ensure the font description has a size (default 10pt if missing).
> - if (pango_font_description_get_size(pd.font_desc) =3D=3D 0)
> - pango_font_description_set_size(pd.font_desc, 10 * PANGO_SCALE);
> + psettings->user_abort_msg =3D FALSE;
> + return NULL;
> + }
> + print_file =3D g_file_new_for_path((char *)temp);
>
> -# ifdef FEAT_SYN_HL
> - pd.do_syntax =3D syntax_present(curwin);
> -# endif
> + print_dialog =3D dialog;
>
> - op =3D gtk_print_operation_new();
> + return temp;
> +}
>
> - if (settings !=3D NULL)
> - gtk_print_operation_set_print_settings(op, settings);
> + static void
> +print_file_cb(
> + GtkPrintDialog *dialog,
> + GAsyncResult *result,
> + GFile *file)
> +{
> + char *path =3D g_file_get_path(file);
>
> - gtk_print_operation_set_job_name(op,
> - curbuf->b_fname !=3D NULL
> - ? (const char *)curbuf->b_fname : "Vim");
> - gtk_print_operation_set_show_progress(op, TRUE);
> - gtk_print_operation_set_unit(op, GTK_UNIT_POINTS);
> + (void)gtk_print_dialog_print_file_finish(dialog, result, NULL);
> + g_object_unref(dialog);
>
> - g_signal_connect(op, "begin-print", G_CALLBACK(print_begin_cb), &pd)=
;
> - g_signal_connect(op, "draw-page", G_CALLBACK(print_draw_page_cb), &p=
d);
> + // Don't use g_file_delete() to be consistent
> + mch_remove(path);
> + g_free(path);
> +}
>
> - res =3D gtk_print_operation_run(op,
> - GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
> - GTK_WINDOW(gui.mainwin), NULL);
>
> - if (res =3D=3D GTK_PRINT_OPERATION_RESULT_APPLY)
> + void
> +gui_gtk4_print_finish(void)
> +{
> + if (print_dialog !=3D NULL)
> {
> - if (settings !=3D NULL)
> - g_object_unref(settings);
> - settings =3D g_object_ref(
> - gtk_print_operation_get_print_settings(op));
> + gtk_print_dialog_print_file(
> + print_dialog, GTK_WINDOW(gui.mainwin),
> + print_setup, print_file, NULL,
> + (GAsyncReadyCallback)print_file_cb, print_file);
> + print_dialog =3D NULL;
> + g_clear_pointer(&print_setup, gtk_print_setup_unref);
> }
> -
> - g_object_unref(op);
> - pango_font_description_free(pd.font_desc);
> }
> -
> -#endif // FEAT_GUI_GTK_PRINT
> +#endif // USE_GTK4_PRINT_DIALOG
>
> #endif // FEAT_GUI_GTK
> diff --git a/src/hardcopy.c b/src/hardcopy.c
> index 10c3beb8f..d7f229895 100644
> --- a/src/hardcopy.c
> +++ b/src/hardcopy.c
> @@ -15,6 +15,15 @@
> #include "version.h"
>
> #if defined(FEAT_PRINTER)
> +
> +#include "hardcopy.h"
> +#ifdef FEAT_POSTSCRIPT
> +# include "hardcopy_postscript.h"
> +#endif
> +#ifdef FEAT_PRINT_PANGO
> +# include "hardcopy_pango.h"
> +#endif
> +
> /*
> * To implement printing on a platform, the following functions must be
> * defined:
> @@ -92,35 +101,12 @@ static const long_u cterm_color_16[16] =3D
> static int current_syn_id;
> #endif
>
> -#define PRCOLOR_BLACK (long_u)0
> -#define PRCOLOR_WHITE (long_u)0xFFFFFFL
> -
> -static int curr_italic;
> -static int curr_bold;
> -static int curr_underline;
> -static long_u curr_bg;
> -static long_u curr_fg;
> -static int page_count;
> -
> -#if defined(FEAT_POSTSCRIPT)
> -# define OPT_MBFONT_USECOURIER 0
> -# define OPT_MBFONT_ASCII 1
> -# define OPT_MBFONT_REGULAR 2
> -# define OPT_MBFONT_BOLD 3
> -# define OPT_MBFONT_OBLIQUE 4
> -# define OPT_MBFONT_BOLDOBLIQUE 5
> -# define OPT_MBFONT_NUM_OPTIONS 6
> -
> -static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =3D
> -{
> - {"c", FALSE, 0, NULL, 0, FALSE},
> - {"a", FALSE, 0, NULL, 0, FALSE},
> - {"r", FALSE, 0, NULL, 0, FALSE},
> - {"b", FALSE, 0, NULL, 0, FALSE},
> - {"i", FALSE, 0, NULL, 0, FALSE},
> - {"o", FALSE, 0, NULL, 0, FALSE},
> -};
> -#endif
> +int prt_curr_italic;
> +int prt_curr_bold;
> +int prt_curr_underline;
> +long_u prt_curr_bg;
> +long_u prt_curr_fg;
> +int prt_page_count;
>
> /*
> * These values determine the print position on a page.
> @@ -135,6 +121,25 @@ typedef struct
> int ff; // seen form feed character
> } prt_pos_T;
>
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> +prt_mediasize_T prt_mediasize[PRT_MEDIASIZE_LEN] =3D {
> + {"A4", 595.0, 842.0},
> + {"letter", 612.0, 792.0},
> + {"10x14", 720.0, 1008.0},
> + {"A3", 842.0, 1191.0},
> + {"A5", 420.0, 595.0},
> + {"B4", 729.0, 1032.0},
> + {"B5", 516.0, 729.0},
> + {"executive", 522.0, 756.0},
> + {"folio", 595.0, 935.0},
> + {"ledger", 1224.0, 792.0},
> + {"legal", 612.0, 1008.0},
> + {"quarto", 610.0, 780.0},
> + {"statement", 396.0, 612.0},
> + {"tabloid", 792.0, 1224.0}
> +};
> +#endif
> +
> static char *parse_list_options(char_u *option_str, option_table_T *table=
, int table_size);
>
> static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, pr=
t_pos_T *ppos);
> @@ -334,34 +339,34 @@ prt_get_attr(
> static void
> prt_set_fg(long_u fg)
> {
> - if (fg =3D=3D curr_fg)
> + if (fg =3D=3D prt_curr_fg)
> return;
>
> - curr_fg =3D fg;
> + prt_curr_fg =3D fg;
> mch_print_set_fg(fg);
> }
>
> static void
> prt_set_bg(long_u bg)
> {
> - if (bg =3D=3D curr_bg)
> + if (bg =3D=3D prt_curr_bg)
> return;
>
> - curr_bg =3D bg;
> + prt_curr_bg =3D bg;
> mch_print_set_bg(bg);
> }
>
> static void
> prt_set_font(int bold, int italic, int underline)
> {
> - if (curr_bold =3D=3D bold
> - && curr_italic =3D=3D italic
> - && curr_underline =3D=3D underline)
> + if (prt_curr_bold =3D=3D bold
> + && prt_curr_italic =3D=3D italic
> + && prt_curr_underline =3D=3D underline)
> return;
>
> - curr_underline =3D underline;
> - curr_italic =3D italic;
> - curr_bold =3D bold;
> + prt_curr_underline =3D underline;
> + prt_curr_italic =3D italic;
> + prt_curr_bold =3D bold;
> mch_print_set_font(bold, italic, underline);
> }
>
> @@ -539,7 +544,7 @@ prt_header(
> /*
> * Display a print status message.
> */
> - static void
> + void
> prt_message(char_u *s)
> {
> screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
> @@ -559,18 +564,11 @@ ex_hardcopy(exarg_T *eap)
>
> CLEAR_FIELD(settings);
> settings.has_color =3D TRUE;
> -
> -#ifdef FEAT_GUI_GTK_PRINT
> - // Use the native GTK print dialog only for interactive printing;
> - // ":hardcopy >file" must fall through to the PostScript writer.
> - if (gui.in_use && *eap->arg !=3D '>')
> - {
> - gui_gtk4_hardcopy(eap);
> - return;
> - }
> +#ifdef FEAT_PRINT_PANGO
> + settings.user_abort_msg =3D TRUE;
> #endif
>
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> if (*eap->arg =3D=3D '>')
> {
> char *errormsg =3D NULL;
> @@ -659,11 +657,11 @@ ex_hardcopy(exarg_T *eap)
> }
>
> // Set colors and font to normal.
> - curr_bg =3D (long_u)0xffffffffL;
> - curr_fg =3D (long_u)0xffffffffL;
> - curr_italic =3D MAYBE;
> - curr_bold =3D MAYBE;
> - curr_underline =3D MAYBE;
> + prt_curr_bg =3D (long_u)0xffffffffL;
> + prt_curr_fg =3D (long_u)0xffffffffL;
> + prt_curr_italic =3D MAYBE;
> + prt_curr_bold =3D MAYBE;
> + prt_curr_underline =3D MAYBE;
>
> prt_set_fg(PRCOLOR_BLACK);
> prt_set_bg(PRCOLOR_WHITE);
> @@ -681,7 +679,7 @@ ex_hardcopy(exarg_T *eap)
> /*
> * Loop over collated copies: 1 2 3, 1 2 3, ...
> */
> - page_count =3D 0;
> + prt_page_count =3D 0;
> for (collated_copies =3D 0;
> collated_copies < settings.n_collated_copies;
> collated_copies++)
> @@ -705,7 +703,7 @@ ex_hardcopy(exarg_T *eap)
> /*
> * Loop over all pages in the print job: 1 2 3 ...
> */
> - for (page_count =3D 0; prtpos.file_line <=3D eap->line2; ++page_count)
> + for (prt_page_count =3D 0; prtpos.file_line <=3D eap->line2; ++prt_page=
_count)
> {
> /*
> * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
> @@ -733,7 +731,7 @@ ex_hardcopy(exarg_T *eap)
> goto print_fail;
>
> sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
> - page_count + 1 + side,
> + prt_page_count + 1 + side,
> prtpos.bytes_printed > 1000000
> ? (int)(prtpos.bytes_printed /
> (bytes_to_print / 100))
> @@ -753,7 +751,7 @@ ex_hardcopy(exarg_T *eap)
> * Output header if required
> */
> if (prt_header_height() > 0)
> - prt_header(&settings, page_count + 1 + side,
> + prt_header(&settings, prt_page_count + 1 + side,
> prtpos.file_line);
>
> for (page_line =3D 0; page_line < settings.lines_per_page;
> @@ -796,7 +794,7 @@ ex_hardcopy(exarg_T *eap)
> }
> }
> if (settings.duplex && prtpos.file_line <=3D eap->line2)
> - ++page_count;
> + ++prt_page_count;
>
> // Remember the position where the next page starts.
> page_prtpos =3D prtpos;
> @@ -808,7 +806,11 @@ ex_hardcopy(exarg_T *eap)
> }
>
> print_fail:
> - if (got_int || settings.user_abort)
> + if (got_int || (settings.user_abort
> +#ifdef FEAT_PRINT_PANGO
> + && settings.user_abort_msg
> +#endif
> + ))
> {
> sprintf((char *)IObuff, "%s", _("Printing aborted"));
> prt_message(IObuff);
> @@ -950,2519 +952,4 @@ hardcopy_line(
> return col;
> }
>
> -#if defined(FEAT_POSTSCRIPT)
> -
> -/*
> - * PS printer stuff.
> - *
> - * Sources of information to help maintain the PS printing code:
> - *
> - * 1. PostScript Language Reference, 3rd Edition,
> - * Addison-Wesley, 1999, ISBN 0-201-37922-8
> - * 2. PostScript Language Program Design,
> - * Addison-Wesley, 1988, ISBN 0-201-14396-8
> - * 3. PostScript Tutorial and Cookbook,
> - * Addison Wesley, 1985, ISBN 0-201-10179-3
> - * 4. PostScript Language Document Structuring Conventions Specification=
,
> - * version 3.0,
> - * Adobe Technote 5001, 25th September 1992
> - * 5. PostScript Printer Description File Format Specification, Version =
4.3,
> - * Adobe technote 5003, 9th February 1996
> - * 6. Adobe Font Metrics File Format Specification, Version 4.1,
> - * Adobe Technote 5007, 7th October 1998
> - * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
> - * Adobe Technote 5014, 8th October 1996
> - * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
> - * Adoboe Technote 5094, 8th September, 2001
> - * 9. CJKV Information Processing, 2nd Edition,
> - * O'Reilly, 2002, ISBN 1-56592-224-7
> - *
> - * Some of these documents can be found in PDF form on Adobe's web site =
-
> - * http://www.adobe.com
> - */
> -
> -# define PRT_PS_DEFAULT_DPI (72) // Default user space resolution
> -# define PRT_PS_DEFAULT_FONTSIZE (10)
> -# define PRT_PS_DEFAULT_BUFFER_SIZE (80)
> -
> -struct prt_mediasize_S
> -{
> - char *name;
> - float width; // width and height in points for portrait
> - float height;
> -};
> -
> -# define PRT_MEDIASIZE_LEN ARRAY_LENGTH(prt_mediasize)
> -
> -static struct prt_mediasize_S prt_mediasize[] =3D
> -{
> - {"A4", 595.0, 842.0},
> - {"letter", 612.0, 792.0},
> - {"10x14", 720.0, 1008.0},
> - {"A3", 842.0, 1191.0},
> - {"A5", 420.0, 595.0},
> - {"B4", 729.0, 1032.0},
> - {"B5", 516.0, 729.0},
> - {"executive", 522.0, 756.0},
> - {"folio", 595.0, 935.0},
> - {"ledger", 1224.0, 792.0}, // Yes, it is wider than taller=
!
> - {"legal", 612.0, 1008.0},
> - {"quarto", 610.0, 780.0},
> - {"statement", 396.0, 612.0},
> - {"tabloid", 792.0, 1224.0}
> -};
> -
> -// PS font names, must be in Roman, Bold, Italic, Bold-Italic order
> -struct prt_ps_font_S
> -{
> - int wx;
> - int uline_offset;
> - int uline_width;
> - int bbox_min_y;
> - int bbox_max_y;
> - char *(ps_fontname[4]);
> -};
> -
> -# define PRT_PS_FONT_ROMAN (0)
> -# define PRT_PS_FONT_BOLD (1)
> -# define PRT_PS_FONT_OBLIQUE (2)
> -# define PRT_PS_FONT_BOLDOBLIQUE (3)
> -
> -// Standard font metrics for Courier family
> -static struct prt_ps_font_S prt_ps_courier_font =3D
> -{
> - 600,
> - -100, 50,
> - -250, 805,
> - {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"=
}
> -};
> -
> -// Generic font metrics for multi-byte fonts
> -static struct prt_ps_font_S prt_ps_mb_font =3D
> -{
> - 1000,
> - -100, 50,
> - -250, 805,
> - {NULL, NULL, NULL, NULL}
> -};
> -
> -// Pointer to current font set being used
> -static struct prt_ps_font_S* prt_ps_font;
> -
> -// Structures to map user named encoding and mapping to PS equivalents f=
or
> -// building CID font name
> -struct prt_ps_encoding_S
> -{
> - char *encoding;
> - char *cmap_encoding;
> - int needs_charset;
> -};
> -
> -struct prt_ps_charset_S
> -{
> - char *charset;
> - char *cmap_charset;
> - int has_charset;
> -};
> -
> -
> -# define CS_JIS_C_1978 (0x01)
> -# define CS_JIS_X_1983 (0x02)
> -# define CS_JIS_X_1990 (0x04)
> -# define CS_NEC (0x08)
> -# define CS_MSWINDOWS (0x10)
> -# define CS_CP932 (0x20)
> -# define CS_KANJITALK6 (0x40)
> -# define CS_KANJITALK7 (0x80)
> -
> -// Japanese encodings and charsets
> -static struct prt_ps_encoding_S j_encodings[] =3D
> -{
> - {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_19=
90|
> - CS_NEC)},
> - {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
> - {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
> - CS_KANJITALK6|CS_KANJITALK7)},
> - {"cp932", "RKSJ", CS_JIS_X_1983},
> - {"ucs-2", "UCS2", CS_JIS_X_1990},
> - {"utf-8", "UTF8" , CS_JIS_X_1990}
> -};
> -static struct prt_ps_charset_S j_charsets[] =3D
> -{
> - {"JIS_C_1978", "78", CS_JIS_C_1978},
> - {"JIS_X_1983", NULL, CS_JIS_X_1983},
> - {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
> - {"NEC", "Ext", CS_NEC},
> - {"MSWINDOWS", "90ms", CS_MSWINDOWS},
> - {"CP932", "90ms", CS_JIS_X_1983},
> - {"KANJITALK6", "83pv", CS_KANJITALK6},
> - {"KANJITALK7", "90pv", CS_KANJITALK7}
> -};
> -
> -# define CS_GB_2312_80 (0x01)
> -# define CS_GBT_12345_90 (0x02)
> -# define CS_GBK2K (0x04)
> -# define CS_SC_MAC (0x08)
> -# define CS_GBT_90_MAC (0x10)
> -# define CS_GBK (0x20)
> -# define CS_SC_ISO10646 (0x40)
> -
> -// Simplified Chinese encodings and charsets
> -static struct prt_ps_encoding_S sc_encodings[] =3D
> -{
> - {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
> - {"gb18030", NULL, CS_GBK2K},
> - {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC=
|
> - CS_GBT_90_MAC)},
> - {"gbk", "EUC", CS_GBK},
> - {"ucs-2", "UCS2", CS_SC_ISO10646},
> - {"utf-8", "UTF8", CS_SC_ISO10646}
> -};
> -static struct prt_ps_charset_S sc_charsets[] =3D
> -{
> - {"GB_2312-80", "GB", CS_GB_2312_80},
> - {"GBT_12345-90","GBT", CS_GBT_12345_90},
> - {"MAC", "GBpc", CS_SC_MAC},
> - {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
> - {"GBK", "GBK", CS_GBK},
> - {"GB18030", "GBK2K", CS_GBK2K},
> - {"ISO10646", "UniGB", CS_SC_ISO10646}
> -};
> -
> -# define CS_CNS_PLANE_1 (0x01)
> -# define CS_CNS_PLANE_2 (0x02)
> -# define CS_CNS_PLANE_1_2 (0x04)
> -# define CS_B5 (0x08)
> -# define CS_ETEN (0x10)
> -# define CS_HK_GCCS (0x20)
> -# define CS_HK_SCS (0x40)
> -# define CS_HK_SCS_ETEN (0x80)
> -# define CS_MTHKL (0x100)
> -# define CS_MTHKS (0x200)
> -# define CS_DLHKL (0x400)
> -# define CS_DLHKS (0x800)
> -# define CS_TC_ISO10646 (0x1000)
> -
> -// Traditional Chinese encodings and charsets
> -static struct prt_ps_encoding_S tc_encodings[] =3D
> -{
> - {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
> - {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
> - {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
> - CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
> - CS_DLHKS)},
> - {"cp950", "B5", CS_B5},
> - {"ucs-2", "UCS2", CS_TC_ISO10646},
> - {"utf-8", "UTF8", CS_TC_ISO10646},
> - {"utf-16", "UTF16", CS_TC_ISO10646},
> - {"utf-32", "UTF32", CS_TC_ISO10646}
> -};
> -static struct prt_ps_charset_S tc_charsets[] =3D
> -{
> - {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
> - {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
> - {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
> - {"BIG5", NULL, CS_B5},
> - {"CP950", NULL, CS_B5},
> - {"ETEN", "ETen", CS_ETEN},
> - {"HK_GCCS", "HKgccs", CS_HK_GCCS},
> - {"SCS", "HKscs", CS_HK_SCS},
> - {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
> - {"MTHKL", "HKm471", CS_MTHKL},
> - {"MTHKS", "HKm314", CS_MTHKS},
> - {"DLHKL", "HKdla", CS_DLHKL},
> - {"DLHKS", "HKdlb", CS_DLHKS},
> - {"ISO10646", "UniCNS", CS_TC_ISO10646}
> -};
> -
> -# define CS_KR_X_1992 (0x01)
> -# define CS_KR_MAC (0x02)
> -# define CS_KR_X_1992_MS (0x04)
> -# define CS_KR_ISO10646 (0x08)
> -
> -// Korean encodings and charsets
> -static struct prt_ps_encoding_S k_encodings[] =3D
> -{
> - {"iso-2022-kr", NULL, CS_KR_X_1992},
> - {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
> - {"johab", "Johab", CS_KR_X_1992},
> - {"cp1361", "Johab", CS_KR_X_1992},
> - {"uhc", "UHC", CS_KR_X_1992_MS},
> - {"cp949", "UHC", CS_KR_X_1992_MS},
> - {"ucs-2", "UCS2", CS_KR_ISO10646},
> - {"utf-8", "UTF8", CS_KR_ISO10646}
> -};
> -static struct prt_ps_charset_S k_charsets[] =3D
> -{
> - {"KS_X_1992", "KSC", CS_KR_X_1992},
> - {"CP1361", "KSC", CS_KR_X_1992},
> - {"MAC", "KSCpc", CS_KR_MAC},
> - {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
> - {"CP949", "KSCms", CS_KR_X_1992_MS},
> - {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
> - {"ISO10646", "UniKS", CS_KR_ISO10646}
> -};
> -
> -// Collections of encodings and charsets for multi-byte printing
> -struct prt_ps_mbfont_S
> -{
> - int num_encodings;
> - struct prt_ps_encoding_S *encodings;
> - int num_charsets;
> - struct prt_ps_charset_S *charsets;
> - char *ascii_enc;
> - char *defcs;
> -};
> -
> -static struct prt_ps_mbfont_S prt_ps_mbfonts[] =3D
> -{
> - {
> - ARRAY_LENGTH(j_encodings),
> - j_encodings,
> - ARRAY_LENGTH(j_charsets),
> - j_charsets,
> - "jis_roman",
> - "JIS_X_1983"
> - },
> - {
> - ARRAY_LENGTH(sc_encodings),
> - sc_encodings,
> - ARRAY_LENGTH(sc_charsets),
> - sc_charsets,
> - "gb_roman",
> - "GB_2312-80"
> - },
> - {
> - ARRAY_LENGTH(tc_encodings),
> - tc_encodings,
> - ARRAY_LENGTH(tc_charsets),
> - tc_charsets,
> - "cns_roman",
> - "BIG5"
> - },
> - {
> - ARRAY_LENGTH(k_encodings),
> - k_encodings,
> - ARRAY_LENGTH(k_charsets),
> - k_charsets,
> - "ks_roman",
> - "KS_X_1992"
> - }
> -};
> -
> -struct prt_ps_resource_S
> -{
> - char_u name[64];
> - char_u filename[MAXPATHL + 1];
> - int type;
> - char_u title[256];
> - char_u version[256];
> -};
> -
> -// Types of PS resource file currently used
> -# define PRT_RESOURCE_TYPE_PROCSET (0)
> -# define PRT_RESOURCE_TYPE_ENCODING (1)
> -# define PRT_RESOURCE_TYPE_CMAP (2)
> -
> -// The PS prolog file version number has to match - if the prolog file i=
s
> -// updated, increment the number in the file and here. Version checking=
was
> -// added as of VIM 6.2.
> -// The CID prolog file version number behaves as per PS prolog.
> -// Table of VIM and prolog versions:
> -//
> -// VIM Prolog CIDProlog
> -// 6.2 1.3
> -// 7.0 1.4 1.0
> -# define PRT_PROLOG_VERSION ((char_u *)"1.4")
> -# define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
> -
> -// String versions of PS resource types - indexed by constants above so =
don't
> -// re-order!
> -static char *prt_resource_types[] =3D
> -{
> - "procset",
> - "encoding",
> - "cmap"
> -};
> -
> -// Strings to look for in a PS resource file
> -# define PRT_RESOURCE_HEADER "%!PS-Adobe-"
> -# define PRT_RESOURCE_RESOURCE "Resource-"
> -# define PRT_RESOURCE_PROCSET "ProcSet"
> -# define PRT_RESOURCE_ENCODING "Encoding"
> -# define PRT_RESOURCE_CMAP "CMap"
> -
> -
> -// Data for table based DSC comment recognition, easy to extend if VIM n=
eeds to
> -// read more comments.
> -# define PRT_DSC_MISC_TYPE (-1)
> -# define PRT_DSC_TITLE_TYPE (1)
> -# define PRT_DSC_VERSION_TYPE (2)
> -# define PRT_DSC_ENDCOMMENTS_TYPE (3)
> -
> -# define PRT_DSC_TITLE "%%Title:"
> -# define PRT_DSC_VERSION "%%Version:"
> -# define PRT_DSC_ENDCOMMENTS "%%EndComments:"
> -
> -struct prt_dsc_comment_S
> -{
> - char *string;
> - int len;
> - int type;
> -};
> -
> -struct prt_dsc_line_S
> -{
> - int type;
> - char_u *string;
> - int len;
> -};
> -
> -
> -# define SIZEOF_CSTR(s) (sizeof(s) - 1)
> -static struct prt_dsc_comment_S prt_dsc_table[] =3D
> -{
> - {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_=
TYPE},
> - {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
> - PRT_DSC_VERSION_TYPE},
> - {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
> - PRT_DSC_ENDCOMMENTS_TYPE}
> -};
> -
> -static void prt_write_file_len(char_u *buffer, int bytes);
> -static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
> -
> -/*
> - * Variables for the output PostScript file.
> - */
> -static FILE *prt_ps_fd;
> -static int prt_file_error;
> -static char_u *prt_ps_file_name =3D NULL;
> -
> -/*
> - * Various offsets and dimensions in default PostScript user space (poin=
ts).
> - * Used for text positioning calculations
> - */
> -static float prt_page_width;
> -static float prt_page_height;
> -static float prt_left_margin;
> -static float prt_right_margin;
> -static float prt_top_margin;
> -static float prt_bottom_margin;
> -static float prt_line_height;
> -static float prt_first_line_height;
> -static float prt_char_width;
> -static float prt_number_width;
> -static float prt_bgcol_offset;
> -static float prt_pos_x_moveto =3D 0.0;
> -static float prt_pos_y_moveto =3D 0.0;
> -
> -/*
> - * Various control variables used to decide when and how to change the
> - * PostScript graphics state.
> - */
> -static int prt_need_moveto;
> -static int prt_do_moveto;
> -static int prt_need_font;
> -static int prt_font;
> -static int prt_need_underline;
> -static int prt_underline;
> -static int prt_do_underline;
> -static int prt_need_fgcol;
> -static int prt_fgcol;
> -static int prt_need_bgcol;
> -static int prt_do_bgcol;
> -static int prt_bgcol;
> -static int prt_new_bgcol;
> -static int prt_attribute_change;
> -static float prt_text_run;
> -static int prt_page_num;
> -static int prt_bufsiz;
> -
> -/*
> - * Variables controlling physical printing.
> - */
> -static int prt_media;
> -static int prt_portrait;
> -static int prt_num_copies;
> -static int prt_duplex;
> -static int prt_tumble;
> -static int prt_collate;
> -
> -/*
> - * Buffers used when generating PostScript output
> - */
> -static char_u prt_line_buffer[257];
> -static garray_T prt_ps_buffer;
> -
> -static int prt_do_conv;
> -static vimconv_T prt_conv;
> -
> -static int prt_out_mbyte;
> -static int prt_custom_cmap;
> -static char prt_cmap[80];
> -static int prt_use_courier;
> -static int prt_in_ascii;
> -static int prt_half_width;
> -static char *prt_ascii_encoding;
> -static const char_u prt_hexchar[] =3D "0123456789abcdef";
> -
> - static void
> -prt_write_file_raw_len(char_u *buffer, int bytes)
> -{
> - if (!prt_file_error
> - && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
> - !=3D (size_t)bytes)
> - {
> - emsg(_(e_error_writing_to_postscript_output_file));
> - prt_file_error =3D TRUE;
> - }
> -}
> -
> - static void
> -prt_write_file(char_u *buffer)
> -{
> - prt_write_file_len(buffer, (int)STRLEN(buffer));
> -}
> -
> - static void
> -prt_write_file_len(char_u *buffer, int bytes)
> -{
> - prt_write_file_raw_len(buffer, bytes);
> -}
> -
> -/*
> - * Write a string.
> - */
> - static void
> -prt_write_string(char *s)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s",=
s);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write an int and a space.
> - */
> - static void
> -prt_write_int(int i)
> -{
> - sprintf((char *)prt_line_buffer, "%d ", i);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write a boolean and a space.
> - */
> - static void
> -prt_write_boolean(int b)
> -{
> - sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write PostScript to re-encode and define the font.
> - */
> - static void
> -prt_def_font(
> - char *new_name,
> - char *encoding,
> - int height,
> - char *font)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/_%s /VIM-%s /%s ref
> ", new_name, encoding, font);
> - prt_write_file(prt_line_buffer);
> - if (prt_out_mbyte)
> - sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs
> ",
> - new_name, height, 500./prt_ps_courier_font.wx, new_name);
> - else
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/%s %d /_%s ffs
> ", new_name, height, new_name);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write a line to define the CID font.
> - */
> - static void
> -prt_def_cidfont(char *new_name, int height, char *cidfont)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/_%s /%s[/%s] vim_composefont
> ", new_name, prt_cmap, cidfont);
> - prt_write_file(prt_line_buffer);
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/%s %d /_%s ffs
> ", new_name, height, new_name);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write a line to define a duplicate of a CID font
> - */
> - static void
> -prt_dup_cidfont(char *original_name, char *new_name)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/%s %s d
> ", new_name, original_name);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Convert a real value into an integer and fractional part as integers,=
with
> - * the fractional part being in the range [0,10^precision). The fractio=
nal part
> - * is also rounded based on the precision + 1'th fractional digit.
> - */
> - static void
> -prt_real_bits(
> - double real,
> - int precision,
> - int *pinteger,
> - int *pfraction)
> -{
> - int i;
> - int integer;
> - float fraction;
> -
> - integer =3D (int)real;
> - fraction =3D (float)(real - integer);
> - if (real < (double)integer)
> - fraction =3D -fraction;
> - for (i =3D 0; i < precision; i++)
> - fraction *=3D 10.0;
> -
> - *pinteger =3D integer;
> - *pfraction =3D (int)(fraction + 0.5);
> -}
> -
> -/*
> - * Write a real and a space. Save bytes if real value has no fractional=
part!
> - * We use prt_real_bits() as %f in sprintf uses the locale setting to de=
cide
> - * what decimal point character to use, but PS always requires a '.'.
> - */
> - static void
> -prt_write_real(double val, int prec)
> -{
> - int integer;
> - int fraction;
> -
> - prt_real_bits(val, prec, &integer, &fraction);
> - // Emit integer part
> - sprintf((char *)prt_line_buffer, "%d", integer);
> - prt_write_file(prt_line_buffer);
> - // Only emit fraction if necessary
> - if (fraction !=3D 0)
> - {
> - // Remove any trailing zeros
> - while ((fraction % 10) =3D=3D 0)
> - {
> - prec--;
> - fraction /=3D 10;
> - }
> - // Emit fraction left padded with zeros
> - sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
> - prt_write_file(prt_line_buffer);
> - }
> - sprintf((char *)prt_line_buffer, " ");
> - prt_write_file(prt_line_buffer);
> -}
> -
> -/*
> - * Write a line to define a numeric variable.
> - */
> - static void
> -prt_def_var(char *name, double value, int prec)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "/%s ", name);
> - prt_write_file(prt_line_buffer);
> - prt_write_real(value, prec);
> - sprintf((char *)prt_line_buffer, "d
> ");
> - prt_write_file(prt_line_buffer);
> -}
> -
> -// Convert size from font space to user space at current font scale
> -# define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0))
> -
> - static void
> -prt_flush_buffer(void)
> -{
> - if (prt_ps_buffer.ga_len <=3D 0)
> - return;
> -
> - // Any background color must be drawn first
> - if (prt_do_bgcol && (prt_new_bgcol !=3D PRCOLOR_WHITE))
> - {
> - int r, g, b;
> -
> - if (prt_do_moveto)
> - {
> - prt_write_real(prt_pos_x_moveto, 2);
> - prt_write_real(prt_pos_y_moveto, 2);
> - prt_write_string("m
> ");
> - prt_do_moveto =3D FALSE;
> - }
> -
> - // Size of rect of background color on which text is printed
> - prt_write_real(prt_text_run, 2);
> - prt_write_real(prt_line_height, 2);
> -
> - // Lastly add the color of the background
> - r =3D ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
> - g =3D ((unsigned)prt_new_bgcol & 0xff00) >> 8;
> - b =3D prt_new_bgcol & 0xff;
> - prt_write_real(r / 255.0, 3);
> - prt_write_real(g / 255.0, 3);
> - prt_write_real(b / 255.0, 3);
> - prt_write_string("bg
> ");
> - }
> - // Draw underlines before the text as it makes it slightly easier to
> - // find the starting point.
> - if (prt_do_underline)
> - {
> - if (prt_do_moveto)
> - {
> - prt_write_real(prt_pos_x_moveto, 2);
> - prt_write_real(prt_pos_y_moveto, 2);
> - prt_write_string("m
> ");
> - prt_do_moveto =3D FALSE;
> - }
> -
> - // Underline length of text run
> - prt_write_real(prt_text_run, 2);
> - prt_write_string("ul
> ");
> - }
> - // Draw the text
> - if (prt_out_mbyte)
> - prt_write_string("<");
> - else
> - prt_write_string("(");
> - prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
> - if (prt_out_mbyte)
> - prt_write_string(">");
> - else
> - prt_write_string(")");
> - // Add a moveto if need be and use the appropriate show procedure
> - if (prt_do_moveto)
> - {
> - prt_write_real(prt_pos_x_moveto, 2);
> - prt_write_real(prt_pos_y_moveto, 2);
> - // moveto and a show
> - prt_write_string("ms
> ");
> - prt_do_moveto =3D FALSE;
> - }
> - else // Simple show
> - prt_write_string("s
> ");
> -
> - ga_clear(&prt_ps_buffer);
> - ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
> -}
> -
> -
> - static void
> -prt_resource_name(char_u *filename, void *cookie)
> -{
> - char_u *resource_filename =3D cookie;
> -
> - if (STRLEN(filename) >=3D MAXPATHL)
> - *resource_filename =3D NUL;
> - else
> - STRCPY(resource_filename, filename);
> -}
> -
> - static int
> -prt_find_resource(char *name, struct prt_ps_resource_S *resource)
> -{
> - char_u *buffer;
> - int retval;
> -
> - buffer =3D alloc(MAXPATHL + 1);
> - if (buffer =3D=3D NULL)
> - return FALSE;
> -
> - vim_strncpy(resource->name, (char_u *)name, 63);
> - // Look for named resource file in runtimepath
> - STRCPY(buffer, "print");
> - add_pathsep(buffer);
> - vim_strcat(buffer, (char_u *)name, MAXPATHL);
> - vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
> - resource->filename[0] =3D NUL;
> - retval =3D (do_in_runtimepath(buffer, 0, prt_resource_name,
> - resource->filename)
> - && resource->filename[0] !=3D NUL);
> - vim_free(buffer);
> - return retval;
> -}
> -
> -// PS CR and LF characters have platform independent values
> -# define PSLF (0x0a)
> -# define PSCR (0x0d)
> -
> -// Static buffer to read initial comments in a resource file, some can h=
ave a
> -// couple of KB of comments!
> -# define PRT_FILE_BUFFER_LEN (2048)
> -struct prt_resfile_buffer_S
> -{
> - char_u buffer[PRT_FILE_BUFFER_LEN];
> - int len;
> - int line_start;
> - int line_end;
> -};
> -
> -static struct prt_resfile_buffer_S prt_resfile;
> -
> - static int
> -prt_resfile_next_line(void)
> -{
> - int idx;
> -
> - // Move to start of next line and then find end of line
> - idx =3D prt_resfile.line_end + 1;
> - while (idx < prt_resfile.len)
> - {
> - if (prt_resfile.buffer[idx] !=3D PSLF && prt_resfile.buffer[idx] !=3D P=
SCR)
> - break;
> - idx++;
> - }
> - prt_resfile.line_start =3D idx;
> -
> - while (idx < prt_resfile.len)
> - {
> - if (prt_resfile.buffer[idx] =3D=3D PSLF || prt_resfile.buffer[idx] =3D=
=3D PSCR)
> - break;
> - idx++;
> - }
> - prt_resfile.line_end =3D idx;
> -
> - return (idx < prt_resfile.len);
> -}
> -
> - static int
> -prt_resfile_strncmp(int offset, char *string, int len)
> -{
> - // Force not equal if string is longer than remainder of line
> - if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))=
)
> - return 1;
> -
> - return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
> - string, len);
> -}
> -
> - static int
> -prt_resfile_skip_nonws(int offset)
> -{
> - int idx;
> -
> - idx =3D prt_resfile.line_start + offset;
> - while (idx < prt_resfile.line_end)
> - {
> - if (SAFE_isspace(prt_resfile.buffer[idx]))
> - return idx - prt_resfile.line_start;
> - idx++;
> - }
> - return -1;
> -}
> -
> - static int
> -prt_resfile_skip_ws(int offset)
> -{
> - int idx;
> -
> - idx =3D prt_resfile.line_start + offset;
> - while (idx < prt_resfile.line_end)
> - {
> - if (!SAFE_isspace(prt_resfile.buffer[idx]))
> - return idx - prt_resfile.line_start;
> - idx++;
> - }
> - return -1;
> -}
> -
> -// prt_next_dsc() - returns detail on next DSC comment line found. Retu=
rns true
> -// if a DSC comment is found, else false
> - static int
> -prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
> -{
> - int comment;
> - int offset;
> -
> - // Move to start of next line
> - if (!prt_resfile_next_line())
> - return FALSE;
> -
> - // DSC comments always start %%
> - if (prt_resfile_strncmp(0, "%%", 2) !=3D 0)
> - return FALSE;
> -
> - // Find type of DSC comment
> - for (comment =3D 0; comment < (int)ARRAY_LENGTH(prt_dsc_table); comm=
ent++)
> - if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
> - prt_dsc_table[comment].len) =3D=3D 0)
> - break;
> -
> - if (comment !=3D ARRAY_LENGTH(prt_dsc_table))
> - {
> - // Return type of comment
> - p_dsc_line->type =3D prt_dsc_table[comment].type;
> - offset =3D prt_dsc_table[comment].len;
> - }
> - else
> - {
> - // Unrecognised DSC comment, skip to ws after comment leader
> - p_dsc_line->type =3D PRT_DSC_MISC_TYPE;
> - offset =3D prt_resfile_skip_nonws(0);
> - if (offset =3D=3D -1)
> - return FALSE;
> - }
> -
> - // Skip ws to comment value
> - offset =3D prt_resfile_skip_ws(offset);
> - if (offset =3D=3D -1)
> - return FALSE;
> -
> - p_dsc_line->string =3D &prt_resfile.buffer[prt_resfile.line_start + =
offset];
> - p_dsc_line->len =3D prt_resfile.line_end - (prt_resfile.line_start +=
offset);
> -
> - return TRUE;
> -}
> -
> -/*
> - * Improved hand crafted parser to get the type, title, and version numb=
er of a
> - * PS resource file so the file details can be added to the DSC header c=
omments.
> - */
> - static int
> -prt_open_resource(struct prt_ps_resource_S *resource)
> -{
> - int offset;
> - int seen_all;
> - int seen_title;
> - int seen_version;
> - FILE *fd_resource;
> - struct prt_dsc_line_S dsc_line;
> -
> - fd_resource =3D mch_fopen((char *)resource->filename, READBIN);
> - if (fd_resource =3D=3D NULL)
> - {
> - semsg(_(e_cant_open_file_str_3), resource->filename);
> - return FALSE;
> - }
> - CLEAR_FIELD(prt_resfile.buffer);
> -
> - // Parse first line to ensure valid resource file
> - prt_resfile.len =3D (int)fread((char *)prt_resfile.buffer, sizeof(ch=
ar_u),
> - PRT_FILE_BUFFER_LEN, fd_resource);
> - if (ferror(fd_resource))
> - {
> - semsg(_(e_cant_read_postscript_resource_file_str),
> - resource->filename);
> - fclose(fd_resource);
> - return FALSE;
> - }
> - fclose(fd_resource);
> -
> - prt_resfile.line_end =3D -1;
> - prt_resfile.line_start =3D 0;
> - if (!prt_resfile_next_line())
> - return FALSE;
> -
> - offset =3D 0;
> -
> - if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
> - (int)STRLEN_LITERAL(PRT_RESOURCE_HEADER)) !=3D 0)
> - {
> - semsg(_(e_file_str_is_not_postscript_resource_file),
> - resource->filename);
> - return FALSE;
> - }
> -
> - // Skip over any version numbers and following ws
> - offset +=3D (int)STRLEN_LITERAL(PRT_RESOURCE_HEADER);
> - offset =3D prt_resfile_skip_nonws(offset);
> - if (offset =3D=3D -1)
> - return FALSE;
> - offset =3D prt_resfile_skip_ws(offset);
> - if (offset =3D=3D -1)
> - return FALSE;
> -
> - if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
> - (int)STRLEN_LITERAL(PRT_RESOURCE_RESOURCE)) !=3D 0)
> - {
> - semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> - resource->filename);
> - return FALSE;
> - }
> - offset +=3D (int)STRLEN_LITERAL(PRT_RESOURCE_RESOURCE);
> -
> - // Decide type of resource in the file
> - if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
> - (int)STRLEN_LITERAL(PRT_RESOURCE_PROCSET)) =3D=3D 0)
> - resource->type =3D PRT_RESOURCE_TYPE_PROCSET;
> - else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
> - (int)STRLEN_LITERAL(PRT_RESOURCE_ENCODING)) =3D=3D 0)
> - resource->type =3D PRT_RESOURCE_TYPE_ENCODING;
> - else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
> - (int)STRLEN_LITERAL(PRT_RESOURCE_CMAP)) =3D=3D 0)
> - resource->type =3D PRT_RESOURCE_TYPE_CMAP;
> - else
> - {
> - semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> - resource->filename);
> - return FALSE;
> - }
> -
> - // Look for title and version of resource
> - resource->title[0] =3D '
> - resource->version[0] =3D '
> - seen_title =3D FALSE;
> - seen_version =3D FALSE;
> - seen_all =3D FALSE;
> - while (!seen_all && prt_next_dsc(&dsc_line))
> - {
> - switch (dsc_line.type)
> - {
> - case PRT_DSC_TITLE_TYPE:
> - vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
> - seen_title =3D TRUE;
> - if (seen_version)
> - seen_all =3D TRUE;
> - break;
> -
> - case PRT_DSC_VERSION_TYPE:
> - vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
> - seen_version =3D TRUE;
> - if (seen_title)
> - seen_all =3D TRUE;
> - break;
> -
> - case PRT_DSC_ENDCOMMENTS_TYPE:
> - // Won't find title or resource after this comment, stop searching
> - seen_all =3D TRUE;
> - break;
> -
> - case PRT_DSC_MISC_TYPE:
> - // Not interested in whatever comment this line had
> - break;
> - }
> - }
> -
> - if (!seen_title || !seen_version)
> - {
> - semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> - resource->filename);
> - return FALSE;
> - }
> -
> - return TRUE;
> -}
> -
> - static int
> -prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
> -{
> - // Version number m.n should match, the revision number does not mat=
ter
> - if (STRNCMP(resource->version, version, STRLEN(version)) !=3D 0)
> - {
> - semsg(_(e_str_resource_file_has_wrong_version),
> - resource->name);
> - return FALSE;
> - }
> -
> - // Other checks to be added as needed
> - return TRUE;
> -}
> -
> - static void
> -prt_dsc_start(void)
> -{
> - prt_write_string("%!PS-Adobe-3.0
> ");
> -}
> -
> - static void
> -prt_dsc_noarg(char *comment)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%%s
> ", comment);
> - prt_write_file(prt_line_buffer);
> -}
> -
> - static void
> -prt_dsc_textline(char *comment, char *text)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%%s: %s
> ", comment, text);
> - prt_write_file(prt_line_buffer);
> -}
> -
> - static void
> -prt_dsc_text(char *comment, char *text)
> -{
> - // TODO - should scan 'text' for any chars needing escaping!
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%%s: (%s)
> ", comment, text);
> - prt_write_file(prt_line_buffer);
> -}
> -
> -# define prt_dsc_atend(c) prt_dsc_text((c), "atend")
> -
> - static void
> -prt_dsc_ints(char *comment, int count, int *ints)
> -{
> - int i;
> -
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%%s:", comment);
> - prt_write_file(prt_line_buffer);
> -
> - for (i =3D 0; i < count; i++)
> - {
> - sprintf((char *)prt_line_buffer, " %d", ints[i]);
> - prt_write_file(prt_line_buffer);
> - }
> -
> - prt_write_string("
> ");
> -}
> -
> - static void
> -prt_dsc_resources(
> - char *comment, // if NULL add to previous
> - char *type,
> - char *string)
> -{
> - if (comment !=3D NULL)
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%%s: %s", comment, type);
> - else
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%+ %s", type);
> - prt_write_file(prt_line_buffer);
> -
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - " %s
> ", string);
> - prt_write_file(prt_line_buffer);
> -}
> -
> - static void
> -prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
> -{
> - int i;
> -
> - prt_dsc_resources(resource, "font",
> - ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
> - for (i =3D PRT_PS_FONT_BOLD ; i <=3D PRT_PS_FONT_BOLDOBLIQUE ; i++)
> - if (ps_font->ps_fontname[i] !=3D NULL)
> - prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
> -}
> -
> - static void
> -prt_dsc_requirements(
> - int duplex,
> - int tumble,
> - int collate,
> - int color,
> - int num_copies)
> -{
> - // Only output the comment if we need to.
> - // Note: tumble is ignored if we are not duplexing
> - if (!(duplex || collate || color || (num_copies > 1)))
> - return;
> -
> - sprintf((char *)prt_line_buffer, "%%%%Requirements:");
> - prt_write_file(prt_line_buffer);
> -
> - if (duplex)
> - {
> - prt_write_string(" duplex");
> - if (tumble)
> - prt_write_string("(tumble)");
> - }
> - if (collate)
> - prt_write_string(" collate");
> - if (color)
> - prt_write_string(" color");
> - if (num_copies > 1)
> - {
> - prt_write_string(" numcopies(");
> - // Note: no space wanted so don't use prt_write_int()
> - sprintf((char *)prt_line_buffer, "%d", num_copies);
> - prt_write_file(prt_line_buffer);
> - prt_write_string(")");
> - }
> - prt_write_string("
> ");
> -}
> -
> - static void
> -prt_dsc_docmedia(
> - char *paper_name,
> - double width,
> - double height,
> - double weight,
> - char *colour,
> - char *type)
> -{
> - vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> - "%%%%DocumentMedia: %s ", paper_name);
> - prt_write_file(prt_line_buffer);
> - prt_write_real(width, 2);
> - prt_write_real(height, 2);
> - prt_write_real(weight, 2);
> - if (colour =3D=3D NULL)
> - prt_write_string("()");
> - else
> - prt_write_string(colour);
> - prt_write_string(" ");
> - if (type =3D=3D NULL)
> - prt_write_string("()");
> - else
> - prt_write_string(type);
> - prt_write_string("
> ");
> -}
> -
> - void
> -mch_print_cleanup(void)
> -{
> - if (prt_out_mbyte)
> - {
> - int i;
> -
> - // Free off all CID font names created, but first clear duplicate
> - // pointers to the same string (when the same font is used for more tha=
n
> - // one style).
> - for (i =3D PRT_PS_FONT_ROMAN; i <=3D PRT_PS_FONT_BOLDOBLIQUE; i++)
> - {
> - if (prt_ps_mb_font.ps_fontname[i] !=3D NULL)
> - VIM_CLEAR(prt_ps_mb_font.ps_fontname[i]);
> - }
> - }
> -
> - if (prt_do_conv)
> - {
> - convert_setup(&prt_conv, NULL, NULL);
> - prt_do_conv =3D FALSE;
> - }
> - if (prt_ps_fd !=3D NULL)
> - {
> - fclose(prt_ps_fd);
> - prt_ps_fd =3D NULL;
> - prt_file_error =3D FALSE;
> - }
> - if (prt_ps_file_name !=3D NULL)
> - VIM_CLEAR(prt_ps_file_name);
> -}
> -
> - static float
> -to_device_units(int idx, double physsize, int def_number)
> -{
> - float ret;
> - int u;
> - int nr;
> -
> - u =3D prt_get_unit(idx);
> - if (u =3D=3D PRT_UNIT_NONE)
> - {
> - u =3D PRT_UNIT_PERC;
> - nr =3D def_number;
> - }
> - else
> - nr =3D printer_opts[idx].number;
> -
> - switch (u)
> - {
> - case PRT_UNIT_INCH:
> - ret =3D (float)(nr * PRT_PS_DEFAULT_DPI);
> - break;
> - case PRT_UNIT_MM:
> - ret =3D (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
> - break;
> - case PRT_UNIT_POINT:
> - ret =3D (float)nr;
> - break;
> - case PRT_UNIT_PERC:
> - default:
> - ret =3D (float)(physsize * nr) / 100;
> - break;
> - }
> -
> - return ret;
> -}
> -
> -/*
> - * Calculate margins for given width and height from printoptions settin=
gs.
> - */
> - static void
> -prt_page_margins(
> - double width,
> - double height,
> - double *left,
> - double *right,
> - double *top,
> - double *bottom)
> -{
> - *left =3D to_device_units(OPT_PRINT_LEFT, width, 10);
> - *right =3D width - to_device_units(OPT_PRINT_RIGHT, width, 5);
> - *top =3D height - to_device_units(OPT_PRINT_TOP, height, 5);
> - *bottom =3D to_device_units(OPT_PRINT_BOT, height, 5);
> -}
> -
> - static void
> -prt_font_metrics(int font_scale)
> -{
> - prt_line_height =3D (float)font_scale;
> - prt_char_width =3D (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_fon=
t->wx);
> -}
> -
> -
> - static int
> -prt_get_cpl(void)
> -{
> - if (prt_use_number())
> - {
> - prt_number_width =3D PRINT_NUMBER_WIDTH * prt_char_width;
> - // If we are outputting multi-byte characters then line numbers will be
> - // printed with half width characters
> - if (prt_out_mbyte)
> - prt_number_width /=3D 2;
> - prt_left_margin +=3D prt_number_width;
> - }
> - else
> - prt_number_width =3D 0.0;
> -
> - return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
> -}
> -
> - static int
> -prt_build_cid_fontname(int font, char_u *name, int name_len)
> -{
> - char *fontname;
> -
> - fontname =3D alloc(name_len + 1);
> - if (fontname =3D=3D NULL)
> - return FALSE;
> - vim_strncpy((char_u *)fontname, name, name_len);
> - prt_ps_mb_font.ps_fontname[font] =3D fontname;
> -
> - return TRUE;
> -}
> -
> -/*
> - * Get number of lines of text that fit on a page (excluding the header)=
.
> - */
> - static int
> -prt_get_lpp(void)
> -{
> - int lpp;
> -
> - /*
> - * Calculate offset to lower left corner of background rect based on=
actual
> - * font height (based on its bounding box) and the line height, hand=
ling the
> - * case where the font height can exceed the line height.
> - */
> - prt_bgcol_offset =3D (float)PRT_PS_FONT_TO_USER(prt_line_height,
> - prt_ps_font->bbox_min_y);
> - if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
> - {
> - prt_bgcol_offset -=3D (float)PRT_PS_FONT_TO_USER(prt_line_height,
> - (1000.0 - (prt_ps_font->bbox_max_y -
> - prt_ps_font->bbox_min_y)) / 2);
> - }
> -
> - // Get height for topmost line based on background rect offset.
> - prt_first_line_height =3D prt_line_height + prt_bgcol_offset;
> -
> - // Calculate lpp
> - lpp =3D (int)((prt_top_margin - prt_bottom_margin) / prt_line_height=
);
> -
> - // Adjust top margin if there is a header
> - prt_top_margin -=3D prt_line_height * prt_header_height();
> -
> - return lpp - prt_header_height();
> -}
> -
> - static int
> -prt_match_encoding(
> - char *p_encoding,
> - struct prt_ps_mbfont_S *p_cmap,
> - struct prt_ps_encoding_S **pp_mbenc)
> -{
> - int mbenc;
> - int enc_len;
> - struct prt_ps_encoding_S *p_mbenc;
> -
> - *pp_mbenc =3D NULL;
> - // Look for recognised encoding
> - enc_len =3D (int)STRLEN(p_encoding);
> - p_mbenc =3D p_cmap->encodings;
> - for (mbenc =3D 0; mbenc < p_cmap->num_encodings; mbenc++)
> - {
> - if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) =3D=3D 0)
> - {
> - *pp_mbenc =3D p_mbenc;
> - return TRUE;
> - }
> - p_mbenc++;
> - }
> - return FALSE;
> -}
> -
> - static int
> -prt_match_charset(
> - char *p_charset,
> - struct prt_ps_mbfont_S *p_cmap,
> - struct prt_ps_charset_S **pp_mbchar)
> -{
> - int mbchar;
> - int char_len;
> - struct prt_ps_charset_S *p_mbchar;
> -
> - // Look for recognised character set, using default if one is not gi=
ven
> - if (*p_charset =3D=3D NUL)
> - p_charset =3D p_cmap->defcs;
> - char_len =3D (int)STRLEN(p_charset);
> - p_mbchar =3D p_cmap->charsets;
> - for (mbchar =3D 0; mbchar < p_cmap->num_charsets; mbchar++)
> - {
> - if (STRNICMP(p_mbchar->charset, p_charset, char_len) =3D=3D 0)
> - {
> - *pp_mbchar =3D p_mbchar;
> - return TRUE;
> - }
> - p_mbchar++;
> - }
> - return FALSE;
> -}
> -
> - int
> -mch_print_init(
> - prt_settings_T *psettings,
> - char_u *jobname,
> - int forceit UNUSED)
> -{
> - int i;
> - char *paper_name;
> - int paper_strlen;
> - int fontsize;
> - char_u *p;
> - double left;
> - double right;
> - double top;
> - double bottom;
> - int props;
> - int cmap =3D 0;
> - char_u *p_encoding;
> - struct prt_ps_encoding_S *p_mbenc;
> - struct prt_ps_encoding_S *p_mbenc_first;
> - struct prt_ps_charset_S *p_mbchar =3D NULL;
> -
> -# if 0
> - /*
> - * TODO:
> - * If "forceit" is false: pop up a dialog to select:
> - * - printer name
> - * - copies
> - * - collated/uncollated
> - * - duplex off/long side/short side
> - * - paper size
> - * - portrait/landscape
> - * - font size
> - *
> - * If "forceit" is true: use the default printer and settings
> - */
> - if (forceit)
> - s_pd.Flags |=3D PD_RETURNDEFAULT;
> -# endif
> -
> - /*
> - * Set up font and encoding.
> - */
> - p_encoding =3D enc_skip(p_penc);
> - if (*p_encoding =3D=3D NUL)
> - p_encoding =3D enc_skip(p_enc);
> -
> - // Look for a multi-byte font that matches the encoding and characte=
r set.
> - // Only look if multi-byte character set is defined, or using multi-=
byte
> - // encoding other than Unicode. This is because a Unicode encoding =
does not
> - // uniquely identify a CJK character set to use.
> - p_mbenc =3D NULL;
> - props =3D enc_canon_props(p_encoding);
> - if (!(props & ENC_8BIT) && ((*p_pmcs !=3D NUL) || !(props & ENC_UNIC=
ODE)))
> - {
> - int cmap_first =3D 0;
> -
> - p_mbenc_first =3D NULL;
> - for (cmap =3D 0; cmap < (int)ARRAY_LENGTH(prt_ps_mbfonts); cmap++)
> - if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
> - &p_mbenc))
> - {
> - if (p_mbenc_first =3D=3D NULL)
> - {
> - p_mbenc_first =3D p_mbenc;
> - cmap_first =3D cmap;
> - }
> - if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
> - &p_mbchar))
> - break;
> - }
> -
> - // Use first encoding matched if no charset matched
> - if (p_mbchar =3D=3D NULL && p_mbenc_first !=3D NULL)
> - {
> - p_mbenc =3D p_mbenc_first;
> - cmap =3D cmap_first;
> - }
> - }
> -
> - prt_out_mbyte =3D (p_mbenc !=3D NULL);
> - if (prt_out_mbyte)
> - {
> - // Build CMap name - will be same for all multi-byte fonts used
> - prt_cmap[0] =3D NUL;
> -
> - prt_custom_cmap =3D (p_mbchar =3D=3D NULL);
> - if (!prt_custom_cmap)
> - {
> - // Check encoding and character set are compatible
> - if ((p_mbenc->needs_charset & p_mbchar->has_charset) =3D=3D 0)
> - {
> - emsg(_(e_incompatible_multi_byte_encoding_and_character_set));
> - return FALSE;
> - }
> -
> - // Add charset name if not empty
> - if (p_mbchar->cmap_charset !=3D NULL)
> - {
> - vim_strncpy((char_u *)prt_cmap,
> - (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
> - STRCAT(prt_cmap, "-");
> - }
> - }
> - else
> - {
> - // Add custom CMap character set name
> - if (*p_pmcs =3D=3D NUL)
> - {
> - emsg(_(e_printmbcharset_cannot_be_empty_with_multi_byte_encoding));
> - return FALSE;
> - }
> - vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
> - STRCAT(prt_cmap, "-");
> - }
> -
> - // CMap name ends with (optional) encoding name and -H for horizontal
> - if (p_mbenc->cmap_encoding !=3D NULL && STRLEN(prt_cmap)
> - + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
> - {
> - STRCAT(prt_cmap, p_mbenc->cmap_encoding);
> - STRCAT(prt_cmap, "-");
> - }
> - STRCAT(prt_cmap, "H");
> -
> - if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
> - {
> - emsg(_(e_no_default_font_specified_for_multi_byte_printing));
> - return FALSE;
> - }
> -
> - // Derive CID font names with fallbacks if not defined
> - if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
> - mbfont_opts[OPT_MBFONT_REGULAR].string,
> - mbfont_opts[OPT_MBFONT_REGULAR].strlen))
> - return FALSE;
> - if (mbfont_opts[OPT_MBFONT_BOLD].present)
> - if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
> - mbfont_opts[OPT_MBFONT_BOLD].string,
> - mbfont_opts[OPT_MBFONT_BOLD].strlen))
> - return FALSE;
> - if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
> - if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
> - mbfont_opts[OPT_MBFONT_OBLIQUE].string,
> - mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
> - return FALSE;
> - if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
> - if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
> - mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
> - mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
> - return FALSE;
> -
> - // Check if need to use Courier for ASCII code range, and if so pick up
> - // the encoding to use
> - prt_use_courier =3D mbfont_opts[OPT_MBFONT_USECOURIER].present &&
> - (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) =3D=3D '=
y');
> - if (prt_use_courier)
> - {
> - // Use national ASCII variant unless ASCII wanted
> - if (mbfont_opts[OPT_MBFONT_ASCII].present &&
> - (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) =3D=3D 'y'))
> - prt_ascii_encoding =3D "ascii";
> - else
> - prt_ascii_encoding =3D prt_ps_mbfonts[cmap].ascii_enc;
> - }
> -
> - prt_ps_font =3D &prt_ps_mb_font;
> - }
> - else
> - {
> - prt_use_courier =3D FALSE;
> - prt_ps_font =3D &prt_ps_courier_font;
> - }
> -
> - /*
> - * Find the size of the paper and set the margins.
> - */
> - prt_portrait =3D (!printer_opts[OPT_PRINT_PORTRAIT].present
> - || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) =3D=3D 'y=
');
> - if (printer_opts[OPT_PRINT_PAPER].present)
> - {
> - paper_name =3D (char *)printer_opts[OPT_PRINT_PAPER].string;
> - paper_strlen =3D printer_opts[OPT_PRINT_PAPER].strlen;
> - }
> - else
> - {
> - paper_name =3D "A4";
> - paper_strlen =3D 2;
> - }
> - for (i =3D 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
> - if (STRLEN(prt_mediasize[i].name) =3D=3D (unsigned)paper_strlen
> - && STRNICMP(prt_mediasize[i].name, paper_name,
> - paper_strlen) =3D=3D 0)
> - break;
> - if (i =3D=3D PRT_MEDIASIZE_LEN)
> - i =3D 0;
> - prt_media =3D i;
> -
> - /*
> - * Set PS pagesize based on media dimensions and print orientation.
> - * Note: Media and page sizes have defined meanings in PostScript an=
d should
> - * be kept distinct. Media is the paper (or transparency, or ...) t=
hat is
> - * printed on, whereas the page size is the area that the PostScript
> - * interpreter renders into.
> - */
> - if (prt_portrait)
> - {
> - prt_page_width =3D prt_mediasize[i].width;
> - prt_page_height =3D prt_mediasize[i].height;
> - }
> - else
> - {
> - prt_page_width =3D prt_mediasize[i].height;
> - prt_page_height =3D prt_mediasize[i].width;
> - }
> -
> - /*
> - * Set PS page margins based on the PS pagesize, not the mediasize -=
this
> - * needs to be done before the cpl and lpp are calculated.
> - */
> - prt_page_margins(prt_page_width, prt_page_height, &left, &right, &to=
p,
> - &bottom);
> - prt_left_margin =3D (float)left;
> - prt_right_margin =3D (float)right;
> - prt_top_margin =3D (float)top;
> - prt_bottom_margin =3D (float)bottom;
> -
> - /*
> - * Set up the font size.
> - */
> - fontsize =3D PRT_PS_DEFAULT_FONTSIZE;
> - for (p =3D p_pfn; (p =3D vim_strchr(p, ':')) !=3D NULL; ++p)
> - if (p[1] =3D=3D 'h' && VIM_ISDIGIT(p[2]))
> - fontsize =3D atoi((char *)p + 2);
> - prt_font_metrics(fontsize);
> -
> - /*
> - * Return the number of characters per line, and lines per page for =
the
> - * generic print code.
> - */
> - psettings->chars_per_line =3D prt_get_cpl();
> - psettings->lines_per_page =3D prt_get_lpp();
> -
> - // Catch margin settings that leave no space for output!
> - if (psettings->chars_per_line <=3D 0 || psettings->lines_per_page <=
=3D 0)
> - return FAIL;
> -
> - /*
> - * Sort out the number of copies to be printed. PS by default will =
do
> - * uncollated copies for you, so once we know how many uncollated co=
pies are
> - * wanted cache it away and lie to the generic code that we only wan=
t one
> - * uncollated copy.
> - */
> - psettings->n_collated_copies =3D 1;
> - psettings->n_uncollated_copies =3D 1;
> - prt_num_copies =3D 1;
> - prt_collate =3D (!printer_opts[OPT_PRINT_COLLATE].present
> - || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) =3D=3D 'y=
');
> - if (prt_collate)
> - {
> - // TODO: Get number of collated copies wanted.
> - psettings->n_collated_copies =3D 1;
> - }
> - else
> - {
> - // TODO: Get number of uncollated copies wanted and update the cached
> - // count.
> - prt_num_copies =3D 1;
> - }
> -
> - psettings->jobname =3D jobname;
> -
> - /*
> - * Set up printer duplex and tumble based on Duplex option setting -=
default
> - * is long sided duplex printing (i.e. no tumble).
> - */
> - prt_duplex =3D TRUE;
> - prt_tumble =3D FALSE;
> - psettings->duplex =3D 1;
> - if (printer_opts[OPT_PRINT_DUPLEX].present)
> - {
> - if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) =3D=3D 0)
> - {
> - prt_duplex =3D FALSE;
> - psettings->duplex =3D 0;
> - }
> - else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
> - =3D=3D 0)
> - prt_tumble =3D TRUE;
> - }
> -
> - // For now user abort not supported
> - psettings->user_abort =3D 0;
> -
> - // If the user didn't specify a file name, use a temp file.
> - if (psettings->outfile =3D=3D NULL)
> - {
> - prt_ps_file_name =3D vim_tempname('p', TRUE);
> - if (prt_ps_file_name =3D=3D NULL)
> - {
> - emsg(_(e_cant_get_temp_file_name));
> - return FAIL;
> - }
> - prt_ps_fd =3D mch_fopen((char *)prt_ps_file_name, WRITEBIN);
> - }
> - else
> - {
> - p =3D expand_env_save(psettings->outfile);
> - if (p !=3D NULL)
> - {
> - prt_ps_fd =3D mch_fopen((char *)p, WRITEBIN);
> - vim_free(p);
> - }
> - }
> - if (prt_ps_fd =3D=3D NULL)
> - {
> - emsg(_(e_cant_open_postscript_output_file));
> - mch_print_cleanup();
> - return FAIL;
> - }
> -
> - prt_bufsiz =3D psettings->chars_per_line;
> - if (prt_out_mbyte)
> - prt_bufsiz *=3D 2;
> - ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
> -
> - prt_page_num =3D 0;
> -
> - prt_attribute_change =3D FALSE;
> - prt_need_moveto =3D FALSE;
> - prt_need_font =3D FALSE;
> - prt_need_fgcol =3D FALSE;
> - prt_need_bgcol =3D FALSE;
> - prt_need_underline =3D FALSE;
> -
> - prt_file_error =3D FALSE;
> -
> - return OK;
> -}
> -
> - static int
> -prt_add_resource(struct prt_ps_resource_S *resource)
> -{
> - FILE* fd_resource;
> - char_u resource_buffer[512];
> - size_t bytes_read;
> -
> - fd_resource =3D mch_fopen((char *)resource->filename, READBIN);
> - if (fd_resource =3D=3D NULL)
> - {
> - semsg(_(e_cant_open_file_str_2), resource->filename);
> - return FALSE;
> - }
> - prt_dsc_resources("BeginResource", prt_resource_types[resource->type=
],
> - (char *)resource->title);
> -
> - prt_dsc_textline("BeginDocument", (char *)resource->filename);
> -
> - for (;;)
> - {
> - bytes_read =3D fread((char *)resource_buffer, sizeof(char_u),
> - sizeof(resource_buffer), fd_resource);
> - if (ferror(fd_resource))
> - {
> - semsg(_(e_cant_read_postscript_resource_file_str),
> - resource->filename);
> - fclose(fd_resource);
> - return FALSE;
> - }
> - if (bytes_read =3D=3D 0)
> - break;
> - prt_write_file_raw_len(resource_buffer, (int)bytes_read);
> - if (prt_file_error)
> - {
> - fclose(fd_resource);
> - return FALSE;
> - }
> - }
> - fclose(fd_resource);
> -
> - prt_dsc_noarg("EndDocument");
> -
> - prt_dsc_noarg("EndResource");
> -
> - return TRUE;
> -}
> -
> - int
> -mch_print_begin(prt_settings_T *psettings)
> -{
> - int bbox[4];
> - double left;
> - double right;
> - double top;
> - double bottom;
> - struct prt_ps_resource_S *res_prolog;
> - struct prt_ps_resource_S *res_encoding;
> - char buffer[256];
> - char_u *p_encoding;
> - struct prt_ps_resource_S *res_cidfont;
> - struct prt_ps_resource_S *res_cmap;
> - int retval =3D FALSE;
> -
> - res_prolog =3D ALLOC_ONE(struct prt_ps_resource_S);
> - res_encoding =3D ALLOC_ONE(struct prt_ps_resource_S);
> - res_cidfont =3D ALLOC_ONE(struct prt_ps_resource_S);
> - res_cmap =3D ALLOC_ONE(struct prt_ps_resource_S);
> - if (res_prolog =3D=3D NULL || res_encoding =3D=3D NULL
> - || res_cidfont =3D=3D NULL || res_cmap =3D=3D NULL)
> - goto theend;
> -
> - /*
> - * PS DSC Header comments - no PS code!
> - */
> - prt_dsc_start();
> - prt_dsc_textline("Title", (char *)psettings->jobname);
> - if (!get_user_name((char_u *)buffer, 256))
> - STRCPY(buffer, "Unknown");
> - prt_dsc_textline("For", buffer);
> - prt_dsc_textline("Creator", VIM_VERSION_LONG);
> - // Note: to ensure Clean8bit I don't think we can use LC_TIME
> -
> - prt_dsc_textline("CreationDate", get_ctime(time(NULL), FALSE));
> - prt_dsc_textline("DocumentData", "Clean8Bit");
> - prt_dsc_textline("Orientation", prt_portrait ? "Portrait" : "Landsca=
pe");
> - prt_dsc_atend("Pages");
> - prt_dsc_textline("PageOrder", "Ascend");
> - // The bbox does not change with orientation - it is always in the d=
efault
> - // user coordinate system! We have to recalculate right and bottom
> - // coordinates based on the font metrics for the bbox to be accurate=
.
> - prt_page_margins(prt_mediasize[prt_media].width,
> - prt_mediasize[prt_media].height,
> - &left, &right, &top, &bottom);
> - bbox[0] =3D (int)left;
> - if (prt_portrait)
> - {
> - // In portrait printing the fixed point is the top left corner so we
> - // derive the bbox from that point. We have the expected cpl chars
> - // across the media and lpp lines down the media.
> - bbox[1] =3D (int)(top - (psettings->lines_per_page + prt_header_height(=
))
> - * (double)prt_line_height);
> - bbox[2] =3D (int)(left + psettings->chars_per_line
> - * (double)prt_char_width + 0.5);
> - bbox[3] =3D (int)(top + 0.5);
> - }
> - else
> - {
> - // In landscape printing the fixed point is the bottom left corner so w=
e
> - // derive the bbox from that point. We have lpp chars across the media
> - // and cpl lines up the media.
> - bbox[1] =3D (int)bottom;
> - bbox[2] =3D (int)(left + ((psettings->lines_per_page
> - + prt_header_height()) * prt_line_height) + 0.5);
> - bbox[3] =3D (int)(bottom + psettings->chars_per_line
> - * (double)prt_char_width + 0.5);
> - }
> - prt_dsc_ints("BoundingBox", 4, bbox);
> - // The media width and height does not change with landscape printin=
g!
> - prt_dsc_docmedia(prt_mediasize[prt_media].name,
> - prt_mediasize[prt_media].width,
> - prt_mediasize[prt_media].height,
> - (double)0, NULL, NULL);
> - // Define fonts needed
> - if (!prt_out_mbyte || prt_use_courier)
> - prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
> - if (prt_out_mbyte)
> - {
> - prt_dsc_font_resource((prt_use_courier ? NULL
> - : "DocumentNeededResources"), &prt_ps_mb_font);
> - if (!prt_custom_cmap)
> - prt_dsc_resources(NULL, "cmap", prt_cmap);
> - }
> -
> - // Search for external resources VIM supplies
> - if (!prt_find_resource("prolog", res_prolog))
> - {
> - semsg(_(e_cant_find_postscript_resource_file_str_ps), "prolog");
> - goto theend;
> - }
> - if (!prt_open_resource(res_prolog))
> - goto theend;
> - if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
> - goto theend;
> - if (prt_out_mbyte)
> - {
> - // Look for required version of multi-byte printing procset
> - if (!prt_find_resource("cidfont", res_cidfont))
> - {
> - semsg(_(e_cant_find_postscript_resource_file_str_ps), "cidfont");
> - goto theend;
> - }
> - if (!prt_open_resource(res_cidfont))
> - goto theend;
> - if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
> - goto theend;
> - }
> -
> - // Find an encoding to use for printing.
> - // Check 'printencoding'. If not set or not found, then use 'encodin=
g'. If
> - // that cannot be found then default to "latin1".
> - // Note: VIM specific encoding header is always skipped.
> - if (!prt_out_mbyte)
> - {
> - p_encoding =3D enc_skip(p_penc);
> - if (*p_encoding =3D=3D NUL
> - || !prt_find_resource((char *)p_encoding, res_encoding))
> - {
> - // 'printencoding' not set or not supported - find alternate
> - int props;
> -
> - p_encoding =3D enc_skip(p_enc);
> - props =3D enc_canon_props(p_encoding);
> - if (!(props & ENC_8BIT)
> - || !prt_find_resource((char *)p_encoding, res_encoding))
> - // 8-bit 'encoding' is not supported
> - {
> - // Use latin1 as default printing encoding
> - p_encoding =3D (char_u *)"latin1";
> - if (!prt_find_resource((char *)p_encoding, res_encoding))
> - {
> - semsg(_(e_cant_find_postscript_resource_file_str_ps),
> - p_encoding);
> - goto theend;
> - }
> - }
> - }
> - if (!prt_open_resource(res_encoding))
> - goto theend;
> - // For the moment there are no checks on encoding resource files to
> - // perform
> - }
> - else
> - {
> - p_encoding =3D enc_skip(p_penc);
> - if (*p_encoding =3D=3D NUL)
> - p_encoding =3D enc_skip(p_enc);
> - if (prt_use_courier)
> - {
> - // Include ASCII range encoding vector
> - if (!prt_find_resource(prt_ascii_encoding, res_encoding))
> - {
> - semsg(_(e_cant_find_postscript_resource_file_str_ps),
> - prt_ascii_encoding);
> - goto theend;
> - }
> - if (!prt_open_resource(res_encoding))
> - goto theend;
> - // For the moment there are no checks on encoding resource files to
> - // perform
> - }
> - }
> -
> - prt_conv.vc_type =3D CONV_NONE;
> - if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BI=
T))
> - {
> - // Set up encoding conversion if required
> - if (FAIL =3D=3D convert_setup(&prt_conv, p_enc, p_encoding))
> - {
> - semsg(_(e_unable_to_convert_to_print_encoding_str), p_encoding);
> - goto theend;
> - }
> - prt_do_conv =3D TRUE;
> - }
> - prt_do_conv =3D prt_conv.vc_type !=3D CONV_NONE;
> -
> - if (prt_out_mbyte && prt_custom_cmap)
> - {
> - // Find user supplied CMap
> - if (!prt_find_resource(prt_cmap, res_cmap))
> - {
> - semsg(_(e_cant_find_postscript_resource_file_str_ps), prt_cmap);
> - goto theend;
> - }
> - if (!prt_open_resource(res_cmap))
> - goto theend;
> - }
> -
> - // List resources supplied
> - STRCPY(buffer, res_prolog->title);
> - STRCAT(buffer, " ");
> - STRCAT(buffer, res_prolog->version);
> - prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
> - if (prt_out_mbyte)
> - {
> - STRCPY(buffer, res_cidfont->title);
> - STRCAT(buffer, " ");
> - STRCAT(buffer, res_cidfont->version);
> - prt_dsc_resources(NULL, "procset", buffer);
> -
> - if (prt_custom_cmap)
> - {
> - STRCPY(buffer, res_cmap->title);
> - STRCAT(buffer, " ");
> - STRCAT(buffer, res_cmap->version);
> - prt_dsc_resources(NULL, "cmap", buffer);
> - }
> - }
> - if (!prt_out_mbyte || prt_use_courier)
> - {
> - STRCPY(buffer, res_encoding->title);
> - STRCAT(buffer, " ");
> - STRCAT(buffer, res_encoding->version);
> - prt_dsc_resources(NULL, "encoding", buffer);
> - }
> - prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
> -# ifdef FEAT_SYN_HL
> - psettings->do_syntax
> -# else
> - 0
> -# endif
> - , prt_num_copies);
> - prt_dsc_noarg("EndComments");
> -
> - /*
> - * PS Document page defaults
> - */
> - prt_dsc_noarg("BeginDefaults");
> -
> - // List font resources most likely common to all pages
> - if (!prt_out_mbyte || prt_use_courier)
> - prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
> - if (prt_out_mbyte)
> - {
> - prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
> - &prt_ps_mb_font);
> - if (!prt_custom_cmap)
> - prt_dsc_resources(NULL, "cmap", prt_cmap);
> - }
> -
> - // Paper will be used for all pages
> - prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
> -
> - prt_dsc_noarg("EndDefaults");
> -
> - /*
> - * PS Document prolog inclusion - all required procsets.
> - */
> - prt_dsc_noarg("BeginProlog");
> -
> - // Add required procsets - NOTE: order is important!
> - if (!prt_add_resource(res_prolog))
> - goto theend;
> - if (prt_out_mbyte)
> - {
> - // Add CID font procset, and any user supplied CMap
> - if (!prt_add_resource(res_cidfont))
> - goto theend;
> - if (prt_custom_cmap && !prt_add_resource(res_cmap))
> - goto theend;
> - }
> -
> - if (!prt_out_mbyte || prt_use_courier)
> - // There will be only one Roman font encoding to be included in the PS
> - // file.
> - if (!prt_add_resource(res_encoding))
> - goto theend;
> -
> - prt_dsc_noarg("EndProlog");
> -
> - /*
> - * PS Document setup - must appear after the prolog
> - */
> - prt_dsc_noarg("BeginSetup");
> -
> - // Device setup - page size and number of uncollated copies
> - prt_write_int((int)prt_mediasize[prt_media].width);
> - prt_write_int((int)prt_mediasize[prt_media].height);
> - prt_write_int(0);
> - prt_write_string("sps
> ");
> - prt_write_int(prt_num_copies);
> - prt_write_string("nc
> ");
> - prt_write_boolean(prt_duplex);
> - prt_write_boolean(prt_tumble);
> - prt_write_string("dt
> ");
> - prt_write_boolean(prt_collate);
> - prt_write_string("c
> ");
> -
> - // Font resource inclusion and definition
> - if (!prt_out_mbyte || prt_use_courier)
> - {
> - // When using Courier for ASCII range when printing multi-byte, need to
> - // pick up ASCII encoding to use with it.
> - if (prt_use_courier)
> - p_encoding =3D (char_u *)prt_ascii_encoding;
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> - prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
> - prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> - prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> - prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
> - prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> - }
> - if (prt_out_mbyte)
> - {
> - // Define the CID fonts to be used in the job. Typically CJKV fonts do
> - // not have an italic form being a western style, so where no font is
> - // defined for these faces VIM falls back to an existing face.
> - // Note: if using Courier for the ASCII range then the printout will
> - // have bold/italic/bolditalic regardless of the setting of printmbfont=
.
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> - if (!prt_custom_cmap)
> - prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> - prt_def_cidfont("CF0", (int)prt_line_height,
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> -
> - if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] !=3D NULL)
> - {
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
> - if (!prt_custom_cmap)
> - prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> - prt_def_cidfont("CF1", (int)prt_line_height,
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
> - }
> - else
> - // Use ROMAN for BOLD
> - prt_dup_cidfont("CF0", "CF1");
> -
> - if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] !=3D NULL)
> - {
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> - if (!prt_custom_cmap)
> - prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> - prt_def_cidfont("CF2", (int)prt_line_height,
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> - }
> - else
> - // Use ROMAN for OBLIQUE
> - prt_dup_cidfont("CF0", "CF2");
> -
> - if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] !=3D NULL)
> - {
> - prt_dsc_resources("IncludeResource", "font",
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> - if (!prt_custom_cmap)
> - prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> - prt_def_cidfont("CF3", (int)prt_line_height,
> - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> - }
> - else
> - // Use BOLD for BOLDOBLIQUE
> - prt_dup_cidfont("CF1", "CF3");
> - }
> -
> - // Misc constant vars used for underlining and background rects
> - prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
> - prt_ps_font->uline_offset), 2);
> - prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
> - prt_ps_font->uline_width), 2);
> - prt_def_var("BO", prt_bgcol_offset, 2);
> -
> - prt_dsc_noarg("EndSetup");
> -
> - // Fail if any problems writing out to the PS file
> - retval =3D !prt_file_error;
> -
> -theend:
> - vim_free(res_prolog);
> - vim_free(res_encoding);
> - vim_free(res_cidfont);
> - vim_free(res_cmap);
> -
> - return retval;
> -}
> -
> - void
> -mch_print_end(prt_settings_T *psettings)
> -{
> - prt_dsc_noarg("Trailer");
> -
> - /*
> - * Output any info we don't know in toto until we finish
> - */
> - prt_dsc_ints("Pages", 1, &prt_page_num);
> -
> - prt_dsc_noarg("EOF");
> -
> - // Write CTRL-D to close serial communication link if used.
> - // NOTHING MUST BE WRITTEN AFTER THIS!
> - prt_write_file((char_u *)" ");
> -
> - if (!prt_file_error && psettings->outfile =3D=3D NULL
> - && !got_int && !psettings->user_abort)
> - {
> - // Close the file first.
> - if (prt_ps_fd !=3D NULL)
> - {
> - fclose(prt_ps_fd);
> - prt_ps_fd =3D NULL;
> - }
> - prt_message((char_u *)_("Sending to printer..."));
> -
> - // Not printing to a file: use 'printexpr' to print the file.
> - if (eval_printexpr(prt_ps_file_name, psettings->arguments) =3D=3D FAIL)
> - emsg(_(e_failed_to_print_postscript_file));
> - else
> - prt_message((char_u *)_("Print job sent."));
> - }
> -
> - mch_print_cleanup();
> -}
> -
> - int
> -mch_print_end_page(void)
> -{
> - prt_flush_buffer();
> -
> - prt_write_string("re sp
> ");
> -
> - prt_dsc_noarg("PageTrailer");
> -
> - return !prt_file_error;
> -}
> -
> - int
> -mch_print_begin_page(char_u *str UNUSED)
> -{
> - int page_num[2];
> -
> - prt_page_num++;
> -
> - page_num[0] =3D page_num[1] =3D prt_page_num;
> - prt_dsc_ints("Page", 2, page_num);
> -
> - prt_dsc_noarg("BeginPageSetup");
> -
> - prt_write_string("sv
> 0 g
> ");
> - prt_in_ascii =3D !prt_out_mbyte;
> - if (prt_out_mbyte)
> - prt_write_string("CF0 sf
> ");
> - else
> - prt_write_string("F0 sf
> ");
> - prt_fgcol =3D PRCOLOR_BLACK;
> - prt_bgcol =3D PRCOLOR_WHITE;
> - prt_font =3D PRT_PS_FONT_ROMAN;
> -
> - // Set up page transformation for landscape printing.
> - if (!prt_portrait)
> - {
> - prt_write_int(-((int)prt_mediasize[prt_media].width));
> - prt_write_string("sl
> ");
> - }
> -
> - prt_dsc_noarg("EndPageSetup");
> -
> - // We have reset the font attributes, force setting them again.
> - curr_bg =3D (long_u)0xffffffff;
> - curr_fg =3D (long_u)0xffffffff;
> - curr_bold =3D MAYBE;
> -
> - return !prt_file_error;
> -}
> -
> - int
> -mch_print_blank_page(void)
> -{
> - return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE)=
;
> -}
> -
> -static float prt_pos_x =3D 0;
> -static float prt_pos_y =3D 0;
> -
> - void
> -mch_print_start_line(int margin, int page_line)
> -{
> - prt_pos_x =3D prt_left_margin;
> - if (margin)
> - prt_pos_x -=3D prt_number_width;
> -
> - prt_pos_y =3D prt_top_margin - prt_first_line_height -
> - page_line * prt_line_height;
> -
> - prt_attribute_change =3D TRUE;
> - prt_need_moveto =3D TRUE;
> - prt_half_width =3D FALSE;
> -}
> -
> - int
> -mch_print_text_out(char_u *textp, int len UNUSED)
> -{
> - char_u *p =3D textp;
> - int need_break;
> - char_u ch;
> - char_u ch_buff[8];
> - float char_width;
> - float next_pos;
> - int in_ascii;
> - int half_width;
> - char_u *tofree =3D NULL;
> -
> - char_width =3D prt_char_width;
> -
> - // Ideally VIM would create a rearranged CID font to combine a Roman=
and
> - // CJKV font to do what VIM is doing here - use a Roman font for cha=
racters
> - // in the ASCII range, and the original CID font for everything else=
.
> - // The problem is that GhostScript still (as of 8.13) does not suppo=
rt
> - // rearranged fonts even though they have been documented by Adobe f=
or 7
> - // years! If they ever do, a lot of this code will disappear.
> - if (prt_use_courier)
> - {
> - in_ascii =3D (len =3D=3D 1 && *p < 0x80);
> - if (prt_in_ascii)
> - {
> - if (!in_ascii)
> - {
> - // No longer in ASCII range - need to switch font
> - prt_in_ascii =3D FALSE;
> - prt_need_font =3D TRUE;
> - prt_attribute_change =3D TRUE;
> - }
> - }
> - else if (in_ascii)
> - {
> - // Now in ASCII range - need to switch font
> - prt_in_ascii =3D TRUE;
> - prt_need_font =3D TRUE;
> - prt_attribute_change =3D TRUE;
> - }
> - }
> - if (prt_out_mbyte)
> - {
> - half_width =3D ((*mb_ptr2cells)(p) =3D=3D 1);
> - if (half_width)
> - char_width /=3D 2;
> - if (prt_half_width)
> - {
> - if (!half_width)
> - {
> - prt_half_width =3D FALSE;
> - prt_pos_x +=3D prt_char_width/4;
> - prt_need_moveto =3D TRUE;
> - prt_attribute_change =3D TRUE;
> - }
> - }
> - else if (half_width)
> - {
> - prt_half_width =3D TRUE;
> - prt_pos_x +=3D prt_char_width/4;
> - prt_need_moveto =3D TRUE;
> - prt_attribute_change =3D TRUE;
> - }
> - }
> -
> - // Output any required changes to the graphics state, after flushing=
any
> - // text buffered so far.
> - if (prt_attribute_change)
> - {
> - prt_flush_buffer();
> - // Reset count of number of chars that will be printed
> - prt_text_run =3D 0;
> -
> - if (prt_need_moveto)
> - {
> - prt_pos_x_moveto =3D prt_pos_x;
> - prt_pos_y_moveto =3D prt_pos_y;
> - prt_do_moveto =3D TRUE;
> -
> - prt_need_moveto =3D FALSE;
> - }
> - if (prt_need_font)
> - {
> - if (!prt_in_ascii)
> - prt_write_string("CF");
> - else
> - prt_write_string("F");
> - prt_write_int(prt_font);
> - prt_write_string("sf
> ");
> - prt_need_font =3D FALSE;
> - }
> - if (prt_need_fgcol)
> - {
> - int r, g, b;
> - r =3D ((unsigned)prt_fgcol & 0xff0000) >> 16;
> - g =3D ((unsigned)prt_fgcol & 0xff00) >> 8;
> - b =3D prt_fgcol & 0xff;
> -
> - prt_write_real(r / 255.0, 3);
> - if (r =3D=3D g && g =3D=3D b)
> - prt_write_string("g
> ");
> - else
> - {
> - prt_write_real(g / 255.0, 3);
> - prt_write_real(b / 255.0, 3);
> - prt_write_string("r
> ");
> - }
> - prt_need_fgcol =3D FALSE;
> - }
> -
> - if (prt_bgcol !=3D PRCOLOR_WHITE)
> - {
> - prt_new_bgcol =3D prt_bgcol;
> - if (prt_need_bgcol)
> - prt_do_bgcol =3D TRUE;
> - }
> - else
> - prt_do_bgcol =3D FALSE;
> - prt_need_bgcol =3D FALSE;
> -
> - if (prt_need_underline)
> - prt_do_underline =3D prt_underline;
> - prt_need_underline =3D FALSE;
> -
> - prt_attribute_change =3D FALSE;
> - }
> -
> - if (prt_do_conv)
> - {
> - // Convert from multi-byte to 8-bit encoding
> - tofree =3D p =3D string_convert(&prt_conv, p, &len);
> - if (p =3D=3D NULL)
> - {
> - p =3D (char_u *)"";
> - len =3D 0;
> - }
> - }
> -
> - if (prt_out_mbyte)
> - {
> - // Multi-byte character strings are represented more efficiently as hex
> - // strings when outputting clean 8 bit PS.
> - while (len-- > 0)
> - {
> - ch =3D prt_hexchar[(unsigned)(*p) >> 4];
> - ga_append(&prt_ps_buffer, ch);
> - ch =3D prt_hexchar[(*p) & 0xf];
> - ga_append(&prt_ps_buffer, ch);
> - p++;
> - }
> - }
> - else
> - {
> - // Add next character to buffer of characters to output.
> - // Note: One printed character may require several PS characters to
> - // represent it, but we only count them as one printed character.
> - ch =3D *p;
> - if (ch < 32 || ch =3D=3D '(' || ch =3D=3D ')' || ch =3D=3D '\')
> - {
> - // Convert non-printing characters to either their escape or octal
> - // sequence, ensures PS sent over a serial line does not interfere
> - // with the comms protocol.
> - ga_append(&prt_ps_buffer, '\');
> - switch (ch)
> - {
> - case BS: ga_append(&prt_ps_buffer, 'b'); break;
> - case TAB: ga_append(&prt_ps_buffer, 't'); break;
> - case NL: ga_append(&prt_ps_buffer, 'n'); break;
> - case FF: ga_append(&prt_ps_buffer, 'f'); break;
> - case CAR: ga_append(&prt_ps_buffer, 'r'); break;
> - case '(': ga_append(&prt_ps_buffer, '('); break;
> - case ')': ga_append(&prt_ps_buffer, ')'); break;
> - case '\': ga_append(&prt_ps_buffer, '\'); break;
> -
> - default:
> - sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
> - ga_append(&prt_ps_buffer, ch_buff[0]);
> - ga_append(&prt_ps_buffer, ch_buff[1]);
> - ga_append(&prt_ps_buffer, ch_buff[2]);
> - break;
> - }
> - }
> - else
> - ga_append(&prt_ps_buffer, ch);
> - }
> -
> - // Need to free any translated characters
> - vim_free(tofree);
> -
> - prt_text_run +=3D char_width;
> - prt_pos_x +=3D char_width;
> -
> - // The downside of fp - use relative error on right margin check
> - next_pos =3D prt_pos_x + prt_char_width;
> - need_break =3D (next_pos > prt_right_margin) &&
> - ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
> -
> - if (need_break)
> - prt_flush_buffer();
> -
> - return need_break;
> -}
> -
> - void
> -mch_print_set_font(int iBold, int iItalic, int iUnderline)
> -{
> - int font =3D 0;
> -
> - if (iBold)
> - font |=3D 0x01;
> - if (iItalic)
> - font |=3D 0x02;
> -
> - if (font !=3D prt_font)
> - {
> - prt_font =3D font;
> - prt_attribute_change =3D TRUE;
> - prt_need_font =3D TRUE;
> - }
> - if (prt_underline !=3D iUnderline)
> - {
> - prt_underline =3D iUnderline;
> - prt_attribute_change =3D TRUE;
> - prt_need_underline =3D TRUE;
> - }
> -}
> -
> - void
> -mch_print_set_bg(long_u bgcol)
> -{
> - prt_bgcol =3D (int)bgcol;
> - prt_attribute_change =3D TRUE;
> - prt_need_bgcol =3D TRUE;
> -}
> -
> - void
> -mch_print_set_fg(long_u fgcol)
> -{
> - if (fgcol =3D=3D (long_u)prt_fgcol)
> - return;
> -
> - prt_fgcol =3D (int)fgcol;
> - prt_attribute_change =3D TRUE;
> - prt_need_fgcol =3D TRUE;
> -}
> -
> -#endif //FEAT_POSTSCRIPT
> #endif //FEAT_PRINTER
> diff --git a/src/hardcopy.h b/src/hardcopy.h
> new file mode 100644
> index 000000000..0d8d6e574
> --- /dev/null
> +++ b/src/hardcopy.h
> @@ -0,0 +1,46 @@
> +/* vi:set ts=3D8 sts=3D4 sw=3D4 noet:
> + *
> + * VIM - Vi IMproved by Bram Moolenaar
> + *
> + * Do ":help uganda" in Vim to read copying and usage conditions.
> + * Do ":help credits" in Vim to see a list of people who contributed.
> + * See README.txt for an overview of the Vim source code.
> + */
> +
> +/*
> + * hardcopy.h: common stuff for hardcopy feature
> + */
> +
> +#ifndef HARDCOPY_H
> +#define HARDCOPY_H
> +
> +#include "vim.h"
> +
> +#if defined(FEAT_PRINTER)
> +
> +# define PRCOLOR_BLACK (long_u)0
> +# define PRCOLOR_WHITE (long_u)0xFFFFFFL
> +
> +extern int prt_curr_italic;
> +extern int prt_curr_bold;
> +extern int prt_curr_underline;
> +extern long_u prt_curr_bg;
> +extern long_u prt_curr_fg;
> +extern int prt_page_count;
> +
> +# if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> +typedef struct
> +{
> + char *name;
> + double width; // Width and height in points for portrait
> + double height;
> +} prt_mediasize_T;
> +
> +# define PRT_MEDIASIZE_LEN 14
> +
> +extern prt_mediasize_T prt_mediasize[PRT_MEDIASIZE_LEN];
> +# endif
> +
> +#endif
> +
> +#endif
> diff --git a/src/hardcopy_pango.c b/src/hardcopy_pango.c
> new file mode 100644
> index 000000000..e3d46a57b
> --- /dev/null
> +++ b/src/hardcopy_pango.c
> @@ -0,0 +1,783 @@
> +/* vi:set ts=3D8 sts=3D4 sw=3D4 noet:
> + *
> + * VIM - Vi IMproved by Bram Moolenaar
> + *
> + * Do ":help uganda" in Vim to read copying and usage conditions.
> + * Do ":help credits" in Vim to see a list of people who contributed.
> + * See README.txt for an overview of the Vim source code.
> + */
> +
> +/*
> + * See https://www.cairographics.org/documentation/using_the_postscript_=
surface/
> + * for information about Cairo's postscript backend.
> + *
> + * Related:
> + * https://www.cairographics.org/manual/cairo-PDF-Surfaces.html#cairo-pd=
f-surface-set-size
> + */
> +
> +#include "vim.h"
> +#include "version.h"
> +
> +#ifdef FEAT_PRINT_PANGO
> +
> +#include "hardcopy.h"
> +#include "hardcopy_pango.h"
> +
> +#include <cairo/cairo-ps.h>
> +#include <cairo/cairo-pdf.h>
> +#include <pango/pango.h>
> +#include <pango/pangocairo.h>
> +
> +#define PRINT_DPI 72.0
> +
> +#define PRT_DRAW_BOLD 1
> +#define PRT_DRAW_ITALIC 2
> +#define PRT_DRAW_UNDERLINE 4
> +
> +#define GET_Y(l) (pctx.top_margin + (l) * pctx.char_height)
> +#define GET_TEXT_Y(l) (GET_Y(l) + pctx.char_ascent)
> +
> +typedef enum
> +{
> + PRT_FORMAT_PS, // Postscript
> + PRT_FORMAT_PDF, // PDF
> +} prt_format_T;
> +
> +/*
> + * Global state for printing
> + */
> +static struct
> +{
> + // Cairo surface to draw on. Note that surface is scaled in points (=
1/72 of
> + // an inch), for all formats.
> + cairo_surface_t *surface;
> + cairo_t *cr;
> + PangoContext *text_context;
> +
> + PangoFontDescription *font;
> +
> + char_u *filename;
> +
> + int media;
> + bool portrait;
> + bool collate;
> + bool duplex;
> + bool tumble; // Short edge duplex
> +
> + prt_format_T format;
> +
> + double char_width;
> + double char_ascent;
> + double char_height;
> + double line_spacing;
> + double ul_pos;
> + double ul_thickness;
> +
> + double page_width;
> + double page_height;
> +
> + double left_margin;
> + double right_margin;
> + double top_margin;
> + double bottom_margin;
> +
> + double number_width;
> +
> + // Current position to draw from
> + double cur_x;
> + int cur_line;
> + long_u cur_fg;
> + long_u cur_bg;
> +
> + char_u draw_flags;
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + bool dialog;
> +#endif
> +} pctx;
> +
> +static const char *print_formats[] =3D {
> + [PRT_FORMAT_PS] =3D "postscript",
> + [PRT_FORMAT_PDF] =3D "pdf",
> +};
> +
> +/*
> + * Convert the margin specified in "idx" to device units. "physsize" is =
the size
> + * (width or height).
> + */
> + static double
> +to_device_units(int idx, double physsize, int def_number)
> +{
> + float ret;
> + int u;
> + int nr;
> +
> + u =3D prt_get_unit(idx);
> + if (u =3D=3D PRT_UNIT_NONE)
> + {
> + u =3D PRT_UNIT_PERC;
> + nr =3D def_number;
> + }
> + else
> + nr =3D printer_opts[idx].number;
> +
> + switch (u)
> + {
> + case PRT_UNIT_INCH:
> + ret =3D (nr * PRINT_DPI);
> + break;
> + case PRT_UNIT_MM:
> + ret =3D (nr * PRINT_DPI) / 25.4;
> + break;
> + case PRT_UNIT_POINT:
> + ret =3D (double)nr;
> + break;
> + case PRT_UNIT_PERC:
> + default:
> + ret =3D physsize * (nr / 100.0);
> + break;
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Calculate margins for given width and height from printoptions settin=
gs.
> + */
> + static void
> +get_page_margins(
> + double width,
> + double height,
> + double *left,
> + double *right,
> + double *top,
> + double *bottom)
> +{
> + *left =3D to_device_units(OPT_PRINT_LEFT, width, 10);
> + *right =3D width - to_device_units(OPT_PRINT_RIGHT, width, 5);
> +
> + *top =3D to_device_units(OPT_PRINT_TOP, height, 5);
> + *bottom =3D height - to_device_units(OPT_PRINT_BOT, height, 5);
> +}
> +
> +/*
> + * Get characters per line (excluding margins).
> + */
> + static int
> +get_cpl(void)
> +{
> + if (prt_use_number())
> + {
> + pctx.number_width =3D PRINT_NUMBER_WIDTH * pctx.char_width;
> + pctx.left_margin +=3D pctx.number_width;
> + }
> + else
> + pctx.number_width =3D 0.0;
> +
> + return (int)((pctx.right_margin - pctx.left_margin) / pctx.char_widt=
h);
> +}
> +
> +/*
> + * Get number of lines of text that fit on a page (excluding the header)=
.
> + */
> + static int
> +get_lpp(void)
> +{
> + int lpp;
> +
> + // Calculate lpp
> + lpp =3D (int)((pctx.bottom_margin - pctx.top_margin) / pctx.char_hei=
ght);
> +
> + // Adjust top margin if there is a header
> + pctx.top_margin +=3D pctx.char_height * prt_header_height();
> +
> + return lpp - prt_header_height();
> +}
> +
> +/*
> + * Get the font descrption from the given name. Returns NULL on failure.
> + */
> + static PangoFontDescription *
> +get_font(char_u *name)
> +{
> + PangoFontDescription *font;
> +
> + if (name =3D=3D NULL)
> + return NULL;
> +
> + font =3D pango_font_description_from_string((const char *)name);
> + if (font =3D=3D NULL)
> + {
> + semsg(_(e_unknown_printer_font_str), name);
> + return NULL;
> + }
> +
> + // Ensure a size is set
> + if (pango_font_description_get_size(font) <=3D 0)
> + pango_font_description_set_size(font, 10 * PANGO_SCALE);
> +
> + return font;
> +}
> +
> + int
> +mch_print_init(
> + prt_settings_T *psettings,
> + char_u *jobname,
> + int forceit UNUSED)
> +{
> + char_u *paper_name;
> + int paper_strlen;
> + bool portrait;
> + int media;
> + char_u *filename =3D NULL;
> +#ifdef USE_GTK4_PRINT_DIALOG
> + bool dialog =3D false;
> +
> + if (gui.in_use && !forceit && psettings->outfile =3D=3D NULL)
> + {
> + filename =3D gui_gtk4_print_dialog(psettings, jobname,
> + &pctx.page_width, &pctx.page_height);
> +
> + if (filename =3D=3D NULL)
> + return FAIL;
> + dialog =3D true;
> + }
> +#endif
> +
> + pctx.format =3D PRT_FORMAT_PS;
> +
> + // Let GTK handle stuff when using dialog. Not sure if our postscrip=
t DSC
> + // comments can intefere with dialog settings, but don't add them...
> +#ifdef USE_GTK4_PRINT_DIALOG
> + if (!dialog)
> +#endif
> + {
> + // Get paper type to use
> + portrait =3D (!printer_opts[OPT_PRINT_PORTRAIT].present ||
> + TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) =3D=3D 'y');
> + pctx.portrait =3D portrait;
> + if (printer_opts[OPT_PRINT_PAPER].present)
> + {
> + paper_name =3D printer_opts[OPT_PRINT_PAPER].string;
> + paper_strlen =3D printer_opts[OPT_PRINT_PAPER].strlen;
> + }
> + else
> + {
> + paper_name =3D (char_u *)"A4";
> + paper_strlen =3D 2;
> + }
> +
> + // Set width and height using given paper type
> + for (media =3D 0; media < (int)PRT_MEDIASIZE_LEN; ++media)
> + if ((int)STRLEN(prt_mediasize[media].name) =3D=3D paper_strlen
> + && STRNICMP(prt_mediasize[media].name,
> + paper_name, paper_strlen) =3D=3D 0)
> + break;
> + if (media =3D=3D PRT_MEDIASIZE_LEN)
> + media =3D 0;
> + pctx.media =3D media;
> +
> + if (portrait)
> + {
> + pctx.page_width =3D prt_mediasize[media].width;
> + pctx.page_height =3D prt_mediasize[media].height;
> + }
> + else
> + {
> + pctx.page_width =3D prt_mediasize[media].height;
> + pctx.page_height =3D prt_mediasize[media].width;
> + }
> +
> + if (printer_opts[OPT_PRINT_FORMAT].present)
> + {
> + for (int i =3D 0; i < (int)ARRAY_LENGTH(print_formats); i++)
> + if (STRNCMP(printer_opts[OPT_PRINT_FORMAT].string,
> + print_formats[i],
> + printer_opts[OPT_PRINT_FORMAT].strlen) =3D=3D 0)
> + {
> + pctx.format =3D i;
> + break;
> + }
> + }
> + }
> + psettings->user_abort =3D FALSE;
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + if (dialog)
> + // Always use PDF for dialog
> + pctx.format =3D PRT_FORMAT_PDF;
> +#endif
> +
> + if (filename =3D=3D NULL)
> + {
> + // If the user didn't specify a file name, use a temp file.
> + if (psettings->outfile =3D=3D NULL)
> + {
> + filename =3D vim_tempname('p', TRUE);
> + if (filename =3D=3D NULL)
> + {
> + emsg(_(e_cant_get_temp_file_name));
> + return FAIL;
> + }
> + }
> + else
> + filename =3D expand_env_save(psettings->outfile);
> + }
> +
> + // If using dialog, then always use PDF
> + if (pctx.format =3D=3D PRT_FORMAT_PS)
> + pctx.surface =3D cairo_ps_surface_create((const char *)filename,
> + pctx.page_width, pctx.page_height);
> + else
> + pctx.surface =3D cairo_pdf_surface_create((const char *)filename,
> + pctx.page_width, pctx.page_height);
> +
> + pctx.filename =3D (char_u *)filename;
> +
> + if (cairo_surface_status(pctx.surface) !=3D CAIRO_STATUS_SUCCESS)
> + {
> + emsg(_(e_cant_open_postscript_output_file));
> + mch_print_cleanup();
> + return FAIL;
> + }
> +
> + pctx.cr =3D cairo_create(pctx.surface);
> + pctx.text_context =3D pango_cairo_create_context(pctx.cr);
> + pctx.font =3D get_font(p_pfn);
> +
> + if (pctx.font =3D=3D NULL)
> + {
> + mch_print_cleanup();
> + return FAIL;
> + }
> +
> + pango_context_set_font_description(pctx.text_context, pctx.font);
> + // Pango DPI is 96, must adjust
> + pango_cairo_context_set_resolution(pctx.text_context, 72.0);
> +
> + // Get line height and char width
> + {
> + PangoLayout *layout;
> + PangoFontMetrics *metrics;
> + int ascent;
> + int descent;
> +
> + layout =3D pango_layout_new(pctx.text_context);
> + pango_layout_set_font_description(layout, pctx.font);
> +
> + metrics =3D pango_context_get_metrics(
> + pango_layout_get_context(layout), pctx.font, NULL);
> +
> + pctx.char_width =3D
> + (double)pango_font_metrics_get_approximate_char_width(metrics)
> + / PANGO_SCALE;
> +
> + ascent =3D pango_font_metrics_get_ascent(metrics);
> + descent =3D pango_font_metrics_get_descent(metrics);
> +
> + pctx.char_ascent =3D (double)ascent / PANGO_SCALE;
> + pctx.char_height =3D (double)(ascent + descent
> + + (PANGO_SCALE * 15.0) / 16.0) / PANGO_SCALE;
> +
> + pctx.line_spacing =3D (double)
> + (pango_font_metrics_get_height(metrics) - (ascent + descent))
> + / PANGO_SCALE;
> +
> + pctx.ul_pos =3D
> + (double)pango_font_metrics_get_underline_position(metrics)
> + / PANGO_SCALE;
> + pctx.ul_thickness =3D
> + (double)pango_font_metrics_get_underline_thickness(metrics)
> + / PANGO_SCALE;
> +
> + pango_font_metrics_unref(metrics);
> + g_object_unref(layout);
> + }
> +
> + // Calculate margins
> + {
> + double left;
> + double right;
> + double top;
> + double bottom;
> +
> + get_page_margins(pctx.page_width, pctx.page_height, &left, &right, &top=
,
> + &bottom);
> + pctx.left_margin =3D left;
> + pctx.right_margin =3D right;
> + pctx.top_margin =3D top;
> + pctx.bottom_margin =3D bottom;
> + }
> +
> + psettings->chars_per_line =3D get_cpl();
> + psettings->lines_per_page =3D get_lpp();
> +
> + // Postscript handles collating pages, don't let Vim handle it. This=
means
> + // we don't need to worry about the "jobsplit" value in 'printoption=
s'
> + psettings->n_collated_copies =3D 1;
> + psettings->n_uncollated_copies =3D 1;
> +
> + psettings->jobname =3D jobname;
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + if (!dialog)
> +#endif
> + {
> + pctx.collate =3D (!printer_opts[OPT_PRINT_COLLATE].present ||
> + TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) =3D=3D 'y');
> +
> + pctx.duplex =3D TRUE;
> + pctx.tumble =3D FALSE;
> + psettings->duplex =3D TRUE;
> + if (printer_opts[OPT_PRINT_DUPLEX].present)
> + {
> + if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) =3D=
=3D 0)
> + {
> + pctx.duplex =3D FALSE;
> + psettings->duplex =3D 0;
> + }
> + else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short",
> + 5) =3D=3D 0)
> + pctx.tumble =3D TRUE;
> + }
> + }
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + pctx.dialog =3D dialog;
> +#endif
> +
> + return OK;
> +}
> +
> +/*
> + * Emit a DSC comment, "fmt" may be NULL to indicate no arguments.
> + */
> + static void
> +emit_dsc_comment(char *comment, char *fmt, ...)
> +{
> + static char buf[257];
> +
> + va_list ap;
> + int len =3D sizeof(buf);
> + int o;
> + char *s =3D buf;
> +
> + if (fmt =3D=3D NULL)
> + {
> + o =3D vim_snprintf(s, len, "%%%%%s", comment);
> + goto exit;
> + }
> + else
> + o =3D vim_snprintf(s, len, "%%%%%s: ", comment);
> +
> + len -=3D o;
> + s +=3D o;
> + if (len <=3D 0)
> + return;
> +
> + va_start(ap, fmt);
> + vim_vsnprintf(s, len, fmt, ap);
> + va_end(ap);
> +
> +exit:
> + cairo_ps_surface_dsc_comment(pctx.surface, buf);
> +}
> +
> + int
> +mch_print_begin(prt_settings_T *psettings)
> +{
> + char user[256];
> +
> + pctx.cur_x =3D 0.0;
> + pctx.cur_line =3D 0;
> + pctx.draw_flags =3D 0;
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + if (pctx.dialog)
> + return TRUE;
> +#endif
> +
> + if (!get_user_name((char_u *)user, sizeof(user)))
> + STRCPY(user, "Unknown");
> +
> + if (pctx.format =3D=3D PRT_FORMAT_PS)
> + {
> + emit_dsc_comment("Title", (char *)psettings->jobname);
> + emit_dsc_comment("For", user);
> + emit_dsc_comment("Orientation",
> + pctx.portrait ? "Portrait" : "Landscape");
> + emit_dsc_comment("PageOrder", "Ascend");
> +
> + emit_dsc_comment("DocumentMedia",
> + "%s %.2lf %.2lf 0 () ()",
> + prt_mediasize[pctx.media].name,
> + prt_mediasize[pctx.media].width,
> + prt_mediasize[pctx.media].height);
> +
> + emit_dsc_comment("Requirements", "%s%s %s %s",
> + pctx.duplex ? "duplex" : "",
> + pctx.tumble ? "(tumble)" : "",
> + pctx.collate ? "collate" : "",
> + psettings->do_syntax ? "color" : "");
> +
> + // In defaults section (defaults for every page)
> + emit_dsc_comment("BeginDefaults", NULL);
> + emit_dsc_comment("PageMedia", prt_mediasize[pctx.media].name);
> + emit_dsc_comment("EndDefaults", NULL);
> + }
> + else if (pctx.format =3D=3D PRT_FORMAT_PDF)
> + {
> + char_u *str =3D (char_u *)user;
> +
> + if (output_conv.vc_type !=3D CONV_NONE)
> + str =3D string_convert(&output_conv, str, NULL);
> +
> + cairo_pdf_surface_set_metadata(pctx.surface,
> + CAIRO_PDF_METADATA_AUTHOR, (char *)str);
> + if (output_conv.vc_type !=3D CONV_NONE)
> + vim_free(str);
> +
> + str =3D psettings->jobname;
> + if (output_conv.vc_type !=3D CONV_NONE)
> + str =3D string_convert(&output_conv, str, NULL);
> + cairo_pdf_surface_set_metadata(pctx.surface,
> + CAIRO_PDF_METADATA_TITLE, (char *)str);
> + if (output_conv.vc_type !=3D CONV_NONE)
> + vim_free(str);
> +
> + cairo_pdf_surface_set_metadata(pctx.surface,
> + CAIRO_PDF_METADATA_CREATOR, VIM_VERSION_LONG);
> + }
> +
> + return TRUE;
> +}
> +
> + void
> +mch_print_end(prt_settings_T *psettings)
> +{
> + // Make sure surface flushes to file or stream
> + cairo_surface_finish(pctx.surface);
> +
> + if (psettings->outfile =3D=3D NULL && !got_int && !psettings->user_a=
bort
> + && pctx.filename !=3D NULL
> +#ifdef USE_GTK4_PRINT_DIALOG
> + && !pctx.dialog
> +#endif
> + )
> + {
> + msg(_("Sending to printer..."));
> +
> + // Not printing to a file: use 'printexpr' to print the file.
> + if (eval_printexpr(pctx.filename, psettings->arguments) =3D=3D FAIL)
> + emsg(_(e_failed_to_print_postscript_file));
> + else
> + msg(_("Print job sent."));
> + }
> +
> + mch_print_cleanup();
> +}
> +
> + int
> +mch_print_end_page(void)
> +{
> + cairo_show_page(pctx.cr);
> + return TRUE;
> +}
> +
> +/*
> + * Do nothing because we create a new page for the cairo surface at the =
end of
> + * every page.
> + */
> + int
> +mch_print_begin_page(char_u *str UNUSED)
> +{
> + return TRUE;
> +}
> +
> + int
> +mch_print_blank_page(void)
> +{
> + mch_print_end_page();
> + return TRUE;
> +}
> +
> + void
> +mch_print_start_line(int margin, int page_line)
> +{
> + pctx.cur_x =3D pctx.left_margin;
> + if (margin)
> + pctx.cur_x -=3D pctx.number_width;
> +
> + pctx.cur_line =3D page_line;
> +}
> +
> + static void
> +long_to_rgb(long_u c, double *r, double *g, double *b)
> +{
> + *r =3D ((c >> 16) & 0xFF) / 255.0;
> + *g =3D ((c >> 8) & 0xFF) / 255.0;
> + *b =3D ((c >> 0) & 0xFF) / 255.0;
> +}
> +
> +/*
> + * Don't use PangoLayout for rendering the text, so that we can handle t=
he
> + * positioning and sizing ourselves.
> + */
> + int
> +mch_print_text_out(char_u *textp, int len)
> +{
> + PangoAttrList *attr_list;
> + GList *item_list;
> + PangoGlyphString *glyphs;
> + char_u *str;
> + double r, g, b;
> + double width =3D 0;
> + double next_x;
> +
> + // Always convert to UTF-8, Pango expects that
> + if (output_conv.vc_type =3D=3D CONV_NONE)
> + str =3D textp;
> + else
> + str =3D string_convert(&output_conv, textp, &len);
> +
> + if (str =3D=3D NULL)
> + return TRUE;
> +
> + attr_list =3D pango_attr_list_new();
> +
> +#define INSERT_PANGO_ATTR(Attribute, AttrList, Start, End) \
> + G_STMT_START{ \
> + PangoAttribute *tmp_attr_; \
> + tmp_attr_ =3D (Attribute); \
> + tmp_attr_->start_index =3D (Start); \
> + tmp_attr_->end_index =3D (End); \
> + pango_attr_list_insert((AttrList), tmp_attr_); \
> + }G_STMT_END
> +
> + // Underline attribute does not work with pango_itemize().
> + if ((pctx.draw_flags & PRT_DRAW_BOLD))
> + INSERT_PANGO_ATTR(pango_attr_weight_new(PANGO_WEIGHT_BOLD),
> + attr_list, 0, len);
> + if (pctx.draw_flags & PRT_DRAW_ITALIC)
> + INSERT_PANGO_ATTR(pango_attr_style_new(PANGO_STYLE_ITALIC),
> + attr_list, 0, len);
> +
> +#undef INSERT_PANGO_ATTR
> +
> + item_list =3D pango_itemize(pctx.text_context,
> + (const char *)str, 0, len, attr_list, NULL);
> + pango_attr_list_unref(attr_list);
> +
> + glyphs =3D pango_glyph_string_new();
> +
> + // Loop is probably unecessary, because "str" represents a single ch=
aracter.
> + // Do it anyways to be sure.
> + while (item_list !=3D NULL)
> + {
> + PangoItem *item;
> + double o;
> +
> + item =3D (PangoItem *)item_list->data;
> + item_list =3D g_list_delete_link(item_list, item_list);
> +
> + pango_shape_full((const char *)str + item->offset, item->length,
> + (const char *)str, len, &item->analysis, glyphs);
> +
> + // Benefit of directly getting the width instead of deriving it from th=
e
> + // char width and number of cells, is that non-monospace fonts look
> + // better.
> + o =3D (double)pango_glyph_string_get_width(glyphs) / PANGO_SCALE;
> +
> + // Draw background color (only if different). Cannot batch bg color,
> + // because then we would overwrite glyphs.
> + if (pctx.cur_bg !=3D PRCOLOR_WHITE)
> + {
> + long_to_rgb(pctx.cur_bg, &r, &g, &b);
> + cairo_set_source_rgb(pctx.cr, r, g, b);
> + cairo_rectangle(pctx.cr, pctx.cur_x + width,
> + GET_Y(pctx.cur_line) - pctx.line_spacing, o, pctx.char_height);
> + cairo_fill(pctx.cr);
> + }
> +
> + // Draw actual text
> + long_to_rgb(pctx.cur_fg, &r, &g, &b);
> + cairo_set_source_rgb(pctx.cr, r, g, b);
> + cairo_move_to(pctx.cr, pctx.cur_x + width, GET_TEXT_Y(pctx.cur_line));
> + pango_cairo_show_glyph_string(pctx.cr, item->analysis.font, glyphs);
> +
> + pango_item_free(item);
> + width +=3D o;
> + }
> +
> + // Draw underline if needed
> + if (pctx.draw_flags & PRT_DRAW_UNDERLINE)
> + {
> + double y =3D GET_TEXT_Y(pctx.cur_line) - pctx.ul_pos;
> +
> + long_to_rgb(pctx.cur_fg, &r, &g, &b);
> + cairo_set_source_rgb(pctx.cr, r, g, b);
> + cairo_set_line_width(pctx.cr, pctx.ul_thickness);
> + cairo_move_to(pctx.cr, pctx.cur_x, y);
> + cairo_line_to(pctx.cr, pctx.cur_x + width, y);
> + cairo_stroke(pctx.cr);
> + }
> +
> + pango_glyph_string_free(glyphs);
> +
> + pctx.cur_x +=3D width;
> +
> + next_x =3D pctx.cur_x + pctx.char_width;
> +
> + if (output_conv.vc_type !=3D CONV_NONE)
> + vim_free(str);
> +
> + // Use epsilon when comparing floating point
> + return (next_x > pctx.right_margin) &&
> + ((next_x - pctx.right_margin) > (pctx.right_margin * 1e-5));
> +}
> +
> + void
> +mch_print_set_font(int bold, int italic, int underline)
> +{
> + pctx.draw_flags =3D 0;
> +
> + if (bold)
> + pctx.draw_flags |=3D PRT_DRAW_BOLD;
> + if (italic)
> + pctx.draw_flags |=3D PRT_DRAW_ITALIC;
> + if (underline)
> + pctx.draw_flags |=3D PRT_DRAW_UNDERLINE;
> +}
> +
> + void
> +mch_print_set_bg(long_u bgcol)
> +{
> + pctx.cur_bg =3D bgcol;
> +}
> +
> + void
> +mch_print_set_fg(long_u fgcol)
> +{
> + // Probably can just call cairo_set_source_rgba() here but defer it =
later to
> + // be consistent with bg color.
> + pctx.cur_fg =3D fgcol;
> +}
> +
> + void
> +mch_print_cleanup(void)
> +{
> + g_clear_pointer(&pctx.cr, cairo_destroy);
> + g_clear_pointer(&pctx.surface, cairo_surface_destroy);
> + g_clear_object(&pctx.text_context);
> + g_clear_pointer(&pctx.font, pango_font_description_free);
> +
> +#ifdef USE_GTK4_PRINT_DIALOG
> + // If using dialog, defer the temp file deletion later
> + if (pctx.dialog)
> + gui_gtk4_print_finish();
> +#endif
> +
> + g_clear_pointer(&pctx.filename, vim_free);
> +}
> +
> +#endif // FEAT_PRINT_PANGO
> diff --git a/src/hardcopy_pango.h b/src/hardcopy_pango.h
> new file mode 100644
> index 000000000..26a4c227a
> --- /dev/null
> +++ b/src/hardcopy_pango.h
> @@ -0,0 +1,32 @@
> +/* vi:set ts=3D8 sts=3D4 sw=3D4 noet:
> + *
> + * VIM - Vi IMproved by Bram Moolenaar
> + *
> + * Do ":help uganda" in Vim to read copying and usage conditions.
> + * Do ":help credits" in Vim to see a list of people who contributed.
> + * See README.txt for an overview of the Vim source code.
> + */
> +
> +#ifndef HARDCOPY_PANGO_H
> +#define HARDCOPY_PANGO_H
> +
> +#include "vim.h"
> +
> +#if defined(FEAT_PRINT_PANGO)
> +
> +int mch_print_init(prt_settings_T *psettings, char_u *jobname, int force=
it);
> +int mch_print_begin(prt_settings_T *psettings);
> +void mch_print_end(prt_settings_T *psettings);
> +int mch_print_end_page(void);
> +int mch_print_begin_page(char_u *str);
> +int mch_print_blank_page(void);
> +void mch_print_start_line(int margin, int page_line);
> +int mch_print_text_out(char_u *textp, int len);
> +void mch_print_set_font(int bold, int italic, int underline);
> +void mch_print_set_bg(long_u bgcol);
> +void mch_print_set_fg(long_u fgcol);
> +void mch_print_cleanup(void);
> +
> +#endif
> +
> +#endif
> diff --git a/src/hardcopy_postscript.c b/src/hardcopy_postscript.c
> new file mode 100644
> index 000000000..123b9f340
> --- /dev/null
> +++ b/src/hardcopy_postscript.c
> @@ -0,0 +1,2512 @@
> +/* vi:set ts=3D8 sts=3D4 sw=3D4 noet:
> + *
> + * VIM - Vi IMproved by Bram Moolenaar
> + *
> + * Do ":help uganda" in Vim to read copying and usage conditions.
> + * Do ":help credits" in Vim to see a list of people who contributed.
> + * See README.txt for an overview of the Vim source code.
> + */
> +
> +/*
> + * PS printer stuff.
> + *
> + * Sources of information to help maintain the PS printing code:
> + *
> + * 1. PostScript Language Reference, 3rd Edition,
> + * Addison-Wesley, 1999, ISBN 0-201-37922-8
> + * 2. PostScript Language Program Design,
> + * Addison-Wesley, 1988, ISBN 0-201-14396-8
> + * 3. PostScript Tutorial and Cookbook,
> + * Addison Wesley, 1985, ISBN 0-201-10179-3
> + * 4. PostScript Language Document Structuring Conventions Specification=
,
> + * version 3.0,
> + * Adobe Technote 5001, 25th September 1992
> + * 5. PostScript Printer Description File Format Specification, Version =
4.3,
> + * Adobe technote 5003, 9th February 1996
> + * 6. Adobe Font Metrics File Format Specification, Version 4.1,
> + * Adobe Technote 5007, 7th October 1998
> + * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
> + * Adobe Technote 5014, 8th October 1996
> + * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
> + * Adoboe Technote 5094, 8th September, 2001
> + * 9. CJKV Information Processing, 2nd Edition,
> + * O'Reilly, 2002, ISBN 1-56592-224-7
> + *
> + * Some of these documents can be found in PDF form on Adobe's web site =
-
> + * http://www.adobe.com
> + */
> +
> +#include "vim.h"
> +#include "version.h"
> +
> +#ifdef FEAT_POSTSCRIPT
> +
> +# include "hardcopy.h"
> +# include "hardcopy_postscript.h"
> +
> +option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =3D
> +{
> + {"c", FALSE, 0, NULL, 0, FALSE},
> + {"a", FALSE, 0, NULL, 0, FALSE},
> + {"r", FALSE, 0, NULL, 0, FALSE},
> + {"b", FALSE, 0, NULL, 0, FALSE},
> + {"i", FALSE, 0, NULL, 0, FALSE},
> + {"o", FALSE, 0, NULL, 0, FALSE},
> +};
> +
> +# define PRT_PS_DEFAULT_DPI (72) // Default user space resolution
> +# define PRT_PS_DEFAULT_FONTSIZE (10)
> +# define PRT_PS_DEFAULT_BUFFER_SIZE (80)
> +
> +// PS font names, must be in Roman, Bold, Italic, Bold-Italic order
> +struct prt_ps_font_S
> +{
> + int wx;
> + int uline_offset;
> + int uline_width;
> + int bbox_min_y;
> + int bbox_max_y;
> + char *(ps_fontname[4]);
> +};
> +
> +# define PRT_PS_FONT_ROMAN (0)
> +# define PRT_PS_FONT_BOLD (1)
> +# define PRT_PS_FONT_OBLIQUE (2)
> +# define PRT_PS_FONT_BOLDOBLIQUE (3)
> +
> +// Standard font metrics for Courier family
> +static struct prt_ps_font_S prt_ps_courier_font =3D
> +{
> + 600,
> + -100, 50,
> + -250, 805,
> + {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"=
}
> +};
> +
> +// Generic font metrics for multi-byte fonts
> +static struct prt_ps_font_S prt_ps_mb_font =3D
> +{
> + 1000,
> + -100, 50,
> + -250, 805,
> + {NULL, NULL, NULL, NULL}
> +};
> +
> +// Pointer to current font set being used
> +static struct prt_ps_font_S* prt_ps_font;
> +
> +// Structures to map user named encoding and mapping to PS equivalents f=
or
> +// building CID font name
> +struct prt_ps_encoding_S
> +{
> + char *encoding;
> + char *cmap_encoding;
> + int needs_charset;
> +};
> +
> +struct prt_ps_charset_S
> +{
> + char *charset;
> + char *cmap_charset;
> + int has_charset;
> +};
> +
> +# define CS_JIS_C_1978 (0x01)
> +# define CS_JIS_X_1983 (0x02)
> +# define CS_JIS_X_1990 (0x04)
> +# define CS_NEC (0x08)
> +# define CS_MSWINDOWS (0x10)
> +# define CS_CP932 (0x20)
> +# define CS_KANJITALK6 (0x40)
> +# define CS_KANJITALK7 (0x80)
> +
> +// Japanese encodings and charsets
> +static struct prt_ps_encoding_S j_encodings[] =3D
> +{
> + {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_19=
90|
> + CS_NEC)},
> + {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
> + {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
> + CS_KANJITALK6|CS_KANJITALK7)},
> + {"cp932", "RKSJ", CS_JIS_X_1983},
> + {"ucs-2", "UCS2", CS_JIS_X_1990},
> + {"utf-8", "UTF8" , CS_JIS_X_1990}
> +};
> +static struct prt_ps_charset_S j_charsets[] =3D
> +{
> + {"JIS_C_1978", "78", CS_JIS_C_1978},
> + {"JIS_X_1983", NULL, CS_JIS_X_1983},
> + {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
> + {"NEC", "Ext", CS_NEC},
> + {"MSWINDOWS", "90ms", CS_MSWINDOWS},
> + {"CP932", "90ms", CS_JIS_X_1983},
> + {"KANJITALK6", "83pv", CS_KANJITALK6},
> + {"KANJITALK7", "90pv", CS_KANJITALK7}
> +};
> +
> +# define CS_GB_2312_80 (0x01)
> +# define CS_GBT_12345_90 (0x02)
> +# define CS_GBK2K (0x04)
> +# define CS_SC_MAC (0x08)
> +# define CS_GBT_90_MAC (0x10)
> +# define CS_GBK (0x20)
> +# define CS_SC_ISO10646 (0x40)
> +
> +// Simplified Chinese encodings and charsets
> +static struct prt_ps_encoding_S sc_encodings[] =3D
> +{
> + {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
> + {"gb18030", NULL, CS_GBK2K},
> + {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC=
|
> + CS_GBT_90_MAC)},
> + {"gbk", "EUC", CS_GBK},
> + {"ucs-2", "UCS2", CS_SC_ISO10646},
> + {"utf-8", "UTF8", CS_SC_ISO10646}
> +};
> +static struct prt_ps_charset_S sc_charsets[] =3D
> +{
> + {"GB_2312-80", "GB", CS_GB_2312_80},
> + {"GBT_12345-90","GBT", CS_GBT_12345_90},
> + {"MAC", "GBpc", CS_SC_MAC},
> + {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
> + {"GBK", "GBK", CS_GBK},
> + {"GB18030", "GBK2K", CS_GBK2K},
> + {"ISO10646", "UniGB", CS_SC_ISO10646}
> +};
> +
> +# define CS_CNS_PLANE_1 (0x01)
> +# define CS_CNS_PLANE_2 (0x02)
> +# define CS_CNS_PLANE_1_2 (0x04)
> +# define CS_B5 (0x08)
> +# define CS_ETEN (0x10)
> +# define CS_HK_GCCS (0x20)
> +# define CS_HK_SCS (0x40)
> +# define CS_HK_SCS_ETEN (0x80)
> +# define CS_MTHKL (0x100)
> +# define CS_MTHKS (0x200)
> +# define CS_DLHKL (0x400)
> +# define CS_DLHKS (0x800)
> +# define CS_TC_ISO10646 (0x1000)
> +
> +// Traditional Chinese encodings and charsets
> +static struct prt_ps_encoding_S tc_encodings[] =3D
> +{
> + {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
> + {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
> + {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
> + CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
> + CS_DLHKS)},
> + {"cp950", "B5", CS_B5},
> + {"ucs-2", "UCS2", CS_TC_ISO10646},
> + {"utf-8", "UTF8", CS_TC_ISO10646},
> + {"utf-16", "UTF16", CS_TC_ISO10646},
> + {"utf-32", "UTF32", CS_TC_ISO10646}
> +};
> +static struct prt_ps_charset_S tc_charsets[] =3D
> +{
> + {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
> + {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
> + {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
> + {"BIG5", NULL, CS_B5},
> + {"CP950", NULL, CS_B5},
> + {"ETEN", "ETen", CS_ETEN},
> + {"HK_GCCS", "HKgccs", CS_HK_GCCS},
> + {"SCS", "HKscs", CS_HK_SCS},
> + {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
> + {"MTHKL", "HKm471", CS_MTHKL},
> + {"MTHKS", "HKm314", CS_MTHKS},
> + {"DLHKL", "HKdla", CS_DLHKL},
> + {"DLHKS", "HKdlb", CS_DLHKS},
> + {"ISO10646", "UniCNS", CS_TC_ISO10646}
> +};
> +
> +# define CS_KR_X_1992 (0x01)
> +# define CS_KR_MAC (0x02)
> +# define CS_KR_X_1992_MS (0x04)
> +# define CS_KR_ISO10646 (0x08)
> +
> +// Korean encodings and charsets
> +static struct prt_ps_encoding_S k_encodings[] =3D
> +{
> + {"iso-2022-kr", NULL, CS_KR_X_1992},
> + {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
> + {"johab", "Johab", CS_KR_X_1992},
> + {"cp1361", "Johab", CS_KR_X_1992},
> + {"uhc", "UHC", CS_KR_X_1992_MS},
> + {"cp949", "UHC", CS_KR_X_1992_MS},
> + {"ucs-2", "UCS2", CS_KR_ISO10646},
> + {"utf-8", "UTF8", CS_KR_ISO10646}
> +};
> +static struct prt_ps_charset_S k_charsets[] =3D
> +{
> + {"KS_X_1992", "KSC", CS_KR_X_1992},
> + {"CP1361", "KSC", CS_KR_X_1992},
> + {"MAC", "KSCpc", CS_KR_MAC},
> + {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
> + {"CP949", "KSCms", CS_KR_X_1992_MS},
> + {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
> + {"ISO10646", "UniKS", CS_KR_ISO10646}
> +};
> +
> +// Collections of encodings and charsets for multi-byte printing
> +struct prt_ps_mbfont_S
> +{
> + int num_encodings;
> + struct prt_ps_encoding_S *encodings;
> + int num_charsets;
> + struct prt_ps_charset_S *charsets;
> + char *ascii_enc;
> + char *defcs;
> +};
> +
> +static struct prt_ps_mbfont_S prt_ps_mbfonts[] =3D
> +{
> + {
> + ARRAY_LENGTH(j_encodings),
> + j_encodings,
> + ARRAY_LENGTH(j_charsets),
> + j_charsets,
> + "jis_roman",
> + "JIS_X_1983"
> + },
> + {
> + ARRAY_LENGTH(sc_encodings),
> + sc_encodings,
> + ARRAY_LENGTH(sc_charsets),
> + sc_charsets,
> + "gb_roman",
> + "GB_2312-80"
> + },
> + {
> + ARRAY_LENGTH(tc_encodings),
> + tc_encodings,
> + ARRAY_LENGTH(tc_charsets),
> + tc_charsets,
> + "cns_roman",
> + "BIG5"
> + },
> + {
> + ARRAY_LENGTH(k_encodings),
> + k_encodings,
> + ARRAY_LENGTH(k_charsets),
> + k_charsets,
> + "ks_roman",
> + "KS_X_1992"
> + }
> +};
> +
> +struct prt_ps_resource_S
> +{
> + char_u name[64];
> + char_u filename[MAXPATHL + 1];
> + int type;
> + char_u title[256];
> + char_u version[256];
> +};
> +
> +// Types of PS resource file currently used
> +# define PRT_RESOURCE_TYPE_PROCSET (0)
> +# define PRT_RESOURCE_TYPE_ENCODING (1)
> +# define PRT_RESOURCE_TYPE_CMAP (2)
> +
> +// The PS prolog file version number has to match - if the prolog file i=
s
> +// updated, increment the number in the file and here. Version checking=
was
> +// added as of VIM 6.2.
> +// The CID prolog file version number behaves as per PS prolog.
> +// Table of VIM and prolog versions:
> +//
> +// VIM Prolog CIDProlog
> +// 6.2 1.3
> +// 7.0 1.4 1.0
> +# define PRT_PROLOG_VERSION ((char_u *)"1.4")
> +# define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
> +
> +// String versions of PS resource types - indexed by constants above so =
don't
> +// re-order!
> +static char *prt_resource_types[] =3D
> +{
> + "procset",
> + "encoding",
> + "cmap"
> +};
> +
> +// Strings to look for in a PS resource file
> +# define PRT_RESOURCE_HEADER "%!PS-Adobe-"
> +# define PRT_RESOURCE_RESOURCE "Resource-"
> +# define PRT_RESOURCE_PROCSET "ProcSet"
> +# define PRT_RESOURCE_ENCODING "Encoding"
> +# define PRT_RESOURCE_CMAP "CMap"
> +
> +
> +// Data for table based DSC comment recognition, easy to extend if VIM n=
eeds to
> +// read more comments.
> +# define PRT_DSC_MISC_TYPE (-1)
> +# define PRT_DSC_TITLE_TYPE (1)
> +# define PRT_DSC_VERSION_TYPE (2)
> +# define PRT_DSC_ENDCOMMENTS_TYPE (3)
> +
> +# define PRT_DSC_TITLE "%%Title:"
> +# define PRT_DSC_VERSION "%%Version:"
> +# define PRT_DSC_ENDCOMMENTS "%%EndComments:"
> +
> +struct prt_dsc_comment_S
> +{
> + char *string;
> + int len;
> + int type;
> +};
> +
> +struct prt_dsc_line_S
> +{
> + int type;
> + char_u *string;
> + int len;
> +};
> +
> +
> +# define SIZEOF_CSTR(s) (sizeof(s) - 1)
> +static struct prt_dsc_comment_S prt_dsc_table[] =3D
> +{
> + {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_=
TYPE},
> + {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
> + PRT_DSC_VERSION_TYPE},
> + {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
> + PRT_DSC_ENDCOMMENTS_TYPE}
> +};
> +
> +static void prt_write_file_len(char_u *buffer, int bytes);
> +static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
> +
> +/*
> + * Variables for the output PostScript file.
> + */
> +static FILE *prt_ps_fd;
> +static int prt_file_error;
> +static char_u *prt_ps_file_name =3D NULL;
> +
> +/*
> + * Various offsets and dimensions in default PostScript user space (poin=
ts).
> + * Used for text positioning calculations
> + */
> +static float prt_page_width;
> +static float prt_page_height;
> +static float prt_left_margin;
> +static float prt_right_margin;
> +static float prt_top_margin;
> +static float prt_bottom_margin;
> +static float prt_line_height;
> +static float prt_first_line_height;
> +static float prt_char_width;
> +static float prt_number_width;
> +static float prt_bgcol_offset;
> +static float prt_pos_x_moveto =3D 0.0;
> +static float prt_pos_y_moveto =3D 0.0;
> +
> +/*
> + * Various control variables used to decide when and how to change the
> + * PostScript graphics state.
> + */
> +static int prt_need_moveto;
> +static int prt_do_moveto;
> +static int prt_need_font;
> +static int prt_font;
> +static int prt_need_underline;
> +static int prt_underline;
> +static int prt_do_underline;
> +static int prt_need_fgcol;
> +static int prt_fgcol;
> +static int prt_need_bgcol;
> +static int prt_do_bgcol;
> +static int prt_bgcol;
> +static int prt_new_bgcol;
> +static int prt_attribute_change;
> +static float prt_text_run;
> +static int prt_page_num;
> +static int prt_bufsiz;
> +
> +/*
> + * Variables controlling physical printing.
> + */
> +static int prt_media;
> +static int prt_portrait;
> +static int prt_num_copies;
> +static int prt_duplex;
> +static int prt_tumble;
> +static int prt_collate;
> +
> +/*
> + * Buffers used when generating PostScript output
> + */
> +static char_u prt_line_buffer[257];
> +static garray_T prt_ps_buffer;
> +
> +static int prt_do_conv;
> +static vimconv_T prt_conv;
> +
> +static int prt_out_mbyte;
> +static int prt_custom_cmap;
> +static char prt_cmap[80];
> +static int prt_use_courier;
> +static int prt_in_ascii;
> +static int prt_half_width;
> +static char *prt_ascii_encoding;
> +static const char_u prt_hexchar[] =3D "0123456789abcdef";
> +
> + static void
> +prt_write_file_raw_len(char_u *buffer, int bytes)
> +{
> + if (!prt_file_error
> + && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
> + !=3D (size_t)bytes)
> + {
> + emsg(_(e_error_writing_to_postscript_output_file));
> + prt_file_error =3D TRUE;
> + }
> +}
> +
> + static void
> +prt_write_file(char_u *buffer)
> +{
> + prt_write_file_len(buffer, (int)STRLEN(buffer));
> +}
> +
> + static void
> +prt_write_file_len(char_u *buffer, int bytes)
> +{
> + prt_write_file_raw_len(buffer, bytes);
> +}
> +
> +/*
> + * Write a string.
> + */
> + static void
> +prt_write_string(char *s)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s",=
s);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write an int and a space.
> + */
> + static void
> +prt_write_int(int i)
> +{
> + sprintf((char *)prt_line_buffer, "%d ", i);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write a boolean and a space.
> + */
> + static void
> +prt_write_boolean(int b)
> +{
> + sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write PostScript to re-encode and define the font.
> + */
> + static void
> +prt_def_font(
> + char *new_name,
> + char *encoding,
> + int height,
> + char *font)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/_%s /VIM-%s /%s ref
> ", new_name, encoding, font);
> + prt_write_file(prt_line_buffer);
> + if (prt_out_mbyte)
> + sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs
> ",
> + new_name, height, 500./prt_ps_courier_font.wx, new_name);
> + else
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/%s %d /_%s ffs
> ", new_name, height, new_name);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write a line to define the CID font.
> + */
> + static void
> +prt_def_cidfont(char *new_name, int height, char *cidfont)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/_%s /%s[/%s] vim_composefont
> ", new_name, prt_cmap, cidfont);
> + prt_write_file(prt_line_buffer);
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/%s %d /_%s ffs
> ", new_name, height, new_name);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write a line to define a duplicate of a CID font
> + */
> + static void
> +prt_dup_cidfont(char *original_name, char *new_name)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/%s %s d
> ", new_name, original_name);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Convert a real value into an integer and fractional part as integers,=
with
> + * the fractional part being in the range [0,10^precision). The fractio=
nal part
> + * is also rounded based on the precision + 1'th fractional digit.
> + */
> + static void
> +prt_real_bits(
> + double real,
> + int precision,
> + int *pinteger,
> + int *pfraction)
> +{
> + int i;
> + int integer;
> + float fraction;
> +
> + integer =3D (int)real;
> + fraction =3D (float)(real - integer);
> + if (real < (double)integer)
> + fraction =3D -fraction;
> + for (i =3D 0; i < precision; i++)
> + fraction *=3D 10.0;
> +
> + *pinteger =3D integer;
> + *pfraction =3D (int)(fraction + 0.5);
> +}
> +
> +/*
> + * Write a real and a space. Save bytes if real value has no fractional=
part!
> + * We use prt_real_bits() as %f in sprintf uses the locale setting to de=
cide
> + * what decimal point character to use, but PS always requires a '.'.
> + */
> + static void
> +prt_write_real(double val, int prec)
> +{
> + int integer;
> + int fraction;
> +
> + prt_real_bits(val, prec, &integer, &fraction);
> + // Emit integer part
> + sprintf((char *)prt_line_buffer, "%d", integer);
> + prt_write_file(prt_line_buffer);
> + // Only emit fraction if necessary
> + if (fraction !=3D 0)
> + {
> + // Remove any trailing zeros
> + while ((fraction % 10) =3D=3D 0)
> + {
> + prec--;
> + fraction /=3D 10;
> + }
> + // Emit fraction left padded with zeros
> + sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
> + prt_write_file(prt_line_buffer);
> + }
> + sprintf((char *)prt_line_buffer, " ");
> + prt_write_file(prt_line_buffer);
> +}
> +
> +/*
> + * Write a line to define a numeric variable.
> + */
> + static void
> +prt_def_var(char *name, double value, int prec)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "/%s ", name);
> + prt_write_file(prt_line_buffer);
> + prt_write_real(value, prec);
> + sprintf((char *)prt_line_buffer, "d
> ");
> + prt_write_file(prt_line_buffer);
> +}
> +
> +// Convert size from font space to user space at current font scale
> +# define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0))
> +
> + static void
> +prt_flush_buffer(void)
> +{
> + if (prt_ps_buffer.ga_len <=3D 0)
> + return;
> +
> + // Any background color must be drawn first
> + if (prt_do_bgcol && (prt_new_bgcol !=3D PRCOLOR_WHITE))
> + {
> + int r, g, b;
> +
> + if (prt_do_moveto)
> + {
> + prt_write_real(prt_pos_x_moveto, 2);
> + prt_write_real(prt_pos_y_moveto, 2);
> + prt_write_string("m
> ");
> + prt_do_moveto =3D FALSE;
> + }
> +
> + // Size of rect of background color on which text is printed
> + prt_write_real(prt_text_run, 2);
> + prt_write_real(prt_line_height, 2);
> +
> + // Lastly add the color of the background
> + r =3D ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
> + g =3D ((unsigned)prt_new_bgcol & 0xff00) >> 8;
> + b =3D prt_new_bgcol & 0xff;
> + prt_write_real(r / 255.0, 3);
> + prt_write_real(g / 255.0, 3);
> + prt_write_real(b / 255.0, 3);
> + prt_write_string("bg
> ");
> + }
> + // Draw underlines before the text as it makes it slightly easier to
> + // find the starting point.
> + if (prt_do_underline)
> + {
> + if (prt_do_moveto)
> + {
> + prt_write_real(prt_pos_x_moveto, 2);
> + prt_write_real(prt_pos_y_moveto, 2);
> + prt_write_string("m
> ");
> + prt_do_moveto =3D FALSE;
> + }
> +
> + // Underline length of text run
> + prt_write_real(prt_text_run, 2);
> + prt_write_string("ul
> ");
> + }
> + // Draw the text
> + if (prt_out_mbyte)
> + prt_write_string("<");
> + else
> + prt_write_string("(");
> + prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
> + if (prt_out_mbyte)
> + prt_write_string(">");
> + else
> + prt_write_string(")");
> + // Add a moveto if need be and use the appropriate show procedure
> + if (prt_do_moveto)
> + {
> + prt_write_real(prt_pos_x_moveto, 2);
> + prt_write_real(prt_pos_y_moveto, 2);
> + // moveto and a show
> + prt_write_string("ms
> ");
> + prt_do_moveto =3D FALSE;
> + }
> + else // Simple show
> + prt_write_string("s
> ");
> +
> + ga_clear(&prt_ps_buffer);
> + ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
> +}
> +
> +
> + static void
> +prt_resource_name(char_u *filename, void *cookie)
> +{
> + char_u *resource_filename =3D cookie;
> +
> + if (STRLEN(filename) >=3D MAXPATHL)
> + *resource_filename =3D NUL;
> + else
> + STRCPY(resource_filename, filename);
> +}
> +
> + static int
> +prt_find_resource(char *name, struct prt_ps_resource_S *resource)
> +{
> + char_u *buffer;
> + int retval;
> +
> + buffer =3D alloc(MAXPATHL + 1);
> + if (buffer =3D=3D NULL)
> + return FALSE;
> +
> + vim_strncpy(resource->name, (char_u *)name, 63);
> + // Look for named resource file in runtimepath
> + STRCPY(buffer, "print");
> + add_pathsep(buffer);
> + vim_strcat(buffer, (char_u *)name, MAXPATHL);
> + vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
> + resource->filename[0] =3D NUL;
> + retval =3D (do_in_runtimepath(buffer, 0, prt_resource_name,
> + resource->filename)
> + && resource->filename[0] !=3D NUL);
> + vim_free(buffer);
> + return retval;
> +}
> +
> +// PS CR and LF characters have platform independent values
> +# define PSLF (0x0a)
> +# define PSCR (0x0d)
> +
> +// Static buffer to read initial comments in a resource file, some can h=
ave a
> +// couple of KB of comments!
> +# define PRT_FILE_BUFFER_LEN (2048)
> +struct prt_resfile_buffer_S
> +{
> + char_u buffer[PRT_FILE_BUFFER_LEN];
> + int len;
> + int line_start;
> + int line_end;
> +};
> +
> +static struct prt_resfile_buffer_S prt_resfile;
> +
> + static int
> +prt_resfile_next_line(void)
> +{
> + int idx;
> +
> + // Move to start of next line and then find end of line
> + idx =3D prt_resfile.line_end + 1;
> + while (idx < prt_resfile.len)
> + {
> + if (prt_resfile.buffer[idx] !=3D PSLF && prt_resfile.buffer[idx] !=3D P=
SCR)
> + break;
> + idx++;
> + }
> + prt_resfile.line_start =3D idx;
> +
> + while (idx < prt_resfile.len)
> + {
> + if (prt_resfile.buffer[idx] =3D=3D PSLF || prt_resfile.buffer[idx] =3D=
=3D PSCR)
> + break;
> + idx++;
> + }
> + prt_resfile.line_end =3D idx;
> +
> + return (idx < prt_resfile.len);
> +}
> +
> + static int
> +prt_resfile_strncmp(int offset, char *string, int len)
> +{
> + // Force not equal if string is longer than remainder of line
> + if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))=
)
> + return 1;
> +
> + return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
> + string, len);
> +}
> +
> + static int
> +prt_resfile_skip_nonws(int offset)
> +{
> + int idx;
> +
> + idx =3D prt_resfile.line_start + offset;
> + while (idx < prt_resfile.line_end)
> + {
> + if (SAFE_isspace(prt_resfile.buffer[idx]))
> + return idx - prt_resfile.line_start;
> + idx++;
> + }
> + return -1;
> +}
> +
> + static int
> +prt_resfile_skip_ws(int offset)
> +{
> + int idx;
> +
> + idx =3D prt_resfile.line_start + offset;
> + while (idx < prt_resfile.line_end)
> + {
> + if (!SAFE_isspace(prt_resfile.buffer[idx]))
> + return idx - prt_resfile.line_start;
> + idx++;
> + }
> + return -1;
> +}
> +
> +// prt_next_dsc() - returns detail on next DSC comment line found. Retu=
rns true
> +// if a DSC comment is found, else false
> + static int
> +prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
> +{
> + int comment;
> + int offset;
> +
> + // Move to start of next line
> + if (!prt_resfile_next_line())
> + return FALSE;
> +
> + // DSC comments always start %%
> + if (prt_resfile_strncmp(0, "%%", 2) !=3D 0)
> + return FALSE;
> +
> + // Find type of DSC comment
> + for (comment =3D 0; comment < (int)ARRAY_LENGTH(prt_dsc_table); comm=
ent++)
> + if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
> + prt_dsc_table[comment].len) =3D=3D 0)
> + break;
> +
> + if (comment !=3D ARRAY_LENGTH(prt_dsc_table))
> + {
> + // Return type of comment
> + p_dsc_line->type =3D prt_dsc_table[comment].type;
> + offset =3D prt_dsc_table[comment].len;
> + }
> + else
> + {
> + // Unrecognised DSC comment, skip to ws after comment leader
> + p_dsc_line->type =3D PRT_DSC_MISC_TYPE;
> + offset =3D prt_resfile_skip_nonws(0);
> + if (offset =3D=3D -1)
> + return FALSE;
> + }
> +
> + // Skip ws to comment value
> + offset =3D prt_resfile_skip_ws(offset);
> + if (offset =3D=3D -1)
> + return FALSE;
> +
> + p_dsc_line->string =3D &prt_resfile.buffer[prt_resfile.line_start + =
offset];
> + p_dsc_line->len =3D prt_resfile.line_end - (prt_resfile.line_start +=
offset);
> +
> + return TRUE;
> +}
> +
> +/*
> + * Improved hand crafted parser to get the type, title, and version numb=
er of a
> + * PS resource file so the file details can be added to the DSC header c=
omments.
> + */
> + static int
> +prt_open_resource(struct prt_ps_resource_S *resource)
> +{
> + int offset;
> + int seen_all;
> + int seen_title;
> + int seen_version;
> + FILE *fd_resource;
> + struct prt_dsc_line_S dsc_line;
> +
> + fd_resource =3D mch_fopen((char *)resource->filename, READBIN);
> + if (fd_resource =3D=3D NULL)
> + {
> + semsg(_(e_cant_open_file_str_3), resource->filename);
> + return FALSE;
> + }
> + CLEAR_FIELD(prt_resfile.buffer);
> +
> + // Parse first line to ensure valid resource file
> + prt_resfile.len =3D (int)fread((char *)prt_resfile.buffer, sizeof(ch=
ar_u),
> + PRT_FILE_BUFFER_LEN, fd_resource);
> + if (ferror(fd_resource))
> + {
> + semsg(_(e_cant_read_postscript_resource_file_str),
> + resource->filename);
> + fclose(fd_resource);
> + return FALSE;
> + }
> + fclose(fd_resource);
> +
> + prt_resfile.line_end =3D -1;
> + prt_resfile.line_start =3D 0;
> + if (!prt_resfile_next_line())
> + return FALSE;
> +
> + offset =3D 0;
> +
> + if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
> + (int)STRLEN_LITERAL(PRT_RESOURCE_HEADER)) !=3D 0)
> + {
> + semsg(_(e_file_str_is_not_postscript_resource_file),
> + resource->filename);
> + return FALSE;
> + }
> +
> + // Skip over any version numbers and following ws
> + offset +=3D (int)STRLEN_LITERAL(PRT_RESOURCE_HEADER);
> + offset =3D prt_resfile_skip_nonws(offset);
> + if (offset =3D=3D -1)
> + return FALSE;
> + offset =3D prt_resfile_skip_ws(offset);
> + if (offset =3D=3D -1)
> + return FALSE;
> +
> + if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
> + (int)STRLEN_LITERAL(PRT_RESOURCE_RESOURCE)) !=3D 0)
> + {
> + semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> + resource->filename);
> + return FALSE;
> + }
> + offset +=3D (int)STRLEN_LITERAL(PRT_RESOURCE_RESOURCE);
> +
> + // Decide type of resource in the file
> + if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
> + (int)STRLEN_LITERAL(PRT_RESOURCE_PROCSET)) =3D=3D 0)
> + resource->type =3D PRT_RESOURCE_TYPE_PROCSET;
> + else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
> + (int)STRLEN_LITERAL(PRT_RESOURCE_ENCODING)) =3D=3D 0)
> + resource->type =3D PRT_RESOURCE_TYPE_ENCODING;
> + else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
> + (int)STRLEN_LITERAL(PRT_RESOURCE_CMAP)) =3D=3D 0)
> + resource->type =3D PRT_RESOURCE_TYPE_CMAP;
> + else
> + {
> + semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> + resource->filename);
> + return FALSE;
> + }
> +
> + // Look for title and version of resource
> + resource->title[0] =3D '
> + resource->version[0] =3D '
> + seen_title =3D FALSE;
> + seen_version =3D FALSE;
> + seen_all =3D FALSE;
> + while (!seen_all && prt_next_dsc(&dsc_line))
> + {
> + switch (dsc_line.type)
> + {
> + case PRT_DSC_TITLE_TYPE:
> + vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
> + seen_title =3D TRUE;
> + if (seen_version)
> + seen_all =3D TRUE;
> + break;
> +
> + case PRT_DSC_VERSION_TYPE:
> + vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
> + seen_version =3D TRUE;
> + if (seen_title)
> + seen_all =3D TRUE;
> + break;
> +
> + case PRT_DSC_ENDCOMMENTS_TYPE:
> + // Won't find title or resource after this comment, stop searching
> + seen_all =3D TRUE;
> + break;
> +
> + case PRT_DSC_MISC_TYPE:
> + // Not interested in whatever comment this line had
> + break;
> + }
> + }
> +
> + if (!seen_title || !seen_version)
> + {
> + semsg(_(e_file_str_is_not_supported_postscript_resource_file),
> + resource->filename);
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> + static int
> +prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
> +{
> + // Version number m.n should match, the revision number does not mat=
ter
> + if (STRNCMP(resource->version, version, STRLEN(version)) !=3D 0)
> + {
> + semsg(_(e_str_resource_file_has_wrong_version),
> + resource->name);
> + return FALSE;
> + }
> +
> + // Other checks to be added as needed
> + return TRUE;
> +}
> +
> + static void
> +prt_dsc_start(void)
> +{
> + prt_write_string("%!PS-Adobe-3.0
> ");
> +}
> +
> + static void
> +prt_dsc_noarg(char *comment)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%%s
> ", comment);
> + prt_write_file(prt_line_buffer);
> +}
> +
> + static void
> +prt_dsc_textline(char *comment, char *text)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%%s: %s
> ", comment, text);
> + prt_write_file(prt_line_buffer);
> +}
> +
> + static void
> +prt_dsc_text(char *comment, char *text)
> +{
> + // TODO - should scan 'text' for any chars needing escaping!
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%%s: (%s)
> ", comment, text);
> + prt_write_file(prt_line_buffer);
> +}
> +
> +# define prt_dsc_atend(c) prt_dsc_text((c), "atend")
> +
> + static void
> +prt_dsc_ints(char *comment, int count, int *ints)
> +{
> + int i;
> +
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%%s:", comment);
> + prt_write_file(prt_line_buffer);
> +
> + for (i =3D 0; i < count; i++)
> + {
> + sprintf((char *)prt_line_buffer, " %d", ints[i]);
> + prt_write_file(prt_line_buffer);
> + }
> +
> + prt_write_string("
> ");
> +}
> +
> + static void
> +prt_dsc_resources(
> + char *comment, // if NULL add to previous
> + char *type,
> + char *string)
> +{
> + if (comment !=3D NULL)
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%%s: %s", comment, type);
> + else
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%+ %s", type);
> + prt_write_file(prt_line_buffer);
> +
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + " %s
> ", string);
> + prt_write_file(prt_line_buffer);
> +}
> +
> + static void
> +prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
> +{
> + int i;
> +
> + prt_dsc_resources(resource, "font",
> + ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
> + for (i =3D PRT_PS_FONT_BOLD ; i <=3D PRT_PS_FONT_BOLDOBLIQUE ; i++)
> + if (ps_font->ps_fontname[i] !=3D NULL)
> + prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
> +}
> +
> + static void
> +prt_dsc_requirements(
> + int duplex,
> + int tumble,
> + int collate,
> + int color,
> + int num_copies)
> +{
> + // Only output the comment if we need to.
> + // Note: tumble is ignored if we are not duplexing
> + if (!(duplex || collate || color || (num_copies > 1)))
> + return;
> +
> + sprintf((char *)prt_line_buffer, "%%%%Requirements:");
> + prt_write_file(prt_line_buffer);
> +
> + if (duplex)
> + {
> + prt_write_string(" duplex");
> + if (tumble)
> + prt_write_string("(tumble)");
> + }
> + if (collate)
> + prt_write_string(" collate");
> + if (color)
> + prt_write_string(" color");
> + if (num_copies > 1)
> + {
> + prt_write_string(" numcopies(");
> + // Note: no space wanted so don't use prt_write_int()
> + sprintf((char *)prt_line_buffer, "%d", num_copies);
> + prt_write_file(prt_line_buffer);
> + prt_write_string(")");
> + }
> + prt_write_string("
> ");
> +}
> +
> + static void
> +prt_dsc_docmedia(
> + char *paper_name,
> + double width,
> + double height,
> + double weight,
> + char *colour,
> + char *type)
> +{
> + vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
> + "%%%%DocumentMedia: %s ", paper_name);
> + prt_write_file(prt_line_buffer);
> + prt_write_real(width, 2);
> + prt_write_real(height, 2);
> + prt_write_real(weight, 2);
> + if (colour =3D=3D NULL)
> + prt_write_string("()");
> + else
> + prt_write_string(colour);
> + prt_write_string(" ");
> + if (type =3D=3D NULL)
> + prt_write_string("()");
> + else
> + prt_write_string(type);
> + prt_write_string("
> ");
> +}
> +
> + void
> +mch_print_cleanup(void)
> +{
> + if (prt_out_mbyte)
> + {
> + int i;
> +
> + // Free off all CID font names created, but first clear duplicate
> + // pointers to the same string (when the same font is used for more tha=
n
> + // one style).
> + for (i =3D PRT_PS_FONT_ROMAN; i <=3D PRT_PS_FONT_BOLDOBLIQUE; i++)
> + {
> + if (prt_ps_mb_font.ps_fontname[i] !=3D NULL)
> + VIM_CLEAR(prt_ps_mb_font.ps_fontname[i]);
> + }
> + }
> +
> + if (prt_do_conv)
> + {
> + convert_setup(&prt_conv, NULL, NULL);
> + prt_do_conv =3D FALSE;
> + }
> + if (prt_ps_fd !=3D NULL)
> + {
> + fclose(prt_ps_fd);
> + prt_ps_fd =3D NULL;
> + prt_file_error =3D FALSE;
> + }
> + if (prt_ps_file_name !=3D NULL)
> + VIM_CLEAR(prt_ps_file_name);
> +}
> +
> + static float
> +to_device_units(int idx, double physsize, int def_number)
> +{
> + float ret;
> + int u;
> + int nr;
> +
> + u =3D prt_get_unit(idx);
> + if (u =3D=3D PRT_UNIT_NONE)
> + {
> + u =3D PRT_UNIT_PERC;
> + nr =3D def_number;
> + }
> + else
> + nr =3D printer_opts[idx].number;
> +
> + switch (u)
> + {
> + case PRT_UNIT_INCH:
> + ret =3D (float)(nr * PRT_PS_DEFAULT_DPI);
> + break;
> + case PRT_UNIT_MM:
> + ret =3D (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
> + break;
> + case PRT_UNIT_POINT:
> + ret =3D (float)nr;
> + break;
> + case PRT_UNIT_PERC:
> + default:
> + ret =3D (float)(physsize * nr) / 100;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Calculate margins for given width and height from printoptions settin=
gs.
> + */
> + static void
> +prt_page_margins(
> + double width,
> + double height,
> + double *left,
> + double *right,
> + double *top,
> + double *bottom)
> +{
> + *left =3D to_device_units(OPT_PRINT_LEFT, width, 10);
> + *right =3D width - to_device_units(OPT_PRINT_RIGHT, width, 5);
> + *top =3D height - to_device_units(OPT_PRINT_TOP, height, 5);
> + *bottom =3D to_device_units(OPT_PRINT_BOT, height, 5);
> +}
> +
> + static void
> +prt_font_metrics(int font_scale)
> +{
> + prt_line_height =3D (float)font_scale;
> + prt_char_width =3D (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_fon=
t->wx);
> +}
> +
> +
> + static int
> +prt_get_cpl(void)
> +{
> + if (prt_use_number())
> + {
> + prt_number_width =3D PRINT_NUMBER_WIDTH * prt_char_width;
> + // If we are outputting multi-byte characters then line numbers will be
> + // printed with half width characters
> + if (prt_out_mbyte)
> + prt_number_width /=3D 2;
> + prt_left_margin +=3D prt_number_width;
> + }
> + else
> + prt_number_width =3D 0.0;
> +
> + return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
> +}
> +
> + static int
> +prt_build_cid_fontname(int font, char_u *name, int name_len)
> +{
> + char *fontname;
> +
> + fontname =3D alloc(name_len + 1);
> + if (fontname =3D=3D NULL)
> + return FALSE;
> + vim_strncpy((char_u *)fontname, name, name_len);
> + prt_ps_mb_font.ps_fontname[font] =3D fontname;
> +
> + return TRUE;
> +}
> +
> +/*
> + * Get number of lines of text that fit on a page (excluding the header)=
.
> + */
> + static int
> +prt_get_lpp(void)
> +{
> + int lpp;
> +
> + /*
> + * Calculate offset to lower left corner of background rect based on=
actual
> + * font height (based on its bounding box) and the line height, hand=
ling the
> + * case where the font height can exceed the line height.
> + */
> + prt_bgcol_offset =3D (float)PRT_PS_FONT_TO_USER(prt_line_height,
> + prt_ps_font->bbox_min_y);
> + if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
> + {
> + prt_bgcol_offset -=3D (float)PRT_PS_FONT_TO_USER(prt_line_height,
> + (1000.0 - (prt_ps_font->bbox_max_y -
> + prt_ps_font->bbox_min_y)) / 2);
> + }
> +
> + // Get height for topmost line based on background rect offset.
> + prt_first_line_height =3D prt_line_height + prt_bgcol_offset;
> +
> + // Calculate lpp
> + lpp =3D (int)((prt_top_margin - prt_bottom_margin) / prt_line_height=
);
> +
> + // Adjust top margin if there is a header
> + prt_top_margin -=3D prt_line_height * prt_header_height();
> +
> + return lpp - prt_header_height();
> +}
> +
> + static int
> +prt_match_encoding(
> + char *p_encoding,
> + struct prt_ps_mbfont_S *p_cmap,
> + struct prt_ps_encoding_S **pp_mbenc)
> +{
> + int mbenc;
> + int enc_len;
> + struct prt_ps_encoding_S *p_mbenc;
> +
> + *pp_mbenc =3D NULL;
> + // Look for recognised encoding
> + enc_len =3D (int)STRLEN(p_encoding);
> + p_mbenc =3D p_cmap->encodings;
> + for (mbenc =3D 0; mbenc < p_cmap->num_encodings; mbenc++)
> + {
> + if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) =3D=3D 0)
> + {
> + *pp_mbenc =3D p_mbenc;
> + return TRUE;
> + }
> + p_mbenc++;
> + }
> + return FALSE;
> +}
> +
> + static int
> +prt_match_charset(
> + char *p_charset,
> + struct prt_ps_mbfont_S *p_cmap,
> + struct prt_ps_charset_S **pp_mbchar)
> +{
> + int mbchar;
> + int char_len;
> + struct prt_ps_charset_S *p_mbchar;
> +
> + // Look for recognised character set, using default if one is not gi=
ven
> + if (*p_charset =3D=3D NUL)
> + p_charset =3D p_cmap->defcs;
> + char_len =3D (int)STRLEN(p_charset);
> + p_mbchar =3D p_cmap->charsets;
> + for (mbchar =3D 0; mbchar < p_cmap->num_charsets; mbchar++)
> + {
> + if (STRNICMP(p_mbchar->charset, p_charset, char_len) =3D=3D 0)
> + {
> + *pp_mbchar =3D p_mbchar;
> + return TRUE;
> + }
> + p_mbchar++;
> + }
> + return FALSE;
> +}
> +
> + int
> +mch_print_init(
> + prt_settings_T *psettings,
> + char_u *jobname,
> + int forceit UNUSED)
> +{
> + int i;
> + char *paper_name;
> + int paper_strlen;
> + int fontsize;
> + char_u *p;
> + double left;
> + double right;
> + double top;
> + double bottom;
> + int props;
> + int cmap =3D 0;
> + char_u *p_encoding;
> + struct prt_ps_encoding_S *p_mbenc;
> + struct prt_ps_encoding_S *p_mbenc_first;
> + struct prt_ps_charset_S *p_mbchar =3D NULL;
> +
> +# if 0
> + /*
> + * TODO:
> + * If "forceit" is false: pop up a dialog to select:
> + * - printer name
> + * - copies
> + * - collated/uncollated
> + * - duplex off/long side/short side
> + * - paper size
> + * - portrait/landscape
> + * - font size
> + *
> + * If "forceit" is true: use the default printer and settings
> + */
> + if (forceit)
> + s_pd.Flags |=3D PD_RETURNDEFAULT;
> +# endif
> +
> + /*
> + * Set up font and encoding.
> + */
> + p_encoding =3D enc_skip(p_penc);
> + if (*p_encoding =3D=3D NUL)
> + p_encoding =3D enc_skip(p_enc);
> +
> + // Look for a multi-byte font that matches the encoding and characte=
r set.
> + // Only look if multi-byte character set is defined, or using multi-=
byte
> + // encoding other than Unicode. This is because a Unicode encoding =
does not
> + // uniquely identify a CJK character set to use.
> + p_mbenc =3D NULL;
> + props =3D enc_canon_props(p_encoding);
> + if (!(props & ENC_8BIT) && ((*p_pmcs !=3D NUL) || !(props & ENC_UNIC=
ODE)))
> + {
> + int cmap_first =3D 0;
> +
> + p_mbenc_first =3D NULL;
> + for (cmap =3D 0; cmap < (int)ARRAY_LENGTH(prt_ps_mbfonts); cmap++)
> + if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
> + &p_mbenc))
> + {
> + if (p_mbenc_first =3D=3D NULL)
> + {
> + p_mbenc_first =3D p_mbenc;
> + cmap_first =3D cmap;
> + }
> + if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
> + &p_mbchar))
> + break;
> + }
> +
> + // Use first encoding matched if no charset matched
> + if (p_mbchar =3D=3D NULL && p_mbenc_first !=3D NULL)
> + {
> + p_mbenc =3D p_mbenc_first;
> + cmap =3D cmap_first;
> + }
> + }
> +
> + prt_out_mbyte =3D (p_mbenc !=3D NULL);
> + if (prt_out_mbyte)
> + {
> + // Build CMap name - will be same for all multi-byte fonts used
> + prt_cmap[0] =3D NUL;
> +
> + prt_custom_cmap =3D (p_mbchar =3D=3D NULL);
> + if (!prt_custom_cmap)
> + {
> + // Check encoding and character set are compatible
> + if ((p_mbenc->needs_charset & p_mbchar->has_charset) =3D=3D 0)
> + {
> + emsg(_(e_incompatible_multi_byte_encoding_and_character_set));
> + return FALSE;
> + }
> +
> + // Add charset name if not empty
> + if (p_mbchar->cmap_charset !=3D NULL)
> + {
> + vim_strncpy((char_u *)prt_cmap,
> + (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
> + STRCAT(prt_cmap, "-");
> + }
> + }
> + else
> + {
> + // Add custom CMap character set name
> + if (*p_pmcs =3D=3D NUL)
> + {
> + emsg(_(e_printmbcharset_cannot_be_empty_with_multi_byte_encoding));
> + return FALSE;
> + }
> + vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
> + STRCAT(prt_cmap, "-");
> + }
> +
> + // CMap name ends with (optional) encoding name and -H for horizontal
> + if (p_mbenc->cmap_encoding !=3D NULL && STRLEN(prt_cmap)
> + + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
> + {
> + STRCAT(prt_cmap, p_mbenc->cmap_encoding);
> + STRCAT(prt_cmap, "-");
> + }
> + STRCAT(prt_cmap, "H");
> +
> + if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
> + {
> + emsg(_(e_no_default_font_specified_for_multi_byte_printing));
> + return FALSE;
> + }
> +
> + // Derive CID font names with fallbacks if not defined
> + if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
> + mbfont_opts[OPT_MBFONT_REGULAR].string,
> + mbfont_opts[OPT_MBFONT_REGULAR].strlen))
> + return FALSE;
> + if (mbfont_opts[OPT_MBFONT_BOLD].present)
> + if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
> + mbfont_opts[OPT_MBFONT_BOLD].string,
> + mbfont_opts[OPT_MBFONT_BOLD].strlen))
> + return FALSE;
> + if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
> + if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
> + mbfont_opts[OPT_MBFONT_OBLIQUE].string,
> + mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
> + return FALSE;
> + if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
> + if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
> + mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
> + mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
> + return FALSE;
> +
> + // Check if need to use Courier for ASCII code range, and if so pick up
> + // the encoding to use
> + prt_use_courier =3D mbfont_opts[OPT_MBFONT_USECOURIER].present &&
> + (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) =3D=3D '=
y');
> + if (prt_use_courier)
> + {
> + // Use national ASCII variant unless ASCII wanted
> + if (mbfont_opts[OPT_MBFONT_ASCII].present &&
> + (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) =3D=3D 'y'))
> + prt_ascii_encoding =3D "ascii";
> + else
> + prt_ascii_encoding =3D prt_ps_mbfonts[cmap].ascii_enc;
> + }
> +
> + prt_ps_font =3D &prt_ps_mb_font;
> + }
> + else
> + {
> + prt_use_courier =3D FALSE;
> + prt_ps_font =3D &prt_ps_courier_font;
> + }
> +
> + /*
> + * Find the size of the paper and set the margins.
> + */
> + prt_portrait =3D (!printer_opts[OPT_PRINT_PORTRAIT].present
> + || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) =3D=3D 'y=
');
> + if (printer_opts[OPT_PRINT_PAPER].present)
> + {
> + paper_name =3D (char *)printer_opts[OPT_PRINT_PAPER].string;
> + paper_strlen =3D printer_opts[OPT_PRINT_PAPER].strlen;
> + }
> + else
> + {
> + paper_name =3D "A4";
> + paper_strlen =3D 2;
> + }
> + for (i =3D 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
> + if (STRLEN(prt_mediasize[i].name) =3D=3D (unsigned)paper_strlen
> + && STRNICMP(prt_mediasize[i].name, paper_name,
> + paper_strlen) =3D=3D 0)
> + break;
> + if (i =3D=3D PRT_MEDIASIZE_LEN)
> + i =3D 0;
> + prt_media =3D i;
> +
> + /*
> + * Set PS pagesize based on media dimensions and print orientation.
> + * Note: Media and page sizes have defined meanings in PostScript an=
d should
> + * be kept distinct. Media is the paper (or transparency, or ...) t=
hat is
> + * printed on, whereas the page size is the area that the PostScript
> + * interpreter renders into.
> + */
> + if (prt_portrait)
> + {
> + prt_page_width =3D prt_mediasize[i].width;
> + prt_page_height =3D prt_mediasize[i].height;
> + }
> + else
> + {
> + prt_page_width =3D prt_mediasize[i].height;
> + prt_page_height =3D prt_mediasize[i].width;
> + }
> +
> + /*
> + * Set PS page margins based on the PS pagesize, not the mediasize -=
this
> + * needs to be done before the cpl and lpp are calculated.
> + */
> + prt_page_margins(prt_page_width, prt_page_height, &left, &right, &to=
p,
> + &bottom);
> + prt_left_margin =3D (float)left;
> + prt_right_margin =3D (float)right;
> + prt_top_margin =3D (float)top;
> + prt_bottom_margin =3D (float)bottom;
> +
> + /*
> + * Set up the font size.
> + */
> + fontsize =3D PRT_PS_DEFAULT_FONTSIZE;
> + for (p =3D p_pfn; (p =3D vim_strchr(p, ':')) !=3D NULL; ++p)
> + if (p[1] =3D=3D 'h' && VIM_ISDIGIT(p[2]))
> + fontsize =3D atoi((char *)p + 2);
> + prt_font_metrics(fontsize);
> +
> + /*
> + * Return the number of characters per line, and lines per page for =
the
> + * generic print code.
> + */
> + psettings->chars_per_line =3D prt_get_cpl();
> + psettings->lines_per_page =3D prt_get_lpp();
> +
> + // Catch margin settings that leave no space for output!
> + if (psettings->chars_per_line <=3D 0 || psettings->lines_per_page <=
=3D 0)
> + return FAIL;
> +
> + /*
> + * Sort out the number of copies to be printed. PS by default will =
do
> + * uncollated copies for you, so once we know how many uncollated co=
pies are
> + * wanted cache it away and lie to the generic code that we only wan=
t one
> + * uncollated copy.
> + */
> + psettings->n_collated_copies =3D 1;
> + psettings->n_uncollated_copies =3D 1;
> + prt_num_copies =3D 1;
> + prt_collate =3D (!printer_opts[OPT_PRINT_COLLATE].present
> + || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) =3D=3D 'y=
');
> + if (prt_collate)
> + {
> + // TODO: Get number of collated copies wanted.
> + psettings->n_collated_copies =3D 1;
> + }
> + else
> + {
> + // TODO: Get number of uncollated copies wanted and update the cached
> + // count.
> + prt_num_copies =3D 1;
> + }
> +
> + psettings->jobname =3D jobname;
> +
> + /*
> + * Set up printer duplex and tumble based on Duplex option setting -=
default
> + * is long sided duplex printing (i.e. no tumble).
> + */
> + prt_duplex =3D TRUE;
> + prt_tumble =3D FALSE;
> + psettings->duplex =3D 1;
> + if (printer_opts[OPT_PRINT_DUPLEX].present)
> + {
> + if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) =3D=3D 0)
> + {
> + prt_duplex =3D FALSE;
> + psettings->duplex =3D 0;
> + }
> + else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
> + =3D=3D 0)
> + prt_tumble =3D TRUE;
> + }
> +
> + // For now user abort not supported
> + psettings->user_abort =3D 0;
> +
> + // If the user didn't specify a file name, use a temp file.
> + if (psettings->outfile =3D=3D NULL)
> + {
> + prt_ps_file_name =3D vim_tempname('p', TRUE);
> + if (prt_ps_file_name =3D=3D NULL)
> + {
> + emsg(_(e_cant_get_temp_file_name));
> + return FAIL;
> + }
> + prt_ps_fd =3D mch_fopen((char *)prt_ps_file_name, WRITEBIN);
> + }
> + else
> + {
> + p =3D expand_env_save(psettings->outfile);
> + if (p !=3D NULL)
> + {
> + prt_ps_fd =3D mch_fopen((char *)p, WRITEBIN);
> + vim_free(p);
> + }
> + }
> + if (prt_ps_fd =3D=3D NULL)
> + {
> + emsg(_(e_cant_open_postscript_output_file));
> + mch_print_cleanup();
> + return FAIL;
> + }
> +
> + prt_bufsiz =3D psettings->chars_per_line;
> + if (prt_out_mbyte)
> + prt_bufsiz *=3D 2;
> + ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
> +
> + prt_page_num =3D 0;
> +
> + prt_attribute_change =3D FALSE;
> + prt_need_moveto =3D FALSE;
> + prt_need_font =3D FALSE;
> + prt_need_fgcol =3D FALSE;
> + prt_need_bgcol =3D FALSE;
> + prt_need_underline =3D FALSE;
> +
> + prt_file_error =3D FALSE;
> +
> + return OK;
> +}
> +
> + static int
> +prt_add_resource(struct prt_ps_resource_S *resource)
> +{
> + FILE* fd_resource;
> + char_u resource_buffer[512];
> + size_t bytes_read;
> +
> + fd_resource =3D mch_fopen((char *)resource->filename, READBIN);
> + if (fd_resource =3D=3D NULL)
> + {
> + semsg(_(e_cant_open_file_str_2), resource->filename);
> + return FALSE;
> + }
> + prt_dsc_resources("BeginResource", prt_resource_types[resource->type=
],
> + (char *)resource->title);
> +
> + prt_dsc_textline("BeginDocument", (char *)resource->filename);
> +
> + for (;;)
> + {
> + bytes_read =3D fread((char *)resource_buffer, sizeof(char_u),
> + sizeof(resource_buffer), fd_resource);
> + if (ferror(fd_resource))
> + {
> + semsg(_(e_cant_read_postscript_resource_file_str),
> + resource->filename);
> + fclose(fd_resource);
> + return FALSE;
> + }
> + if (bytes_read =3D=3D 0)
> + break;
> + prt_write_file_raw_len(resource_buffer, (int)bytes_read);
> + if (prt_file_error)
> + {
> + fclose(fd_resource);
> + return FALSE;
> + }
> + }
> + fclose(fd_resource);
> +
> + prt_dsc_noarg("EndDocument");
> +
> + prt_dsc_noarg("EndResource");
> +
> + return TRUE;
> +}
> +
> + int
> +mch_print_begin(prt_settings_T *psettings)
> +{
> + int bbox[4];
> + double left;
> + double right;
> + double top;
> + double bottom;
> + struct prt_ps_resource_S *res_prolog;
> + struct prt_ps_resource_S *res_encoding;
> + char buffer[256];
> + char_u *p_encoding;
> + struct prt_ps_resource_S *res_cidfont;
> + struct prt_ps_resource_S *res_cmap;
> + int retval =3D FALSE;
> +
> + res_prolog =3D ALLOC_ONE(struct prt_ps_resource_S);
> + res_encoding =3D ALLOC_ONE(struct prt_ps_resource_S);
> + res_cidfont =3D ALLOC_ONE(struct prt_ps_resource_S);
> + res_cmap =3D ALLOC_ONE(struct prt_ps_resource_S);
> + if (res_prolog =3D=3D NULL || res_encoding =3D=3D NULL
> + || res_cidfont =3D=3D NULL || res_cmap =3D=3D NULL)
> + goto theend;
> +
> + /*
> + * PS DSC Header comments - no PS code!
> + */
> + prt_dsc_start();
> + prt_dsc_textline("Title", (char *)psettings->jobname);
> + if (!get_user_name((char_u *)buffer, 256))
> + STRCPY(buffer, "Unknown");
> + prt_dsc_textline("For", buffer);
> + prt_dsc_textline("Creator", VIM_VERSION_LONG);
> + // Note: to ensure Clean8bit I don't think we can use LC_TIME
> +
> + prt_dsc_textline("CreationDate", get_ctime(time(NULL), FALSE));
> + prt_dsc_textline("DocumentData", "Clean8Bit");
> + prt_dsc_textline("Orientation", prt_portrait ? "Portrait" : "Landsca=
pe");
> + prt_dsc_atend("Pages");
> + prt_dsc_textline("PageOrder", "Ascend");
> + // The bbox does not change with orientation - it is always in the d=
efault
> + // user coordinate system! We have to recalculate right and bottom
> + // coordinates based on the font metrics for the bbox to be accurate=
.
> + prt_page_margins(prt_mediasize[prt_media].width,
> + prt_mediasize[prt_media].height,
> + &left, &right, &top, &bottom);
> + bbox[0] =3D (int)left;
> + if (prt_portrait)
> + {
> + // In portrait printing the fixed point is the top left corner so we
> + // derive the bbox from that point. We have the expected cpl chars
> + // across the media and lpp lines down the media.
> + bbox[1] =3D (int)(top - (psettings->lines_per_page + prt_header_height(=
))
> + * (double)prt_line_height);
> + bbox[2] =3D (int)(left + psettings->chars_per_line
> + * (double)prt_char_width + 0.5);
> + bbox[3] =3D (int)(top + 0.5);
> + }
> + else
> + {
> + // In landscape printing the fixed point is the bottom left corner so w=
e
> + // derive the bbox from that point. We have lpp chars across the media
> + // and cpl lines up the media.
> + bbox[1] =3D (int)bottom;
> + bbox[2] =3D (int)(left + ((psettings->lines_per_page
> + + prt_header_height()) * prt_line_height) + 0.5);
> + bbox[3] =3D (int)(bottom + psettings->chars_per_line
> + * (double)prt_char_width + 0.5);
> + }
> + prt_dsc_ints("BoundingBox", 4, bbox);
> + // The media width and height does not change with landscape printin=
g!
> + prt_dsc_docmedia(prt_mediasize[prt_media].name,
> + prt_mediasize[prt_media].width,
> + prt_mediasize[prt_media].height,
> + (double)0, NULL, NULL);
> + // Define fonts needed
> + if (!prt_out_mbyte || prt_use_courier)
> + prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
> + if (prt_out_mbyte)
> + {
> + prt_dsc_font_resource((prt_use_courier ? NULL
> + : "DocumentNeededResources"), &prt_ps_mb_font);
> + if (!prt_custom_cmap)
> + prt_dsc_resources(NULL, "cmap", prt_cmap);
> + }
> +
> + // Search for external resources VIM supplies
> + if (!prt_find_resource("prolog", res_prolog))
> + {
> + semsg(_(e_cant_find_postscript_resource_file_str_ps), "prolog");
> + goto theend;
> + }
> + if (!prt_open_resource(res_prolog))
> + goto theend;
> + if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
> + goto theend;
> + if (prt_out_mbyte)
> + {
> + // Look for required version of multi-byte printing procset
> + if (!prt_find_resource("cidfont", res_cidfont))
> + {
> + semsg(_(e_cant_find_postscript_resource_file_str_ps), "cidfont");
> + goto theend;
> + }
> + if (!prt_open_resource(res_cidfont))
> + goto theend;
> + if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
> + goto theend;
> + }
> +
> + // Find an encoding to use for printing.
> + // Check 'printencoding'. If not set or not found, then use 'encodin=
g'. If
> + // that cannot be found then default to "latin1".
> + // Note: VIM specific encoding header is always skipped.
> + if (!prt_out_mbyte)
> + {
> + p_encoding =3D enc_skip(p_penc);
> + if (*p_encoding =3D=3D NUL
> + || !prt_find_resource((char *)p_encoding, res_encoding))
> + {
> + // 'printencoding' not set or not supported - find alternate
> + int props;
> +
> + p_encoding =3D enc_skip(p_enc);
> + props =3D enc_canon_props(p_encoding);
> + if (!(props & ENC_8BIT)
> + || !prt_find_resource((char *)p_encoding, res_encoding))
> + // 8-bit 'encoding' is not supported
> + {
> + // Use latin1 as default printing encoding
> + p_encoding =3D (char_u *)"latin1";
> + if (!prt_find_resource((char *)p_encoding, res_encoding))
> + {
> + semsg(_(e_cant_find_postscript_resource_file_str_ps),
> + p_encoding);
> + goto theend;
> + }
> + }
> + }
> + if (!prt_open_resource(res_encoding))
> + goto theend;
> + // For the moment there are no checks on encoding resource files to
> + // perform
> + }
> + else
> + {
> + p_encoding =3D enc_skip(p_penc);
> + if (*p_encoding =3D=3D NUL)
> + p_encoding =3D enc_skip(p_enc);
> + if (prt_use_courier)
> + {
> + // Include ASCII range encoding vector
> + if (!prt_find_resource(prt_ascii_encoding, res_encoding))
> + {
> + semsg(_(e_cant_find_postscript_resource_file_str_ps),
> + prt_ascii_encoding);
> + goto theend;
> + }
> + if (!prt_open_resource(res_encoding))
> + goto theend;
> + // For the moment there are no checks on encoding resource files to
> + // perform
> + }
> + }
> +
> + prt_conv.vc_type =3D CONV_NONE;
> + if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BI=
T))
> + {
> + // Set up encoding conversion if required
> + if (FAIL =3D=3D convert_setup(&prt_conv, p_enc, p_encoding))
> + {
> + semsg(_(e_unable_to_convert_to_print_encoding_str), p_encoding);
> + goto theend;
> + }
> + prt_do_conv =3D TRUE;
> + }
> + prt_do_conv =3D prt_conv.vc_type !=3D CONV_NONE;
> +
> + if (prt_out_mbyte && prt_custom_cmap)
> + {
> + // Find user supplied CMap
> + if (!prt_find_resource(prt_cmap, res_cmap))
> + {
> + semsg(_(e_cant_find_postscript_resource_file_str_ps), prt_cmap);
> + goto theend;
> + }
> + if (!prt_open_resource(res_cmap))
> + goto theend;
> + }
> +
> + // List resources supplied
> + STRCPY(buffer, res_prolog->title);
> + STRCAT(buffer, " ");
> + STRCAT(buffer, res_prolog->version);
> + prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
> + if (prt_out_mbyte)
> + {
> + STRCPY(buffer, res_cidfont->title);
> + STRCAT(buffer, " ");
> + STRCAT(buffer, res_cidfont->version);
> + prt_dsc_resources(NULL, "procset", buffer);
> +
> + if (prt_custom_cmap)
> + {
> + STRCPY(buffer, res_cmap->title);
> + STRCAT(buffer, " ");
> + STRCAT(buffer, res_cmap->version);
> + prt_dsc_resources(NULL, "cmap", buffer);
> + }
> + }
> + if (!prt_out_mbyte || prt_use_courier)
> + {
> + STRCPY(buffer, res_encoding->title);
> + STRCAT(buffer, " ");
> + STRCAT(buffer, res_encoding->version);
> + prt_dsc_resources(NULL, "encoding", buffer);
> + }
> + prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
> +# ifdef FEAT_SYN_HL
> + psettings->do_syntax
> +# else
> + 0
> +# endif
> + , prt_num_copies);
> + prt_dsc_noarg("EndComments");
> +
> + /*
> + * PS Document page defaults
> + */
> + prt_dsc_noarg("BeginDefaults");
> +
> + // List font resources most likely common to all pages
> + if (!prt_out_mbyte || prt_use_courier)
> + prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
> + if (prt_out_mbyte)
> + {
> + prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
> + &prt_ps_mb_font);
> + if (!prt_custom_cmap)
> + prt_dsc_resources(NULL, "cmap", prt_cmap);
> + }
> +
> + // Paper will be used for all pages
> + prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
> +
> + prt_dsc_noarg("EndDefaults");
> +
> + /*
> + * PS Document prolog inclusion - all required procsets.
> + */
> + prt_dsc_noarg("BeginProlog");
> +
> + // Add required procsets - NOTE: order is important!
> + if (!prt_add_resource(res_prolog))
> + goto theend;
> + if (prt_out_mbyte)
> + {
> + // Add CID font procset, and any user supplied CMap
> + if (!prt_add_resource(res_cidfont))
> + goto theend;
> + if (prt_custom_cmap && !prt_add_resource(res_cmap))
> + goto theend;
> + }
> +
> + if (!prt_out_mbyte || prt_use_courier)
> + // There will be only one Roman font encoding to be included in the PS
> + // file.
> + if (!prt_add_resource(res_encoding))
> + goto theend;
> +
> + prt_dsc_noarg("EndProlog");
> +
> + /*
> + * PS Document setup - must appear after the prolog
> + */
> + prt_dsc_noarg("BeginSetup");
> +
> + // Device setup - page size and number of uncollated copies
> + prt_write_int((int)prt_mediasize[prt_media].width);
> + prt_write_int((int)prt_mediasize[prt_media].height);
> + prt_write_int(0);
> + prt_write_string("sps
> ");
> + prt_write_int(prt_num_copies);
> + prt_write_string("nc
> ");
> + prt_write_boolean(prt_duplex);
> + prt_write_boolean(prt_tumble);
> + prt_write_string("dt
> ");
> + prt_write_boolean(prt_collate);
> + prt_write_string("c
> ");
> +
> + // Font resource inclusion and definition
> + if (!prt_out_mbyte || prt_use_courier)
> + {
> + // When using Courier for ASCII range when printing multi-byte, need to
> + // pick up ASCII encoding to use with it.
> + if (prt_use_courier)
> + p_encoding =3D (char_u *)prt_ascii_encoding;
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> + prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
> + prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> + prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> + prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
> + prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> + }
> + if (prt_out_mbyte)
> + {
> + // Define the CID fonts to be used in the job. Typically CJKV fonts do
> + // not have an italic form being a western style, so where no font is
> + // defined for these faces VIM falls back to an existing face.
> + // Note: if using Courier for the ASCII range then the printout will
> + // have bold/italic/bolditalic regardless of the setting of printmbfont=
.
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> + if (!prt_custom_cmap)
> + prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> + prt_def_cidfont("CF0", (int)prt_line_height,
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
> +
> + if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] !=3D NULL)
> + {
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
> + if (!prt_custom_cmap)
> + prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> + prt_def_cidfont("CF1", (int)prt_line_height,
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
> + }
> + else
> + // Use ROMAN for BOLD
> + prt_dup_cidfont("CF0", "CF1");
> +
> + if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] !=3D NULL)
> + {
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> + if (!prt_custom_cmap)
> + prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> + prt_def_cidfont("CF2", (int)prt_line_height,
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
> + }
> + else
> + // Use ROMAN for OBLIQUE
> + prt_dup_cidfont("CF0", "CF2");
> +
> + if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] !=3D NULL)
> + {
> + prt_dsc_resources("IncludeResource", "font",
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> + if (!prt_custom_cmap)
> + prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
> + prt_def_cidfont("CF3", (int)prt_line_height,
> + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
> + }
> + else
> + // Use BOLD for BOLDOBLIQUE
> + prt_dup_cidfont("CF1", "CF3");
> + }
> +
> + // Misc constant vars used for underlining and background rects
> + prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
> + prt_ps_font->uline_offset), 2);
> + prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
> + prt_ps_font->uline_width), 2);
> + prt_def_var("BO", prt_bgcol_offset, 2);
> +
> + prt_dsc_noarg("EndSetup");
> +
> + // Fail if any problems writing out to the PS file
> + retval =3D !prt_file_error;
> +
> +theend:
> + vim_free(res_prolog);
> + vim_free(res_encoding);
> + vim_free(res_cidfont);
> + vim_free(res_cmap);
> +
> + return retval;
> +}
> +
> + void
> +mch_print_end(prt_settings_T *psettings)
> +{
> + prt_dsc_noarg("Trailer");
> +
> + /*
> + * Output any info we don't know in toto until we finish
> + */
> + prt_dsc_ints("Pages", 1, &prt_page_num);
> +
> + prt_dsc_noarg("EOF");
> +
> + // Write CTRL-D to close serial communication link if used.
> + // NOTHING MUST BE WRITTEN AFTER THIS!
> + prt_write_file((char_u *)" ");
> +
> + if (!prt_file_error && psettings->outfile =3D=3D NULL
> + && !got_int && !psettings->user_abort)
> + {
> + // Close the file first.
> + if (prt_ps_fd !=3D NULL)
> + {
> + fclose(prt_ps_fd);
> + prt_ps_fd =3D NULL;
> + }
> + prt_message((char_u *)_("Sending to printer..."));
> +
> + // Not printing to a file: use 'printexpr' to print the file.
> + if (eval_printexpr(prt_ps_file_name, psettings->arguments) =3D=3D FAIL)
> + emsg(_(e_failed_to_print_postscript_file));
> + else
> + prt_message((char_u *)_("Print job sent."));
> + }
> +
> + mch_print_cleanup();
> +}
> +
> + int
> +mch_print_end_page(void)
> +{
> + prt_flush_buffer();
> +
> + prt_write_string("re sp
> ");
> +
> + prt_dsc_noarg("PageTrailer");
> +
> + return !prt_file_error;
> +}
> +
> + int
> +mch_print_begin_page(char_u *str UNUSED)
> +{
> + int page_num[2];
> +
> + prt_page_num++;
> +
> + page_num[0] =3D page_num[1] =3D prt_page_num;
> + prt_dsc_ints("Page", 2, page_num);
> +
> + prt_dsc_noarg("BeginPageSetup");
> +
> + prt_write_string("sv
> 0 g
> ");
> + prt_in_ascii =3D !prt_out_mbyte;
> + if (prt_out_mbyte)
> + prt_write_string("CF0 sf
> ");
> + else
> + prt_write_string("F0 sf
> ");
> + prt_fgcol =3D PRCOLOR_BLACK;
> + prt_bgcol =3D PRCOLOR_WHITE;
> + prt_font =3D PRT_PS_FONT_ROMAN;
> +
> + // Set up page transformation for landscape printing.
> + if (!prt_portrait)
> + {
> + prt_write_int(-((int)prt_mediasize[prt_media].width));
> + prt_write_string("sl
> ");
> + }
> +
> + prt_dsc_noarg("EndPageSetup");
> +
> + // We have reset the font attributes, force setting them again.
> + prt_curr_bg =3D (long_u)0xffffffff;
> + prt_curr_fg =3D (long_u)0xffffffff;
> + prt_curr_bold =3D MAYBE;
> +
> + return !prt_file_error;
> +}
> +
> + int
> +mch_print_blank_page(void)
> +{
> + return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE)=
;
> +}
> +
> +static float prt_pos_x =3D 0;
> +static float prt_pos_y =3D 0;
> +
> + void
> +mch_print_start_line(int margin, int page_line)
> +{
> + prt_pos_x =3D prt_left_margin;
> + if (margin)
> + prt_pos_x -=3D prt_number_width;
> +
> + prt_pos_y =3D prt_top_margin - prt_first_line_height -
> + page_line * prt_line_height;
> +
> + prt_attribute_change =3D TRUE;
> + prt_need_moveto =3D TRUE;
> + prt_half_width =3D FALSE;
> +}
> +
> + int
> +mch_print_text_out(char_u *textp, int len UNUSED)
> +{
> + char_u *p =3D textp;
> + int need_break;
> + char_u ch;
> + char_u ch_buff[8];
> + float char_width;
> + float next_pos;
> + int in_ascii;
> + int half_width;
> + char_u *tofree =3D NULL;
> +
> + char_width =3D prt_char_width;
> +
> + // Ideally VIM would create a rearranged CID font to combine a Roman=
and
> + // CJKV font to do what VIM is doing here - use a Roman font for cha=
racters
> + // in the ASCII range, and the original CID font for everything else=
.
> + // The problem is that GhostScript still (as of 8.13) does not suppo=
rt
> + // rearranged fonts even though they have been documented by Adobe f=
or 7
> + // years! If they ever do, a lot of this code will disappear.
> + if (prt_use_courier)
> + {
> + in_ascii =3D (len =3D=3D 1 && *p < 0x80);
> + if (prt_in_ascii)
> + {
> + if (!in_ascii)
> + {
> + // No longer in ASCII range - need to switch font
> + prt_in_ascii =3D FALSE;
> + prt_need_font =3D TRUE;
> + prt_attribute_change =3D TRUE;
> + }
> + }
> + else if (in_ascii)
> + {
> + // Now in ASCII range - need to switch font
> + prt_in_ascii =3D TRUE;
> + prt_need_font =3D TRUE;
> + prt_attribute_change =3D TRUE;
> + }
> + }
> + if (prt_out_mbyte)
> + {
> + half_width =3D ((*mb_ptr2cells)(p) =3D=3D 1);
> + if (half_width)
> + char_width /=3D 2;
> + if (prt_half_width)
> + {
> + if (!half_width)
> + {
> + prt_half_width =3D FALSE;
> + prt_pos_x +=3D prt_char_width/4;
> + prt_need_moveto =3D TRUE;
> + prt_attribute_change =3D TRUE;
> + }
> + }
> + else if (half_width)
> + {
> + prt_half_width =3D TRUE;
> + prt_pos_x +=3D prt_char_width/4;
> + prt_need_moveto =3D TRUE;
> + prt_attribute_change =3D TRUE;
> + }
> + }
> +
> + // Output any required changes to the graphics state, after flushing=
any
> + // text buffered so far.
> + if (prt_attribute_change)
> + {
> + prt_flush_buffer();
> + // Reset count of number of chars that will be printed
> + prt_text_run =3D 0;
> +
> + if (prt_need_moveto)
> + {
> + prt_pos_x_moveto =3D prt_pos_x;
> + prt_pos_y_moveto =3D prt_pos_y;
> + prt_do_moveto =3D TRUE;
> +
> + prt_need_moveto =3D FALSE;
> + }
> + if (prt_need_font)
> + {
> + if (!prt_in_ascii)
> + prt_write_string("CF");
> + else
> + prt_write_string("F");
> + prt_write_int(prt_font);
> + prt_write_string("sf
> ");
> + prt_need_font =3D FALSE;
> + }
> + if (prt_need_fgcol)
> + {
> + int r, g, b;
> + r =3D ((unsigned)prt_fgcol & 0xff0000) >> 16;
> + g =3D ((unsigned)prt_fgcol & 0xff00) >> 8;
> + b =3D prt_fgcol & 0xff;
> +
> + prt_write_real(r / 255.0, 3);
> + if (r =3D=3D g && g =3D=3D b)
> + prt_write_string("g
> ");
> + else
> + {
> + prt_write_real(g / 255.0, 3);
> + prt_write_real(b / 255.0, 3);
> + prt_write_string("r
> ");
> + }
> + prt_need_fgcol =3D FALSE;
> + }
> +
> + if (prt_bgcol !=3D PRCOLOR_WHITE)
> + {
> + prt_new_bgcol =3D prt_bgcol;
> + if (prt_need_bgcol)
> + prt_do_bgcol =3D TRUE;
> + }
> + else
> + prt_do_bgcol =3D FALSE;
> + prt_need_bgcol =3D FALSE;
> +
> + if (prt_need_underline)
> + prt_do_underline =3D prt_underline;
> + prt_need_underline =3D FALSE;
> +
> + prt_attribute_change =3D FALSE;
> + }
> +
> + if (prt_do_conv)
> + {
> + // Convert from multi-byte to 8-bit encoding
> + tofree =3D p =3D string_convert(&prt_conv, p, &len);
> + if (p =3D=3D NULL)
> + {
> + p =3D (char_u *)"";
> + len =3D 0;
> + }
> + }
> +
> + if (prt_out_mbyte)
> + {
> + // Multi-byte character strings are represented more efficiently as hex
> + // strings when outputting clean 8 bit PS.
> + while (len-- > 0)
> + {
> + ch =3D prt_hexchar[(unsigned)(*p) >> 4];
> + ga_append(&prt_ps_buffer, ch);
> + ch =3D prt_hexchar[(*p) & 0xf];
> + ga_append(&prt_ps_buffer, ch);
> + p++;
> + }
> + }
> + else
> + {
> + // Add next character to buffer of characters to output.
> + // Note: One printed character may require several PS characters to
> + // represent it, but we only count them as one printed character.
> + ch =3D *p;
> + if (ch < 32 || ch =3D=3D '(' || ch =3D=3D ')' || ch =3D=3D '\')
> + {
> + // Convert non-printing characters to either their escape or octal
> + // sequence, ensures PS sent over a serial line does not interfere
> + // with the comms protocol.
> + ga_append(&prt_ps_buffer, '\');
> + switch (ch)
> + {
> + case BS: ga_append(&prt_ps_buffer, 'b'); break;
> + case TAB: ga_append(&prt_ps_buffer, 't'); break;
> + case NL: ga_append(&prt_ps_buffer, 'n'); break;
> + case FF: ga_append(&prt_ps_buffer, 'f'); break;
> + case CAR: ga_append(&prt_ps_buffer, 'r'); break;
> + case '(': ga_append(&prt_ps_buffer, '('); break;
> + case ')': ga_append(&prt_ps_buffer, ')'); break;
> + case '\': ga_append(&prt_ps_buffer, '\'); break;
> +
> + default:
> + sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
> + ga_append(&prt_ps_buffer, ch_buff[0]);
> + ga_append(&prt_ps_buffer, ch_buff[1]);
> + ga_append(&prt_ps_buffer, ch_buff[2]);
> + break;
> + }
> + }
> + else
> + ga_append(&prt_ps_buffer, ch);
> + }
> +
> + // Need to free any translated characters
> + vim_free(tofree);
> +
> + prt_text_run +=3D char_width;
> + prt_pos_x +=3D char_width;
> +
> + // The downside of fp - use relative error on right margin check
> + next_pos =3D prt_pos_x + prt_char_width;
> + need_break =3D (next_pos > prt_right_margin) &&
> + ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
> +
> + if (need_break)
> + prt_flush_buffer();
> +
> + return need_break;
> +}
> +
> + void
> +mch_print_set_font(int iBold, int iItalic, int iUnderline)
> +{
> + int font =3D 0;
> +
> + if (iBold)
> + font |=3D 0x01;
> + if (iItalic)
> + font |=3D 0x02;
> +
> + if (font !=3D prt_font)
> + {
> + prt_font =3D font;
> + prt_attribute_change =3D TRUE;
> + prt_need_font =3D TRUE;
> + }
> + if (prt_underline !=3D iUnderline)
> + {
> + prt_underline =3D iUnderline;
> + prt_attribute_change =3D TRUE;
> + prt_need_underline =3D TRUE;
> + }
> +}
> +
> + void
> +mch_print_set_bg(long_u bgcol)
> +{
> + prt_bgcol =3D (int)bgcol;
> + prt_attribute_change =3D TRUE;
> + prt_need_bgcol =3D TRUE;
> +}
> +
> + void
> +mch_print_set_fg(long_u fgcol)
> +{
> + if (fgcol =3D=3D (long_u)prt_fgcol)
> + return;
> +
> + prt_fgcol =3D (int)fgcol;
> + prt_attribute_change =3D TRUE;
> + prt_need_fgcol =3D TRUE;
> +}
> +
> +#endif // FEAT_POSTSCRIPT
> diff --git a/src/hardcopy_postscript.h b/src/hardcopy_postscript.h
> new file mode 100644
> index 000000000..fe41df8f8
> --- /dev/null
> +++ b/src/hardcopy_postscript.h
> @@ -0,0 +1,42 @@
> +/* vi:set ts=3D8 sts=3D4 sw=3D4 noet:
> + *
> + * VIM - Vi IMproved by Bram Moolenaar
> + *
> + * Do ":help uganda" in Vim to read copying and usage conditions.
> + * Do ":help credits" in Vim to see a list of people who contributed.
> + * See README.txt for an overview of the Vim source code.
> + */
> +
> +#ifndef HARDCOPY_POSTSCRIPT_H
> +#define HARDCOPY_POSTSCRIPT_H
> +
> +#include "vim.h"
> +
> +#if defined(FEAT_POSTSCRIPT)
> +
> +# define OPT_MBFONT_USECOURIER 0
> +# define OPT_MBFONT_ASCII 1
> +# define OPT_MBFONT_REGULAR 2
> +# define OPT_MBFONT_BOLD 3
> +# define OPT_MBFONT_OBLIQUE 4
> +# define OPT_MBFONT_BOLDOBLIQUE 5
> +# define OPT_MBFONT_NUM_OPTIONS 6
> +
> +extern option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS];
> +
> +void mch_print_cleanup(void);
> +int mch_print_init(prt_settings_T *psettings, char_u *jobname, int force=
it);
> +int mch_print_begin(prt_settings_T *psettings);
> +void mch_print_end(prt_settings_T *psettings);
> +int mch_print_end_page(void);
> +int mch_print_begin_page(char_u *str);
> +int mch_print_blank_page(void);
> +void mch_print_start_line(int margin, int page_line);
> +int mch_print_text_out(char_u *textp, int len);
> +void mch_print_set_font(int iBold, int iItalic, int iUnderline);
> +void mch_print_set_bg(long_u bgcol);
> +void mch_print_set_fg(long_u fgcol);
> +
> +#endif
> +
> +#endif
> diff --git a/src/option.c b/src/option.c
> index aa4c990dc..353082cda 100644
> --- a/src/option.c
> +++ b/src/option.c
> @@ -323,7 +323,7 @@ set_init_default_printencoding(void)
> #endif
> }
>
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> /*
> * Initialize the 'printexpr' option to a default value.
> */
> @@ -724,7 +724,7 @@ set_init_1(int clean_arg)
> set_init_default_maxmemtot();
> set_init_default_cdpath();
> set_init_default_printencoding();
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> set_init_default_printexpr();
> #endif
>
> diff --git a/src/option.h b/src/option.h
> index c3df71fca..326b48b63 100644
> --- a/src/option.h
> +++ b/src/option.h
> @@ -666,10 +666,12 @@ EXTERN char_u *p_pvp; // 'previewpopup'
> EXTERN char_u *p_pdev; // 'printdevice'
> # ifdef FEAT_POSTSCRIPT
> EXTERN char_u *p_penc; // 'printencoding'
> -EXTERN char_u *p_pexpr; // 'printexpr'
> EXTERN char_u *p_pmfn; // 'printmbfont'
> EXTERN char_u *p_pmcs; // 'printmbcharset'
> # endif
> +# if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> +EXTERN char_u *p_pexpr; // 'printexpr'
> +# endif
> EXTERN char_u *p_pfn; // 'printfont'
> EXTERN char_u *p_popt; // 'printoptions'
> EXTERN char_u *p_header; // 'printheader'
> diff --git a/src/optiondefs.h b/src/optiondefs.h
> index f238209a7..187747368 100644
> --- a/src/optiondefs.h
> +++ b/src/optiondefs.h
> @@ -2022,7 +2022,7 @@ static struct vimoption options[] =3D
> #endif
> SCTX_INIT},
> {"printexpr", "pexpr", P_STRING|P_VI_DEF|P_SECURE,
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> (char_u *)&p_pexpr, PV_NONE, did_set_optexpr, NULL,
> {(char_u *)"", (char_u *)0L}
> #else
> @@ -2036,6 +2036,8 @@ static struct vimoption options[] =3D
> {
> # ifdef MSWIN
> (char_u *)"Courier_New:h10",
> +# elif defined(FEAT_PRINT_PANGO)
> + (char_u *)"Courier New 10",
> # else
> (char_u *)"courier",
> # endif
> diff --git a/src/proto/gui_gtk4.pro b/src/proto/gui_gtk4.pro
> index 3c5f7a925..d4a9b5283 100644
> --- a/src/proto/gui_gtk4.pro
> +++ b/src/proto/gui_gtk4.pro
> @@ -109,5 +109,6 @@ int gui_mch_dialog(int type, char_u *title, char_u *m=
essage, char_u *buttons, in
> void gui_mch_find_dialog(exarg_T *eap);
> void gui_mch_replace_dialog(exarg_T *eap);
> void ex_helpfind(exarg_T *eap);
> -void gui_gtk4_hardcopy(exarg_T *eap);
> +char_u *gui_gtk4_print_dialog(prt_settings_T *psettings, char_u *jobname=
, double *page_width, double *page_height);
> +void gui_gtk4_print_finish(void);
> /* vim: set ft=3Dc : */
> diff --git a/src/proto/hardcopy.pro b/src/proto/hardcopy.pro
> index 8a8c73e56..369aab398 100644
> --- a/src/proto/hardcopy.pro
> +++ b/src/proto/hardcopy.pro
> @@ -4,17 +4,6 @@ char *parse_printmbfont(optset_T *args);
> int prt_header_height(void);
> int prt_use_number(void);
> int prt_get_unit(int idx);
> +void prt_message(char_u *s);
> void ex_hardcopy(exarg_T *eap);
> -void mch_print_cleanup(void);
> -int mch_print_init(prt_settings_T *psettings, char_u *jobname, int force=
it);
> -int mch_print_begin(prt_settings_T *psettings);
> -void mch_print_end(prt_settings_T *psettings);
> -int mch_print_end_page(void);
> -int mch_print_begin_page(char_u *str);
> -int mch_print_blank_page(void);
> -void mch_print_start_line(int margin, int page_line);
> -int mch_print_text_out(char_u *textp, int len);
> -void mch_print_set_font(int iBold, int iItalic, int iUnderline);
> -void mch_print_set_bg(long_u bgcol);
> -void mch_print_set_fg(long_u fgcol);
> /* vim: set ft=3Dc : */
> diff --git a/src/structs.h b/src/structs.h
> index 38037c9d5..b1ec3fa78 100644
> --- a/src/structs.h
> +++ b/src/structs.h
> @@ -4831,8 +4831,11 @@ typedef struct
> int do_syntax;
> #endif
> int user_abort;
> +#ifdef FEAT_PRINT_PANGO
> + int user_abort_msg;
> +#endif
> char_u *jobname;
> -#ifdef FEAT_POSTSCRIPT
> +#if defined(FEAT_POSTSCRIPT) || defined(FEAT_PRINT_PANGO)
> char_u *outfile;
> char_u *arguments;
> #endif
> diff --git a/src/testdir/test_hardcopy.vim b/src/testdir/test_hardcopy.vi=
m
> index 33ef4bff1..62065139c 100644
> --- a/src/testdir/test_hardcopy.vim
> +++ b/src/testdir/test_hardcopy.vim
> @@ -1,5 +1,13 @@
> " Test :hardcopy
>
> +func s:HasPostscript()
> + if has('postscript') || has('pango')
> + return
> + endif
> + throw 'Skipped: hardcopy backend does not use postscript'
> +endfunc
> +command -nargs=3D0 HasPostscript call s:HasPostscript()
> +
> func Test_printoptions()
> edit test_hardcopy.vim
> syn on
> @@ -97,7 +105,7 @@ func Test_printmbcharset()
> endfunc
>
> func Test_printexpr()
> - CheckFeature postscript
> + HasPostscript
>
> " Not a very useful printexpr value, but enough to test
> " hardcopy with 'printexpr'.
> @@ -136,7 +144,7 @@ func Test_printexpr()
> endfunc
>
> func Test_errors()
> - CheckFeature postscript
> + HasPostscript
>
> edit test_hardcopy.vim
> call assert_fails('hardcopy >', 'E324:')
> @@ -150,7 +158,7 @@ func Test_dark_background()
> for bg in ['dark', 'light']
> exe 'set background=3D' .. bg
>
> - if has('postscript')
> + if has('postscript') || has('pango')
> hardcopy > Xhardcopy_dark_background
> let lines =3D readfile('Xhardcopy_dark_background')
> call assert_true(len(lines) > 20)
> @@ -164,7 +172,7 @@ func Test_dark_background()
> endfun
>
> func Test_empty_buffer()
> - CheckFeature postscript
> + HasPostscript
>
> new
> call assert_equal("
> No text to be printed", execute('hardcopy'))
> @@ -182,7 +190,7 @@ func Test_printheader_parsing()
> endfunc
>
> func Test_fname_with_spaces()
> - CheckFeature postscript
> + HasPostscript
>
> split t\ e\ s\ t.txt
> call setline(1, ['just', 'some', 'text'])
> @@ -208,27 +216,34 @@ func Test_illegal_byte()
> endfunc
>
> func Test_printoptions_portrait()
> - CheckFeature postscript
> + HasPostscript
> edit test_hardcopy.vim
> syn on
>
> set printoptions=3Dportrait:y
> 1,50hardcopy > Xhardcopy_printoptions_portrait
> let lines =3D readfile('Xhardcopy_printoptions_portrait')
> - call assert_match('Orientation: Portrait', lines[6])
> - call assert_match('BoundingBox: 59 49 564 800', lines[9])
> - call assert_match('DocumentMedia: A4', lines[10])
> - call assert_match('PageMedia: A4', lines[24])
> - call delete('Xhardcopy_printoptions')
> +
> + call assert_true(match(lines, 'Orientation: Portrait') !=3D -1)
> + if has('postscript')
> + call assert_true(match(lines, 'BoundingBox: 59 49 564 800') !=3D -1)
> + endif
> + call assert_true(match(lines, 'DocumentMedia: A4') !=3D -1)
> + call assert_true(match(lines, 'PageMedia: A4') !=3D -1)
> + call delete('Xhardcopy_printoptions_portrait')
>
> set printoptions=3Dportrait:n
> 1,50hardcopy > Xhardcopy_printoptions_portrait
> let lines =3D readfile('Xhardcopy_printoptions_portrait')
> - call assert_match('Orientation: Landscape', lines[6])
> - call assert_match('BoundingBox: 59 42 590 756', lines[9])
> - call assert_match('DocumentMedia: A4', lines[10])
> - call assert_match('PageMedia: A4', lines[24])
> - call delete('Xhardcopy_printoptions')
> + call delete('Xhardcopy_printoptions_portrait')
> +
> + call assert_true(match(lines, 'Orientation: Landscape') !=3D -1)
> + if has('postscript')
> + call assert_true(match(lines, 'BoundingBox: 59 42 590 756') !=3D -1)
> + endif
> + call assert_true(match(lines, 'DocumentMedia: A4') !=3D -1)
> + call assert_true(match(lines, 'PageMedia: A4') !=3D -1)
> + call delete('Xhardcopy_printoptions_portrait')
>
> set printoptions&
> bwipe
> diff --git a/src/version.c b/src/version.c
> index 7c831d2ae..fedd56dba 100644
> --- a/src/version.c
> +++ b/src/version.c
> @@ -461,6 +461,11 @@ static char *(features[]) =3D
> "+packages",
> #else
> "-packages",
> +#endif
> +#ifdef FEAT_PRINT_PANGO
> + "+pango",
> +#else
> + "-pango",
> #endif
> "+path_extra",
> #ifdef FEAT_PERL
> @@ -758,6 +763,8 @@ static char *(features[]) =3D
>
> static int included_patches[] =3D
> { /* Add new patch number below this line */
> +/**/
> + 898,
> /**/
> 897,
> /**/
> diff --git a/src/vim.h b/src/vim.h
> index 0caf43740..ce402f666 100644
> --- a/src/vim.h
> +++ b/src/vim.h
> @@ -2780,6 +2780,12 @@ typedef int (*opt_expand_cb_T)(optexpand_T *args, =
int *numMatches, char_u ***mat
> # endif
> #endif
>
> +#if defined(FEAT_PRINT_PANGO) && defined(FEAT_GUI_GTK) && defined(USE_GT=
K4)
> +# if GTK_CHECK_VERSION(4, 14, 0)
> +# define USE_GTK4_PRINT_DIALOG
> +# endif
> +#endif
> +
> #ifndef FEAT_NETBEANS_INTG
> # undef NBDEBUG
> #endif
>
>
--=20
Hisashi T Fujinaka - [email protected]
BSEE + BSChem + BAEnglish + MSCS + $2.50 =3D coffee
--=20
--=20
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---=20
You received this message because you are subscribed to the Google Groups "=
vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/423=
a5932-e2fb-d8d9-51ab-432f16423717%40twofifty.com.