summaryrefslogtreecommitdiff
path: root/vcl/win/gdi
diff options
context:
space:
mode:
authorKhaled Hosny <khaledhosny@eglug.org>2016-12-01 03:33:30 +0200
committerKhaled Hosny <khaledhosny@eglug.org>2016-12-01 08:50:01 +0000
commit6c436ba09cb35235ce6f4065cf74c9a6ff14a4bd (patch)
tree8f86b4f2889e42dd2ba9ebe036b6f9665299eb87 /vcl/win/gdi
parent6e5e55c29eee285e56fe7f9708e9faf3ad62eec2 (diff)
Kill old Windows layout engines
Change-Id: I33f8322a6371150698bf926165fb6dddb9d4092c Reviewed-on: https://gerrit.libreoffice.org/31452 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
Diffstat (limited to 'vcl/win/gdi')
-rw-r--r--vcl/win/gdi/salfont.cxx129
-rw-r--r--vcl/win/gdi/salgdi.cxx5
-rw-r--r--vcl/win/gdi/winlayout.cxx2949
3 files changed, 18 insertions, 3065 deletions
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 5d1e6bc9b20d..7147be10f6c5 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -613,16 +613,12 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
: PhysicalFontFace( rDFS ),
mnId( 0 ),
- mbHasCJKSupport( false ),
- mbHasArabicSupport ( false ),
mbFontCapabilitiesRead( false ),
mxUnicodeMap( nullptr ),
- mpEncodingVector( nullptr ),
meWinCharSet( eWinCharSet ),
mnPitchAndFamily( nPitchAndFamily ),
mbAliasSymbolsHigh( false ),
mbAliasSymbolsLow( false ),
- mbGsubRead( false ),
mpHbFont( nullptr )
{
SetBitmapSize( 0, nHeight );
@@ -657,8 +653,6 @@ WinFontFace::~WinFontFace()
if( mxUnicodeMap.Is() )
mxUnicodeMap = nullptr;
- delete mpEncodingVector;
-
if( mpHbFont )
hb_font_destroy( mpHbFont );
}
@@ -681,18 +675,6 @@ void WinFontFace::UpdateFromHDC( HDC hDC ) const
GetFontCapabilities( hDC );
}
-bool WinFontFace::HasGSUBstitutions( HDC hDC ) const
-{
- if( !mbGsubRead )
- ReadGsubTable( hDC );
- return !maGsubTable.empty();
-}
-
-bool WinFontFace::IsGSUBstituted( sal_UCS4 cChar ) const
-{
- return( maGsubTable.find( cChar ) != maGsubTable.end() );
-}
-
FontCharMapRef WinFontFace::GetFontCharMap() const
{
return mxUnicodeMap;
@@ -704,51 +686,6 @@ bool WinFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities)
return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange;
}
-void WinFontFace::ReadGsubTable( HDC hDC ) const
-{
- mbGsubRead = true;
-
- // check the existence of a GSUB table
- const DWORD GsubTag = CalcTag( "GSUB" );
- DWORD nRC = ::GetFontData( hDC, GsubTag, 0, nullptr, 0 );
- if( (nRC == GDI_ERROR) || !nRC )
- return;
-
- // parse the GSUB table through sft
- // TODO: parse it directly
-
- // sft needs the full font file data => get it
- const RawFontData aRawFontData( hDC );
- if( !aRawFontData.get() )
- return;
-
- // open font file
- sal_uInt32 nFaceNum = 0;
- if( !*aRawFontData.get() ) // TTC candidate
- nFaceNum = ~0U; // indicate "TTC font extracts only"
-
- TrueTypeFont* pTTFont = nullptr;
- ::OpenTTFontBuffer( aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
- if( !pTTFont )
- return;
-
- // add vertically substituted characters to list
- static const sal_Unicode aGSUBCandidates[] = {
- 0x0020, 0x0080, // ASCII
- 0x2000, 0x2600, // misc
- 0x3000, 0x3100, // CJK punctutation
- 0x3300, 0x3400, // squared words
- 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
- 0 };
-
- for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
- for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
- if( ::MapChar( pTTFont, cChar, false ) != ::MapChar( pTTFont, cChar, true ) )
- maGsubTable.insert( cChar ); // insert GSUBbed unicodes
-
- CloseTTFont( pTTFont );
-}
-
void WinFontFace::ReadCmapTable( HDC hDC ) const
{
if( mxUnicodeMap.Is() )
@@ -784,37 +721,15 @@ void WinFontFace::GetFontCapabilities( HDC hDC ) const
mbFontCapabilitiesRead = true;
- // GSUB table
- DWORD nLength;
- const DWORD GsubTag = CalcTag( "GSUB" );
- nLength = ::GetFontData( hDC, GsubTag, 0, nullptr, 0 );
- if( (nLength != GDI_ERROR) && nLength )
- {
- std::vector<unsigned char> aTable( nLength );
- unsigned char* pTable = &aTable[0];
- ::GetFontData( hDC, GsubTag, 0, pTable, nLength );
- vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pTable, nLength);
- }
-
// OS/2 table
const DWORD OS2Tag = CalcTag( "OS/2" );
- nLength = ::GetFontData( hDC, OS2Tag, 0, nullptr, 0 );
+ DWORD nLength = ::GetFontData( hDC, OS2Tag, 0, nullptr, 0 );
if( (nLength != GDI_ERROR) && nLength )
{
std::vector<unsigned char> aTable( nLength );
unsigned char* pTable = &aTable[0];
::GetFontData( hDC, OS2Tag, 0, pTable, nLength );
- if (vcl::getTTCoverage(maFontCapabilities.oUnicodeRange, maFontCapabilities.oCodePageRange, pTable, nLength))
- {
- // Check for CJK capabilities of the current font
- // TODO, we have this info already from getTT, decode bits to
- // a readable bitset
- sal_uInt32 ulUnicodeRange1 = GetUInt( pTable + 42 );
- sal_uInt32 ulUnicodeRange2 = GetUInt( pTable + 46 );
-
- mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
- mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
- }
+ vcl::getTTCoverage(maFontCapabilities.oUnicodeRange, maFontCapabilities.oCodePageRange, pTable, nLength);
}
}
@@ -1051,17 +966,6 @@ void WinSalGraphics::SetFont( FontSelectPattern* pFont, int nFallbackLevel )
// now the font is live => update font face
if( mpWinFontData[ nFallbackLevel ] )
mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( getHDC() );
-
- if( !nFallbackLevel )
- {
- mbFontKernInit = TRUE;
- if ( mpFontKernPairs )
- {
- delete[] mpFontKernPairs;
- mpFontKernPairs = nullptr;
- }
- mnFontKernPairCount = 0;
- }
}
void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel )
@@ -1106,35 +1010,6 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFa
rxFontMetric->SetMinKashida( GetMinKashidaWidth() );
}
-sal_uLong WinSalGraphics::GetKernPairs()
-{
- if ( mbFontKernInit )
- {
- if( mpFontKernPairs )
- {
- delete[] mpFontKernPairs;
- mpFontKernPairs = nullptr;
- }
- mnFontKernPairCount = 0;
-
- KERNINGPAIR* pPairs = nullptr;
- int nCount = ::GetKerningPairsW( getHDC(), 0, nullptr );
- if( nCount )
- {
- pPairs = new KERNINGPAIR[ nCount+1 ];
- mpFontKernPairs = pPairs;
- mnFontKernPairCount = nCount;
- ::GetKerningPairsW( getHDC(), nCount, pPairs );
- }
-
- mbFontKernInit = FALSE;
-
- std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
- }
-
- return mnFontKernPairCount;
-}
-
const FontCharMapRef WinSalGraphics::GetFontCharMap() const
{
if( !mpWinFontData[0] )
diff --git a/vcl/win/gdi/salgdi.cxx b/vcl/win/gdi/salgdi.cxx
index 2956fed9f6a6..4c63eeaade00 100644
--- a/vcl/win/gdi/salgdi.cxx
+++ b/vcl/win/gdi/salgdi.cxx
@@ -615,9 +615,6 @@ WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hW
mhDefFont(nullptr),
mhDefPal(nullptr),
mpStdClipRgnData(nullptr),
- mbFontKernInit(false),
- mpFontKernPairs(nullptr),
- mnFontKernPairCount(0),
mnPenWidth(GSL_PEN_WIDTH)
{
if (OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter)
@@ -647,8 +644,6 @@ WinSalGraphics::~WinSalGraphics()
// delete cache data
delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
-
- delete [] mpFontKernPairs;
}
SalGraphicsImpl* WinSalGraphics::GetImpl() const
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index e2ea86581c1a..621c24118728 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -37,7 +37,6 @@
#include <cstdio>
#include <cstdlib>
-#include <sal/alloca.h>
#include <rtl/character.hxx>
#include <algorithm>
@@ -45,49 +44,24 @@
#include <shlwapi.h>
#include <winver.h>
-#include <unordered_map>
-#include <unordered_set>
-
-#define DROPPED_OUTGLYPH 0xFFFF
-
// static initialization
std::unique_ptr<GlobalGlyphCache> GlyphCache::gGlobalGlyphCache(new GlobalGlyphCache);
-inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth )
-{
- maWidthMap[ nCharCode ] = nCharWidth;
-}
-
-inline int WinFontInstance::GetCachedGlyphWidth( int nCharCode ) const
-{
- auto it = maWidthMap.find( nCharCode );
- if( it == maWidthMap.end() )
- return -1;
- return it->second;
-}
-
-bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
+bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, SalGraphics& rGraphics)
{
- if (nGlyphIndex == DROPPED_OUTGLYPH)
- return true;
-
OpenGLGlyphDrawElement aElement;
- aElement.mbRealGlyphIndices = bRealGlyphIndices;
- std::vector<uint32_t> aCodePointsOrGlyphIndices(1);
- aCodePointsOrGlyphIndices[0] = nGlyphIndex;
-
- HDC hDC = CreateCompatibleDC(rLayout.mhDC);
- if (hDC == nullptr)
+ HDC hNewDC = CreateCompatibleDC(hDC);
+ if (hNewDC == nullptr)
{
SAL_WARN("vcl.gdi", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError()));
return false;
}
- HFONT hOrigFont = static_cast<HFONT>(SelectObject(hDC, rLayout.mhFont));
+ HFONT hOrigFont = static_cast<HFONT>(SelectObject(hDC, hFont));
if (hOrigFont == nullptr)
{
SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
- DeleteDC(hDC);
+ DeleteDC(hNewDC);
return false;
}
@@ -96,26 +70,26 @@ bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex,
if (!pTxt)
return false;
- if (!pTxt->BindFont(hDC))
+ if (!pTxt->BindFont(hNewDC))
{
SAL_WARN("vcl.gdi", "Binding of font failed. The font might not be supported by Direct Write.");
- DeleteDC(hDC);
+ DeleteDC(hNewDC);
return false;
}
// Bail for non-horizontal text.
{
wchar_t sFaceName[200];
- int nFaceNameLen = GetTextFaceW(hDC, SAL_N_ELEMENTS(sFaceName), sFaceName);
+ int nFaceNameLen = GetTextFaceW(hNewDC, SAL_N_ELEMENTS(sFaceName), sFaceName);
if (!nFaceNameLen)
SAL_WARN("vcl.gdi", "GetTextFace failed: " << WindowsErrorString(GetLastError()));
LOGFONTW aLogFont;
- GetObjectW(rLayout.mhFont, sizeof(LOGFONTW), &aLogFont);
+ GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont);
- SelectObject(hDC, hOrigFont);
- DeleteDC(hDC);
+ SelectObject(hNewDC, hOrigFont);
+ DeleteDC(hNewDC);
if (sFaceName[0] == '@' || aLogFont.lfOrientation != 0 || aLogFont.lfEscapement != 0)
{
@@ -124,25 +98,8 @@ bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex,
}
}
std::vector<WORD> aGlyphIndices(1);
+ aGlyphIndices[0] = nGlyphIndex;
// Fetch the ink boxes and calculate the size of the atlas.
- if (!bRealGlyphIndices)
- {
- if (!pTxt->GetFontFace())
- {
- SAL_WARN("vcl.gdi", "Font face is not available.");
- return false;
- }
- if (!SUCCEEDED(pTxt->GetFontFace()->GetGlyphIndices(aCodePointsOrGlyphIndices.data(), aCodePointsOrGlyphIndices.size(), aGlyphIndices.data())))
- {
- pTxt->ReleaseFont();
- return false;
- }
- }
- else
- {
- aGlyphIndices[0] = aCodePointsOrGlyphIndices[0];
- }
-
Rectangle bounds(0, 0, 0, 0);
auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + 1);
for (auto &box : aInkBoxes)
@@ -268,2787 +225,6 @@ bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex,
return true;
}
-SimpleWinLayout::SimpleWinLayout(HDC hDC, const WinFontFace& rWinFontData,
- WinFontInstance& rWinFontEntry, bool bUseOpenGL)
-: WinLayout(hDC, rWinFontData, rWinFontEntry, bUseOpenGL),
- mnGlyphCount( 0 ),
- mnCharCount( 0 ),
- mpOutGlyphs( nullptr ),
- mpGlyphAdvances( nullptr ),
- mpGlyphOrigAdvs( nullptr ),
- mpCharWidths( nullptr ),
- mpChars2Glyphs( nullptr ),
- mpGlyphs2Chars( nullptr ),
- mpGlyphRTLFlags( nullptr ),
- mnWidth( 0 ),
- mnNotdefWidth( -1 )
-{
-}
-
-SimpleWinLayout::~SimpleWinLayout()
-{
- delete[] mpGlyphRTLFlags;
- delete[] mpGlyphs2Chars;
- delete[] mpChars2Glyphs;
- if( mpCharWidths != mpGlyphAdvances )
- delete[] mpCharWidths;
- delete[] mpGlyphOrigAdvs;
- delete[] mpGlyphAdvances;
- delete[] mpOutGlyphs;
-}
-
-bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
-{
- // prepare layout
- // TODO: fix case when recyclying old SimpleWinLayout object
- mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
-
- // TODO: use a cached value for bDisableAsianKern from upper layers
- if( rArgs.mnFlags & SalLayoutFlags::KerningAsian )
- {
- TEXTMETRICA aTextMetricA;
- if( GetTextMetricsA( mhDC, &aTextMetricA )
- && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) )
- rArgs.mnFlags &= ~SalLayoutFlags::KerningAsian;
- }
-
- // layout text
- int i, j;
-
- mnGlyphCount = 0;
- bool bVertical(rArgs.mnFlags & SalLayoutFlags::Vertical);
-
- // count the number of chars to process if no RTL run
- rArgs.ResetPos();
- bool bHasRTL = false;
- while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
- mnGlyphCount += j - i;
-
- // if there are RTL runs we need room to remember individual BiDi flags
- if( bHasRTL )
- {
- mpGlyphRTLFlags = new bool[ mnCharCount ];
- for( i = 0; i < mnCharCount; ++i )
- mpGlyphRTLFlags[i] = false;
- }
-
- // rewrite the logical string if needed to prepare for the API calls
- const sal_Unicode* pBidiStr = rArgs.mrStr.pData->buffer + rArgs.mnMinCharPos;
- if( (mnGlyphCount != mnCharCount) || bVertical )
- {
- // we need to rewrite the pBidiStr when any of
- // - BiDirectional layout
- // - vertical layout
- // - partial runs (e.g. with control chars or for glyph fallback)
- // are involved
- sal_Unicode* pRewrittenStr = static_cast<sal_Unicode*>(alloca( mnCharCount * sizeof(sal_Unicode) ));
- pBidiStr = pRewrittenStr;
-
- // note: glyph to char mapping is relative to first character
- mpChars2Glyphs = new int[ mnCharCount ];
- mpGlyphs2Chars = new int[ mnCharCount ];
- for( i = 0; i < mnCharCount; ++i )
- mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
-
- mnGlyphCount = 0;
- rArgs.ResetPos();
- bool bIsRTL = false;
- while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
- {
- do
- {
- // get the next leftmost character in this run
- int nCharPos = bIsRTL ? --j : i++;
- sal_UCS4 cChar = rArgs.mrStr[ nCharPos ];
-
- // in the RTL case mirror the character and remember its RTL status
- if( bIsRTL )
- {
- cChar = GetMirroredChar( cChar );
- mpGlyphRTLFlags[ mnGlyphCount ] = true;
- }
-
- // rewrite the original string
- // update the mappings between original and rewritten string
- // TODO: support surrogates in rewritten strings
- pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar);
- mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
- mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
- ++mnGlyphCount;
- } while( i < j );
- }
- }
-
- mpOutGlyphs = new WCHAR[ mnGlyphCount ];
- mpGlyphAdvances = new int[ mnGlyphCount ];
-
- if( rArgs.mnFlags & (SalLayoutFlags::KerningPairs | SalLayoutFlags::KerningAsian) )
- mpGlyphOrigAdvs = new int[ mnGlyphCount ];
-
- for( i = 0; i < mnGlyphCount; ++i )
- mpOutGlyphs[i] = pBidiStr[ i ];
- mnWidth = 0;
- for( i = 0; i < mnGlyphCount; ++i )
- {
- // get the current UCS-4 code point, check for surrogate pairs
- const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]);
- unsigned nCharCode = pCodes[0];
- bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF));
- if( bSurrogate )
- {
- // ignore high surrogates, they were already processed with their low surrogates
- if( nCharCode >= 0xDC00 )
- continue;
- // check the second half of the surrogate pair
- bSurrogate &= (0xDC00 <= pCodes[1]) && (pCodes[1] <= 0xDFFF);
- // calculate the UTF-32 code of valid surrogate pairs
- if( bSurrogate )
- nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00);
- else // or fall back to a replacement character
- {
- // FIXME: Surely this is an error situation that should not happen?
- nCharCode = '?';
- }
- }
-
- int nGlyphWidth = 0;
- // Unicode variance selectors selects glyph of previous base character, do not have width itself.
- if ( (nCharCode >= 0xFE00 && nCharCode <= 0xFE0F) || (nCharCode >= 0xE0100 && nCharCode <= 0xE01EF) )
- {
- mpOutGlyphs[ i ] = DROPPED_OUTGLYPH;
- mpGlyphAdvances[ i ] = 0;
- if ( bSurrogate && ( i+1 ) < mnGlyphCount )
- {
- mpOutGlyphs[ ++i ] = DROPPED_OUTGLYPH;
- mpGlyphAdvances[ i ] = 0;
- }
- continue;
- }
- else
- {
- // get the advance width for the current UTF-32 code point
- nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode );
- }
-
- if( nGlyphWidth == -1 )
- {
- ABC aABC;
- SIZE aExtent;
- if( GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) )
- nGlyphWidth = aExtent.cx;
- else if( GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) )
- nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC;
- else if( !GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth )
- && !GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) )
- nGlyphWidth = 0;
- mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
- }
- mpGlyphAdvances[ i ] = nGlyphWidth;
- mnWidth += nGlyphWidth;
-
- // the second half of surrogate pair gets a zero width
- if( bSurrogate && ((i+1) < mnGlyphCount) )
- mpGlyphAdvances[ i+1 ] = 0;
-
- // check with the font face if glyph fallback is needed
- if( mrWinFontData.HasChar( nCharCode ) )
- continue;
-
- // request glyph fallback at this position in the string
- bool bRTL = mpGlyphRTLFlags && mpGlyphRTLFlags[i];
- int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
- rArgs.NeedFallback( nCharPos, bRTL );
- if( bSurrogate && ((nCharPos+1) < rArgs.mrStr.getLength()) )
- rArgs.NeedFallback( nCharPos+1, bRTL );
-
- // replace the current glyph shape with the NotDef glyph shape
- if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
- {
- // when we already are layouting for glyph fallback
- // then a new unresolved glyph is not interesting
- mnNotdefWidth = 0;
- mpOutGlyphs[i] = DROPPED_OUTGLYPH;
- }
- else
- {
- if( mnNotdefWidth < 0 )
- {
- // get the width of the NotDef glyph
- SIZE aExtent;
- WCHAR cNotDef = rArgs.mrStr[ nCharPos ];
- mnNotdefWidth = 0;
- if( GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) )
- mnNotdefWidth = aExtent.cx;
- }
- }
- if( bSurrogate && ((i+1) < mnGlyphCount) )
- mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
-
- // adjust the current glyph width to the NotDef glyph width
- mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
- mpGlyphAdvances[i] = mnNotdefWidth;
- if( mpGlyphOrigAdvs )
- mpGlyphOrigAdvs[i] = mnNotdefWidth;
- }
-
- // apply kerning if the layout engine has not yet done it
- if( rArgs.mnFlags & (SalLayoutFlags::KerningAsian|SalLayoutFlags::KerningPairs) )
- {
- for( i = 0; i < mnGlyphCount; ++i )
- mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
-
- // #99658# also apply asian kerning on the substring border
- int nLen = mnGlyphCount;
- if( rArgs.mnMinCharPos + nLen < rArgs.mrStr.getLength() )
- ++nLen;
- for( i = 1; i < nLen; ++i )
- {
- if( rArgs.mnFlags & SalLayoutFlags::KerningPairs )
- {
- int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
- mpGlyphAdvances[ i-1 ] += nKernAmount;
- mnWidth += nKernAmount;
- }
- else if( rArgs.mnFlags & SalLayoutFlags::KerningAsian )
-
- if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1])))
- && ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) )
- {
- long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
- long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical );
-
- long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
- if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
- {
- nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
- mpGlyphAdvances[i-1] += nDelta;
- mnWidth += nDelta;
- }
- }
- }
- }
-
- // calculate virtual char widths
- if( !mpGlyphs2Chars )
- mpCharWidths = mpGlyphAdvances;
- else
- {
- mpCharWidths = new int[ mnCharCount ];
- for( i = 0; i < mnCharCount; ++i )
- mpCharWidths[ i ] = 0;
- for( i = 0; i < mnGlyphCount; ++i )
- {
- int k = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
- if( k >= 0 )
- mpCharWidths[ k ] += mpGlyphAdvances[ i ];
- }
- }
-
- // scale layout metrics if needed
- // TODO: does it make the code more simple if the metric scaling
- // is moved to the methods that need metric scaling (e.g. FillDXArray())?
- if( mfFontScale != 1.0 )
- {
- mnWidth = (long)(mnWidth * mfFontScale);
- mnBaseAdv = (int)(mnBaseAdv * mfFontScale);
- for( i = 0; i < mnCharCount; ++i )
- mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
- if( mpGlyphAdvances != mpCharWidths )
- for( i = 0; i < mnGlyphCount; ++i )
- mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
- if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
- for( i = 0; i < mnGlyphCount; ++i )
- mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale);
- }
-
- return true;
-}
-
-int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIds, Point& rPos, int& nStart,
- DeviceCoordinate* pGlyphAdvances, int* pCharIndexes,
- const PhysicalFontFace** /*pFallbackFonts*/ ) const
-{
- // return zero if no more glyph found
- if( nStart >= mnGlyphCount )
- return 0;
-
- // calculate glyph position relative to layout base
- // TODO: avoid for nStart!=0 case by reusing rPos
- long nXOffset = mnBaseAdv;
- for( int i = 0; i < nStart; ++i )
- nXOffset += mpGlyphAdvances[ i ];
-
- // calculate absolute position in pixel units
- Point aRelativePos( nXOffset, 0 );
- rPos = GetDrawPosition( aRelativePos );
-
- int nCount = 0;
- while( nCount < nLen )
- {
- // update return values {aGlyphId,nCharPos,nGlyphAdvance}
- sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
- if( mnLayoutFlags & SalLayoutFlags::Vertical )
- {
- const sal_UCS4 cChar = static_cast<sal_UCS4>(aGlyphId & GF_IDXMASK);
- if( mrWinFontData.HasGSUBstitutions( mhDC )
- && mrWinFontData.IsGSUBstituted( cChar ) )
- aGlyphId |= GF_GSUB | GF_ROTL;
- else
- {
- aGlyphId |= GetVerticalFlags( cChar );
- if( (aGlyphId & GF_ROTMASK) == 0 )
- aGlyphId |= GF_VERT;
- }
- }
- aGlyphId |= GF_ISCHAR;
-
- ++nCount;
- *(pGlyphIds++) = aGlyphId;
- if( pGlyphAdvances )
- *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
- if( pCharIndexes )
- {
- int nCharPos;
- if( !mpGlyphs2Chars )
- nCharPos = nStart + mnMinCharPos;
- else
- nCharPos = mpGlyphs2Chars[nStart];
- *(pCharIndexes++) = nCharPos;
- }
-
- // stop at last glyph
- if( ++nStart >= mnGlyphCount )
- break;
-
- // stop when next x-position is unexpected
- if( !pGlyphAdvances && mpGlyphOrigAdvs )
- if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
- break;
- }
-
- return nCount;
-}
-
-bool SimpleWinLayout::DrawTextImpl(HDC hDC,
- const Rectangle* /* pRectToErase */,
- Point* /* pPos */,
- int* /* pGetNextGlypInfo */) const
-{
- if( mnGlyphCount <= 0 )
- return false;
-
- HFONT hOrigFont = DisableFontScaling();
- Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
-
- // #108267#, break up into glyph portions of a limited size required by Win32 API
- const unsigned int maxGlyphCount = 8192;
- UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
- UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
-
- if( numGlyphPortions )
- {
- // #108267#,#109387# break up string into smaller chunks
- // the output positions will be updated by windows (SetTextAlign)
- POINT oldPos;
- UINT oldTa = GetTextAlign(hDC);
- SetTextAlign(hDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP);
- MoveToEx(hDC, aPos.X(), aPos.Y(), &oldPos);
- unsigned int i = 0;
- for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount )
- {
- ExtTextOutW(hDC, 0, 0, 0, nullptr, mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i);
- }
- ExtTextOutW(hDC, 0, 0, 0, nullptr, mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i);
- MoveToEx(hDC, oldPos.x, oldPos.y, nullptr);
- SetTextAlign(hDC, oldTa);
- }
- else
- ExtTextOutW(hDC, aPos.X(), aPos.Y(), 0, nullptr, mpOutGlyphs, mnGlyphCount, mpGlyphAdvances);
-
- if( hOrigFont )
- DeleteFont(SelectFont(hDC, hOrigFont));
-
- return false;
-}
-
-DeviceCoordinate SimpleWinLayout::FillDXArray( DeviceCoordinate* pDXArray ) const
-{
- if( !mnWidth )
- {
- mnWidth = mnBaseAdv;
- for( int i = 0; i < mnGlyphCount; ++i )
- mnWidth += mpGlyphAdvances[ i ];
- }
-
- if( pDXArray != nullptr )
- {
- for( int i = 0; i < mnCharCount; ++i )
- pDXArray[ i ] = mpCharWidths[ i ];
- }
-
- return mnWidth;
-}
-
-sal_Int32 SimpleWinLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor ) const
-// NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
-{
- if( mnWidth )
- if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
- return -1;
-
- long nExtraWidth = mnBaseAdv * nFactor;
- for( int n = 0; n < mnCharCount; ++n )
- {
- // skip unused characters
- if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
- continue;
- // add char widths until max
- nExtraWidth += mpCharWidths[ n ] * nFactor;
- if( nExtraWidth > nMaxWidth )
- return (mnMinCharPos + n);
- nExtraWidth += nCharExtra;
- }
-
- return -1;
-}
-
-void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
-{
- long nXPos = mnBaseAdv;
-
- if( !mpGlyphs2Chars )
- {
- for( int i = 0; i < nMaxIdx; i += 2 )
- {
- pCaretXArray[ i ] = nXPos;
- nXPos += mpGlyphAdvances[ i>>1 ];
- pCaretXArray[ i+1 ] = nXPos;
- }
- }
- else
- {
- int i;
- for( i = 0; i < nMaxIdx; ++i )
- pCaretXArray[ i ] = -1;
-
- // assign glyph positions to character positions
- for( i = 0; i < mnGlyphCount; ++i )
- {
- int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
- long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
- nCurrIdx *= 2;
- if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
- {
- // normal positions for LTR case
- pCaretXArray[ nCurrIdx ] = nXPos;
- pCaretXArray[ nCurrIdx+1 ] = nXRight;
- }
- else
- {
- // reverse positions for RTL case
- pCaretXArray[ nCurrIdx ] = nXRight;
- pCaretXArray[ nCurrIdx+1 ] = nXPos;
- }
- nXPos += mpGlyphAdvances[ i ];
- }
- }
-}
-
-void SimpleWinLayout::Justify( DeviceCoordinate nNewWidth )
-{
- DeviceCoordinate nOldWidth = mnWidth;
- mnWidth = nNewWidth;
-
- if( mnGlyphCount <= 0 )
- return;
-
- if( nNewWidth == nOldWidth )
- return;
-
- // the rightmost glyph cannot be stretched
- const int nRight = mnGlyphCount - 1;
- nOldWidth -= mpGlyphAdvances[ nRight ];
- nNewWidth -= mpGlyphAdvances[ nRight ];
-
- // count stretchable glyphs
- int nStretchable = 0, i;
- for( i = 0; i < nRight; ++i )
- if( mpGlyphAdvances[i] >= 0 )
- ++nStretchable;
-
- // stretch these glyphs
- DeviceCoordinate nDiffWidth = nNewWidth - nOldWidth;
- for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
- {
- if( mpGlyphAdvances[i] <= 0 )
- continue;
- DeviceCoordinate nDeltaWidth = nDiffWidth / nStretchable;
- mpGlyphAdvances[i] += nDeltaWidth;
- --nStretchable;
- nDiffWidth -= nDeltaWidth;
- }
-}
-
-void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
-{
- SalLayout::AdjustLayout( rArgs );
-
- // adjust positions if requested
- if( rArgs.mpDXArray )
- ApplyDXArray( rArgs );
- else if( rArgs.mnLayoutWidth )
- Justify( rArgs.mnLayoutWidth );
- else
- return;
-
- // recalculate virtual char widths if they were changed
- if( mpCharWidths != mpGlyphAdvances )
- {
- int i;
- if( !mpGlyphs2Chars )
- {
- // standard LTR case
- for( i = 0; i < mnGlyphCount; ++i )
- mpCharWidths[ i ] = mpGlyphAdvances[ i ];
- }
- else
- {
- // BiDi or complex case
- for( i = 0; i < mnCharCount; ++i )
- mpCharWidths[ i ] = 0;
- for( i = 0; i < mnGlyphCount; ++i )
- {
- int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
- if( j >= 0 )
- mpCharWidths[ j ] += mpGlyphAdvances[ i ];
- }
- }
- }
-}
-
-void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
-{
- // try to avoid disturbance of text flow for LSB rounding case;
- const long* pDXArray = rArgs.mpDXArray;
-
- int i = 0;
- long nOldWidth = mnBaseAdv;
- for(; i < mnCharCount; ++i )
- {
- int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
- if( j >= 0 )
- {
- nOldWidth += mpGlyphAdvances[ j ];
- long nDiff = nOldWidth - pDXArray[ i ];
-
- // disabled because of #104768#
- // works great for static text, but problems when typing
- // if( nDiff>+1 || nDiff<-1 )
- // only bother with changing anything when something moved
- if( nDiff != 0 )
- break;
- }
- }
- if( i >= mnCharCount )
- return;
-
- if( !mpGlyphOrigAdvs )
- {
- mpGlyphOrigAdvs = new int[ mnGlyphCount ];
- for( i = 0; i < mnGlyphCount; ++i )
- mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
- }
-
- mnWidth = mnBaseAdv;
- for( i = 0; i < mnCharCount; ++i )
- {
- int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
- if( j >= 0 )
- mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
- mnWidth = pDXArray[i];
- }
-}
-
-void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
-{
- if( nStart > mnGlyphCount )
- return;
-
- // calculate the current x-position of the requested glyph
- // TODO: cache absolute positions
- int nXPos = mnBaseAdv;
- for( int i = 0; i < nStart; ++i )
- nXPos += mpGlyphAdvances[i];
-
- // calculate the difference to the current glyph position
- int nDelta = nNewXPos - nXPos;
-
- // adjust the width of the layout if it was already cached
- if( mnWidth )
- mnWidth += nDelta;
-
- // depending on whether the requested glyph is leftmost in the layout
- // adjust either the layout's or the requested glyph's relative position
- if( nStart > 0 )
- mpGlyphAdvances[ nStart-1 ] += nDelta;
- else
- mnBaseAdv += nDelta;
-}
-
-void SimpleWinLayout::DropGlyph( int nStart )
-{
- mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
-}
-
-void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
-{
- // return early if no glyph has been dropped
- int i = mnGlyphCount;
- while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
- if( i < 0 )
- return;
-
- // convert the layout to a sparse layout if it is not already
- if( !mpGlyphs2Chars )
- {
- mpGlyphs2Chars = new int[ mnGlyphCount ];
- mpCharWidths = new int[ mnCharCount ];
- // assertion: mnGlyphCount == mnCharCount
- for( int k = 0; k < mnGlyphCount; ++k )
- {
- mpGlyphs2Chars[ k ] = mnMinCharPos + k;
- mpCharWidths[ k ] = mpGlyphAdvances[ k ];
- }
- }
-
- // remove dropped glyphs that are rightmost in the layout
- for( i = mnGlyphCount; --i >= 0; )
- {
- if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
- break;
- if( mnWidth )
- mnWidth -= mpGlyphAdvances[ i ];
- int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
- if( nRelCharPos >= 0 )
- mpCharWidths[ nRelCharPos ] = 0;
- }
- mnGlyphCount = i + 1;
-
- // keep original glyph widths around
- if( !mpGlyphOrigAdvs )
- {
- mpGlyphOrigAdvs = new int[ mnGlyphCount ];
- for( int k = 0; k < mnGlyphCount; ++k )
- mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
- }
-
- // remove dropped glyphs inside the layout
- int nNewGC = 0;
- for( i = 0; i < mnGlyphCount; ++i )
- {
- if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
- {
- // adjust relative position to last valid glyph
- int nDroppedWidth = mpGlyphAdvances[ i ];
- mpGlyphAdvances[ i ] = 0;
- if( nNewGC > 0 )
- mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
- else
- mnBaseAdv += nDroppedWidth;
-
- // zero the virtual char width for the char that has a fallback
- int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
- if( nRelCharPos >= 0 )
- mpCharWidths[ nRelCharPos ] = 0;
- }
- else
- {
- if( nNewGC != i )
- {
- // rearrange the glyph array to get rid of the dropped glyph
- mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ];
- mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
- mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
- mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ];
- }
- ++nNewGC;
- }
- }
-
- mnGlyphCount = nNewGC;
- if( mnGlyphCount <= 0 )
- mnWidth = mnBaseAdv = 0;
-}
-
-WinLayout::WinLayout(HDC hDC, const WinFontFace& rWFD, WinFontInstance& rWFE, bool bUseOpenGL)
-: mhDC( hDC ),
- mhFont( static_cast<HFONT>(GetCurrentObject(hDC,OBJ_FONT)) ),
- mnBaseAdv( 0 ),
- mfFontScale( 1.0 ),
- mbUseOpenGL(bUseOpenGL),
- mrWinFontData( rWFD ),
- mrWinFontEntry(rWFE)
-{
- assert(mrWinFontEntry.mnRefCount > 0);
- // keep mrWinFontEntry alive
- mrWinFontEntry.mpFontCache->Acquire(&mrWinFontEntry);
-}
-
-WinLayout::~WinLayout()
-{
- mrWinFontEntry.mpFontCache->Release(&mrWinFontEntry);
-}
-
-void WinLayout::InitFont() const
-{
- SelectObject( mhDC, mhFont );
-}
-
-// Using reasonably sized fonts to emulate huge fonts works around
-// a lot of problems in printer and display drivers. Huge fonts are
-// mostly used by high resolution reference devices which are never
-// painted to anyway. In the rare case that a huge font needs to be
-// displayed somewhere then the workaround doesn't help anymore.
-// If the drivers fail silently for huge fonts, so be it...
-HFONT WinLayout::DisableFontScaling() const
-{
- if( mfFontScale == 1.0 )
- return nullptr;
-
- LOGFONTW aLogFont;
- GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
- aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
- aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth);
- HFONT hHugeFont = CreateFontIndirectW( &aLogFont);
- if( !hHugeFont )
- return nullptr;
-
- return SelectFont( mhDC, hHugeFont );
-}
-
-SCRIPT_CACHE& WinLayout::GetScriptCache() const
-{
- return mrWinFontEntry.GetScriptCache();
-}
-
-void WinLayout::DrawText(SalGraphics& rGraphics) const
-{
- WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
- HDC hDC = rWinGraphics.getHDC();
-
- if (!mbUseOpenGL)
- {
- // no OpenGL, just classic rendering
- Point aPos(0, 0);
- int nGetNextGlypInfo(0);
- bool bContinue = DrawTextImpl(hDC, nullptr, &aPos, &nGetNextGlypInfo);
- assert(!bContinue);
- }
- else if (CacheGlyphs(rGraphics) &&
- DrawCachedGlyphs(rGraphics))
- {
- // Nothing
- }
- else
- {
- // We have to render the text to a hidden texture, and draw it.
- //
- // Note that Windows GDI does not really support the alpha correctly
- // when drawing - ie. it draws nothing to the alpha channel when
- // rendering the text, even the antialiasing is done as 'real' pixels,
- // not alpha...
- //
- // Luckily, this does not really limit us:
- //
- // To blend properly, we draw the texture, but then use it as an alpha
- // channel for solid color (that will define the text color). This
- // destroys the subpixel antialiasing - turns it into 'classic'
- // antialiasing - but that is the best we can do, because the subpixel
- // antialiasing needs to know what is in the background: When the
- // background is white, or white-ish, it does the subpixel, but when
- // there is a color, it just darkens the color (and does this even
- // when part of the character is on a colored background, and part on
- // white). It has to work this way, the results would look strange
- // otherwise.
- //
- // For the GL rendering to work even with the subpixel antialiasing,
- // we would need to get the current texture from the screen, let GDI
- // draw the text to it (so that it can decide well where to use the
- // subpixel and where not), and draw the result - but in that case we
- // don't need alpha anyway.
- //
- // TODO: check the performance of this 2nd approach at some stage and
- // switch to that if it performs well.
-
- Rectangle aRect;
- GetBoundRect(rGraphics, aRect);
-
- WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
-
- if (pImpl)
- {
- pImpl->PreDraw();
-
- Point aPos(0, 0);
- int nGetNextGlypInfo(0);
- while (true)
- {
- OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
-
- // we are making changes to the DC, make sure we got a new one
- assert(aDC.getCompatibleHDC() != hDC);
-
- RECT aWinRect = { aRect.Left(), aRect.Top(), aRect.Left() + aRect.GetWidth(), aRect.Top() + aRect.GetHeight() };
- FillRect(aDC.getCompatibleHDC(), &aWinRect, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
-
- // setup the hidden DC with black color and white background, we will
- // use the result of the text drawing later as a mask only
- HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont);
-
- SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
- SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
-
- UINT nTextAlign = GetTextAlign(hDC);
- SetTextAlign(aDC.getCompatibleHDC(), nTextAlign);
-
- COLORREF color = GetTextColor(hDC);
- SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
- // the actual drawing
- bool bContinue = DrawTextImpl(aDC.getCompatibleHDC(), &aRect, &aPos, &nGetNextGlypInfo);
-
- std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture());
- if (xTexture)
- pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect());
-
- SelectFont(aDC.getCompatibleHDC(), hOrigFont);
-
- if (!bContinue)
- break;
- }
- pImpl->PostDraw();
- }
-
- }
-}
-
-bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const
-{
- static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == nullptr);
-
- if (!bDoGlyphCaching)
- return false;
-
- for (int i = 0; i < mnGlyphCount; i++)
- {
- int nCodePoint;
- if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1]))
- {
-#if 1 // Don't remove the #else branch in case somebody wants to
- // continue trying to figure out why sequential non-BMP glyphs
- // get scribbled on top of each others if caching is used.
- return false;
-#else
- nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]);
- i++;
-#endif
- }
- else
- {
- nCodePoint = mpOutGlyphs[i];
- }
-
- if (!mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
- {
- if (!mrWinFontEntry.CacheGlyphToAtlas(false, nCodePoint, *this, rGraphics))
- return false;
- }
- }
-
- return true;
-}
-
-bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
-{
- WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
- HDC hDC = rWinGraphics.getHDC();
-
- Rectangle aRect;
- GetBoundRect(rGraphics, aRect);
-
- COLORREF color = GetTextColor(hDC);
- SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
- WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
- if (!pImpl)
- return false;
-
- HFONT hOrigFont = DisableFontScaling();
- Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
-
- int nAdvance = 0;
-
- for (int i = 0; i < mnGlyphCount; i++)
- {
- if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
- continue;
-
- int nCodePoint;
- if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1]))
- {
- nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]);
- i++;
- }
- else
- {
- nCodePoint = mpOutGlyphs[i];
- }
-
- OpenGLGlyphDrawElement& rElement(mrWinFontEntry.GetGlyphCache().GetDrawElement(nCodePoint));
- OpenGLTexture& rTexture = rElement.maTexture;
-
- if (!rTexture)
- return false;
-
- SalTwoRect a2Rects(0, 0,
- rTexture.GetWidth(), rTexture.GetHeight(),
- nAdvance + aPos.X() - rElement.getExtraOffset() + rElement.maLeftOverhangs,
- aPos.Y() - rElement.mnBaselineOffset - rElement.getExtraOffset(),
- rTexture.GetWidth(), rTexture.GetHeight());
-
- pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
-
- nAdvance += mpGlyphAdvances[i];
- }
-
- if( hOrigFont )
- DeleteFont(SelectFont(hDC, hOrigFont));
-
- return true;
-}
-
-struct VisualItem
-{
-public:
- SCRIPT_ITEM* mpScriptItem;
- int mnMinGlyphPos;
- int mnEndGlyphPos;
- int mnMinCharPos;
- int mnEndCharPos;
- int mnXOffset;
- ABC maABCWidths;
- bool mbHasKashidas;
-
-public:
- bool IsEmpty() const { return (mnEndGlyphPos <= 0); }
- bool IsRTL() const { return mpScriptItem->a.fRTL; }
- bool HasKashidas() const { return mbHasKashidas; }
-};
-
-static bool bUspInited = false;
-
-static bool bManualCellAlign = true;
-
-static void InitUSP()
-{
-#if _WIN32_WINNT < _WIN32_WINNT_VISTA
- // get the usp10.dll version info
- HMODULE usp10 = GetModuleHandle("usp10.dll");
- void *pScriptIsComplex = reinterpret_cast< void* >( GetProcAddress(usp10, "ScriptIsComplex"));
- int nUspVersion = 0;
- rtl_uString* pModuleURL = NULL;
- osl_getModuleURLFromAddress( pScriptIsComplex, &pModuleURL );
- rtl_uString* pModuleFileName = NULL;
- if( pModuleURL )
- osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
- const sal_Unicode* pModuleFileCStr = NULL;
- if( pModuleFileName )
- pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
- if( pModuleFileCStr )
- {
- DWORD nHandle;
- DWORD nBufSize = GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
- char* pBuffer = (char*)alloca( nBufSize );
- BOOL bRC = GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
- VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
- UINT nFixedFileSize = 0;
- if( bRC )
- VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
- if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
- nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
- + LOWORD(pFixedFileInfo->dwProductVersionMS);
- }
-
- // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
- if( nUspVersion >= 10600 )
-#endif
- {
- bManualCellAlign = false;
- }
-
- bUspInited = true;
-}
-
-UniscribeLayout::UniscribeLayout(HDC hDC, const WinFontFace& rWinFontData,
- WinFontInstance& rWinFontEntry, bool bUseOpenGL)
-: WinLayout(hDC, rWinFontData, rWinFontEntry, bUseOpenGL),
- mpScriptItems( nullptr ),
- mpVisualItems( nullptr ),
- mnItemCount( 0 ),
- mnCharCapacity( 0 ),
- mpLogClusters( nullptr ),
- mpCharWidths( nullptr ),
- mnSubStringMin( 0 ),
- mnGlyphCount( 0 ),
- mnGlyphCapacity( 0 ),
- mpGlyphAdvances( nullptr ),
- mpJustifications( nullptr ),
- mpOutGlyphs( nullptr ),
- mpGlyphOffsets( nullptr ),
- mpVisualAttrs( nullptr ),
- mpGlyphs2Chars( nullptr ),
- mnMinKashidaWidth( 0 ),
- mnMinKashidaGlyph( 0 ),
- mbDisableGlyphInjection( false )
-{
-}
-
-UniscribeLayout::~UniscribeLayout()
-{
- delete[] mpScriptItems;
- delete[] mpVisualItems;
- delete[] mpLogClusters;
- delete[] mpCharWidths;
- delete[] mpOutGlyphs;
- delete[] mpGlyphAdvances;
- delete[] mpJustifications;
- delete[] mpGlyphOffsets;
- delete[] mpVisualAttrs;
- delete[] mpGlyphs2Chars;
-}
-
-#if 0 // Don't remove -- useful for temporary SAL_ DEBUG when hacking on this
-
-namespace {
-
-template<typename IntegerType>
-OUString IntegerArrayToString(IntegerType *pWords, int n)
-{
- OUString result = "{";
- for (int i = 0; i < n; ++i)
- {
- if (i > 0)
- result += ",";
- if (i > 0 && i % 10 == 0)
- result += OUString::number(i) + ":";
- result += OUString::number(pWords[i]);
- }
- result += "}";
-
- return result;
-}
-
-OUString GoffsetArrayToString(GOFFSET *pGoffsets, int n)
-{
- OUString result = "{";
- for (int i = 0; i < n; ++i)
- {
- if (i > 0)
- result += ",";
- if (i > 0 && i % 10 == 0)
- result += OUString::number(i) + ":";
- result += "(" + OUString::number(pGoffsets[i].du) + "," + OUString::number(pGoffsets[i].dv) + ")";
- }
- result += "}";
-
- return result;
-}
-
-OUString VisAttrArrayToString(SCRIPT_VISATTR *pVisAttrs, int n)
-{
- static const OUString JUSTIFICATION_NAME[] = {
- "NONE",
- "ARABIC_BLANK",
- "CHARACTER",
- "RESERVED1",
- "BLANK",
- "RESERVED2",
- "RESERVED3",
- "ARABIC_NORMAL",
- "ARABIC_KASHIDA",
- "ARABIC_ALEF",
- "ARABIC_HA",
- "ARABIC_RA",
- "ARABIC_BA",
- "ARABIC_BARA",
- "ARABIC_SEEN",
- "ARABIC_SEEN_M"
- };
-
- OUString result = "{";
- for (int i = 0; i < n; ++i)
- {
- if (i > 0)
- result += ",";
- if (i > 0 && i % 10 == 0)
- result += OUString::number(i) + ":";
- result += OUString("{") + JUSTIFICATION_NAME[pVisAttrs[i].uJustification] + (pVisAttrs[i].fClusterStart ? OUString(",ClusterStart") : OUString()) + (pVisAttrs[i].fDiacritic ? OUString(",Diacritic") : OUString()) + OUString(pVisAttrs[i].fZeroWidth ? OUString(",ZeroWidth") : OUString()) + OUString("}");
- }
- result += "}";
-
- return result;
-}
-
-} // anonymous namespace
-
-#endif // 0
-
-bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
-{
- msTheString = rArgs.mrStr;
-
- // for a base layout only the context glyphs have to be dropped
- // => when the whole string is involved there is no extra context
- std::vector<int> aDropChars;
- if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
- {
- // calculate superfluous context char positions
- aDropChars.push_back(0);
- aDropChars.push_back(rArgs.mrStr.getLength());
- int nMin, nEnd;
- bool bRTL;
- for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
- {
- aDropChars.push_back( nMin );
- aDropChars.push_back( nEnd );
- }
- // prepare aDropChars for binary search which will allow to
- // not bother with visual items that will be dropped anyway
- std::sort( aDropChars.begin(), aDropChars.end() );
- }
-
- // prepare layout
- // TODO: fix case when recycling old UniscribeLayout object
- mnMinCharPos = rArgs.mnMinCharPos;
- mnEndCharPos = rArgs.mnEndCharPos;
-
- // determine script items from string
-
- // prepare itemization
- // TODO: try to avoid itemization since it costs a lot of performance
- SCRIPT_STATE aScriptState = {0,WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),0,0};
- aScriptState.uBidiLevel = WORD(bool(rArgs.mnFlags & SalLayoutFlags::BiDiRtl));
- aScriptState.fOverrideDirection = WORD(bool(rArgs.mnFlags & SalLayoutFlags::BiDiStrong));
- aScriptState.fDigitSubstitute = WORD(bool(rArgs.mnFlags & SalLayoutFlags::SubstituteDigits));
- aScriptState.fArabicNumContext = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
- DWORD nLangId = 0; // TODO: get language from font
- SCRIPT_CONTROL aScriptControl;
- memset(&aScriptControl, 0, sizeof(aScriptControl));
- aScriptControl.uDefaultLanguage = nLangId;
- aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
- aScriptControl.fContextDigits = DWORD(bool(rArgs.mnFlags & SalLayoutFlags::SubstituteDigits));
- aScriptControl.fMergeNeutralItems = DWORD(true);
-
- // determine relevant substring and work only on it
- // when Bidi status is unknown we need to look at the whole string though
- mnSubStringMin = 0;
- const int nLength = rArgs.mrStr.getLength();
- const sal_Unicode *pStr = rArgs.mrStr.getStr();
- int nSubStringEnd = nLength;
- if( aScriptState.fOverrideDirection )
- {
- // TODO: limit substring to portion limits
- mnSubStringMin = rArgs.mnMinCharPos - 8;
- if( mnSubStringMin < 0 )
- mnSubStringMin = 0;
- nSubStringEnd = rArgs.mnEndCharPos + 8;
- if( nSubStringEnd > nLength )
- nSubStringEnd = nLength;
-
- }
- // now itemize the substring with its context
- for( int nItemCapacity = 16;; nItemCapacity *= 8 )
- {
- mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
- HRESULT nRC = ScriptItemize(
- reinterpret_cast<LPCWSTR>(pStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
- nItemCapacity - 1, &aScriptControl, &aScriptState,
- mpScriptItems, &mnItemCount );
- if( !nRC ) // break loop when everything is correctly itemized
- break;
-
- // prepare bigger buffers for another itemization round
- delete[] mpScriptItems;
- mpScriptItems = nullptr;
- if( nRC != E_OUTOFMEMORY )
- return false;
- if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
- return false;
- }
-
- // calculate the order of visual items
- int nItem, i;
-
- // adjust char positions by substring offset
- for( nItem = 0; nItem <= mnItemCount; ++nItem )
- mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
- // default visual item ordering
- mpVisualItems = new VisualItem[ mnItemCount ];
- for( nItem = 0; nItem < mnItemCount; ++nItem )
- {
- // initialize char specific item info
- VisualItem& rVisualItem = mpVisualItems[ nItem ];
- SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
- rVisualItem.mpScriptItem = pScriptItem;
- rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
- rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
- }
-
- // reorder visual item order if needed
- if( rArgs.mnFlags & SalLayoutFlags::BiDiStrong )
- {
- // force RTL item ordering if requested
- if( rArgs.mnFlags & SalLayoutFlags::BiDiRtl )
- {
- VisualItem* pVI0 = &mpVisualItems[ 0 ];
- VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
- while( pVI0 < --pVI1 )
- {
- VisualItem aVtmp = *pVI0;
- *(pVI0++) = *pVI1;
- *pVI1 = aVtmp;
- }
- }
- }
- else if( mnItemCount > 1 )
- {
- // apply bidi algorithm's rule L2 on item level
- // TODO: use faster L2 algorithm
- int nMaxBidiLevel = 0;
- VisualItem* pVI = &mpVisualItems[0];
- VisualItem* const pVIend = pVI + mnItemCount;
- for(; pVI < pVIend; ++pVI )
- if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
- nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
-
- while( --nMaxBidiLevel >= 0 )
- {
- for( pVI = &mpVisualItems[0]; pVI < pVIend; )
- {
- // find item range that needs reordering
- for(; pVI < pVIend; ++pVI )
- if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
- break;
- VisualItem* pVImin = pVI++;
- for(; pVI < pVIend; ++pVI )
- if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
- break;
- VisualItem* pVImax = pVI++;
-
- // reverse order of items in this range
- while( pVImin < --pVImax )
- {
- VisualItem aVtmp = *pVImin;
- *(pVImin++) = *pVImax;
- *pVImax = aVtmp;
- }
- }
- }
- }
-
- // allocate arrays
- // TODO: when reusing object reuse old allocations or delete them
- // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
- mnCharCapacity = nSubStringEnd;
- mpLogClusters = new WORD[ mnCharCapacity ];
- mpCharWidths = new int[ mnCharCapacity ];
-
- mnGlyphCount = 0;
- mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
- mpGlyphAdvances = new int[ mnGlyphCapacity ];
- mpOutGlyphs = new WORD[ mnGlyphCapacity ];
- mpGlyphOffsets = new GOFFSET[ mnGlyphCapacity ];
- mpVisualAttrs = new SCRIPT_VISATTR[ mnGlyphCapacity ];
-
- long nXOffset = 0;
- for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
- mpCharWidths[j] = 0;
-
- // layout script items
- SCRIPT_CACHE& rScriptCache = GetScriptCache();
- for( nItem = 0; nItem < mnItemCount; ++nItem )
- {
- VisualItem& rVisualItem = mpVisualItems[ nItem ];
-
- // initialize glyph specific item info
- rVisualItem.mnMinGlyphPos = mnGlyphCount;
- rVisualItem.mnEndGlyphPos = 0;
- rVisualItem.mnXOffset = nXOffset;
-
- // shortcut ignorable items
- if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
- || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
- {
- for( int j = rVisualItem.mnMinCharPos; j < rVisualItem.mnEndCharPos; ++j )
- mpLogClusters[j] = sal::static_int_cast<WORD>(~0U);
- if (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos)
- { // fdo#47553 adjust "guessed" min (maybe up to -8 off) to
- // actual min so it can be used properly in GetNextGlyphs
- if (mnSubStringMin < rVisualItem.mnEndCharPos)
- mnSubStringMin = rVisualItem.mnEndCharPos;
- }
- continue;
- }
-
- // override bidi analysis if requested
- if( rArgs.mnFlags & SalLayoutFlags::BiDiStrong )
- {
- // FIXME: is this intended ?
- rVisualItem.mpScriptItem->a.fRTL = (aScriptState.uBidiLevel & 1);
- rVisualItem.mpScriptItem->a.s.uBidiLevel = aScriptState.uBidiLevel;
- rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
- }
-
- // convert the unicodes to glyphs
- int nGlyphCount = 0;
- int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
- HRESULT nRC = ScriptShape( mhDC, &rScriptCache,
- reinterpret_cast<LPCWSTR>(pStr + rVisualItem.mnMinCharPos),
- nCharCount,
- mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
- &rVisualItem.mpScriptItem->a,
- mpOutGlyphs + rVisualItem.mnMinGlyphPos,
- mpLogClusters + rVisualItem.mnMinCharPos,
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- &nGlyphCount );
-
- // find and handle problems in the unicode to glyph conversion
- if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
- {
- // the whole visual item needs a fallback, but make sure that the next
- // fallback request is limited to the characters in the original request
- // => this is handled in ImplLayoutArgs::PrepareFallback()
- rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
- rVisualItem.IsRTL() );
-
- // don't bother to do a default layout in a fallback level
- if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
- continue;
-
- // the primitive layout engine is good enough for the default layout
- rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
- nRC = ScriptShape( mhDC, &rScriptCache,
- reinterpret_cast<LPCWSTR>(pStr + rVisualItem.mnMinCharPos),
- nCharCount,
- mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
- &rVisualItem.mpScriptItem->a,
- mpOutGlyphs + rVisualItem.mnMinGlyphPos,
- mpLogClusters + rVisualItem.mnMinCharPos,
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- &nGlyphCount );
-
- if( nRC != 0 )
- continue;
-
- }
- else if( nRC != 0 )
- // something undefined happened => give up for this visual item
- continue;
- else // if( nRC == 0 )
- {
- // check if there are any NotDef glyphs
- for( i = 0; i < nGlyphCount; ++i )
- if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
- break;
- if( i < nGlyphCount )
- {
- // clip charpos limits to the layout string without context
- int nMinCharPos = rVisualItem.mnMinCharPos;
- if( nMinCharPos < rArgs.mnMinCharPos )
- nMinCharPos = rArgs.mnMinCharPos;
- int nEndCharPos = rVisualItem.mnEndCharPos;
- if( nEndCharPos > rArgs.mnEndCharPos )
- nEndCharPos = rArgs.mnEndCharPos;
- // request fallback for individual NotDef glyphs
- do
- {
- // ignore non-NotDef glyphs
- if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
- continue;
- mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
- // request fallback for the whole cell that resulted in a NotDef glyph
- // TODO: optimize algorithm
- const bool bRTL = rVisualItem.IsRTL();
- if( !bRTL )
- {
- // request fallback for the left-to-right cell
- for( int c = nMinCharPos; c < nEndCharPos; ++c )
- {
- if( mpLogClusters[ c ] == i )
- {
- // #i55716# skip WORDJOINER
- if( pStr[ c ] == 0x2060 )
- mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
- else
- rArgs.NeedFallback( c, false );
- }
- }
- }
- else
- {
- // request fallback for the right to left cell
- for( int c = nEndCharPos; --c >= nMinCharPos; )
- {
- if( mpLogClusters[ c ] == i )
- {
- // #i55716# skip WORDJOINER
- if( pStr[ c ] == 0x2060 )
- mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
- else
- rArgs.NeedFallback( c, true );
- }
- }
- }
- } while( ++i < nGlyphCount );
- }
- }
-
- // now place the glyphs
- nRC = ScriptPlace( mhDC, &rScriptCache,
- mpOutGlyphs + rVisualItem.mnMinGlyphPos,
- nGlyphCount,
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- &rVisualItem.mpScriptItem->a,
- mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
- mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
- &rVisualItem.maABCWidths );
-
- if( nRC != 0 )
- continue;
-
- // calculate the logical char widths from the glyph layout
- nRC = ScriptGetLogicalWidths(
- &rVisualItem.mpScriptItem->a,
- nCharCount, nGlyphCount,
- mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
- mpLogClusters + rVisualItem.mnMinCharPos,
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- mpCharWidths + rVisualItem.mnMinCharPos );
-
- // update the glyph counters
- mnGlyphCount += nGlyphCount;
- rVisualItem.mnEndGlyphPos = mnGlyphCount;
-
- // update nXOffset
- int nEndGlyphPos;
- if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
- for(; i < nEndGlyphPos; ++i )
- nXOffset += mpGlyphAdvances[ i ];
-
- // TODO: shrink glyphpos limits to match charpos/fallback limits
- //pVI->mnMinGlyphPos = nMinGlyphPos;
- //pVI->mnEndGlyphPos = nEndGlyphPos;
-
- // drop the superfluous context glyphs
- auto it = aDropChars.cbegin();
- while( it != aDropChars.cend() )
- {
- // find matching "drop range"
- int nMinDropPos = *(it++); // begin of drop range
- if( nMinDropPos >= rVisualItem.mnEndCharPos )
- break;
- int nEndDropPos = *(it++); // end of drop range
- if( nEndDropPos <= rVisualItem.mnMinCharPos )
- continue;
- // clip "drop range" to visual item's char range
- if( nMinDropPos <= rVisualItem.mnMinCharPos )
- {
- nMinDropPos = rVisualItem.mnMinCharPos;
- // drop the whole visual item if possible
- if( nEndDropPos >= rVisualItem.mnEndCharPos )
- {
- rVisualItem.mnEndGlyphPos = 0;
- break;
- }
- }
- if( nEndDropPos > rVisualItem.mnEndCharPos )
- nEndDropPos = rVisualItem.mnEndCharPos;
-
- // drop the glyphs which correspond to the charpos range
- // drop the corresponding glyphs in the cluster
- for( int c = nMinDropPos; c < nEndDropPos; ++c )
- {
- int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
- // no need to bother when the cluster was already dropped
- if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
- {
- for(;;)
- {
- mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
- // until the end of visual item
- if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
- break;
- // until the next cluster start
- if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
- break;
- }
- }
- }
- }
- }
-
- // scale layout metrics if needed
- // TODO: does it make the code more simple if the metric scaling
- // is moved to the methods that need metric scaling (e.g. FillDXArray())?
- if( mfFontScale != 1.0 )
- {
- mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
-
- for( i = 0; i < mnItemCount; ++i )
- mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
-
- mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
- for( i = 0; i < mnGlyphCount; ++i )
- {
- mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
- mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
- mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
- // mpJustifications are still NULL
- }
-
- for( i = mnSubStringMin; i < nSubStringEnd; ++i )
- mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
- }
-
- return true;
-}
-
-// calculate the range of relevant glyphs for this visual item
-bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
- int& rMinGlyphPos, int& rEndGlyphPos ) const
-{
- // return early when nothing of interest in this item
- if( rVisualItem.IsEmpty()
- || (rVisualItem.mnEndCharPos <= mnMinCharPos)
- || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
- return false;
-
- // default: subrange is complete range
- rMinGlyphPos = rVisualItem.mnMinGlyphPos;
- rEndGlyphPos = rVisualItem.mnEndGlyphPos;
-
- // return early when the whole item is of interest
- if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
- && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
- return true;
-
- // get glyph range from char range by looking at cluster boundries
- // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
- rMinGlyphPos = rVisualItem.mnEndGlyphPos;
- int nMaxGlyphPos = 0;
-
- int i = mnMinCharPos;
- if( i < rVisualItem.mnMinCharPos )
- i = rVisualItem.mnMinCharPos;
- int nCharPosLimit = rVisualItem.mnEndCharPos;
- if( nCharPosLimit > mnEndCharPos )
- nCharPosLimit = mnEndCharPos;
- for(; i < nCharPosLimit; ++i )
- {
- int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
- if( rMinGlyphPos > n )
- rMinGlyphPos = n;
- if( nMaxGlyphPos < n )
- nMaxGlyphPos = n;
- }
- if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
- nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
-
- // extend the glyph range to account for all glyphs in referenced clusters
- if( !rVisualItem.IsRTL() ) // LTR-item
- {
- // extend to rightmost glyph of rightmost referenced cluster
- for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
- if( mpVisualAttrs[i].fClusterStart )
- break;
- }
- else // RTL-item
- {
- // extend to leftmost glyph of leftmost referenced cluster
- for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
- if( mpVisualAttrs[i].fClusterStart )
- break;
- }
- rEndGlyphPos = nMaxGlyphPos + 1;
-
- return true;
-}
-
-int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
- int& nStartx8, DeviceCoordinate* pGlyphAdvances, int* pCharPosAry,
- const PhysicalFontFace** /*pFallbackFonts*/ ) const
-{
- // HACK to allow fake-glyph insertion (e.g. for kashidas)
- // TODO: use iterator idiom instead of GetNextGlyphs(...)
- // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
- int nSubIter = nStartx8 & 0xff;
- int nStart = nStartx8 >> 8;
-
- // check the glyph iterator
- if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs
- return 0;
-
- // find the visual item for the nStart glyph position
- int nItem = 0;
- const VisualItem* pVI = mpVisualItems;
- if( nStart <= 0 ) // nStart<=0 requests the first visible glyph
- {
- // find first visible item
- for(; nItem < mnItemCount; ++nItem, ++pVI )
- if( !pVI->IsEmpty() )
- break;
- // it is possible that there are glyphs but no valid visual item
- // TODO: get rid of these visual items more early
- if( nItem < mnItemCount )
- nStart = pVI->mnMinGlyphPos;
- }
- else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1
- {
- --nStart;
-
- // find matching item
- for(; nItem < mnItemCount; ++nItem, ++pVI )
- if( (nStart >= pVI->mnMinGlyphPos)
- && (nStart < pVI->mnEndGlyphPos) )
- break;
- }
-
- // after the last visual item there are no more glyphs
- if( (nItem >= mnItemCount) || (nStart < 0) )
- {
- nStartx8 = (mnGlyphCount + 1) << 8;
- return 0;
- }
-
- // calculate the first glyph in the next visual item
- int nNextItemStart = mnGlyphCount;
- while( ++nItem < mnItemCount )
- {
- if( mpVisualItems[nItem].IsEmpty() )
- continue;
- nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
- break;
- }
-
- // get the range of relevant glyphs in this visual item
- int nMinGlyphPos, nEndGlyphPos;
- bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
- SAL_WARN_IF( !bRC, "vcl", "USPLayout::GNG GISR() returned false" );
- if( !bRC )
- {
- nStartx8 = (mnGlyphCount + 1) << 8;
- return 0;
- }
-
- // make sure nStart is inside the range of relevant glyphs
- if( nStart < nMinGlyphPos )
- nStart = nMinGlyphPos;
-
- // calculate the start glyph xoffset relative to layout's base position,
- // advance to next visual glyph position by using adjusted glyph widths
- // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
- long nXOffset = pVI->mnXOffset;
- const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
- for( int i = nMinGlyphPos; i < nStart; ++i )
- nXOffset += pGlyphWidths[ i ];
-
- // adjust the nXOffset relative to glyph cluster start
- int c = mnMinCharPos;
- if( !pVI->IsRTL() ) // LTR-case
- {
- // LTR case: subtract the remainder of the cell from xoffset
- int nTmpIndex = mpLogClusters[c];
- while( (--c >= pVI->mnMinCharPos)
- && (nTmpIndex == mpLogClusters[c]) )
- nXOffset -= mpCharWidths[c];
- }
- else // RTL-case
- {
- // RTL case: add the remainder of the cell from xoffset
- int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
- while( (--c >= pVI->mnMinCharPos)
- && (nTmpIndex == mpLogClusters[c]) )
- nXOffset += mpCharWidths[c];
-
- // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
- if( mpJustifications && !bManualCellAlign )
- nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
- }
-
- // create mpGlyphs2Chars[] if it is needed later
- if( pCharPosAry && !mpGlyphs2Chars )
- {
- // create and reset the new array
- mpGlyphs2Chars = new int[ mnGlyphCapacity ];
- for( int i = 0; i < mnGlyphCount; ++i )
- mpGlyphs2Chars[i] = -1;
- // calculate the char->glyph mapping
- for( nItem = 0; nItem < mnItemCount; ++nItem )
- {
- // ignore invisible visual items
- const VisualItem& rVI = mpVisualItems[ nItem ];
- if( rVI.IsEmpty() )
- continue;
-
- //Resolves: fdo#33090 Ensure that all glyph slots, even if 0-width
- //or empty due to combining chars etc, map back to a character
- //position so that iterating over glyph slots one at a time for
- //glyph fallback can keep context as to what characters are the
- //inputs that caused a missing glyph in a given font.
-
- //See: fdo#46923/fdo#46896/fdo#46750 for extra complexities
- {
- int dir = 1;
- int out = rVI.mnMinCharPos;
- if (rVI.IsRTL())
- {
- dir = -1;
- out = rVI.mnEndCharPos-1;
- }
- for(c = rVI.mnMinCharPos; c < rVI.mnEndCharPos; ++c)
- {
- int i = out - mnSubStringMin;
- mpGlyphs2Chars[i] = c;
- out += dir;
- }
- }
-
- // calculate the mapping by using mpLogClusters[]
- // mpGlyphs2Chars[] should obey the logical order
- // => reversing the loop does this by overwriting higher logicals
- for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
- {
- int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
- mpGlyphs2Chars[i] = c;
- }
- // use a heuristic to fill the gaps in the glyphs2chars array
- c = !rVI.IsRTL() ? rVI.mnMinCharPos : rVI.mnEndCharPos - 1;
- for( int i = rVI.mnMinGlyphPos; i < rVI.mnEndGlyphPos; ++i ) {
- if( mpGlyphs2Chars[i] == -1 )
- mpGlyphs2Chars[i] = c;
- else
- c = mpGlyphs2Chars[i];
- }
- }
- }
-
- // calculate the absolute position of the first result glyph in pixel units
- const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
- Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
- rPos = GetDrawPosition( aRelativePos );
-
- // fill the result arrays
- int nCount = 0;
- while( nCount < nLen )
- {
- // prepare return values
- sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
- int nGlyphWidth = pGlyphWidths[ nStart ];
- int nCharPos = -1; // no need to determine charpos
- if( mpGlyphs2Chars ) // unless explicitly requested+provided
- {
- nCharPos = mpGlyphs2Chars[ nStart ];
- }
-
- // inject kashida glyphs if needed
- if( !mbDisableGlyphInjection
- && mpJustifications
- && mnMinKashidaWidth
- && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
- {
- // prepare draw position adjustment
- int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
- // calculate space available for the injected glyphs
- nGlyphWidth = mpGlyphAdvances[ nStart ];
- const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
- const int nToFillWidth = nExtraWidth - nExtraOfs;
- if( (4*nToFillWidth >= mnMinKashidaWidth) // prevent glyph-injection if there is no room
- || ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
- {
- // handle if there is not sufficient room for a full glyph
- if( nToFillWidth < mnMinKashidaWidth )
- {
- // overlap it with the previously injected glyph if possible
- int nOverlap = mnMinKashidaWidth - nToFillWidth;
- // else overlap it with both neighboring glyphs
- if( nSubIter <= 1 )
- nOverlap /= 2;
- nExtraOfs -= nOverlap;
- }
- nGlyphWidth = mnMinKashidaWidth;
- aGlyphId = mnMinKashidaGlyph;
- nCharPos = -1;
- }
- else
- {
- nExtraOfs += nToFillWidth; // at right of cell
- nSubIter = 0; // done with glyph injection
- }
- if( !bManualCellAlign )
- nExtraOfs -= nExtraWidth; // adjust for right-aligned cells
-
- // adjust the draw position for the injected-glyphs case
- if( nExtraOfs )
- {
- aRelativePos.X() += nExtraOfs;
- rPos = GetDrawPosition( aRelativePos );
- }
- }
-
- // update return values
- if( (mnLayoutFlags & SalLayoutFlags::Vertical) &&
- nCharPos != -1 )
- aGlyphId |= GetVerticalFlags( msTheString[nCharPos] );
- *(pGlyphs++) = aGlyphId;
- if( pGlyphAdvances )
- *(pGlyphAdvances++) = nGlyphWidth;
- if( pCharPosAry )
- *(pCharPosAry++) = nCharPos;
-
- // increment counter of returned glyphs
- ++nCount;
-
- // reduce code complexity by returning early in glyph-injection case
- if( nSubIter != 0 )
- break;
-
- // stop after the last visible glyph in this visual item
- if( ++nStart >= nEndGlyphPos )
- {
- nStart = nNextItemStart;
- break;
- }
-
- // RTL-justified glyph positioning is not easy
- // simplify the code by just returning only one glyph at a time
- if( mpJustifications && pVI->IsRTL() )
- break;
-
- // stop when the x-position of the next glyph is unexpected
- if( !pGlyphAdvances )
- if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
- || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
- break;
-
- // stop when the y-position of the next glyph is unexpected
- if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
- break;
- }
-
- ++nStart;
- nStartx8 = (nStart << 8) + nSubIter;
- return nCount;
-}
-
-void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
-{
- SAL_WARN_IF( (nStartx8 & 0xff), "vcl", "USP::MoveGlyph(): glyph injection not disabled!" );
- int nStart = nStartx8 >> 8;
- if( nStart > mnGlyphCount )
- return;
-
- VisualItem* pVI = mpVisualItems;
- int nMinGlyphPos = 0, nEndGlyphPos;
- if( nStart == 0 ) // nStart==0 for first visible glyph
- {
- for( int i = mnItemCount; --i >= 0; ++pVI )
- if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
- break;
- nStart = nMinGlyphPos;
- SAL_WARN_IF( nStart > mnGlyphCount, "vcl", "USPLayout::MoveG overflow" );
- }
- else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1
- {
- --nStart;
- for( int i = mnItemCount; --i >= 0; ++pVI )
- if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
- break;
- bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
- (void)bRC; // avoid var-not-used warning
- SAL_WARN_IF( !bRC, "vcl", "USPLayout::MoveG GISR() returned false" );
- }
-
- long nDelta = nNewXPos - pVI->mnXOffset;
- if( nStart > nMinGlyphPos )
- {
- // move the glyph by expanding its left glyph but ignore dropped glyphs
- int i, nLastUndropped = nMinGlyphPos - 1;
- for( i = nMinGlyphPos; i < nStart; ++i )
- {
- if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
- {
- nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
- nLastUndropped = i;
- }
- }
- if (nLastUndropped >= nMinGlyphPos)
- {
- mpGlyphAdvances[ nLastUndropped ] += nDelta;
- if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
- }
- else
- {
- pVI->mnXOffset += nDelta;
- }
- }
- else
- {
- // move the visual item by having an offset
- pVI->mnXOffset += nDelta;
- }
- // move subsequent items - this often isn't necessary because subsequent
- // moves will correct subsequent items. However, if there is a contiguous
- // range not involving fallback which spans items, this will be needed
- while (++pVI - mpVisualItems < mnItemCount)
- {
- pVI->mnXOffset += nDelta;
- }
-}
-
-void UniscribeLayout::DropGlyph( int nStartx8 )
-{
- SAL_WARN_IF( (nStartx8 & 0xff), "vcl", "USP::DropGlyph(): glyph injection not disabled!" );
- int nStart = nStartx8 >> 8;
- assert(nStart <= mnGlyphCount);
-
- if( nStart > 0 ) // nStart>0 means absolute glyph pos + 1
- --nStart;
- else // nStart<=0 for first visible glyph
- {
- VisualItem* pVI = mpVisualItems;
- for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
- if( GetItemSubrange( *pVI, nStart, nDummy ) )
- break;
- assert(nStart <= mnGlyphCount);
-
- int j = pVI->mnMinGlyphPos;
- while (j < mnGlyphCount && mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
- if (j == nStart)
- {
- pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
- }
- }
-
- mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
-}
-
-void UniscribeLayout::Simplify( bool /*bIsBase*/ )
-{
- int i;
- // if there are no dropped glyphs don't bother
- for( i = 0; i < mnGlyphCount; ++i )
- if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
- break;
- if( i >= mnGlyphCount )
- return;
-
- // prepare for sparse layout
- // => make sure mpGlyphs2Chars[] exists
- if( !mpGlyphs2Chars )
- {
- mpGlyphs2Chars = new int[ mnGlyphCapacity ];
- for( i = 0; i < mnGlyphCount; ++i )
- mpGlyphs2Chars[ i ] = -1;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- // skip invisible items
- VisualItem& rVI = mpVisualItems[ nItem ];
- if( rVI.IsEmpty() )
- continue;
- for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
- {
- int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
- mpGlyphs2Chars[ j ] = i;
- }
- }
- }
-
- // remove the dropped glyphs
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- VisualItem& rVI = mpVisualItems[ nItem ];
- if( rVI.IsEmpty() )
- continue;
-
- // mark replaced character widths
- for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
- {
- int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
- if( mpOutGlyphs[ j ] == DROPPED_OUTGLYPH )
- mpCharWidths[ i ] = 0;
- }
-
- // handle dropped glyphs at start of visual item
- int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
- GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
- i = nMinGlyphPos;
- while( (i < nEndGlyphPos) && (mpOutGlyphs[i] == DROPPED_OUTGLYPH) )
- {
- rVI.mnMinGlyphPos = ++i;
- }
-
- // when all glyphs in item got dropped mark it as empty
- if( i >= nEndGlyphPos )
- {
- rVI.mnEndGlyphPos = 0;
- continue;
- }
- // If there are still glyphs in the cluster and mnMinGlyphPos
- // has changed then we need to remove the dropped glyphs at start
- // to correct logClusters, which is unsigned and relative to the
- // item start.
- if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
- {
- // drop any glyphs in the visual item outside the range
- for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
- mpOutGlyphs[ i ] = DROPPED_OUTGLYPH;
- rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
- }
-
- // handle dropped glyphs in the middle of visual item
- for(; i < nEndGlyphPos; ++i )
- if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
- break;
- int j = i;
- while( ++i < nEndGlyphPos )
- {
- if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
- continue;
- mpOutGlyphs[ j ] = mpOutGlyphs[ i ];
- mpGlyphOffsets[ j ] = mpGlyphOffsets[ i ];
- mpVisualAttrs[ j ] = mpVisualAttrs[ i ];
- mpGlyphAdvances[ j ] = mpGlyphAdvances[ i ];
- if( mpJustifications )
- mpJustifications[ j ] = mpJustifications[ i ];
- const int k = mpGlyphs2Chars[ i ];
- mpGlyphs2Chars[ j ] = k;
- const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
- if( k < 0) // extra glyphs are already mapped
- continue;
- mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
- }
-
- rVI.mnEndGlyphPos = j;
- }
-}
-
-bool UniscribeLayout::DrawTextImpl(HDC hDC,
- const Rectangle* /* pRectToErase */,
- Point* /* pPos */,
- int* /* pGetNextGlypInfo */) const
-{
- HFONT hOrigFont = DisableFontScaling();
-
- int nBaseClusterOffset = 0;
- int nBaseGlyphPos = -1;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- const VisualItem& rVisualItem = mpVisualItems[ nItem ];
-
- // skip if there is nothing to display
- int nMinGlyphPos, nEndGlyphPos;
- if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
- continue;
-
- if( nBaseGlyphPos < 0 )
- {
- // adjust draw position relative to cluster start
- if( rVisualItem.IsRTL() )
- nBaseGlyphPos = nEndGlyphPos - 1;
- else
- nBaseGlyphPos = nMinGlyphPos;
-
- int i = mnMinCharPos;
- while( (--i >= rVisualItem.mnMinCharPos)
- && (nBaseGlyphPos == mpLogClusters[i]) )
- nBaseClusterOffset += mpCharWidths[i];
-
- if( !rVisualItem.IsRTL() )
- nBaseClusterOffset = -nBaseClusterOffset;
- }
-
- // now draw the matching glyphs in this item
- Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
- Point aPos = GetDrawPosition( aRelPos );
- SCRIPT_CACHE& rScriptCache = GetScriptCache();
- ScriptTextOut(hDC, &rScriptCache,
- aPos.X(), aPos.Y(), 0, nullptr,
- &rVisualItem.mpScriptItem->a, nullptr, 0,
- mpOutGlyphs + nMinGlyphPos,
- nEndGlyphPos - nMinGlyphPos,
- mpGlyphAdvances + nMinGlyphPos,
- mpJustifications ? mpJustifications + nMinGlyphPos : nullptr,
- mpGlyphOffsets + nMinGlyphPos);
- }
-
- if( hOrigFont )
- DeleteFont(SelectFont(hDC, hOrigFont));
-
- return false;
-}
-
-bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
-{
- static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == nullptr);
-
- if (!bDoGlyphCaching)
- return false;
-
- for (int i = 0; i < mnGlyphCount; i++)
- {
- int nCodePoint = mpOutGlyphs[i];
- if (!mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
- {
- if (!mrWinFontEntry.CacheGlyphToAtlas(true, nCodePoint, *this, rGraphics))
- return false;
- }
- }
-
- return true;
-}
-
-bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
-{
- WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
- HDC hDC = rWinGraphics.getHDC();
-
- Rectangle aRect;
- GetBoundRect(rGraphics, aRect);
-
- COLORREF color = GetTextColor(hDC);
- SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
- WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
- if (!pImpl)
- return false;
-
- // FIXME: This code snippet is mostly copied from the one in
- // UniscribeLayout::DrawTextImpl. Should be factored out.
- int nBaseClusterOffset = 0;
- int nBaseGlyphPos = -1;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- const VisualItem& rVisualItem = mpVisualItems[ nItem ];
-
- // skip if there is nothing to display
- int nMinGlyphPos, nEndGlyphPos;
- if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
- continue;
-
- if( nBaseGlyphPos < 0 )
- {
- // adjust draw position relative to cluster start
- if( rVisualItem.IsRTL() )
- nBaseGlyphPos = nEndGlyphPos - 1;
- else
- nBaseGlyphPos = nMinGlyphPos;
-
- int i = mnMinCharPos;
- while( (--i >= rVisualItem.mnMinCharPos)
- && (nBaseGlyphPos == mpLogClusters[i]) )
- nBaseClusterOffset += mpCharWidths[i];
-
- if( !rVisualItem.IsRTL() )
- nBaseClusterOffset = -nBaseClusterOffset;
- }
-
- // now draw the matching glyphs in this item
- Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
- Point aPos = GetDrawPosition( aRelPos );
-
- int nAdvance = 0;
-
- // This has to be in sync with UniscribeLayout::FillDXArray(), so that
- // actual and reported glyph positions (used for e.g. cursor caret
- // positioning) match.
- const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
-
- for (int i = nMinGlyphPos; i < nEndGlyphPos; i++)
- {
- // Ignore dropped glyphs.
- if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
- continue;
-
- OpenGLGlyphDrawElement& rElement = mrWinFontEntry.GetGlyphCache().GetDrawElement(mpOutGlyphs[i]);
- OpenGLTexture& rTexture = rElement.maTexture;
-
- if (!rTexture)
- return false;
-
- if (rElement.mbVertical)
- {
- SalTwoRect a2Rects(0, 0,
- rTexture.GetWidth(), rTexture.GetHeight(),
- aPos.X() + rElement.maLeftOverhangs,
- nAdvance + aPos.Y(),
- rTexture.GetWidth(), rTexture.GetHeight());
-
- pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
- }
- else
- {
- SalTwoRect a2Rects(0, 0,
- rTexture.GetWidth(), rTexture.GetHeight(),
- nAdvance + aPos.X() + mpGlyphOffsets[i].du - rElement.getExtraOffset() + rElement.maLeftOverhangs,
- aPos.Y() + mpGlyphOffsets[i].dv - rElement.mnBaselineOffset - rElement.getExtraOffset(),
- rTexture.GetWidth(), rTexture.GetHeight());
-
- pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
- }
-
- nAdvance += pGlyphWidths[i];
- }
- }
-
- return true;
-}
-
-DeviceCoordinate UniscribeLayout::FillDXArray( DeviceCoordinate* pDXArray ) const
-{
- // calculate width of the complete layout
- long nWidth = mnBaseAdv;
- for( int nItem = mnItemCount; --nItem >= 0; )
- {
- const VisualItem& rVI = mpVisualItems[ nItem ];
-
- // skip if there is nothing to display
- int nMinGlyphPos, nEndGlyphPos;
- if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
- continue;
-
- // width = xoffset + width of last item
- nWidth = rVI.mnXOffset;
- const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
- for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
- nWidth += pGlyphWidths[i];
- break;
- }
-
- // copy the virtual char widths into pDXArray[]
- if( pDXArray )
- for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
- pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
-
- return nWidth;
-}
-
-sal_Int32 UniscribeLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor ) const
-{
- long nWidth = 0;
- for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
- {
- nWidth += mpCharWidths[ i ] * nFactor;
-
- // check if the nMaxWidth still fits the current sub-layout
- if( nWidth >= nMaxWidth )
- {
- // go back to cluster start
- // we have to find the visual item first since the mpLogClusters[]
- // needed to find the cluster start is relative to the visual item
- int nMinGlyphIndex = 0;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- const VisualItem& rVisualItem = mpVisualItems[ nItem ];
- nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
- if( (i >= rVisualItem.mnMinCharPos)
- && (i < rVisualItem.mnEndCharPos) )
- break;
- }
- // now go back to the matching cluster start
- do
- {
- int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
- if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
- return i;
- } while( --i >= mnMinCharPos );
-
- // if the cluster starts before the start of the visual item
- // then set the visual breakpoint before this item
- return mnMinCharPos;
- }
-
- // the visual break also depends on the nCharExtra between the characters
- nWidth += nCharExtra;
- }
-
- // the whole layout did fit inside the nMaxWidth
- return -1;
-}
-
-void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
-{
- int i;
- for( i = 0; i < nMaxIdx; ++i )
- pCaretXArray[ i ] = -1;
- std::unique_ptr<long[]> const pGlyphPos(new long[mnGlyphCount + 1]);
- for( i = 0; i <= mnGlyphCount; ++i )
- pGlyphPos[ i ] = -1;
-
- long nXPos = 0;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- const VisualItem& rVisualItem = mpVisualItems[ nItem ];
- if( rVisualItem.IsEmpty() )
- continue;
-
- if (mnLayoutFlags & SalLayoutFlags::ForFallback)
- {
- nXPos = rVisualItem.mnXOffset;
- }
- // get glyph positions
- // TODO: handle when rVisualItem's glyph range is only partially used
- for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
- {
- pGlyphPos[ i ] = nXPos;
- nXPos += mpGlyphAdvances[ i ];
- }
- // rightmost position of this visualitem
- pGlyphPos[ i ] = nXPos;
-
- // convert glyph positions to character positions
- i = rVisualItem.mnMinCharPos;
- if( i < mnMinCharPos )
- i = mnMinCharPos;
- for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
- {
- int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
- int nCurrIdx = (i - mnMinCharPos) * 2;
- if( !rVisualItem.IsRTL() )
- {
- // normal positions for LTR case
- pCaretXArray[ nCurrIdx ] = pGlyphPos[ j ];
- pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
- }
- else
- {
- // reverse positions for RTL case
- pCaretXArray[ nCurrIdx ] = pGlyphPos[ j+1 ];
- pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
- }
- }
- }
-
- if (!(mnLayoutFlags & SalLayoutFlags::ForFallback))
- {
- nXPos = 0;
- // fixup unknown character positions to neighbor
- for( i = 0; i < nMaxIdx; ++i )
- {
- if( pCaretXArray[ i ] >= 0 )
- nXPos = pCaretXArray[ i ];
- else
- pCaretXArray[ i ] = nXPos;
- }
- }
-}
-
-void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
-{
- SalLayout::AdjustLayout( rArgs );
-
- // adjust positions if requested
- if( rArgs.mpDXArray )
- ApplyDXArray( rArgs );
- else if( rArgs.mnLayoutWidth )
- Justify( rArgs.mnLayoutWidth );
-}
-
-void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
-{
- const long* pDXArray = rArgs.mpDXArray;
-
- // increase char widths in string range to desired values
- bool bModified = false;
- int nOldWidth = 0;
- SAL_WARN_IF( mnUnitsPerPixel!=1, "vcl", "UniscribeLayout.mnUnitsPerPixel != 1" );
- int i,j;
- for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
- {
- int nNewCharWidth = (pDXArray[j] - nOldWidth);
- // TODO: nNewCharWidth *= mnUnitsPerPixel;
- if( mpCharWidths[i] != nNewCharWidth )
- {
- mpCharWidths[i] = nNewCharWidth;
- bModified = true;
- }
- nOldWidth = pDXArray[j];
- }
-
- if( !bModified )
- return;
-
- // initialize justifications array
- mpJustifications = new int[ mnGlyphCapacity ];
- for( i = 0; i < mnGlyphCount; ++i )
- mpJustifications[ i ] = mpGlyphAdvances[ i ];
-
- // apply new widths to script items
- long nXOffset = 0;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- VisualItem& rVisualItem = mpVisualItems[ nItem ];
-
- // set the position of this visual item
- rVisualItem.mnXOffset = nXOffset;
-
- // ignore empty visual items
- if( rVisualItem.IsEmpty() )
- {
- for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
- nXOffset += mpCharWidths[i];
- continue;
- }
- // ignore irrelevant visual items
- if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
- || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
- continue;
-
- // if needed prepare special handling for arabic justification
- rVisualItem.mbHasKashidas = false;
- if( rVisualItem.IsRTL() )
- {
- for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
- if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 ) // any Arabic justification
- { // excluding SCRIPT_JUSTIFY_NONE
- // yes
- rVisualItem.mbHasKashidas = true;
- // so prepare for kashida handling
- InitKashidaHandling();
- break;
- }
-
- if( rVisualItem.HasKashidas() )
- for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
- {
- // TODO: check if we still need this hack after correction of kashida placing?
- // (i87688): apparently yes, we still need it!
- if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
- // usp decided that justification can't be applied here
- // but maybe our Kashida algorithm thinks differently.
- // To avoid trouble (gaps within words, last character of
- // a word gets a Kashida appended) override this.
-
- // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
- // just because this previous hack (which I haven't understand, sorry) used
- // the same value to replace. Don't know if this is really the best
- // thing to do, but it seems to fix things
- mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
- }
- }
-
- // convert virtual charwidths to glyph justification values
- HRESULT nRC = ScriptApplyLogicalWidth(
- mpCharWidths + rVisualItem.mnMinCharPos,
- rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
- rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
- mpLogClusters + rVisualItem.mnMinCharPos,
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
- &rVisualItem.mpScriptItem->a,
- &rVisualItem.maABCWidths,
- mpJustifications + rVisualItem.mnMinGlyphPos );
-
- if( nRC != 0 )
- {
- delete[] mpJustifications;
- mpJustifications = nullptr;
- break;
- }
-
- // to prepare for the next visual item
- // update nXOffset to the next items position
- // before the mpJustifications[] array gets modified
- int nMinGlyphPos, nEndGlyphPos;
- if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
- {
- for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
- nXOffset += mpJustifications[ i ];
-
- if( rVisualItem.mbHasKashidas )
- KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
- }
-
- // workaround needed for older USP versions:
- // right align the justification-adjusted glyphs in their cells for RTL-items
- // unless the right alignment is done by inserting kashidas
- if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
- {
- for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
- {
- const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
- // #i99862# skip diacritics, we mustn't add extra justification to diacritics
- int nIdxAdd = i - 1;
- while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
- --nIdxAdd;
- if( nIdxAdd < nMinGlyphPos )
- rVisualItem.mnXOffset += nXOffsetAdjust;
- else
- mpJustifications[nIdxAdd] += nXOffsetAdjust;
- mpJustifications[i] -= nXOffsetAdjust;
- }
- }
-
- // tdf#94897: Don't add extra justification to chars with diacritics when the diacritic is a
- // separate glyph, followed by blank, in LTR
- if( !rVisualItem.IsRTL() )
- {
- for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
- {
- const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
- if( nXOffsetAdjust == 0 )
- continue;
- int nIdxAdd = i + 1;
- while( (nIdxAdd < nEndGlyphPos) && mpVisualAttrs[nIdxAdd].fDiacritic )
- ++nIdxAdd;
- if( nIdxAdd == i + 1 )
- continue;
- if( nIdxAdd >= nEndGlyphPos || mpVisualAttrs[nIdxAdd].uJustification != SCRIPT_JUSTIFY_BLANK )
- continue;
- mpJustifications[nIdxAdd] += nXOffsetAdjust;
- mpJustifications[i] -= nXOffsetAdjust;
- }
- }
- }
-}
-
-void UniscribeLayout::InitKashidaHandling()
-{
- if( mnMinKashidaGlyph != 0 ) // already initialized
- return;
-
- mrWinFontEntry.InitKashidaHandling( mhDC );
- mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
- mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
-}
-
-// adjust the kashida placement matching to the WriterEngine
-void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
-{
- // workaround needed for all known USP versions:
- // ApplyLogicalWidth does not match ScriptJustify behaviour
- for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
- {
- // check for vowels
- if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
- && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types
- { // including SCRIPT_JUSTIFY_NONE
- // vowel, we do it like ScriptJustify does
- // the vowel gets the extra width
- long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
- mpJustifications [ i ] = mpGlyphAdvances [ i ];
- mpJustifications [ i - 1 ] += nSpaceAdded;
- }
- }
-
- // redistribute the widths for kashidas
- for( int i = nMinGlyphPos; i < nEndGlyphPos; )
- KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
-}
-
-bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
-{
- // doing pixel work within a word.
- // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
-
- // find the next kashida
- int nMinPos = *pnCurrentPos;
- int nMaxPos = *pnCurrentPos;
- for( int i = nMaxPos; i < nEndGlyphPos; ++i )
- {
- if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
- && (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
- break;
- nMaxPos = i;
- }
- *pnCurrentPos = nMaxPos + 1;
- if( nMinPos == nMaxPos )
- return false;
-
- // calculate the available space for an extra kashida
- long nMaxAdded = 0;
- int nKashPos = -1;
- for( int i = nMaxPos; i >= nMinPos; --i )
- {
- long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
- if( nSpaceAdded > nMaxAdded )
- {
- nKashPos = i;
- nMaxAdded = nSpaceAdded;
- }
- }
-
- // return early if there is no need for an extra kashida
- if ( nMaxAdded <= 0 )
- return false;
- // return early if there is not enough space for an extra kashida
- if( 2*nMaxAdded < mnMinKashidaWidth )
- return false;
-
- // redistribute the extra spacing to the kashida position
- for( int i = nMinPos; i <= nMaxPos; ++i )
- {
- if( i == nKashPos )
- continue;
- // everything else should not have extra spacing
- long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
- if( nSpaceAdded > 0 )
- {
- mpJustifications[ i ] -= nSpaceAdded;
- mpJustifications[ nKashPos ] += nSpaceAdded;
- }
- }
-
- // check if we fulfill minimal kashida width
- long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
- if( nSpaceAdded < mnMinKashidaWidth )
- {
- // ugly: steal some pixels
- long nSteal = 1;
- if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
- nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
- for( int i = nMinPos; i <= nMaxPos; ++i )
- {
- if( i == nKashPos )
- continue;
- nSteal = std::min( mnMinKashidaWidth - nSpaceAdded, nSteal );
- if ( nSteal > 0 )
- {
- mpJustifications [ i ] -= nSteal;
- mpJustifications [ nKashPos ] += nSteal;
- nSpaceAdded += nSteal;
- }
- if( nSpaceAdded >= mnMinKashidaWidth )
- return true;
- }
- }
-
- // blank padding
- long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
- if( nSpaceMissing > 0 )
- {
- // inner glyph: distribute extra space evenly
- if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
- {
- mpJustifications [ nKashPos ] += nSpaceMissing;
- long nHalfSpace = nSpaceMissing / 2;
- mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
- mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
- }
- // rightmost: left glyph gets extra space
- else if( nMinPos > nMinGlyphPos )
- {
- mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
- mpJustifications [ nKashPos ] += nSpaceMissing;
- }
- // leftmost: right glyph gets extra space
- else if( nMaxPos < nEndGlyphPos - 1 )
- {
- mpJustifications [ nKashPos ] += nSpaceMissing;
- mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
- }
- else
- return false;
- }
-
- return true;
-}
-
-void UniscribeLayout::Justify( DeviceCoordinate nNewWidth )
-{
- DeviceCoordinate nOldWidth = 0;
- int i;
- for( i = mnMinCharPos; i < mnEndCharPos; ++i )
- nOldWidth += mpCharWidths[ i ];
- if( nOldWidth <= 0 )
- return;
-
- nNewWidth *= mnUnitsPerPixel; // convert into font units
- if( nNewWidth == nOldWidth )
- return;
- // prepare to distribute the extra width evenly among the visual items
- const double fStretch = (double)nNewWidth / nOldWidth;
-
- // initialize justifications array
- mpJustifications = new int[ mnGlyphCapacity ];
- for( i = 0; i < mnGlyphCapacity; ++i )
- mpJustifications[ i ] = mpGlyphAdvances[ i ];
-
- // justify stretched script items
- long nXOffset = 0;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- VisualItem& rVisualItem = mpVisualItems[ nItem ];
- if( rVisualItem.IsEmpty() )
- continue;
-
- if( (rVisualItem.mnMinCharPos < mnEndCharPos)
- && (rVisualItem.mnEndCharPos > mnMinCharPos) )
- {
- long nItemWidth = 0;
- for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
- nItemWidth += mpCharWidths[ i ];
- nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
-
- ScriptJustify(
- mpVisualAttrs + rVisualItem.mnMinGlyphPos,
- mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
- rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
- nItemWidth,
- mnMinKashidaWidth,
- mpJustifications + rVisualItem.mnMinGlyphPos );
-
- rVisualItem.mnXOffset = nXOffset;
- nXOffset += nItemWidth;
- }
- }
-}
-
-bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
-{
- // we have to find the visual item first since the mpLogClusters[]
- // needed to find the cluster start is relative to the visual item
- int nMinGlyphIndex = -1;
- for( int nItem = 0; nItem < mnItemCount; ++nItem )
- {
- const VisualItem& rVisualItem = mpVisualItems[ nItem ];
- if( (nCharPos >= rVisualItem.mnMinCharPos)
- && (nCharPos < rVisualItem.mnEndCharPos) )
- {
- nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
- break;
- }
- }
- // Invalid char pos or leftmost glyph in visual item
- if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
- return false;
-
-// This test didn't give the expected results
-/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
- // two chars, one glyph
- return false;*/
-
- const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
- if( nGlyphPos <= 0 )
- return true;
- // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
- // and not SCRIPT_JUSTIFY_ARABIC_BLANK
- // special case: glyph to the left is vowel (no advance width)
- if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
- || ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
- && mpGlyphAdvances [ nGlyphPos-1 ] ))
- return false;
- return true;
-}
HINSTANCE D2DWriteTextOutRenderer::mmD2d1 = nullptr,
D2DWriteTextOutRenderer::mmDWrite = nullptr;
@@ -3435,70 +611,14 @@ bool D2DWriteTextOutRenderer::GetDWriteInkBox(SalLayout const &rLayout, Rectangl
return true;
}
-SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+SalLayout* WinSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int nFallbackLevel)
{
- if (!mpWinFontEntry[nFallbackLevel]) return nullptr;
+ if (!mpWinFontEntry[nFallbackLevel])
+ return nullptr;
assert(mpWinFontData[nFallbackLevel]);
- WinLayout* pWinLayout = nullptr;
-
- const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ];
- WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
-
- if (SalLayout::UseCommonLayout())
- {
- return new CommonSalLayout(getHDC(), rFontInstance, rFontFace);
- }
- else
- {
- bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter;
-
- if (!bUspInited)
- InitUSP();
-
- if( !(rArgs.mnFlags & SalLayoutFlags::ComplexDisabled) )
- {
- {
- // script complexity is determined in upper layers
- pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
- // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
- // the created UniscribeLayout, otherwise the data passed into the
- // constructor might become invalid too early
- }
- }
- else
- {
- {
- static bool bAvoidSimpleWinLayout = (std::getenv("VCL_NO_SIMPLEWINLAYOUT") != nullptr);
-
- if (!bAvoidSimpleWinLayout)
- {
- if( (rArgs.mnFlags & SalLayoutFlags::KerningPairs) && !rFontInstance.HasKernData() )
- {
- // TODO: directly cache kerning info in the rFontInstance
- // TODO: get rid of kerning methods+data in WinSalGraphics object
- GetKernPairs();
- rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
- }
-
- pWinLayout = new SimpleWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
- }
- else
- {
- pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
- // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
- // the created UniscribeLayout, otherwise the data passed into the
- // constructor might become invalid too early
- }
- }
- }
-
- if( mfFontScale[nFallbackLevel] != 1.0 )
- pWinLayout->SetFontScale( mfFontScale[nFallbackLevel] );
-
- return pWinLayout;
- }
+ return new CommonSalLayout(getHDC(), *mpWinFontEntry[nFallbackLevel], *mpWinFontData[nFallbackLevel]);
}
int WinSalGraphics::GetMinKashidaWidth()
@@ -3517,9 +637,6 @@ LogicalFontInstance * WinSalGraphics::GetWinFontEntry(int const nFallbackLevel)
WinFontInstance::WinFontInstance( FontSelectPattern& rFSD )
: LogicalFontInstance( rFSD )
-, mpKerningPairs( nullptr )
-, mnKerningPairs( -1 )
-, maWidthMap( 512 )
, mnMinKashidaWidth( -1 )
, mnMinKashidaGlyph( -1 )
{
@@ -3530,38 +647,6 @@ WinFontInstance::~WinFontInstance()
{
if( maScriptCache != nullptr )
ScriptFreeCache( &maScriptCache );
- delete[] mpKerningPairs;
-}
-
-bool WinFontInstance::HasKernData() const
-{
- return (mnKerningPairs >= 0);
-}
-
-void WinFontInstance::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
-{
- mnKerningPairs = nPairCount;
- mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
- memcpy( mpKerningPairs, pPairData, nPairCount*sizeof(KERNINGPAIR) );
-}
-
-int WinFontInstance::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
-{
- int nKernAmount = 0;
- if( mpKerningPairs )
- {
- const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
- const KERNINGPAIR* pFirstPair = mpKerningPairs;
- const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
- const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
- pEndPair, aRefPair, ImplCmpKernData );
- if( (pPair != pEndPair)
- && (pPair->wFirst == aRefPair.wFirst)
- && (pPair->wSecond == aRefPair.wSecond) )
- nKernAmount = pPair->iKernAmount;
- }
-
- return nKernAmount;
}
bool WinFontInstance::InitKashidaHandling( HDC hDC )
@@ -3572,8 +657,6 @@ bool WinFontInstance::InitKashidaHandling( HDC hDC )
// initialize the kashida width
mnMinKashidaWidth = 0;
mnMinKashidaGlyph = 0;
- if (!bUspInited)
- InitUSP();
SCRIPT_FONTPROPERTIES aFontProperties;
aFontProperties.cBytes = sizeof (aFontProperties);