After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 580508 - Pango tab stops are incorrect if set in Pango units in Win32
Pango tab stops are incorrect if set in Pango units in Win32
Status: RESOLVED OBSOLETE
Product: pango
Classification: Platform
Component: win32
1.22.x
Other All
: Normal normal
: ---
Assigned To: gtk-win32 maintainers
pango-maint
Depends on:
Blocks:
 
 
Reported: 2009-04-27 21:27 UTC by Ian Puleston
Modified: 2018-05-22 12:51 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
A small app that demos the problem. (4.14 KB, application/x-compressed-tar)
2009-04-27 21:28 UTC, Ian Puleston
  Details
A 2nd small app that demos the problem and the workaround. (4.25 KB, application/x-compressed-tar)
2009-04-28 06:32 UTC, Ian Puleston
  Details
A 3rd version of the small app that demos the problem and the workaround. (4.85 KB, application/gzip)
2011-02-23 19:24 UTC, Ian Puleston
  Details
Patch to GtkPrintOperation/GtkPrintContext to convert tabs in Pango units from points (4.09 KB, patch)
2011-03-21 19:57 UTC, Ian Puleston
none Details | Review

Description Ian Puleston 2009-04-27 21:27:51 UTC
Please describe the problem:
If pango_tab_array_new() is used to create tab stops given in Pango units and they are then applied to a PangoLayout for a GtkPrintContext using pango_layout_set_tabs(), the tabs do not print in the correct positions if printing from a Win32 app - they are way smaller than they should be. The same problem does not show up with exactly the same code in Linux and in that case the tabs print in the correct positions.

If tab stops are created in pixels with the correct pixel size for the print device (or scaled for the print device's resolution) then they print correctly in both Windows and Linux.

I suspect that for Pango units in Win32 the tab positions are being calculated using device units for the print device (typically 300dpi or 600dpi for a printer) rather than Pango font "device" units (i.e. points - 72dpi).


Steps to reproduce:
I will attach a small program to demonstrate the problem:
1. Compile and run the app in Linux. Click both test buttons and the printout is identical in both cases (with tab positions at 1", 1.5", 4.5" and 5").
2. Compile and run the app in Windows.
3. Click the button labeled for tab stops in pixels and the printout is the same as was printed in Linux.
3. Click the button labeled for tab stops in pango units and the printout is incorrect with the tab positions way too close together. 


Actual results:
Tab positions in printed output are way too close together.

Expected results:
Just like what happens in Linux.

Does this happen every time?
Yep.

Other information:
Comment 1 Ian Puleston 2009-04-27 21:28:58 UTC
Created attachment 133449 [details]
A small app that demos the problem.

Attached a small app that demos the problem.
Comment 2 Ian Puleston 2009-04-28 06:20:57 UTC
My suspicion that in Win32 the tab positions are being calculated using device units for the print device (typically 300dpi or 600dpi for a printer) rather than Pango font points seems to pan out. I added the following to adjust the tab stops from points to device units, and this works as a work-around to get them positioned correctly in Windows.

This is where the tabs are loaded into the layout for the print context:

    g_assert(!pango_tab_array_get_positions_in_pixels(tabArray));
#ifdef _WIN32
    /* This is a work-around for a Pango bug with tab stops set in Pango
     * uints in Win32: http://bugzilla.gnome.org/show_bug.cgi?id=580508.
     * Tabs given in Pango units should be based on points, but here we
     * adjust them from that to be the number of print device units instead,
     * and this makes them print at the correct positions in Win32!!! */
    {
	PangoTabAlign align;
	int i, tab, numTabs;
	tabArray = pango_tab_array_copy(tabArray);
	g_assert(tabArray);
	numTabs = pango_tab_array_get_size(tabArray);
	for (i = 0; i < numTabs; i++)
	{
	    pango_tab_array_get_tab(tabArray, i, &align, &tab);
	    tab *= prtInfo->dpi_y;
	    tab /= 72;
	    pango_tab_array_set_tab(tabArray, i, align, tab);
	}
	pango_layout_set_tabs(prtInfo->layout, tabArray);
	pango_tab_array_free(tabArray);
    }
#else
    pango_layout_set_tabs(prtInfo->layout, tabArray);
#endif

Comment 3 Ian Puleston 2009-04-28 06:32:21 UTC
Created attachment 133470 [details]
A 2nd small app that demos the problem and the workaround.

I've uploaded a new version of the small app that demos the problem - this one has a 3rd test button which demos the workaround (see comment #2). This also includes the Makefile which I'd missed from the first attachment.
Comment 4 Tor Lillqvist 2009-05-27 12:04:00 UTC
I don't immediately see any mention of tab arrays in the Win32-specific source files in Pango, nor in GTK+. If you could come up with a patch for Pango or GTK+ that would be much appreciated...
Comment 5 Ian Puleston 2009-06-02 05:42:55 UTC
Note that this, http://bugzilla.gnome.org/show_bug.cgi?id=584585 and http://bugzilla.gnome.org/show_bug.cgi?id=584586 are all problems with horizontal metrics of Pango text in Win32. I suspect that the same underlying problem may well causing them all.

I've looked through the Pango code for managing tab settings (in pango-tabs.c and pango-layout.c) and there is nothing Win32 specific in there - so far as I can see it appears to all be identical for Windows and Linux, so maybe the problem is in Cairo rather than Pango.
Comment 6 Ian Puleston 2011-02-23 19:24:06 UTC
Created attachment 181740 [details]
A 3rd version of the small app that demos the problem and the workaround.

I've now spent some more time digging into what is going on here, and have a bit more insight into it, and in particular why the behavior is different in Linux and Windows.

A Cairo surface's device units are points, hence it is 72 dpi, and when I run this test program in Linux the dpi of the print device returned by gtk_print_context_get_dpi_[xy] is always 72, hence if the tabs are set as Pango units being the number of points x PANGO_SCALE then no adjustment is needed. Note that I tried with print to a printer in both normal and high-quality mode, print to pdf file and print preview and got 72 dpi in each case.

In Windows, however, gtk_print_context_get_dpi_[xy] returns the actual dpi of the printer - I got 300 dpi printing to pdf and 600 dpi printing to my laser printer. Hence the tab stops based on points need to be adjusted for this.

I've attached another version of the test program with some minor enhancements including some g_prints to print out the dpi values and tab positions.
Comment 7 Ian Puleston 2011-02-23 19:37:44 UTC
Slight correction to what I said above. Where I said "A Cairo surface's device units are points", I believe that more accurately that should read "When Pango writes text to a Cairo surface, the units it uses are points".
Comment 8 Behdad Esfahbod 2011-03-18 19:31:10 UTC
Humm.  I think the problem is that the tab stop positions are in device units (ie. pixels), not points.  So it's up to the client to calculate the correct number by applying dpi.  That's unfortunate.

Perhaps we can add a new function, pango_layout_set_tabs_points() or something that will apply the dpi.
Comment 9 Ian Puleston 2011-03-19 01:21:07 UTC
Yes that is correct. I did some extensive testing/debugging of this recently amd I've found that in Linux the printer device units are always points (72 dpi) no matter what the actual dpi of the printer, and therefore to the user it doesn't matter whether it works in points or pixels since both are the same. But in Windows the printer device units revealed on the printing API are the actual DPI of the printer. This means that anything that works in device units, like tab stops set in Pango units, the application needs to know the printer DPI. But it can't know that until the user has selected the printer, and therefore it can set tabs in pango units unless it then adjusts them when printing begins.

I have a patch for this which I will submit soon. The patch makes it so that if tabs are set in Pango units those are taken to be based on points rather than on device units. This unfortunately goes against the documented meaning of Pango units (and so should be carefully documented if we decide to use the patch) but it is the only way to give any consistent behavior of tabs for printers that have device units other than points.

Ian
Comment 10 Ian Puleston 2011-03-19 01:24:33 UTC
Sorry, type there: "therefore it can set tabs..." whould read "therefore it cannot set tabs in pango units unless it then adjusts them when printing begins".
Comment 11 Behdad Esfahbod 2011-03-21 18:39:01 UTC
Changing the semantics of the current API is not possible without checking all the current users.  Adding new API is more feasible I guess.
Comment 12 Ian Puleston 2011-03-21 19:17:43 UTC
To clarify what I said above (last paragraph of comment #9) my patch applies only for the case of printing, not to Pango tabs in general, and it (arguably) doesn't really "go against the documented meaning of Pango units" since that documented meaning doesn't apply here (see below).

The only documentation I can find for what Pango units are is that for PANGO_SCALE which says that Pango units are scaled from device units. But when setting tabs for printing there is no device (the user selects the print device later) and hence no concept of device units at that time. Therefore, the API should really specify some default unit for use here, and the most appropriate units for this would be scaled points. This is what my patch does.

This shouldn't break any Linux apps since Linux printers use points for their device units, so the only thing it would be likely to affect would be Windows apps that set tabs in Pango units and then work around this problem by adjusting them when printing starts. I would be very surprised if there are a significant number of those.
Comment 13 Ian Puleston 2011-03-21 19:57:26 UTC
Created attachment 183994 [details] [review]
Patch to GtkPrintOperation/GtkPrintContext to convert tabs in Pango units from points

Attached my patch which updates GtkPrintOperation to convert tabs that are set in in Pango units from points to device units when printing starts. Also includes adding a new function to GtkPrintContext to retrieve the Pango layout for the context.
Comment 14 GNOME Infrastructure Team 2018-05-22 12:51:18 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/pango/issues/156.