Apache OpenOffice (AOO) Bugzilla – Issue 121382
Rotated Text in Metafile rendered wrong
Last modified: 2022-10-28 12:54:32 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.
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.
ALG: Adding myself to CC
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.
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...
@ALG: 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. See http://msdn.microsoft.com/de-de/library/windows/desktop/dd145228%28v=vs.85%29.aspx MHO...
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( basegfx::fround( sqrt( aTransformedSize.Width() * aTransformedSize.Width() + aTransformedSize.Height() * aTransformedSize.Height()))); Then, all this would work with arbitrary transformations. HTH!
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())); Sincerely Armin
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. Sincerely C.
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...?
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.
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.
ALG: WIth my adaptions the rotated text is correctly imported with also the correct Font Widths/Heights. Preparing commit...
ALG: Comitted, done.
ALG: Revision is 1419586
"alg" committed SVN revision 1419586 into trunk: #121382# Corrected size handling including font size handling for EMF/WMF imp...