Issue 121382 - Rotated Text in Metafile rendered wrong
Summary: Rotated Text in Metafile rendered wrong
Alias: None
Product: Writer
Classification: Application
Component: open-import (show other issues)
Version: 3.4.1
Hardware: All All
: P3 Normal (vote)
Target Milestone: 4.0.0
Assignee: Armin Le Grand
QA Contact:
Depends on:
Reported: 2012-11-21 08:26 UTC by christian.rufener
Modified: 2013-07-12 16:31 UTC (History)
3 users (show)

See Also:
Issue Type: DEFECT
Latest Confirmation in: ---
Developer Difficulty: ---

Excel sheet containg the chart. (43.00 KB, application/
2012-11-21 08:26 UTC, christian.rufener
no flags Details
Patch for winmtf.cxx /hxx (1.73 KB, text/plain)
2012-11-30 16:13 UTC, christian.rufener
no flags Details
Patch to get the correct distance (metric) for the DXArray (957 bytes, patch)
2012-12-04 15:04 UTC, Armin Le Grand
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this issue.
Description christian.rufener 2012-11-21 08:26:57 UTC
Created attachment 79932 [details]
Excel sheet containg the chart.

When pasting a chart from Excel containing rotated axis titles or legends, the rendering of the axis title or legends is wrong and not readable. To reproduce the problem use the attached Excel sheet: copy the chart to the clipboard and paste it into Writer. 
Please note that the behavior is the same on Calc.
My assumption is that maybe EMR_MODIFYWORLDTRANSFORM might be handled incorrectly.
Comment 1 christian.rufener 2012-11-29 19:42:22 UTC
Did some investigation in the AOO source: The problem is in the 
WinMtfOutput::DrawText method: the passed pDXArry is converted with the ImplMap(Size) method. This method uses the current XForm to performa the calculation. However, since the current transformation is a rotation of 90/270 deg, the XFrom attributes .eM11 and .eM22 are (close) to zero due to cos(90). This lead to the fact that all x offsets of the characters are 0 and each character is draw at the same location.
Comment 2 Armin Le Grand 2012-11-30 14:57:27 UTC
ALG: Adding myself to CC
Comment 3 christian.rufener 2012-11-30 16:13:25 UTC
Created attachment 79975 [details]
Patch for winmtf.cxx /hxx

I fixed it with the above changes. I am not sure whether or not this is sustainable.
Comment 4 Armin Le Grand 2012-12-03 11:13:23 UTC
ALG: I am not sure, but I would take the metric (the length) directly. Normally this is done by sqrt(x*x + y*y), but in this case only 90 or 270 deg can be used. I would use something like:

		for( i = 0, nSum = 0; i < nLen; i++ )
            // #121382# text may be rotated 90 or 270 degrees, so aMappedSize.Width may be zero
            // and aMappedSize.Height has to be used
            const Size aMappedSize(ImplMap(Size(pDXArry[i], 0)));
            const sal_Int32 nSize(std::max(aMappedSize.Width(), aMappedSize.Height()));
            nSum += nSize;
            pDXArry[ i ] = nSum;

You  wrote that .eM11 and .eM22 are *both* close to zero, in tat case it would not work. I guess that .eM11 and .eM22 are the scalers of a homogen matrix, so when rotated not both should be zero.
Just my 2 cents...
Comment 5 christian.rufener 2012-12-03 15:20:27 UTC
Thanks for your comments. However, the Matrix is derived from the original MS XFORM structure. According to the documentation the members eM11 and eM22 contain the cosine of the rotation angle in the case of a rotation.


Comment 6 Armin Le Grand 2012-12-03 17:14:30 UTC
ALG: I see. But then the problem is 

		double fWidth = rSz.Width() * maXForm.eM11;
		double fHeight = rSz.Height() * maXForm.eM22;

inside Size WinMtfOutput::ImplMap( const Size& rSz )
Were (in contrast) Point WinMtfOutput::ImplMap( const Point& rPt ) contains the whole matrix multiplication:

		fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx;
		fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy;

Thus, the reason that width *and* height are zero is that someone had optimized that matrix multiplication in ImplMap for Size. When bringing this back to it's regular form (which should be)

		double fWidth = rSz.Width() * maXForm.eM11 + rSz.Height() * maXForm.eM21;
		double fHeight = rSz.Height() * maXForm.eM22 + rSz.Width() * maXForm.eM22;

The calls to WinMtfOutput::ImplMap( const Size& rSz ) would execute the normal rotation as part of the linear matrix multiplication. Thus, in 90/270 degree rotation case, the Height returned should be nonzero and is the searched value.

This would generally fix the WinMtfOutput::ImplMap( const Size& rSz ) method, for *all* kinds of transformations coming along. As consequence indeed the length (metric) should be calculated in WinMtfOutput::DrawText as follows:

            const Size aTransformedSize(ImplMap(Size(pDXArry[i], 0)));
            const sal_Int32 nTemp(
                        aTransformedSize.Width() * aTransformedSize.Width() + 
                        aTransformedSize.Height() * aTransformedSize.Height())));

Then, all this would work with arbitrary transformations.
Comment 7 Armin Le Grand 2012-12-03 17:17:27 UTC
ALG: ...or alternatively with more basegfx tooling:

            const Size aTransformedSize(ImplMap(Size(pDXArry[i], 0)));
            const basegfx::B2DVector aVector(aTransformedSize.Width(), aTransformedSize.Height());
            const sal_Int32 nTemp(basegfx::fround(aVector.getLength()));

Comment 8 christian.rufener 2012-12-03 18:06:47 UTC
I think you're right, in theory. However, if you look at the DrawText you'll find that the rotation has been already applied in the font. This is why my kludge solution works: I assume that the MetaFontAction rotates the the device context?

Tested your suggestion with limited success: The rotated text looks the same.

Diving deep in the OutputDevice class resulted in confusion: There I'd need more time.

Comment 9 Armin Le Grand 2012-12-04 12:16:28 UTC
ALG: Hi Christian, thanks for keeping up looking into this :-) Yes, OutputDevice is somewhat confusing sometimes and was not designed to work with homogen transformations at all. Normally, it can only apply scale and transformation in the form of MapModes. I did not even know that there is maXForm as a matrix...
As said, normally it does only scale and translate, no rotation at all. Maybe the ImplMap 2nd part (which is scaling in principle) should be applied first, and the transformation from maXForm last...?
Comment 10 Armin Le Grand 2012-12-04 15:04:24 UTC
Created attachment 79995 [details]
Patch to get the correct distance (metric) for the DXArray

ALG: Hi Christian, I have checked and it works as expected with the patch added. Sorry, I had a small error in the previous descriptions with the matrix multiplication, thus that version could not work.
Remaining is that the FontHeight (in Font) seems to be not adapted, too.
Comment 11 Armin Le Grand 2012-12-10 17:06:25 UTC
ALG: Taking over. Identified tha places where the FontSize also needs to be adapted to the WorldTransform. In principle all this input filters should be rewritten to use double precision, basegfx tooling (with homogen matrices) and produce primitives. This is too dangerous and time consuming now, so I'll just fix the shortcomings.
Comment 12 Armin Le Grand 2012-12-10 17:07:51 UTC
ALG: WIth my adaptions the rotated text is correctly imported with also the correct Font Widths/Heights. Preparing commit...
Comment 13 Armin Le Grand 2012-12-10 17:09:41 UTC
ALG: Comitted, done.
Comment 14 Armin Le Grand 2012-12-10 17:10:55 UTC
ALG: Revision is 1419586
Comment 15 SVN Robot 2012-12-10 17:20:33 UTC
"alg" committed SVN revision 1419586 into trunk:
#121382# Corrected size handling including font size handling for EMF/WMF imp...