41 #include <unicode/ubidi.h>
42 #include <unicode/uchar.h>
50 #define GF_FONTMASK 0xF0000000
51 #define GF_FONTSHIFT 28
56 nChar = u_charMirror( nChar );
63 if( (nChar <
'0') || (
'9' < nChar) )
72 nOffset = 0x0660 -
'0';
78 nOffset = 0x06F0 -
'0';
80 nOffset = 0x09E6 -
'0';
82 nOffset = 0x0966 -
'0';
87 nOffset = 0x1369 -
'0';
89 nOffset = 0x0AE6 -
'0';
90 #ifdef LANGUAGE_GURMUKHI // TODO case:
91 else if ( pri ==
primary(LANGUAGE_GURMUKHI) )
92 nOffset = 0x0A66 -
'0';
95 nOffset = 0x0CE6 -
'0';
97 nOffset = 0x17E0 -
'0';
99 nOffset = 0x0ED0 -
'0';
101 nOffset = 0x0D66 -
'0';
108 nOffset = 0x1810 -
'0';
113 nOffset = 0x1040 -
'0';
115 nOffset = 0x0B66 -
'0';
117 nOffset = 0x0BE7 -
'0';
119 nOffset = 0x0C66 -
'0';
121 nOffset = 0x0E50 -
'0';
123 nOffset = 0x0F20 -
'0';
134 : mnMinCharPos( -1 ),
136 mnUnitsPerPixel( 1 ),
138 maDrawOffset( 0, 0 ),
139 mbTextRenderModeForResolutionIndependentLayout(
false)
164 static double fCos = 1.0, fSin = 0.0;
173 double fX = aOfs.getX();
174 double fY = aOfs.getY();
177 double nX = +fCos * fX + fSin * fY;
178 double nY = +fCos * fY - fSin * fX;
203 while (
GetNextGlyph(&pGlyph, aPos, nStart, &pGlyphFont))
210 if( bSuccess && (aGlyphOutline.
count() > 0) )
218 rVector.push_back( aGlyphOutline );
222 return (bAllOk && bOneOk);
236 while (
GetNextGlyph(&pGlyph, aPos, nStart, &pGlyphFont))
246 rRect.
Union(aRectangle);
281 if( nMinPos > nXPos )
283 nXPos += aGlyphItem.newWidth() - aGlyphItem.xOffset();
284 if( nMaxPos < nXPos )
296 if( !nOldWidth || nNewWidth==nOldWidth )
304 std::vector<GlyphItem>::iterator pGlyphIterRight =
m_GlyphItems.begin();
306 std::vector<GlyphItem>::iterator pGlyphIter;
308 int nStretchable = 0;
309 int nMaxGlyphWidth = 0;
310 for(pGlyphIter =
m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter)
312 if( !pGlyphIter->IsDiacritic() )
314 if (nMaxGlyphWidth < pGlyphIter->origWidth())
315 nMaxGlyphWidth = pGlyphIter->origWidth();
319 nOldWidth -= pGlyphIterRight->origWidth();
322 if( nNewWidth < nMaxGlyphWidth)
323 nNewWidth = nMaxGlyphWidth;
324 nNewWidth -= pGlyphIterRight->origWidth();
325 pGlyphIterRight->setLinearPosX( nNewWidth );
328 int nDiffWidth = nNewWidth - nOldWidth;
333 for( pGlyphIter =
m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter )
336 pGlyphIter->adjustLinearPosX(nDeltaSum);
339 if( pGlyphIter->IsDiacritic() || (nStretchable <= 0) )
343 int nDeltaWidth = nDiffWidth / nStretchable--;
344 nDiffWidth -= nDeltaWidth;
345 pGlyphIter->addNewWidth(nDeltaWidth);
346 nDeltaSum += nDeltaWidth;
352 double fSqueeze =
static_cast<double>(nNewWidth) / nOldWidth;
355 for( pGlyphIter =
m_GlyphItems.begin(); ++pGlyphIter != pGlyphIterRight;)
357 int nX = pGlyphIter->linearPos().getX();
358 nX =
static_cast<int>(nX * fSqueeze);
359 pGlyphIter->setLinearPosX( nX );
363 for( pGlyphIter =
m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter )
364 pGlyphIter->setNewWidth( pGlyphIter[1].linearPos().getX() - pGlyphIter[0].linearPos().getX());
375 static const signed char nTable[0x30] =
377 0, -2, -2, 0, 0, 0, 0, 0, +2, -2, +2, -2, +2, -2, +2, -2,
378 +2, -2, 0, 0, +2, -2, +2, -2, 0, 0, 0, 0, 0, +2, -2, -2,
379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, +2, +2, -2, -2
383 if( (c >= 0x3000) && (c < 0x3030) )
384 nResult = nTable[ c - 0x3000 ];
388 nResult = bLeft ? -1 : +1;
390 case 0x2019:
case 0x201D:
391 case 0xFF01:
case 0xFF09:
case 0xFF0C:
392 case 0xFF1A:
case 0xFF1B:
395 case 0x2018:
case 0x201C:
408 return (0x3000 == (cp & 0xFF00)) || (0xFF00 == (cp & 0xFF00)) || (0x2010 == (cp & 0xFFF0));
413 const int nLength = rStr.getLength();
416 for (std::vector<GlyphItem>::iterator pGlyphIter =
m_GlyphItems.begin(),
418 pGlyphIter != pGlyphIterEnd; ++pGlyphIter)
420 const int n = pGlyphIter->charPos();
433 if (nKernCurrent == 0)
440 DeviceCoordinate nDelta = (nKernCurrent < nKernNext) ? nKernCurrent : nKernNext;
443 nDelta = (nDelta * pGlyphIter->origWidth() + 2) / 4;
444 if( pGlyphIter+1 == pGlyphIterEnd )
445 pGlyphIter->addNewWidth( nDelta );
451 if( pGlyphIter+1 != pGlyphIterEnd )
452 pGlyphIter->adjustLinearPosX(nOffset);
459 for (
int i = 0;
i < nMaxIndex; ++
i)
460 pCaretXArray[
i] = -1;
466 tools::Long nXRight = nXPos + aGlyphItem.origWidth();
467 int n = aGlyphItem.charPos();
470 if (aGlyphItem.IsInCluster() && pCaretXArray[nCurrIdx] != -1)
472 if (!aGlyphItem.IsRTLGlyph() )
475 pCaretXArray[ nCurrIdx ] = nXPos;
476 pCaretXArray[ nCurrIdx+1 ] = nXRight;
481 pCaretXArray[ nCurrIdx ] = nXRight;
482 pCaretXArray[ nCurrIdx+1 ] = nXPos;
489 std::vector<DeviceCoordinate> aCharWidths;
500 if( nWidth > nMaxWidth )
503 nWidth += nCharExtra;
515 std::vector<GlyphItem>::const_iterator pGlyphIter =
m_GlyphItems.begin();
516 std::vector<GlyphItem>::const_iterator pGlyphIterEnd =
m_GlyphItems.end();
517 pGlyphIter += nStart;
520 for(; pGlyphIter != pGlyphIterEnd; ++nStart, ++pGlyphIter )
522 int n = pGlyphIter->charPos();
531 if( pGlyphIter == pGlyphIterEnd )
535 *pGlyph = &(*pGlyphIter);
541 DevicePoint aRelativePos = pGlyphIter->linearPos();
555 std::vector<GlyphItem>::iterator pGlyphIter =
m_GlyphItems.begin();
556 pGlyphIter += nStart;
561 if( pGlyphIter->IsRTLGlyph() )
562 nNewXPos += pGlyphIter->newWidth() - pGlyphIter->origWidth();
564 tools::Long nXDelta = nNewXPos - pGlyphIter->linearPos().getX() + pGlyphIter->xOffset();
568 for( std::vector<GlyphItem>::iterator pGlyphIterEnd =
m_GlyphItems.end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter )
570 pGlyphIter->adjustLinearPosX(nXDelta);
580 std::vector<GlyphItem>::iterator pGlyphIter =
m_GlyphItems.begin();
581 pGlyphIter += nStart;
582 pGlyphIter->dropGlyph();
607 , mbIncomplete(
false )
609 assert(dynamic_cast<GenericSalLayout*>(pBaseLayout.get()));
611 mpLayouts[ 0 ].reset(static_cast<GenericSalLayout*>(pBaseLayout.release()));
633 assert(dynamic_cast<GenericSalLayout*>(pFallback.get()));
637 mpLayouts[
mnLevel ].reset(static_cast<GenericSalLayout*>(pFallback.release()));
655 std::vector<DeviceCoordinate> aJustificationArray;
675 int nStretchable = 0;
676 for(
int i = 0;
i < nCharCount; ++
i )
679 nOrigWidth += aJustificationArray[
i];
680 if( aJustificationArray[
i] > 0 )
685 if( nOrigWidth && (nTargetWidth != nOrigWidth) )
689 for(
int i = 0;
i < nCharCount; ++
i )
692 if( (nJustWidth > 0) && (nStretchable > 0) )
695 nJustWidth += nDeltaWidth;
696 nDiffWidth -= nDeltaWidth;
699 nWidthSum += nJustWidth;
700 aJustificationArray[
i] = nWidthSum;
702 if( nWidthSum != nTargetWidth )
703 aJustificationArray[ nCharCount-1 ] = nTargetWidth;
709 for(
int i = 0;
i < nCharCount; ++
i )
718 aMultiArgs.
mpDXArray = aJustificationArray.data();
728 template<
typename DC>
731 const DC* pMultiDXArray)
738 int nRunStart, nRunEnd;
739 while (rArgs.
GetNextRun(&nRunStart, &nRunEnd, &bRtl))
741 if (bRtl) std::fill(vRtl.begin() + (nRunStart - rArgs.
mnMinCharPos),
774 nStartNew[ nLevel ] = nStartOld[ nLevel ] = 0;
775 bValid[nLevel] =
mpLayouts[
n]->GetNextGlyph(&pGlyphs[nLevel], aPos, nStartNew[nLevel]);
777 if( (
n > 0) && !bValid[ nLevel ] )
797 double fUnitMul = 1.0;
798 for(
n = 0;
n < nLevel; ++
n )
801 int nFirstValid = -1;
802 for(
n = 0;
n < nLevel; ++
n )
810 assert(nFirstValid >= 0);
813 int nActiveCharPos = pGlyphs[nFirstValid]->
charPos();
816 int nLastRunEndChar = (nActiveCharIndex >= 0 && vRtl[nActiveCharIndex]) ?
818 int nRunVisibleEndChar = pGlyphs[nFirstValid]->
charPos();
820 while( bValid[nFirstValid] && (nLevel > 0))
823 for(
n = 0;
n < nLevel; ++
n )
852 nStartOld[0] = nStartNew[0];
853 bValid[nFirstValid] =
mpLayouts[0]->GetNextGlyph(&pGlyphs[nFirstValid], aPos, nStartNew[0]);
855 if( !bValid[nFirstValid] )
862 bool bKeepNotDef = (nFBLevel >= nLevel);
868 nStartOld[
n] = nStartNew[
n];
869 int nOrigCharPos = pGlyphs[
n]->
charPos();
870 bValid[
n] =
mpLayouts[
n]->GetNextGlyph(&pGlyphs[
n], aPos, nStartNew[n]);
883 if ((n+1 < nLevel) && (pGlyphs[n]->charPos() != nOrigCharPos))
885 if (nOrigCharPos < pGlyphs[n]->charPos())
887 if (pGlyphs[n+1]->charPos() > nOrigCharPos && (pGlyphs[n+1]->charPos() < pGlyphs[n]->charPos()))
890 else if (nOrigCharPos > pGlyphs[n]->charPos())
892 if (pGlyphs[n+1]->charPos() > pGlyphs[n]->charPos() && (pGlyphs[n+1]->charPos() < nOrigCharPos))
909 if (!
maFallbackRuns[nLevel-1].PosIsInRun(pGlyphs[nFirstValid]->charPos()))
912 if( bKeepNotDef && !bNeedFallback )
914 bKeepNotDef = bNeedFallback;
919 nRunVisibleEndChar >= mnMinCharPos &&
921 pGlyphs[n]->charPos() >= mnMinCharPos)
923 if (vRtl[nActiveCharPos - mnMinCharPos])
925 if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos]
926 >= pMultiDXArray[pGlyphs[n]->charPos() - mnMinCharPos])
928 nRunVisibleEndChar = pGlyphs[n]->
charPos();
931 else if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos]
932 <= pMultiDXArray[pGlyphs[n]->charPos() - mnMinCharPos])
934 nRunVisibleEndChar = pGlyphs[n]->
charPos();
947 if (nActiveCharIndex >= 0 && vRtl[nActiveCharIndex])
949 if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <=
mnEndCharPos)
950 nRunAdvance -= pMultiDXArray[nRunVisibleEndChar - 1 -
mnMinCharPos];
951 if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <=
mnEndCharPos)
952 nRunAdvance += pMultiDXArray[nLastRunEndChar - 1 -
mnMinCharPos];
956 if (nRunVisibleEndChar >= mnMinCharPos)
957 nRunAdvance += pMultiDXArray[nRunVisibleEndChar -
mnMinCharPos];
958 if (nLastRunEndChar >= mnMinCharPos)
959 nRunAdvance -= pMultiDXArray[nLastRunEndChar -
mnMinCharPos];
961 nLastRunEndChar = nRunVisibleEndChar;
962 nRunVisibleEndChar = pGlyphs[nFirstValid]->
charPos();
972 nRunAdvance =
static_cast<tools::Long>(nRunAdvance*fUnitMul + 0.5);
976 nXPos += nRunAdvance;
979 nActiveCharPos = pGlyphs[nFirstValid]->
charPos();
983 for(
int i = nFBLevel; --
i >= 0;)
989 if (nRunStart > nActiveCharPos)
994 if (nRunEnd <= nActiveCharPos)
1030 return mpLayouts[0]->GetTextBreak( nMaxWidth, nCharExtra, nFactor );
1033 std::vector<DeviceCoordinate> aCharWidths;
1034 std::vector<DeviceCoordinate> aFallbackCharWidths;
1035 mpLayouts[0]->FillDXArray( &aCharWidths );
1043 for(
int i = 0;
i < nCharCount; ++
i )
1045 if( aCharWidths[
i ] == 0 )
1049 aCharWidths[
i ] = w;
1055 for(
int i = 0;
i < nCharCount; ++
i )
1057 nWidth += aCharWidths[
i ] * nFactor;
1058 if( nWidth > nMaxWidth )
1059 return (
i + mnMinCharPos);
1060 nWidth += nCharExtra;
1071 std::vector<DeviceCoordinate> aTempWidths;
1075 pCharWidths->clear();
1076 pCharWidths->resize(nCharCount, 0);
1087 fUnitMul /=
mpLayouts[
n]->GetUnitsPerPixel();
1089 if( nMaxWidth < nTextWidth )
1090 nMaxWidth = nTextWidth;
1094 for(
int i = 0;
i < nCharCount; ++
i )
1098 if( (*pCharWidths)[
i] != 0 )
1104 (*pCharWidths)[
i] = nCharWidth;
1119 std::unique_ptr<sal_Int32[]>
const pTempPos(
new sal_Int32[nMaxIndex]);
1122 mpLayouts[
n ]->GetCaretPositions( nMaxIndex, pTempPos.get() );
1124 fUnitMul /=
mpLayouts[
n]->GetUnitsPerPixel();
1125 for(
int i = 0;
i < nMaxIndex; ++
i )
1126 if( pTempPos[
i] >= 0 )
1128 sal_Int32
w = pTempPos[
i];
1129 w =
static_cast<sal_Int32
>(w*fUnitMul + 0.5);
1130 pCaretXArray[
i] = w;
1141 int nLevel =
static_cast<unsigned>(nStart) >>
GF_FONTSHIFT;
1143 for(; nLevel <
mnLevel; ++nLevel, nStart=0 )
1148 if (rLayout.
GetNextGlyph(pGlyph, rPos, nStart, ppGlyphFont))
1153 *pFallbackFont = pFontFace;
1185 bool bValid =
mpLayouts[0]->IsKashidaPosValid(nCharPos);
1196 bValid =
mpLayouts[
i]->IsKashidaPosValid(nCharPos);
DevicePoint GetDrawPosition(const DevicePoint &rRelative=DevicePoint(0, 0)) const
DeviceCoordinate GetTextWidth() const final override
virtual bool GetOutline(basegfx::B2DPolyPolygonVector &) const
DeviceCoordinate FillDXArray(std::vector< DeviceCoordinate > *pDXArray) const override
void GetCaretPositions(int nArraySize, sal_Int32 *pCaretXArray) const override
void AddFallback(std::unique_ptr< SalLayout > pFallbackLayout, ImplLayoutRuns const &)
void GetCharWidths(std::vector< DeviceCoordinate > &rCharWidths) const
int GetUnitsPerPixel() const
#define LANGUAGE_ARABIC_SAUDI_ARABIA
std::unique_ptr< SalLayout > ReleaseBaseLayout()
#define LANGUAGE_URDU_PAKISTAN
bool GetOutline(basegfx::B2DPolyPolygonVector &) const override
std::unique_ptr< GenericSalLayout > mpLayouts[MAX_FALLBACK]
#define LANGUAGE_MONGOLIAN_MONGOLIAN_LSO
void InitFont() const override
#define LANGUAGE_AMHARIC_ETHIOPIA
void ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs &rArgs, vcl::text::ImplLayoutArgs &rMultiArgs, const DC *pMultiDXArray)
sal_UCS4 GetMirroredChar(sal_UCS4 nChar)
void Justify(DeviceCoordinate nNewWidth)
bool LayoutText(vcl::text::ImplLayoutArgs &, const SalLayoutGlyphsImpl *) override
sal_Int32 DeviceCoordinate
bool GetNextRun(int *nMinRunPos, int *nEndRunPos, bool *bRTL)
LogicalFontInstance & GetFont() const
MultiSalLayout(std::unique_ptr< SalLayout > pBaseLayout)
void AppendImpl(SalLayoutGlyphsImpl *pImpl)
const DeviceCoordinate * mpDXArray
#define LANGUAGE_GUJARATI
void SetIncomplete(bool bIncomplete)
static bool lcl_CanApplyAsianKerning(sal_Unicode cp)
bool IsKashidaPosValid(int nCharPos) const override
bool GetNextGlyph(const GlyphItem **pGlyph, DevicePoint &rPos, int &nStart, const LogicalFontInstance **ppGlyphFont=nullptr, const vcl::font::PhysicalFontFace **pFallbackFont=nullptr) const override
void ApplyAsianKerning(const OUString &rStr)
bool GetBoundRect(tools::Rectangle &) const
SalLayoutGlyphsImpl m_GlyphItems
virtual void AdjustLayout(vcl::text::ImplLayoutArgs &)
bool GetGlyphOutline(const LogicalFontInstance *, basegfx::B2DPolyPolygon &) const
bool GetNextGlyph(const GlyphItem **pGlyph, DevicePoint &rPos, int &nStart, const LogicalFontInstance **ppGlyphFont=nullptr, const vcl::font::PhysicalFontFace **pFallbackFont=nullptr) const override
void AdjustLayout(vcl::text::ImplLayoutArgs &) override
virtual void InitFont() const
virtual void DrawText(SalGraphics &) const =0
bool PosIsInRun(int nCharPos) const
void DropGlyph(int nStart)
DeviceCoordinate FillDXArray(std::vector< DeviceCoordinate > *pDXArray) const final override
void transform(const basegfx::B2DHomMatrix &rMatrix)
#define LANGUAGE_TIGRIGNA_ETHIOPIA
constexpr LanguageType primary(LanguageType lt)
virtual ~MultiSalLayout() override
#define LANGUAGE_MALAYALAM
const rtl::Reference< LogicalFontInstance > & GetFont() const
virtual SalLayoutGlyphs GetGlyphs() const
virtual void GetCaretPositions(int nArraySize, sal_Int32 *pCaretXArray) const =0
void GetCaretPositions(int nArraySize, sal_Int32 *pCaretXArray) const final override
#define LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA
const double * mpAltNaturalDXArray
abstract base class for physical font faces
basegfx::B2DPoint DevicePoint
void MoveGlyph(int nStart, tools::Long nNewXPos)
DeviceCoordinate newWidth() const
static int lcl_CalcAsianKerning(sal_UCS4 c, bool bLeft)
void DrawText(SalGraphics &) const override
#define LANGUAGE_MONGOLIAN_MONGOLIAN_CHINA
sal_UCS4 GetLocalizedChar(sal_UCS4 nChar, LanguageType eLang)
SalLayoutGlyphs GetGlyphs() const final override
bool GetGlyphBoundRect(const LogicalFontInstance *, tools::Rectangle &) const
ImplLayoutRuns maFallbackRuns[MAX_FALLBACK]
virtual bool GetNextGlyph(const GlyphItem **pGlyph, DevicePoint &rPos, int &nStart, const LogicalFontInstance **ppGlyphFont=nullptr, const vcl::font::PhysicalFontFace **pFallbackFont=nullptr) const =0
sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const final override
virtual DeviceCoordinate FillDXArray(std::vector< DeviceCoordinate > *pDXArray) const =0
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
void Simplify(bool bIsBase)
DeviceCoordinate mnLayoutWidth
bool mbTextRenderModeForResolutionIndependentLayout
const vcl::font::PhysicalFontFace * GetFontFace() const
sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override
bool anyOf(strong_int v) const
bool m_bDetectedRangeSegmentation false
::std::vector< B2DPolyPolygon > B2DPolyPolygonVector