diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.cxx b/sdext/source/pdfimport/tree/drawtreevisiting.cxx index d5ce02ad89bf..83a3f8a64d43 100644 --- a/sdext/source/pdfimport/tree/drawtreevisiting.cxx +++ b/sdext/source/pdfimport/tree/drawtreevisiting.cxx @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -647,13 +648,66 @@ static bool isSpaces(TextElement* pTextElem) return true; } -static bool notTransformed(const GraphicsContext& GC) +static bool canConcatenate( + const basegfx::B2DHomMatrix& rCurr, + const basegfx::B2DHomMatrix& rNext, + double& rfExpandedDistance) { - return - rtl::math::approxEqual(GC.Transformation.get(0,0), 100.00) && - GC.Transformation.get(1,0) == 0.00 && - GC.Transformation.get(0,1) == 0.00 && - rtl::math::approxEqual(GC.Transformation.get(1,1), -100.00); + // get FontHeight of both snippets + const double fHeightCurr((rCurr * basegfx::B2DVector(0.0, 1.0)).getLength()); + const double fHeightNext((rNext * basegfx::B2DVector(0.0, 1.0)).getLength()); + + // 1st compare FontHeight to detect FontHeight changes + if(!rtl::math::approxEqual(fHeightCurr, fHeightNext)) + return false; + + // we now need to check if the BottomLeft edge of next is parallel to + // the BaseLine of the current. We could do this by getting the vectors + // and start comparing, but we already have a nice tooling method for + // this, so use it + const basegfx::B2DPoint aBottomLeftNext(rNext * basegfx::B2DPoint(0.0, 1.0)); + const basegfx::B2DPoint aBottomLeftCurr(rCurr * basegfx::B2DPoint(0.0, 1.0)); + const basegfx::B2DPoint aBottomRightCurr(rCurr * basegfx::B2DPoint(1.0, 1.0)); + basegfx::B2DVector aBaselineCurr(aBottomRightCurr - aBottomLeftCurr); + double fCut(0.0); + + // if there is already expanded distance we need to prolongate the vector + // accordingly + if(!basegfx::fTools::equalZero(rfExpandedDistance)) + { + aBaselineCurr.setLength(aBaselineCurr.getLength() + rfExpandedDistance); + } + + if(!basegfx::utils::isPointOnEdge( + aBottomLeftNext, // point to check + aBottomLeftCurr, // edge start + aBaselineCurr, // edge vector + &fCut)) // return value for evtl. found cut in range ]0.0..1.0[ + { + // not on edge -> we are done, we expect it to be on the right part of the given edge, + // but not outside of it (farther away than EdgeLength) + return false; + } + + // rescue the new rfExpandedDistance value before manipulating + // the fCut value for comparison + const double fBaselineLength(aBaselineCurr.getLength()); + rfExpandedDistance = fCut * fBaselineLength; + + // point is on edge and we have the relative cut value for it in fCut. To check + // the distance relative to fontHeight we need to move it from unit coordinates + // to being relative to vector length by mulitplying it. To get immediately + // the distance from the right side, we first substract from 1.0 which would be + // the right edge end point + fCut = (1.0 - fCut) * fBaselineLength; + + // we need to set that in relation to the fontHeight, so e.g. accept as concatenation + // when the new part is more than half fontHeight away from current part. + // Have now stepped from 0.5 to 0.75 and even to 0.77 to get better hits. Please + // adapt this value when needed. 0.77 means that the next char has to have at least + // a gap of 23% relative to fontHeight to the last char. This may need adaption for rtl + // languages (?) + return fCut < fHeightCurr * 0.77; } void DrawXmlOptimizer::optimizeTextElements(Element& rParent) @@ -667,6 +721,7 @@ void DrawXmlOptimizer::optimizeTextElements(Element& rParent) // concatenate child elements with same font id auto next = rParent.Children.begin(); auto it = next++; + double fAlreadyExpandedDistance(0.0); while( next != rParent.Children.end() ) { @@ -693,8 +748,6 @@ void DrawXmlOptimizer::optimizeTextElements(Element& rParent) const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId ); const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId ); - // line and space optimization; works only in strictly horizontal mode - // concatenate consecutive text elements unless there is a // font or text color or matrix change, leave a new span in that case if( (pCur->FontId == pNext->FontId || isSpaces(pNext)) && @@ -702,7 +755,15 @@ void DrawXmlOptimizer::optimizeTextElements(Element& rParent) rCurGC.FillColor.Green == rNextGC.FillColor.Green && rCurGC.FillColor.Blue == rNextGC.FillColor.Blue && rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha && - (rCurGC.Transformation == rNextGC.Transformation || notTransformed(rNextGC)) + // check transformations; we need + // - same fontHeight + // - same baseLine + // - not too big distance/gap between + // also needed is to transport the already expanded distance + // created by concatenations already. It is not feasible to adapt + // rCurGC.Transformation due to that would change the fontScale + // aspect ratio + canConcatenate(rCurGC.Transformation, rNextGC.Transformation, fAlreadyExpandedDistance) ) { pCur->updateGeometryWith( pNext ); @@ -726,6 +787,10 @@ void DrawXmlOptimizer::optimizeTextElements(Element& rParent) rParent.Children.erase( next ); bConcat = true; } + else + { + fAlreadyExpandedDistance = 0.0; + } } } else if( dynamic_cast(it->get()) )