ImproveMathEquationEditor/Baseline AlignmentEquations/Borders of non resizable objects

Back to Baseline alignment for equations

Description
When adding borders to non-resizable objects, the object frame is resized as the object can't change its own size. Moreover the position of the frame is kept the same, causing the actual object rectangle (without the border) move.

This is especially painful for formulas that has to be aligned baseline to baseline.

To try this out follow:


 * 1) insert a formula
 * 2) move it using mouse to certain hight (this way the alignment changes to 'From Bottom') for instance so that the baseline of the formula is aligned to the text around
 * 3) now add borders (wide enough to see it ... or zoom in)
 * 4) the object rectangle is moved down (by the width of the border), misaligning the formula

First view
pFlyFrmRect=0x8af40d8)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/ui/wrtsh/wrtsh1.cxx:698    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/frmtool.cxx:982    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/doc/notxtfrm.cxx:579    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/calcmove.cxx:415    pPage=0xb3137000) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:2490 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:2540 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/objectformatter.cxx:333
 * 1) 0 SwWrtShell::CalcAndSetScale (this=0x85f1d28, xObj=..., pFlyPrtRect=0x8af40e8,
 * 1) 1 0x03eff0a0 in ~SwCntntNotify (this=0xbfffddfc, __in_chrg= )
 * 1) 2 0x040e4c7b in SwNoTxtFrm::MakeAll (this=0x8a250b0)
 * 1) 3 0x03ed3ef2 in SwFrm::OptPrepareMake (this=0x8a250b0)
 * 1) 4 0x03f19ac9 in SwFrm::OptCalc (this=0x8a250b0) at ../inc/frame.hxx:1067
 * 2) 5 0x03f179d5 in SwLayAction::_FormatCntnt (this=0xbfffe23c, pCntnt=0x8a250b0,
 * 1) 6 0x03f17e97 in SwLayAction::_FormatFlyCntnt (this=0xbfffe23c, pFly=0x8af40b0)
 * 1) 7 0x03f265e5 in SwObjectFormatter::_FormatObj (this=0x8b9e7d8, _rAnchoredObj=...)

CalcAndSetScale is basically the function that applies the changes to the object. What happens is that when you add borders to an object, aPrt (object rectangle without the borders) is shrunk by the border size and aFrm (frame rectangle in which the objects sits) remains the same. Now inside CalcAndSetScale the program suddenly realizes that whoops the object is non-resizable and tries to fix it by calling RequestObjectResize to change the aFrm and aPrt so that aPrt has the proper size.

The problem is that in this process aFrm is not moved, causing aPrt to move instead and we would like it the other way. Simply put, we would like the borders paste on the object rectangle (aPrt) without moving it, but the implementation is based on not moving the frame rectangle (aFrm).

Now we have to figure out how to move the aFrm to make the aPrt be where it should be. This is quite a problem because considering current implementation it's not even clear what is the right position for aPrt if the borders added and at the same time the object was moved. If the object only got borders than we want to keep position of aPrt.


 * Update: We actually know where it should be also in the case when object should be moved and frame is resizing at the same time. If we get to the aFrm and aPrt that was before the change, we want to move the aFrm as much as it's going to be moved minus the difference between aPrt offset in the case before resizing and after resizing. aPrt offset is the position of aPrt relative to aFrm (which is actually the position written in the rectangle aPrt). There might be a problem arising from duplicate call of CalcAndSetScale, and consequent adjusting the frame position twice, I'm not sure about this though, will try to implement.


 * The problem here is, that when we get to CalcAndSetScale we don't know what is was the aPrt before, because it was rewritten. Hence we have to look at the method that rewrites it.

For our specific problem of alignment of formulas we don't set the position of rectangles, but we have to set the position in SwFmtVertOrient so that it reflects the added top border on the formula. In this case we can have a look in CalcAndSetScale through SwOleClient, it has access to, what was the last object rectangle, considering the object rectangle that it would be assigned if the object was resizable we can calculate the difference that has to be made in SwFmtVertOrient.

Second view
Once again...

When adding borders there are two different things that happen. If the object is resizable, the frame remains the same, object is shrunk so that the borders can fit in the frame. If the object is non-resizable the position of the frame remains fixed but it's size changes because the borders are added.

The way it's coded now tries to keep the position and size of the frame the same. Which is not good for non-resizable objects, because the frame gets inevitably bigger adding the borders, and the actual object is therefore moved by the width of the border that we added on top and left of the object.

We can't change the behaviour generally (for instance keeping the position of the actual object instead of its frame fixed) because it would effect both resizable and non-resizable objects and one of them would still have problems with this (as they need to be treated separately).

Thus the solution leads to do a small hack for non-resizable objects only. Introducing a new parameter we can store the offset of the object rectangle in frame rectangle. Now when adding borders, this offset changes and we can move the frame by this difference. Hence keeping object rectangle at the same place and moving the frame (when adding the borders). Also when calculating the baseline we have to add this offset.


 * I tried to implement it and it worked well for objects anchored not as character. For objects anchored as character I got to trouble with changing the position.

problem with changing the position
For objects anchored as character we need to change the position of the frame to keep the object rectangle at the same place, when adding borders. This is done in RequestObjectResize which calls ChgRelPos and it changes the position by changing SwFmtVertOrient. As shows the backtrace:

at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/fly.cxx:1166 xObj=...)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/frmedt/fefly1.cxx:1527    pFlyPrtRect=0x8adf110, pFlyFrmRect=0x8adf100) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/ui/wrtsh/wrtsh1.cxx:893 __in_chrg= )   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/frmtool.cxx:982    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/doc/notxtfrm.cxx:579    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/calcmove.cxx:415 ---Type to continue, or q to quit---    pCntnt=0x8a10a98, pPage=0xb3137000) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:2490 pFly=0x8adf0d8)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:2540    _rAnchoredObj=...) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/objectformatter.cxx:394
 * 1) 0 SwFlyFrm::ChgRelPos (this=0x8adf0d8, rNewPos=...)
 * 1) 1 0x042e1c19 in SwFEShell::RequestObjectResize (this=0x85f3b00, rRect=...,
 * 1) 2 0x046db62e in SwWrtShell::CalcAndSetScale (this=0x85f3b00, xObj=...,
 * 1) 3 0x03ef50f0 in ~SwCntntNotify (this=0xbfffd77c,
 * 1) 4 0x040dacfb in SwNoTxtFrm::MakeAll (this=0x8a10a98)
 * 1) 5 0x03ec9f72 in SwFrm::OptPrepareMake (this=0x8a10a98)
 * 1) 6 0x03f0fb19 in SwFrm::OptCalc (this=0x8a10a98) at ../inc/frame.hxx:1067
 * 2) 7 0x03f0da25 in SwLayAction::_FormatCntnt (this=0xbfffdbbc,
 * 1) 8 0x03f0dee7 in SwLayAction::_FormatFlyCntnt (this=0xbfffdbbc,
 * 1) 9 0x03f1c635 in SwObjectFormatter::_FormatObj (this=0x87f2110,

Now the trouble is, when the code gets back to _FormatObj it's in a loop, that will repeat and call:

at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flyincnt.cxx:203 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flyincnt.cxx:340 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/calcmove.cxx:395 pFly=0x8adf0d8)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:1806    _rAnchoredObj=...) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/objectformatter.cxx:366
 * 1) 0 SwFlyInCntFrm::MakeObjPos (this=0x8adf0d8)
 * 1) 1 0x03ee9a33 in SwFlyInCntFrm::MakeAll (this=0x8adf0d8)
 * 1) 2 0x03ec9e7d in SwFrm::PrepareMake (this=0x8adf0d8)
 * 1) 3 0x03e1fb5d in SwFrm::Calc (this=0x8adf0d8) at ../inc/frame.hxx:1062
 * 2) 4 0x03f0b343 in SwLayAction::FormatLayoutFly (this=0xbfffdbbc,
 * 1) 5 0x03f1c580 in SwObjectFormatter::_FormatObj (this=0x87f2110,

Now MakeObjPos simply takes the value of maRelPos (ie relative position) from inside the SwAnchoredObject (base class of SwFlyFrm) and sets SwFmtVertOrient according to it. This will rewrite new position stored in SwFmtVertOrient to the old one.


 * SwFlyInCntFrm::MakeObjPos is very strange because the idea of the method is not at all similar to SwFlyFrm::MakeObjPos which on the other hand sets maRelPos. I did some tracing and it seemed to me that when anything wants to change position it does it by changing SwFmtVertOrient, therefore it would be sensible if a method that makes object position would take the value of SwFmtVertOrient and set it to maRelPos not the other way round. So I tried and commented out whole SwFlyInCntFrm::MakeObjPos. Everything works fine now, I'm just still a bit confused by it, because to me the method really makes no sense.

MakeObjPos for SwFlyInCntFrm is probably so different from SwFlyAtCntFrm and SwFlyFrm MakeObjPos because position of objects anchored as character, needs to be recalculated every time there is some text inserted. So the positioning is handled by text formatter

this=0xbfffc988)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx:105    rBase=..., nLnAscent=224, nLnDescent=52, nFlyAsc=224, nFlyDesc=52,     nFlags=6 '\006') at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/text/porfly.cxx:396 rBase=..., nLnAscent=224, nLnDescent=52, nFlyAsc=224, nFlyDesc=52, nFlags=6 '\006')   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/text/porfly.cxx:308    pHint=0x8a242b8) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/text/txtfly.cxx:734
 * 1) 0 objectpositioning::SwAsCharAnchoredObjectPosition::CalcPosition (
 * 1) 1 0x03fc433b in SwFlyCntPortion::SetBase (this=0x8b663a0, rFrm=...,
 * 1) 2 0x03fc3fb2 in SwFlyCntPortion (this=0x8b663a0, rFrm=..., pFly=0x8a9e478,
 * 1) 3 0x03fe5881 in SwTxtFormatter::NewFlyCntPortion (this=0xbfffd394, rInf=...,

whereas for objects anchored at page or at paragraph you calculate the position only if it's invalidated

this=0xbfffdd84)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx:156    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flycnt.cxx:1542    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flylay.cxx:248    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flycnt.cxx:443    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/calcmove.cxx:395    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/layact.cxx:1806    _rAnchoredObj=...) at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/objectformatter.cxx:366
 * 1) 0 objectpositioning::SwToCntntAnchoredObjectPosition::CalcPosition (
 * 1) 1 0x03ee88cc in SwFlyAtCntFrm::MakeObjPos (this=0x8a87ab8)
 * 1) 2 0x03eea77e in SwFlyFreeFrm::MakeAll (this=0x8a87ab8)
 * 1) 3 0x03ee5838 in SwFlyAtCntFrm::MakeAll (this=0x8a87ab8)
 * 1) 4 0x03ec9f2d in SwFrm::PrepareMake (this=0x8a87ab8)
 * 1) 5 0x03e1fc0d in SwFrm::Calc (this=0x8a87ab8) at ../inc/frame.hxx:1062
 * 2) 6 0x03f0b463 in SwLayAction::FormatLayoutFly (this=0xbfffe30c, pFly=0x8a87ab8)
 * 1) 7 0x03f1c6a0 in SwObjectFormatter::_FormatObj (this=0x8a8ed20,

Now the idea of MakeObjPos for SwFlyInCntFrm is that once the position is calculated it puts it into the item set for format

at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flyincnt.cxx:203 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flyincnt.cxx:340 at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/calcmove.cxx:395 rRelAttr=..., rRelPos=...)   at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/layout/flyincnt.cxx:113    at /home/miko/stable_ooo-build/ooo-build/build/ooo320-m19/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx:331
 * 1) 0 SwFlyInCntFrm::MakeObjPos (this=0x8a9e478)
 * 1) 1 0x03ee9b51 in SwFlyInCntFrm::MakeAll (this=0x8a9e478)
 * 1) 2 0x03ec9f2d in SwFrm::PrepareMake (this=0x8a9e478)
 * 1) 3 0x03e1fc0d in SwFrm::Calc (this=0x8a9e478) at ../inc/frame.hxx:1062
 * 2) 4 0x03ee9362 in SwFlyInCntFrm::SetRefPoint (this=0x8a9e478, rPoint=...,
 * 1) 5 0x042b96a2 in objectpositioning::SwAsCharAnchoredObjectPosition::CalcPosition (this=0xbfffc988)

but the position is calculated foremost using what is stored in the item set, so in fact it's not needed to do this. And my problem is that when borders are inserted and the position is changed MakeObjPos is called before CalcPosition, therefore it rewrites the change. (the problem was not there before, because before you didn't need to move object frame when adding borders) For FlyAtCntFrm this is not a problem because MakeObjPos calls CalcPosition.

So basically we have to make sure somehow, that CalcPosition was called before MakeObjPos.


 * For this I created new bool called SetPosCalculated, to be set true only inside SwAsCharAnchoredPosition::CalcPosition, where it uses MakeObjPos to change the relative position SwFmtVertOrient.