diff options
author | sb <sb@openoffice.org> | 2010-02-08 09:18:14 +0100 |
---|---|---|
committer | sb <sb@openoffice.org> | 2010-02-08 09:18:14 +0100 |
commit | 9ec2223b100751fd4a3f64eb8a4a8686305ab074 (patch) | |
tree | 06fb3197763688a27b16726ad6d10ec601cb1ce1 /vcl/source | |
parent | 4e0a003d8289b16c012fc936cc9f1fa2130b2bd9 (diff) | |
parent | da2c680d23b67d4721aa29f740475fd6d40e2e08 (diff) |
sb118: merged in DEV300_m71
Diffstat (limited to 'vcl/source')
24 files changed, 1006 insertions, 679 deletions
diff --git a/vcl/source/app/vclevent.cxx b/vcl/source/app/vclevent.cxx index 704d68c5bc7f..ffab843ff7bd 100644 --- a/vcl/source/app/vclevent.cxx +++ b/vcl/source/app/vclevent.cxx @@ -34,10 +34,30 @@ #include "vcl/vclevent.hxx" #include "vcl/svdata.hxx" +#include <com/sun/star/accessibility/XAccessible.hpp> + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::accessibility::XAccessible; + TYPEINIT0(VclSimpleEvent); TYPEINIT1(VclWindowEvent, VclSimpleEvent); TYPEINIT1(VclMenuEvent, VclSimpleEvent); +VclAccessibleEvent::VclAccessibleEvent( ULONG n, const Reference<XAccessible>& rxAccessible ) : + VclSimpleEvent(n), + mxAccessible(rxAccessible) +{ +} + +VclAccessibleEvent::~VclAccessibleEvent() +{ +} + +Reference<XAccessible> VclAccessibleEvent::GetAccessible() const +{ + return mxAccessible; +} + void VclEventListeners::Call( VclSimpleEvent* pEvent ) const { // Copy the list, because this can be destroyed when calling a Link... @@ -118,9 +138,8 @@ void VclEventListeners2::callListeners( VclSimpleEvent* i_pEvent ) { vcl::DeletionListener aDel( this ); - m_aIterators.push_back( ListenerIt() ); + m_aIterators.push_back(ListenerIt(m_aListeners.begin())); size_t nIndex = m_aIterators.size() - 1; - m_aIterators[ nIndex ].m_aIt = m_aListeners.begin(); while( ! aDel.isDeleted() && m_aIterators[ nIndex ].m_aIt != m_aListeners.end() ) { m_aIterators[ nIndex ].m_aIt->Call( i_pEvent ); diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx index 21707d0182f5..1eea72131b86 100644 --- a/vcl/source/control/combobox.cxx +++ b/vcl/source/control/combobox.cxx @@ -951,7 +951,7 @@ void ComboBox::ImplUpdateFloatSelection() if( nSelect != LISTBOX_ENTRY_NOTFOUND ) { if ( !mpImplLB->IsVisible( nSelect ) ) - mpImplLB->SetTopEntry( nSelect ); + mpImplLB->ShowProminentEntry( nSelect ); mpImplLB->SelectEntry( nSelect, bSelect ); } else @@ -959,7 +959,6 @@ void ComboBox::ImplUpdateFloatSelection() nSelect = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 ); if( nSelect != LISTBOX_ENTRY_NOTFOUND ) mpImplLB->SelectEntry( nSelect, FALSE ); - // mpImplLB->SetTopEntry( 0 ); #92555# Ugly.... mpImplLB->ResetCurrentPos(); } } @@ -1440,6 +1439,13 @@ void ComboBox::SetTopEntry( USHORT nPos ) // ----------------------------------------------------------------------- +void ComboBox::ShowProminentEntry( USHORT nPos ) +{ + mpImplLB->ShowProminentEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() ); +} + +// ----------------------------------------------------------------------- + USHORT ComboBox::GetTopEntry() const { USHORT nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND; @@ -1450,6 +1456,20 @@ USHORT ComboBox::GetTopEntry() const // ----------------------------------------------------------------------- +void ComboBox::SetProminentEntryType( ProminentEntry eType ) +{ + mpImplLB->SetProminentEntryType( eType ); +} + +// ----------------------------------------------------------------------- + +ProminentEntry ComboBox::GetProminentEntryType() const +{ + return mpImplLB->GetProminentEntryType(); +} + +// ----------------------------------------------------------------------- + Rectangle ComboBox::GetDropDownPosSizePixel() const { return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ComboBox*>(this) ) : Rectangle(); diff --git a/vcl/source/control/ilstbox.cxx b/vcl/source/control/ilstbox.cxx index fd5cd7ae4dac..ab353a4d4798 100644 --- a/vcl/source/control/ilstbox.cxx +++ b/vcl/source/control/ilstbox.cxx @@ -565,6 +565,7 @@ ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND; mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND; mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND; + meProminentType = PROMINENT_TOP; SetLineColor(); SetTextFillColor(); @@ -1067,11 +1068,11 @@ void ImplListBoxWindow::SelectEntry( USHORT nPos, BOOL bSelect ) if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) ) { Resize(); - SetTopEntry( nPos ); + ShowProminentEntry( nPos ); } else { - SetTopEntry( nPos-nVisibleEntries+1 ); + ShowProminentEntry( nPos ); } } } @@ -1702,11 +1703,7 @@ BOOL ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt ) if ( nSelect != LISTBOX_ENTRY_NOTFOUND ) { - USHORT nCurVis = GetLastVisibleEntry() - mnTop + 1; - if( nSelect < mnTop ) - SetTopEntry( nSelect ); - else if( nSelect >= (mnTop + nCurVis) ) - SetTopEntry( nSelect - nCurVis + 1 ); + ShowProminentEntry( nSelect ); if ( mpEntryList->IsEntryPosSelected( nSelect ) ) nSelect = LISTBOX_ENTRY_NOTFOUND; @@ -2053,6 +2050,20 @@ void ImplListBoxWindow::SetTopEntry( USHORT nTop ) // ----------------------------------------------------------------------- +void ImplListBoxWindow::ShowProminentEntry( USHORT nEntryPos ) +{ + if( meProminentType == PROMINENT_MIDDLE ) + { + USHORT nPos = nEntryPos; + long nWHeight = PixelToLogic( GetSizePixel() ).Height(); + while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 ) + nEntryPos--; + } + SetTopEntry( nEntryPos ); +} + +// ----------------------------------------------------------------------- + void ImplListBoxWindow::SetLeftIndent( long n ) { ScrollHorz( n - mnLeft ); @@ -3206,7 +3217,7 @@ void ImplListBoxFloatingWindow::StartFloat( BOOL bStartTracking ) StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN ); if( nPos != LISTBOX_ENTRY_NOTFOUND ) - mpImplLB->SetTopEntry( nPos ); + mpImplLB->ShowProminentEntry( nPos ); if( bStartTracking ) mpImplLB->GetMainWindow()->EnableMouseMoveSelect( TRUE ); diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx index 81a8dc0e8242..ac51d7593c93 100644 --- a/vcl/source/control/lstbox.cxx +++ b/vcl/source/control/lstbox.cxx @@ -1210,6 +1210,13 @@ void ListBox::SetTopEntry( USHORT nPos ) // ----------------------------------------------------------------------- +void ListBox::ShowProminentEntry( USHORT nPos ) +{ + mpImplLB->ShowProminentEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() ); +} + +// ----------------------------------------------------------------------- + USHORT ListBox::GetTopEntry() const { USHORT nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND; @@ -1220,6 +1227,20 @@ USHORT ListBox::GetTopEntry() const // ----------------------------------------------------------------------- +void ListBox::SetProminentEntryType( ProminentEntry eType ) +{ + mpImplLB->SetProminentEntryType( eType ); +} + +// ----------------------------------------------------------------------- + +ProminentEntry ListBox::GetProminentEntryType() const +{ + return mpImplLB->GetProminentEntryType(); +} + +// ----------------------------------------------------------------------- + BOOL ListBox::IsTravelSelect() const { return mpImplLB->IsTravelSelect(); diff --git a/vcl/source/control/tabctrl.cxx b/vcl/source/control/tabctrl.cxx index 56cc2c3fb012..43c459b6c52e 100644 --- a/vcl/source/control/tabctrl.cxx +++ b/vcl/source/control/tabctrl.cxx @@ -1658,7 +1658,7 @@ long TabControl::PreNotify( NotifyEvent& rNEvt ) // ----------------------------------------------------------------------- -long TabControl::Notify( NotifyEvent& rNEvt ) +bool TabControl::ImplHandleNotifyEvent( NotifyEvent& rNEvt ) { if ( (rNEvt.GetType() == EVENT_KEYINPUT) && (GetPageCount() > 1) ) { @@ -1686,8 +1686,16 @@ long TabControl::Notify( NotifyEvent& rNEvt ) } } } + return false; +} + + +// ----------------------------------------------------------------------- + +long TabControl::Notify( NotifyEvent& rNEvt ) +{ - return Control::Notify( rNEvt ); + return ImplHandleNotifyEvent( rNEvt ) ? TRUE : Control::Notify( rNEvt ); } // ----------------------------------------------------------------------- diff --git a/vcl/source/fontsubset/gsub.cxx b/vcl/source/fontsubset/gsub.cxx index 600c03194210..a1c3344f3e5a 100644 --- a/vcl/source/fontsubset/gsub.cxx +++ b/vcl/source/fontsubset/gsub.cxx @@ -42,6 +42,7 @@ namespace vcl { typedef sal_uInt32 ULONG; +typedef sal_uInt32 UINT32; typedef sal_uInt16 USHORT; typedef sal_uInt8 FT_Byte; @@ -280,13 +281,11 @@ int ReadGSUB( struct _TrueTypeFont* pTTFile, return false; for( int i = nCntRange; --i >= 0; ) { - const USHORT nGlyph0 = NEXT_UShort( pCoverage ); - const USHORT nGlyph1 = NEXT_UShort( pCoverage ); - const USHORT nStartCoverageIndex = NEXT_UShort( pCoverage ); - OSL_ENSURE( aSubstVector.size() == nStartCoverageIndex, "coverage index mismatch"); - (void)nStartCoverageIndex; - for( USHORT j = nGlyph0; j <= nGlyph1; ++j ) - aSubstVector.push_back( GlyphSubst( j, 0 ) ); + const UINT32 nGlyph0 = NEXT_UShort( pCoverage ); + const UINT32 nGlyph1 = NEXT_UShort( pCoverage ); + const USHORT nCovIdx = NEXT_UShort( pCoverage ); + for( UINT32 j = nGlyph0; j <= nGlyph1; ++j ) + aSubstVector.push_back( GlyphSubst( static_cast<USHORT>(j + nCovIdx), 0 ) ); } } break; diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index 0accc42af968..964d6a93ac3c 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -1094,6 +1094,14 @@ static void GetNames(TrueTypeFont *t) const sal_uInt8* table = getTable( t, O_name ); int nTableSize = getTableSize(t, O_name); + if (nTableSize < 4) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf(stderr, "O_name table too small\n"); +#endif + return; + } + sal_uInt16 n = GetUInt16(table, 2, 1); int i, r; sal_Bool bPSNameOK = sal_True; @@ -1681,7 +1689,6 @@ int OpenTTFontFile( const char* fname, sal_uInt32 facenum, TrueTypeFont** ttf ) goto cleanup; } - if (((*ttf)->ptr = (sal_uInt8 *) mmap(0, (*ttf)->fsize, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { ret = SF_MEMORY; goto cleanup; @@ -2702,7 +2709,7 @@ void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info) } table = getTable(ttf, O_post); - if (table) { + if (table && getTableSize(ttf, O_post) >= 12+sizeof(sal_uInt32)) { info->pitch = GetUInt32(table, 12, 1); info->italicAngle = GetInt32(table, 4, 1); } @@ -2808,6 +2815,15 @@ int GetTTNameRecords(TrueTypeFont *ttf, NameRecord **nr) { const sal_uInt8* table = getTable(ttf, O_name); int nTableSize = getTableSize(ttf, O_name ); + + if (nTableSize < 6) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf(stderr, "O_name table too small\n"); +#endif + return 0; + } + sal_uInt16 n = GetUInt16(table, 2, 1); int nStrBase = GetUInt16(table, 4, 1); int i; diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 51aad0790a26..28fa4f8f5461 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -5601,6 +5601,8 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr, if ( !IsDeviceOutputNecessary() ) return; + if( !mpGraphics && !ImplGetGraphics() ) + return; if( mbInitClipRegion ) ImplInitClipRegion(); if( mbOutputClipped ) diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index c0205f1f325d..d42e736960d2 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -2814,37 +2814,6 @@ sal_Int32 PDFWriterImpl::emitBuiltinFont( const ImplFontData* pFont, sal_Int32 n return nFontObject; } -typedef int ThreeInts[3]; -static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen, - ThreeInts& rSegmentLengths ) -{ - if( !pFontBytes || (nByteLen < 0) ) - return false; - const unsigned char* pPtr = pFontBytes; - const unsigned char* pEnd = pFontBytes + nByteLen; - - for( int i = 0; i < 3; ++i) { - // read segment1 header - if( pPtr+6 >= pEnd ) - return false; - if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) ) - return false; - const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2]; - if( nLen <= 0) - return false; - rSegmentLengths[i] = nLen; - pPtr += nLen + 6; - } - - // read segment-end header - if( pPtr+2 >= pEnd ) - return false; - if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) ) - return false; - - return true; -} - std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const ImplFontData* pFont, EmbedFont& rEmbed ) { std::map< sal_Int32, sal_Int32 > aRet; @@ -2960,6 +2929,41 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const ImplFontDa return aRet; } +typedef int ThreeInts[3]; +static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen, + ThreeInts& rSegmentLengths ) +{ + if( !pFontBytes || (nByteLen < 0) ) + return false; + const unsigned char* pPtr = pFontBytes; + const unsigned char* pEnd = pFontBytes + nByteLen; + + for( int i = 0; i < 3; ++i) { + // read segment1 header + if( pPtr+6 >= pEnd ) + return false; + if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) ) + return false; + const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2]; + if( nLen <= 0) + return false; + rSegmentLengths[i] = nLen; + pPtr += nLen + 6; + } + + // read segment-end header + if( pPtr+2 >= pEnd ) + return false; + if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) ) + return false; + + return true; +} + +struct FontException : public std::exception +{ +}; + // TODO: always subset instead of embedding the full font => this method becomes obsolete then std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFontData* pFont, EmbedFont& rEmbed ) { @@ -2979,10 +2983,16 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFont sal_Int32 nToUnicodeStream = 0; sal_uInt8 nEncoding[256]; sal_Ucs nEncodedCodes[256]; + std::vector<sal_Ucs> aUnicodes; + aUnicodes.reserve( 256 ); + sal_Int32 pUnicodesPerGlyph[256]; + sal_Int32 pEncToUnicodeIndex[256]; if( pEncoding ) { - memset( nEncodedCodes, 0, sizeof(nEncodedCodes) ); - memset( nEncoding, 0, sizeof(nEncoding) ); + rtl_zeroMemory( nEncoding, sizeof(nEncoding) ); + rtl_zeroMemory( nEncodedCodes, sizeof(nEncodedCodes) ); + rtl_zeroMemory( pUnicodesPerGlyph, sizeof(pUnicodesPerGlyph) ); + rtl_zeroMemory( pEncToUnicodeIndex, sizeof(pEncToUnicodeIndex) ); for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it ) { if( it->second != -1 ) @@ -2990,6 +3000,9 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFont sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff); nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode ); nEncodedCodes[ nCode ] = it->first; + pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size()); + aUnicodes.push_back( it->first ); + pUnicodesPerGlyph[ nCode ] = 1; } } } @@ -2999,553 +3012,525 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFont const unsigned char* pFontData = NULL; long nFontLen = 0; sal_Int32 nLength1, nLength2; - if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL ) - { - if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 ) - goto streamend; - // see whether it is pfb or pfa; if it is a pfb, fill ranges - // of 6 bytes that are not part of the font program - std::list< int > aSections; - std::list< int >::const_iterator it; - int nIndex = 0; - while( pFontData[nIndex] == 0x80 && nIndex < nFontLen-1 ) - { - aSections.push_back( nIndex ); - if( pFontData[nIndex+1] == 0x03 ) - break; - sal_Int32 nBytes = + try + { + if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL ) + { + if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 ) + throw FontException(); + // see whether it is pfb or pfa; if it is a pfb, fill ranges + // of 6 bytes that are not part of the font program + std::list< int > aSections; + std::list< int >::const_iterator it; + int nIndex = 0; + while( pFontData[nIndex] == 0x80 && nIndex < nFontLen-1 ) + { + aSections.push_back( nIndex ); + if( pFontData[nIndex+1] == 0x03 ) + break; + sal_Int32 nBytes = ((sal_Int32)pFontData[nIndex+2]) | ((sal_Int32)pFontData[nIndex+3]) << 8 | ((sal_Int32)pFontData[nIndex+4]) << 16 | ((sal_Int32)pFontData[nIndex+5]) << 24; - nIndex += nBytes+6; - } - - // search for eexec - // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below - nIndex = 0; - int nEndAsciiIndex; - int nBeginBinaryIndex; - int nEndBinaryIndex; - do - { - while( nIndex < nFontLen-4 && - ( pFontData[nIndex] != 'e' || - pFontData[nIndex+1] != 'e' || - pFontData[nIndex+2] != 'x' || - pFontData[nIndex+3] != 'e' || - pFontData[nIndex+4] != 'c' - ) - ) - nIndex++; - // check whether we are in a excluded section - for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) - ; - } while( it != aSections.end() && nIndex < nFontLen-4 ); - // this should end the ascii part - if( nIndex > nFontLen-5 ) - goto streamend; - - nEndAsciiIndex = nIndex+4; - // now count backwards until we can account for 512 '0' - // which is the endmarker of the (hopefully) binary data - // do not count the pfb header sections - int nFound = 0; - nIndex = nFontLen-1; - while( nIndex > 0 && nFound < 512 ) - { - for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) - ; - if( it == aSections.end() ) - { - // inside the 512 '0' block there may only be whitespace - // according to T1 spec; probably it would be to simple - // if all fonts complied - if( pFontData[nIndex] == '0' ) - nFound++; - else if( nFound > 0 && - pFontData[nIndex] != '\r' && - pFontData[nIndex] != '\t' && - pFontData[nIndex] != '\n' && - pFontData[nIndex] != ' ' ) - break; + nIndex += nBytes+6; } - nIndex--; - } - - if( nIndex < 1 || nIndex <= nEndAsciiIndex ) - goto streamend; - // there may be whitespace to ignore before the 512 '0' - while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' ) - { - nIndex--; - for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) - ; - if( it != aSections.end() ) - { - nIndex = (*it)-1; - break; // this is surely a binary boundary, in ascii case it wouldn't matter - } - } - nEndBinaryIndex = nIndex; - // and count forward again to the point where we have nFound '0' - // to get the corect value for nLength3 - sal_Int32 nLength3 = 0; - sal_Int32 nL3Index = nIndex; - while( nFound && nL3Index < nFontLen ) - { - for( it = aSections.begin(); it != aSections.end() && (nL3Index < *it || nL3Index > ((*it) + 5) ); ++it ) - ; - if( it == aSections.end() ) + // search for eexec + // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below + nIndex = 0; + int nEndAsciiIndex; + int nBeginBinaryIndex; + int nEndBinaryIndex; + do { - // inside the 512 '0' block there may only be whitespace - // according to T1 spec; probably it would be to simple - // if all fonts complied - if( pFontData[nL3Index] == '0' ) - nFound--; - nLength3++; - } - nL3Index++; - } - - // search for beginning of binary section - nBeginBinaryIndex = nEndAsciiIndex; - do - { - nBeginBinaryIndex++; - for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it ) - ; - } while( nBeginBinaryIndex < nEndBinaryIndex && - ( pFontData[nBeginBinaryIndex] == '\r' || - pFontData[nBeginBinaryIndex] == '\n' || - it != aSections.end() ) ); - - // it seems to be vital to copy the exact whitespace between binary data - // and eexec, else a invalid font results. so make nEndAsciiIndex - // always immediate in front of nBeginBinaryIndex - nEndAsciiIndex = nBeginBinaryIndex-1; - for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it ) - ; - if( it != aSections.end() ) - nEndAsciiIndex = (*it)-1; - - nLength1 = nEndAsciiIndex+1; // including the last character - for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it ) - nLength1 -= 6; // decrease by pfb section size - - // if the first four bytes are all ascii hex characters, then binary data - // has to be converted to real binary data - for( nIndex = 0; nIndex < 4 && - ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) || - ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) || - ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' ) - ); ++nIndex ) - ; - bool bConvertHexData = true; - if( nIndex < 4 ) - { - bConvertHexData = false; - nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte - for( it = aSections.begin(); it != aSections.end(); ++it ) - if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex ) - nLength2 -= 6; - } - else - { - // count the hex ascii characters to get nLength2 - nLength2 = 0; - int nNextSectionIndex = 0; - for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) - ; - if( it != aSections.end() ) - nNextSectionIndex = *it; - for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) + while( nIndex < nFontLen-4 && + ( pFontData[nIndex] != 'e' || + pFontData[nIndex+1] != 'e' || + pFontData[nIndex+2] != 'x' || + pFontData[nIndex+3] != 'e' || + pFontData[nIndex+4] != 'c' + ) + ) + nIndex++; + // check whether we are in a excluded section + for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) + ; + } while( it != aSections.end() && nIndex < nFontLen-4 ); + // this should end the ascii part + if( nIndex > nFontLen-5 ) + throw FontException(); + + nEndAsciiIndex = nIndex+4; + // now count backwards until we can account for 512 '0' + // which is the endmarker of the (hopefully) binary data + // do not count the pfb header sections + int nFound = 0; + nIndex = nFontLen-1; + while( nIndex > 0 && nFound < 512 ) { - if( nIndex == nNextSectionIndex ) + for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) + ; + if( it == aSections.end() ) { - nIndex += 6; - ++it; - nNextSectionIndex = (it == aSections.end() ? 0 : *it ); + // inside the 512 '0' block there may only be whitespace + // according to T1 spec; probably it would be to simple + // if all fonts complied + if( pFontData[nIndex] == '0' ) + nFound++; + else if( nFound > 0 && + pFontData[nIndex] != '\r' && + pFontData[nIndex] != '\t' && + pFontData[nIndex] != '\n' && + pFontData[nIndex] != ' ' ) + break; } - if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) || - ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) || - ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) ) - nLength2++; + nIndex--; } - DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" ); - nLength2 /= 2; - } - - // now we can actually write the font stream ! -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::emitEmbeddedFont" ); - emitComment( aLine.getStr() ); - } -#endif - OStringBuffer aLine( 512 ); - nStreamObject = createObject(); - if( !updateObject(nStreamObject)) - goto streamend; - sal_Int32 nStreamLengthObject = createObject(); - aLine.append( nStreamObject ); - aLine.append( " 0 obj\n" - "<</Length " ); - aLine.append( nStreamLengthObject ); - aLine.append( " 0 R" -#ifndef DEBUG_DISABLE_PDFCOMPRESSION - "/Filter/FlateDecode" -#endif - "/Length1 " ); - aLine.append( nLength1 ); - aLine.append( " /Length2 " ); - aLine.append( nLength2 ); - aLine.append( " /Length3 "); - aLine.append( nLength3 ); - aLine.append( ">>\n" - "stream\n" ); - if( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; - sal_uInt64 nBeginStreamPos = 0; - osl_getFilePos( m_aFile, &nBeginStreamPos ); + if( nIndex < 1 || nIndex <= nEndAsciiIndex ) + throw FontException(); - beginCompression(); - checkAndEnableStreamEncryption( nStreamObject ); - - // write ascii section - if( aSections.begin() == aSections.end() ) - { - if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) ) - { - endCompression(); - disableStreamEncryption(); - goto streamend; - } - } - else - { - // first section always starts at 0 - it = aSections.begin(); - nIndex = (*it)+6; - ++it; - while( *it < nEndAsciiIndex ) + // nLength3 is the rest of the file - excluding any section headers + // nIndex now points to the first of the 512 '0' characters marking the + // fixed content portion + sal_Int32 nLength3 = nFontLen - nIndex; + for( it = aSections.begin(); it != aSections.end(); ++it ) { - if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) ) + if( *it >= nIndex ) { - endCompression(); - disableStreamEncryption(); - goto streamend; + // special case: nIndex inside a section marker + if( nIndex >= (*it) && (*it)+5 > nIndex ) + nLength3 -= (*it)+5 - nIndex; + else + { + if( *it < nFontLen - 6 ) + nLength3 -= 6; + else // the last section 0x8003 is only 2 bytes after all + nLength3 -= (nFontLen - *it); + } } - nIndex = (*it)+6; - ++it; } - // write partial last section - if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) ) - { - endCompression(); - disableStreamEncryption(); - goto streamend; - } - } - // write binary section - if( ! bConvertHexData ) - { - if( aSections.begin() == aSections.end() ) + // there may be whitespace to ignore before the 512 '0' + while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' ) { - if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) ) + nIndex--; + for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) + ; + if( it != aSections.end() ) { - endCompression(); - disableStreamEncryption(); - goto streamend; + nIndex = (*it)-1; + break; // this is surely a binary boundary, in ascii case it wouldn't matter } } - else + nEndBinaryIndex = nIndex; + + // search for beginning of binary section + nBeginBinaryIndex = nEndAsciiIndex; + do { - for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it ) + nBeginBinaryIndex++; + for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it ) ; - // write first partial section - if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) ) - { - endCompression(); - disableStreamEncryption(); - goto streamend; - } - // write following sections - while( it != aSections.end() ) - { - nIndex = (*it)+6; - ++it; - if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes + } while( nBeginBinaryIndex < nEndBinaryIndex && + ( pFontData[nBeginBinaryIndex] == '\r' || + pFontData[nBeginBinaryIndex] == '\n' || + it != aSections.end() ) ); + + // it seems to be vital to copy the exact whitespace between binary data + // and eexec, else a invalid font results. so make nEndAsciiIndex + // always immediate in front of nBeginBinaryIndex + nEndAsciiIndex = nBeginBinaryIndex-1; + for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it ) + ; + if( it != aSections.end() ) + nEndAsciiIndex = (*it)-1; + + nLength1 = nEndAsciiIndex+1; // including the last character + for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it ) + nLength1 -= 6; // decrease by pfb section size + + // if the first four bytes are all ascii hex characters, then binary data + // has to be converted to real binary data + for( nIndex = 0; nIndex < 4 && + ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) || + ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) || + ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' ) + ); ++nIndex ) + ; + bool bConvertHexData = true; + if( nIndex < 4 ) + { + bConvertHexData = false; + nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte + for( it = aSections.begin(); it != aSections.end(); ++it ) + if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex ) + nLength2 -= 6; + } + else { - sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; - if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) + // count the hex ascii characters to get nLength2 + nLength2 = 0; + int nNextSectionIndex = 0; + for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) + ; + if( it != aSections.end() ) + nNextSectionIndex = *it; + for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) { - endCompression(); - disableStreamEncryption(); - goto streamend; + if( nIndex == nNextSectionIndex ) + { + nIndex += 6; + ++it; + nNextSectionIndex = (it == aSections.end() ? 0 : *it ); + } + if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) || + ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) || + ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) ) + nLength2++; } + DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" ); + nLength2 /= 2; } - } - } - } - else - { - unsigned char* pWriteBuffer = (unsigned char*)rtl_allocateMemory( nLength2 ); - memset( pWriteBuffer, 0, nLength2 ); - int nWriteIndex = 0; - - int nNextSectionIndex = 0; - for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) - ; - if( it != aSections.end() ) - nNextSectionIndex = *it; - for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) - { - if( nIndex == nNextSectionIndex ) - { - nIndex += 6; - ++it; - nNextSectionIndex = (it == aSections.end() ? nFontLen : *it ); - } - unsigned char cNibble = 0x80; - if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) - cNibble = pFontData[nIndex] - '0'; - else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) - cNibble = pFontData[nIndex] - 'a' + 10; - else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) - cNibble = pFontData[nIndex] - 'A' + 10; - if( cNibble != 0x80 ) - { - if( !(nWriteIndex & 1 ) ) - cNibble <<= 4; - pWriteBuffer[ nWriteIndex/2 ] |= cNibble; - nWriteIndex++; - } - } - if( ! writeBuffer( pWriteBuffer, nLength2 ) ) - { - endCompression(); - disableStreamEncryption(); - goto streamend; - } - rtl_freeMemory( pWriteBuffer ); - if( aSections.empty() ) - { - if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) ) - { - endCompression(); - disableStreamEncryption(); - goto streamend; - } - } - else - { - // write rest of this section - if( nIndex < nNextSectionIndex ) - { - if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) ) + // now we can actually write the font stream ! + #if OSL_DEBUG_LEVEL > 1 { - endCompression(); - disableStreamEncryption(); - goto streamend; + OStringBuffer aLine( " PDFWriterImpl::emitEmbeddedFont" ); + emitComment( aLine.getStr() ); } - } - // write following sections - while( it != aSections.end() ) - { - nIndex = (*it)+6; - ++it; - if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes + #endif + OStringBuffer aLine( 512 ); + nStreamObject = createObject(); + if( !updateObject(nStreamObject)) + throw FontException(); + sal_Int32 nStreamLengthObject = createObject(); + aLine.append( nStreamObject ); + aLine.append( " 0 obj\n" + "<</Length " ); + aLine.append( nStreamLengthObject ); + aLine.append( " 0 R" + #ifndef DEBUG_DISABLE_PDFCOMPRESSION + "/Filter/FlateDecode" + #endif + "/Length1 " ); + aLine.append( nLength1 ); + aLine.append( " /Length2 " ); + aLine.append( nLength2 ); + aLine.append( " /Length3 "); + aLine.append( nLength3 ); + aLine.append( ">>\n" + "stream\n" ); + if( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) + throw FontException(); + + sal_uInt64 nBeginStreamPos = 0; + osl_getFilePos( m_aFile, &nBeginStreamPos ); + + beginCompression(); + checkAndEnableStreamEncryption( nStreamObject ); + + // write ascii section + if( aSections.begin() == aSections.end() ) + { + if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) ) + throw FontException(); + } + else { - sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; - if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) + // first section always starts at 0 + it = aSections.begin(); + nIndex = (*it)+6; + ++it; + while( *it < nEndAsciiIndex ) { - endCompression(); - disableStreamEncryption(); - goto streamend; + if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) ) + throw FontException(); + nIndex = (*it)+6; + ++it; } + // write partial last section + if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) ) + throw FontException(); } - } - } - } - endCompression(); - disableStreamEncryption(); - - - sal_uInt64 nEndStreamPos = 0; - osl_getFilePos( m_aFile, &nEndStreamPos ); - // and finally close the stream - aLine.setLength( 0 ); - aLine.append( "\nendstream\nendobj\n\n" ); - if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; + // write binary section + if( ! bConvertHexData ) + { + if( aSections.begin() == aSections.end() ) + { + if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) ) + throw FontException(); + } + else + { + for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it ) + ; + // write first partial section + if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) ) + throw FontException(); + // write following sections + while( it != aSections.end() ) + { + nIndex = (*it)+6; + ++it; + if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes + { + sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; + if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) + throw FontException(); + } + } + } + } + else + { + boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] ); + rtl_zeroMemory( pWriteBuffer.get(), nLength2 ); + int nWriteIndex = 0; + + int nNextSectionIndex = 0; + for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) + ; + if( it != aSections.end() ) + nNextSectionIndex = *it; + for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) + { + if( nIndex == nNextSectionIndex ) + { + nIndex += 6; + ++it; + nNextSectionIndex = (it == aSections.end() ? nFontLen : *it ); + } + unsigned char cNibble = 0x80; + if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) + cNibble = pFontData[nIndex] - '0'; + else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) + cNibble = pFontData[nIndex] - 'a' + 10; + else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) + cNibble = pFontData[nIndex] - 'A' + 10; + if( cNibble != 0x80 ) + { + if( !(nWriteIndex & 1 ) ) + cNibble <<= 4; + pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble; + nWriteIndex++; + } + } + if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) ) + throw FontException(); + if( aSections.empty() ) + { + if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) ) + throw FontException(); + } + else + { + // write rest of this section + if( nIndex < nNextSectionIndex ) + { + if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) ) + throw FontException(); + } + // write following sections + while( it != aSections.end() ) + { + nIndex = (*it)+6; + ++it; + if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes + { + sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; + if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) + throw FontException(); + } + } + } + } + endCompression(); + disableStreamEncryption(); - // write stream length object - aLine.setLength( 0 ); - if( ! updateObject( nStreamLengthObject ) ) - goto streamend; - aLine.append( nStreamLengthObject ); - aLine.append( " 0 obj\n" ); - aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) ); - aLine.append( "\nendobj\n\n" ); - if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; - } - else - { - rtl::OStringBuffer aErrorComment( 256 ); - aErrorComment.append( "GetEmbedFontData failed for font \"" ); - aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) ); - aErrorComment.append( '\"' ); - if( pFont->GetSlant() == ITALIC_NORMAL ) - aErrorComment.append( " italic" ); - else if( pFont->GetSlant() == ITALIC_OBLIQUE ) - aErrorComment.append( " oblique" ); - aErrorComment.append( " weight=" ); - aErrorComment.append( sal_Int32(pFont->GetWeight()) ); - emitComment( aErrorComment.getStr() ); - } - - if( nStreamObject ) - // write font descriptor - nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject ); - if( nFontDescriptor ) - { - if( pEncoding ) - nToUnicodeStream = createToUnicodeCMap( nEncoding, nEncodedCodes, sizeof(nEncoding)/sizeof(nEncoding[0]) ); + sal_uInt64 nEndStreamPos = 0; + osl_getFilePos( m_aFile, &nEndStreamPos ); - // write font object - sal_Int32 nObject = createObject(); - if( ! updateObject( nObject ) ) - goto streamend; + // and finally close the stream + aLine.setLength( 0 ); + aLine.append( "\nendstream\nendobj\n\n" ); + if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) + throw FontException(); - OStringBuffer aLine( 1024 ); - aLine.append( nObject ); - aLine.append( " 0 obj\n" - "<</Type/Font/Subtype/Type1/BaseFont/" ); - appendName( aInfo.m_aPSName, aLine ); - aLine.append( "\n" ); - if( !pFont->mbSymbolFlag && pEncoding == 0 ) - aLine.append( "/Encoding/WinAnsiEncoding\n" ); - if( nToUnicodeStream ) - { - aLine.append( "/ToUnicode " ); - aLine.append( nToUnicodeStream ); - aLine.append( " 0 R\n" ); + // write stream length object + aLine.setLength( 0 ); + if( ! updateObject( nStreamLengthObject ) ) + throw FontException(); + aLine.append( nStreamLengthObject ); + aLine.append( " 0 obj\n" ); + aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) ); + aLine.append( "\nendobj\n\n" ); + if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) + throw FontException(); } - aLine.append( "/FirstChar 0 /LastChar 255\n" - "/Widths[" ); - for( int i = 0; i < 256; i++ ) + else { - aLine.append( pWidths[i] ); - aLine.append( ((i&15) == 15) ? "\n" : " " ); - } - aLine.append( "]\n" - "/FontDescriptor " ); - aLine.append( nFontDescriptor ); - aLine.append( " 0 R>>\n" - "endobj\n\n" ); - if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; - - nFontObject = nObject; - - aRet[ rEmbed.m_nNormalFontID ] = nObject; + rtl::OStringBuffer aErrorComment( 256 ); + aErrorComment.append( "GetEmbedFontData failed for font \"" ); + aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) ); + aErrorComment.append( '\"' ); + if( pFont->GetSlant() == ITALIC_NORMAL ) + aErrorComment.append( " italic" ); + else if( pFont->GetSlant() == ITALIC_OBLIQUE ) + aErrorComment.append( " oblique" ); + aErrorComment.append( " weight=" ); + aErrorComment.append( sal_Int32(pFont->GetWeight()) ); + emitComment( aErrorComment.getStr() ); + } + + if( nStreamObject ) + // write font descriptor + nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject ); - // write additional encodings - for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it ) + if( nFontDescriptor ) { - sal_Int32 aEncWidths[ 256 ]; - // emit encoding dict - sal_Int32 nEncObject = createObject(); - if( ! updateObject( nEncObject ) ) - goto streamend; - - OutputDevice* pRef = getReferenceDevice(); - pRef->Push( PUSH_FONT | PUSH_MAPMODE ); - pRef->SetMapMode( MapMode( MAP_PIXEL ) ); - Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) ); - aFont.SetWeight( pFont->GetWeight() ); - aFont.SetItalic( pFont->GetSlant() ); - aFont.SetPitch( pFont->GetPitch() ); - pRef->SetFont( aFont ); - pRef->ImplNewFont(); - - aLine.setLength( 0 ); - aLine.append( nEncObject ); - aLine.append( " 0 obj\n" - "<</Type/Encoding/Differences[ 0\n" ); - int nEncoded = 0; - for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it ) - { - String aStr( str_it->m_aUnicode ); - aEncWidths[nEncoded] = pRef->GetTextWidth( aStr ); - nEncodedCodes[nEncoded] = str_it->m_aUnicode; - nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded); - - aLine.append( " /" ); - aLine.append( str_it->m_aName ); - if( !((++nEncoded) & 15) ) - aLine.append( "\n" ); - } - aLine.append( "]>>\n" - "endobj\n\n" ); - - pRef->Pop(); - - if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; - - nToUnicodeStream = createToUnicodeCMap( nEncoding, nEncodedCodes, nEncoded ); + if( pEncoding ) + nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, sizeof(nEncoding)/sizeof(nEncoding[0]) ); - nObject = createObject(); + // write font object + sal_Int32 nObject = createObject(); if( ! updateObject( nObject ) ) - goto streamend; + throw FontException(); - aLine.setLength( 0 ); + OStringBuffer aLine( 1024 ); aLine.append( nObject ); aLine.append( " 0 obj\n" - "<</Type/Font/Subtype/Type1/BaseFont/" ); + "<</Type/Font/Subtype/Type1/BaseFont/" ); appendName( aInfo.m_aPSName, aLine ); aLine.append( "\n" ); - aLine.append( "/Encoding " ); - aLine.append( nEncObject ); - aLine.append( " 0 R\n" ); + if( !pFont->mbSymbolFlag && pEncoding == 0 ) + aLine.append( "/Encoding/WinAnsiEncoding\n" ); if( nToUnicodeStream ) { aLine.append( "/ToUnicode " ); aLine.append( nToUnicodeStream ); aLine.append( " 0 R\n" ); } - aLine.append( "/FirstChar 0\n" - "/LastChar " ); - aLine.append( (sal_Int32)(nEncoded-1) ); - aLine.append( "\n" - "/Widths[" ); - for( int i = 0; i < nEncoded; i++ ) + aLine.append( "/FirstChar 0 /LastChar 255\n" + "/Widths[" ); + for( int i = 0; i < 256; i++ ) { - aLine.append( aEncWidths[i] ); + aLine.append( pWidths[i] ); aLine.append( ((i&15) == 15) ? "\n" : " " ); } - aLine.append( " ]\n" - "/FontDescriptor " ); + aLine.append( "]\n" + "/FontDescriptor " ); aLine.append( nFontDescriptor ); aLine.append( " 0 R>>\n" - "endobj\n\n" ); + "endobj\n\n" ); if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) - goto streamend; + throw FontException(); - aRet[ enc_it->m_nFontID ] = nObject; + nFontObject = nObject; + + aRet[ rEmbed.m_nNormalFontID ] = nObject; + + // write additional encodings + for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it ) + { + sal_Int32 aEncWidths[ 256 ]; + // emit encoding dict + sal_Int32 nEncObject = createObject(); + if( ! updateObject( nEncObject ) ) + throw FontException(); + + OutputDevice* pRef = getReferenceDevice(); + pRef->Push( PUSH_FONT | PUSH_MAPMODE ); + pRef->SetMapMode( MapMode( MAP_PIXEL ) ); + Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) ); + aFont.SetWeight( pFont->GetWeight() ); + aFont.SetItalic( pFont->GetSlant() ); + aFont.SetPitch( pFont->GetPitch() ); + pRef->SetFont( aFont ); + pRef->ImplNewFont(); + + aLine.setLength( 0 ); + aLine.append( nEncObject ); + aLine.append( " 0 obj\n" + "<</Type/Encoding/Differences[ 0\n" ); + int nEncoded = 0; + aUnicodes.clear(); + for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it ) + { + String aStr( str_it->m_aUnicode ); + aEncWidths[nEncoded] = pRef->GetTextWidth( aStr ); + nEncodedCodes[nEncoded] = str_it->m_aUnicode; + nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded); + pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size()); + aUnicodes.push_back( nEncodedCodes[nEncoded] ); + pUnicodesPerGlyph[nEncoded] = 1; + + aLine.append( " /" ); + aLine.append( str_it->m_aName ); + if( !((++nEncoded) & 15) ) + aLine.append( "\n" ); + } + aLine.append( "]>>\n" + "endobj\n\n" ); + + pRef->Pop(); + + if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) + throw FontException(); + + nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded ); + + nObject = createObject(); + if( ! updateObject( nObject ) ) + throw FontException(); + + aLine.setLength( 0 ); + aLine.append( nObject ); + aLine.append( " 0 obj\n" + "<</Type/Font/Subtype/Type1/BaseFont/" ); + appendName( aInfo.m_aPSName, aLine ); + aLine.append( "\n" ); + aLine.append( "/Encoding " ); + aLine.append( nEncObject ); + aLine.append( " 0 R\n" ); + if( nToUnicodeStream ) + { + aLine.append( "/ToUnicode " ); + aLine.append( nToUnicodeStream ); + aLine.append( " 0 R\n" ); + } + aLine.append( "/FirstChar 0\n" + "/LastChar " ); + aLine.append( (sal_Int32)(nEncoded-1) ); + aLine.append( "\n" + "/Widths[" ); + for( int i = 0; i < nEncoded; i++ ) + { + aLine.append( aEncWidths[i] ); + aLine.append( ((i&15) == 15) ? "\n" : " " ); + } + aLine.append( " ]\n" + "/FontDescriptor " ); + aLine.append( nFontDescriptor ); + aLine.append( " 0 R>>\n" + "endobj\n\n" ); + if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) + throw FontException(); + + aRet[ enc_it->m_nFontID ] = nObject; + } } } + catch( FontException& ) + { + // these do nothing in case there was no compression or encryption ongoing + endCompression(); + disableStreamEncryption(); + } - streamend: if( pFontData ) m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen ); @@ -3567,11 +3552,15 @@ static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuf appendName( rPSName, rBuffer ); } -sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUnicodes, int nGlyphs ) +sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, + sal_Ucs* pUnicodes, + sal_Int32* pUnicodesPerGlyph, + sal_Int32* pEncToUnicodeIndex, + int nGlyphs ) { int nMapped = 0, n = 0; for( n = 0; n < nGlyphs; n++ ) - if( pUnicodes[n] ) + if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] ) nMapped++; if( nMapped == 0 ) @@ -3599,7 +3588,7 @@ sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUn int nCount = 0; for( n = 0; n < nGlyphs; n++ ) { - if( pUnicodes[n] ) + if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] ) { if( (nCount % 100) == 0 ) { @@ -3611,9 +3600,13 @@ sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUn aContents.append( '<' ); appendHex( (sal_Int8)pEncoding[n], aContents ); aContents.append( "> <" ); - // TODO: handle unicodes>U+FFFF - appendHex( (sal_Int8)(pUnicodes[n] / 256), aContents ); - appendHex( (sal_Int8)(pUnicodes[n] & 255), aContents ); + // TODO: handle unicodes>U+FFFF + sal_Int32 nIndex = pEncToUnicodeIndex[n]; + for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ ) + { + appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents ); + appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents ); + } aContents.append( ">\n" ); nCount++; } @@ -3777,25 +3770,32 @@ bool PDFWriterImpl::emitFonts() sal_Int32 pGlyphIDs[ 256 ]; sal_Int32 pWidths[ 256 ]; sal_uInt8 pEncoding[ 256 ]; - sal_Ucs pUnicodes[ 256 ]; + sal_Int32 pEncToUnicodeIndex[ 256 ]; + sal_Int32 pUnicodesPerGlyph[ 256 ]; + std::vector<sal_Ucs> aUnicodes; + aUnicodes.reserve( 256 ); int nGlyphs = 1; // fill arrays and prepare encoding index map sal_Int32 nToUnicodeStream = 0; - memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) ); - memset( pEncoding, 0, sizeof( pEncoding ) ); - memset( pUnicodes, 0, sizeof( pUnicodes ) ); + rtl_zeroMemory( pGlyphIDs, sizeof( pGlyphIDs ) ); + rtl_zeroMemory( pEncoding, sizeof( pEncoding ) ); + rtl_zeroMemory( pUnicodesPerGlyph, sizeof( pUnicodesPerGlyph ) ); + rtl_zeroMemory( pEncToUnicodeIndex, sizeof( pEncToUnicodeIndex ) ); for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit ) { - sal_uInt8 nEnc = fit->second.m_nSubsetGlyphID; + sal_uInt8 nEnc = fit->second.getGlyphId(); DBG_ASSERT( pGlyphIDs[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" ); DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" ); pGlyphIDs[ nEnc ] = fit->first; pEncoding[ nEnc ] = nEnc; - pUnicodes[ nEnc ] = fit->second.m_aUnicode; - if( pUnicodes[ nEnc ] ) + pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size()); + pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes(); + for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ ) + aUnicodes.push_back( fit->second.getCode( n ) ); + if( fit->second.getCode(0) ) nToUnicodeStream = 1; if( nGlyphs < 256 ) nGlyphs++; @@ -3816,92 +3816,92 @@ bool PDFWriterImpl::emitFonts() CHECK_RETURN( (osl_File_E_None == osl_getFilePos( aFontFile, &nLength1 ) ) ); CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); -#if OSL_DEBUG_LEVEL > 1 + #if OSL_DEBUG_LEVEL > 1 { OStringBuffer aLine1( " PDFWriterImpl::emitFonts" ); emitComment( aLine1.getStr() ); } -#endif + #endif sal_Int32 nFontStream = createObject(); sal_Int32 nStreamLengthObject = createObject(); CHECK_RETURN( updateObject( nFontStream ) ); aLine.setLength( 0 ); aLine.append( nFontStream ); aLine.append( " 0 obj\n" - "<</Length " ); + "<</Length " ); aLine.append( (sal_Int32)nStreamLengthObject ); aLine.append( " 0 R" -#ifndef DEBUG_DISABLE_PDFCOMPRESSION - "/Filter/FlateDecode" -#endif - "/Length1 " ); - - sal_uInt64 nStartPos = 0; - if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF ) - { - aLine.append( (sal_Int32)nLength1 ); + #ifndef DEBUG_DISABLE_PDFCOMPRESSION + "/Filter/FlateDecode" + #endif + "/Length1 " ); - aLine.append( ">>\n" - "stream\n" ); - CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); - CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); - - // copy font file - beginCompression(); - checkAndEnableStreamEncryption( nFontStream ); - sal_Bool bEOF = sal_False; - do + sal_uInt64 nStartPos = 0; + if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF ) { - char buf[8192]; - sal_uInt64 nRead; - CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) ); - CHECK_RETURN( writeBuffer( buf, nRead ) ); - CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) ); - } while( ! bEOF ); - } - else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 ) - { - // TODO: implement - DBG_ERROR( "PDFWriterImpl does not support CFF-font subsets yet!" ); - } - else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA? - { - unsigned char* pBuffer = new unsigned char[ (int)nLength1 ]; - - sal_uInt64 nBytesRead = 0; - CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer, nLength1, &nBytesRead ) ) ); - DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" ); - CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); - // get the PFB-segment lengths - ThreeInts aSegmentLengths = {0,0,0}; - getPfbSegmentLengths( pBuffer, (int)nBytesRead, aSegmentLengths ); - // the lengths below are mandatory for PDF-exported Type1 fonts - // because the PFB segment headers get stripped! WhyOhWhy. - aLine.append( (sal_Int32)aSegmentLengths[0] ); - aLine.append( "/Length2 " ); - aLine.append( (sal_Int32)aSegmentLengths[1] ); - aLine.append( "/Length3 " ); - aLine.append( (sal_Int32)aSegmentLengths[2] ); - - aLine.append( ">>\n" - "stream\n" ); - CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); - CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); - - // emit PFB-sections without section headers - beginCompression(); - checkAndEnableStreamEncryption( nFontStream ); - CHECK_RETURN( writeBuffer( pBuffer+ 6, aSegmentLengths[0] ) ); - CHECK_RETURN( writeBuffer( pBuffer+12 + aSegmentLengths[0], aSegmentLengths[1] ) ); - CHECK_RETURN( writeBuffer( pBuffer+18 + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ); - - delete[] pBuffer; - } - else - { - fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType); - aLine.append( "0 >>\nstream\n" ); - } + aLine.append( (sal_Int32)nLength1 ); + + aLine.append( ">>\n" + "stream\n" ); + CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); + CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); + + // copy font file + beginCompression(); + checkAndEnableStreamEncryption( nFontStream ); + sal_Bool bEOF = sal_False; + do + { + char buf[8192]; + sal_uInt64 nRead; + CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) ); + CHECK_RETURN( writeBuffer( buf, nRead ) ); + CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) ); + } while( ! bEOF ); + } + else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 ) + { + // TODO: implement + DBG_ERROR( "PDFWriterImpl does not support CFF-font subsets yet!" ); + } + else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA? + { + unsigned char* pBuffer = new unsigned char[ (int)nLength1 ]; + + sal_uInt64 nBytesRead = 0; + CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer, nLength1, &nBytesRead ) ) ); + DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" ); + CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); + // get the PFB-segment lengths + ThreeInts aSegmentLengths = {0,0,0}; + getPfbSegmentLengths( pBuffer, (int)nBytesRead, aSegmentLengths ); + // the lengths below are mandatory for PDF-exported Type1 fonts + // because the PFB segment headers get stripped! WhyOhWhy. + aLine.append( (sal_Int32)aSegmentLengths[0] ); + aLine.append( "/Length2 " ); + aLine.append( (sal_Int32)aSegmentLengths[1] ); + aLine.append( "/Length3 " ); + aLine.append( (sal_Int32)aSegmentLengths[2] ); + + aLine.append( ">>\n" + "stream\n" ); + CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); + CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); + + // emit PFB-sections without section headers + beginCompression(); + checkAndEnableStreamEncryption( nFontStream ); + CHECK_RETURN( writeBuffer( pBuffer+ 6, aSegmentLengths[0] ) ); + CHECK_RETURN( writeBuffer( pBuffer+12 + aSegmentLengths[0], aSegmentLengths[1] ) ); + CHECK_RETURN( writeBuffer( pBuffer+18 + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ); + + delete[] pBuffer; + } + else + { + fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType); + aLine.append( "0 >>\nstream\n" ); + } endCompression(); disableStreamEncryption(); @@ -3928,7 +3928,7 @@ bool PDFWriterImpl::emitFonts() sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream ); if( nToUnicodeStream ) - nToUnicodeStream = createToUnicodeCMap( pEncoding, pUnicodes, nGlyphs ); + nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs ); sal_Int32 nFontObject = createObject(); CHECK_RETURN( updateObject( nFontObject ) ); @@ -3937,22 +3937,22 @@ bool PDFWriterImpl::emitFonts() aLine.append( " 0 obj\n" ); aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ? - "<</Type/Font/Subtype/Type1/BaseFont/" : - "<</Type/Font/Subtype/TrueType/BaseFont/" ); + "<</Type/Font/Subtype/Type1/BaseFont/" : + "<</Type/Font/Subtype/TrueType/BaseFont/" ); appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine ); aLine.append( "\n" - "/FirstChar 0\n" - "/LastChar " ); + "/FirstChar 0\n" + "/LastChar " ); aLine.append( (sal_Int32)(nGlyphs-1) ); aLine.append( "\n" - "/Widths[" ); + "/Widths[" ); for( int i = 0; i < nGlyphs; i++ ) { aLine.append( pWidths[ i ] ); aLine.append( ((i & 15) == 15) ? "\n" : " " ); } aLine.append( "]\n" - "/FontDescriptor " ); + "/FontDescriptor " ); aLine.append( nFontDescriptor ); aLine.append( " 0 R\n" ); if( nToUnicodeStream ) @@ -3962,7 +3962,7 @@ bool PDFWriterImpl::emitFonts() aLine.append( " 0 R\n" ); } aLine.append( ">>\n" - "endobj\n\n" ); + "endobj\n\n" ); CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); aFontIDToObject[ lit->m_nFontID ] = nFontObject; @@ -4011,7 +4011,7 @@ bool PDFWriterImpl::emitFonts() OStringBuffer aFontDict( 1024 ); aFontDict.append( getFontDictObject() ); aFontDict.append( " 0 obj\n" - "<<" ); + "<<" ); int ni = 0; for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit ) { @@ -4020,12 +4020,12 @@ bool PDFWriterImpl::emitFonts() aFontDict.append( ' ' ); aFontDict.append( mit->second ); aFontDict.append( " 0 R" ); - if( ((++ni) & 7) == 0 ) - aFontDict.append( '\n' ); + if( ((++ni) & 7) == 0 ) + aFontDict.append( '\n' ); } // emit builtin font for widget apperances / variable text for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin(); - it != m_aBuiltinFontToObjectMap.end(); ++it ) + it != m_aBuiltinFontToObjectMap.end(); ++it ) { ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]); it->second = emitBuiltinFont( &aData, it->second ); @@ -6580,12 +6580,14 @@ void PDFWriterImpl::registerGlyphs( int nGlyphs, sal_GlyphId* pGlyphs, sal_Int32* pGlyphWidths, sal_Ucs* pUnicodes, + sal_Int32* pUnicodesPerGlyph, sal_uInt8* pMappedGlyphs, sal_Int32* pMappedFontObjects, const ImplFontData* pFallbackFonts[] ) { const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData; - for( int i = 0; i < nGlyphs; i++ ) + sal_Ucs* pCurUnicode = pUnicodes; + for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ ) { const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB); const ImplFontData* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont; @@ -6640,8 +6642,9 @@ void PDFWriterImpl::registerGlyphs( int nGlyphs, // add new glyph to emitted font subset GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ]; - rNewGlyphEmit.m_nSubsetGlyphID = nNewId; - rNewGlyphEmit.m_aUnicode = (pUnicodes ? pUnicodes[i] : 0); + rNewGlyphEmit.setGlyphId( nNewId ); + for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ ) + rNewGlyphEmit.addCode( pCurUnicode[n] ); // add new glyph to font mapping Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ]; @@ -6678,7 +6681,7 @@ void PDFWriterImpl::registerGlyphs( int nGlyphs, Ucs2OStrMap::const_iterator nonenc_it; sal_Int32 nCurFontID = nFontID; - sal_Ucs cChar = pUnicodes[i]; + sal_Ucs cChar = *pCurUnicode; if( pEncoding ) { enc_it = pEncoding->find( cChar ); @@ -6740,7 +6743,7 @@ void PDFWriterImpl::registerGlyphs( int nGlyphs, pMappedGlyphs[ i ] = (sal_Int8)cChar; pMappedFontObjects[ i ] = nCurFontID; pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont, - (pEncoding ? pUnicodes[i] : cChar) | GF_ISCHAR, + (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR, false, m_pReferenceDevice->mpGraphics ); } @@ -7020,7 +7023,9 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bT sal_Int32 pGlyphWidths[nMaxGlyphs]; sal_uInt8 pMappedGlyphs[nMaxGlyphs]; sal_Int32 pMappedFontObjects[nMaxGlyphs]; - sal_Ucs pUnicodes[nMaxGlyphs]; + std::vector<sal_Ucs> aUnicodes; + aUnicodes.reserve( nMaxGlyphs ); + sal_Int32 pUnicodesPerGlyph[nMaxGlyphs]; int pCharPosAry[nMaxGlyphs]; sal_Int32 nAdvanceWidths[nMaxGlyphs]; const ImplFontData* pFallbackFonts[nMaxGlyphs]; @@ -7153,15 +7158,29 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bT Point aGNGlyphPos; while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 ) { + aUnicodes.clear(); for( int i = 0; i < nGlyphs; i++ ) { pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] ); + // default case: 1 glyph is one unicode + pUnicodesPerGlyph[i] = 1; if( (pGlyphs[i] & GF_ISCHAR) ) - pUnicodes[i] = static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK); + { + aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) ); + } else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos ) { - pUnicodes[i] = rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ); + int nChars = 1; + aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) ); + pUnicodesPerGlyph[i] = 1; + // try to handle ligatures and such + if( i < nGlyphs-1 ) + { + pUnicodesPerGlyph[i] = nChars = pCharPosAry[i+1] - pCharPosAry[i]; + for( int n = 1; n < nChars; n++ ) + aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) ); + } // #i36691# hack that is needed because currently the pGlyphs[] // argument is ignored for embeddable fonts and so the layout // engine's glyph work is ignored (i.e. char mirroring) @@ -7169,17 +7188,21 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bT // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font) // back to unicode and then to embeddable font's encoding if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL ) - pUnicodes[i] = static_cast<sal_Ucs>(GetMirroredChar(pUnicodes[i])); + { + size_t nI = aUnicodes.size()-1; + for( int n = 0; n < nChars; n++, nI-- ) + aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI])); + } } else - pUnicodes[i] = 0; + aUnicodes.push_back( 0 ); // note: in case of ctl one character may result // in multiple glyphs. The current SalLayout // implementations set -1 then to indicate that no direct // mapping is possible } - registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, pUnicodes, pMappedGlyphs, pMappedFontObjects, pFallbackFonts ); + registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts ); for( int i = 0; i < nGlyphs; i++ ) { @@ -9513,7 +9536,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) sal_uInt64 nStartPos = 0; CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) ); - checkAndEnableStreamEncryption( rObject.m_nObject ); + checkAndEnableStreamEncryption( rObject.m_nObject ); beginCompression(); if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) { @@ -9527,7 +9550,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) else { const int nScanLineBytes = pAccess->Width()*3; - sal_uInt8 *pCol = (sal_uInt8*)rtl_allocateMemory( nScanLineBytes ); + boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] ); for( int y = 0; y < pAccess->Height(); y++ ) { for( int x = 0; x < pAccess->Width(); x++ ) @@ -9537,9 +9560,8 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) pCol[3*x+1] = aColor.GetGreen(); pCol[3*x+2] = aColor.GetBlue(); } - CHECK_RETURN( writeBuffer( pCol, nScanLineBytes ) ); + CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) ); } - rtl_freeMemory( pCol ); } endCompression(); disableStreamEncryption(); diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index e058cfa487db..d54aecf35788 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -52,6 +52,8 @@ #include <hash_map> #include <list> +#include <boost/shared_array.hpp> + class ImplFontSelectData; class ImplFontMetricData; class FontSubsetInfo; @@ -270,10 +272,53 @@ public: }; // font subsets - struct GlyphEmit + class GlyphEmit { - sal_Ucs m_aUnicode; - sal_uInt8 m_nSubsetGlyphID; + // performance: actually this should probably a vector; + sal_Ucs m_aBufferedUnicodes[3]; + sal_Int32 m_nUnicodes; + sal_Int32 m_nMaxUnicodes; + boost::shared_array<sal_Ucs> m_pUnicodes; + sal_uInt8 m_nSubsetGlyphID; + + public: + GlyphEmit() : m_nUnicodes(0), m_nSubsetGlyphID(0) + { + rtl_zeroMemory( m_aBufferedUnicodes, sizeof( m_aBufferedUnicodes ) ); + m_nMaxUnicodes = sizeof(m_aBufferedUnicodes)/sizeof(m_aBufferedUnicodes[0]); + } + ~GlyphEmit() + { + } + + void setGlyphId( sal_uInt8 i_nId ) { m_nSubsetGlyphID = i_nId; } + sal_uInt8 getGlyphId() const { return m_nSubsetGlyphID; } + + void addCode( sal_Ucs i_cCode ) + { + if( m_nUnicodes == m_nMaxUnicodes ) + { + sal_Ucs* pNew = new sal_Ucs[ 2 * m_nMaxUnicodes]; + if( m_pUnicodes.get() ) + rtl_copyMemory( pNew, m_pUnicodes.get(), m_nMaxUnicodes * sizeof(sal_Ucs) ); + else + rtl_copyMemory( pNew, m_aBufferedUnicodes, m_nMaxUnicodes * sizeof(sal_Ucs) ); + m_pUnicodes.reset( pNew ); + m_nMaxUnicodes *= 2; + } + if( m_pUnicodes.get() ) + m_pUnicodes[ m_nUnicodes++ ] = i_cCode; + else + m_aBufferedUnicodes[ m_nUnicodes++ ] = i_cCode; + } + sal_Int32 countCodes() const { return m_nUnicodes; } + sal_Ucs getCode( sal_Int32 i_nIndex ) const + { + sal_Ucs nRet = 0; + if( i_nIndex < m_nUnicodes ) + nRet = m_pUnicodes.get() ? m_pUnicodes[ i_nIndex ] : m_aBufferedUnicodes[ i_nIndex ]; + return nRet; + } }; typedef std::map< sal_GlyphId, GlyphEmit > FontEmitMapping; struct FontEmit @@ -860,7 +905,7 @@ i12626 void appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); /* creates fonts and subsets that will be emitted later */ - void registerGlyphs( int nGlyphs, sal_GlyphId* pGlyphs, sal_Int32* pGlpyhWidths, sal_Ucs* pUnicodes, sal_uInt8* pMappedGlyphs, sal_Int32* pMappedFontObjects, const ImplFontData* pFallbackFonts[] ); + void registerGlyphs( int nGlyphs, sal_GlyphId* pGlyphs, sal_Int32* pGlpyhWidths, sal_Ucs* pUnicodes, sal_Int32* pUnicodesPerGlyph, sal_uInt8* pMappedGlyphs, sal_Int32* pMappedFontObjects, const ImplFontData* pFallbackFonts[] ); /* emits a text object according to the passed layout */ /* TODO: remove rText as soon as SalLayout will change so that rText is not necessary anymore */ @@ -909,7 +954,7 @@ i12626 /* writes a font descriptor and returns its object id (or 0) */ sal_Int32 emitFontDescriptor( const ImplFontData*, FontSubsetInfo&, sal_Int32 nSubsetID, sal_Int32 nStream ); /* writes a ToUnicode cmap, returns the corresponding stream object */ - sal_Int32 createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUnicodes, int nGlyphs ); + sal_Int32 createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUnicodes, sal_Int32* pUnicodesPerGlyph, sal_Int32* pEncToUnicodeIndex, int nGlyphs ); /* get resource dict object number */ sal_Int32 getResourceDictObj() diff --git a/vcl/source/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx index b92bea929c51..b25b9cee83fb 100644 --- a/vcl/source/glyphs/gcach_ftyp.cxx +++ b/vcl/source/glyphs/gcach_ftyp.cxx @@ -2486,14 +2486,12 @@ bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD ) pCoverage += 2; for( int i = nCntRange; --i >= 0; ) { - const USHORT nGlyph0 = GetUShort( pCoverage+0 ); - const USHORT nGlyph1 = GetUShort( pCoverage+2 ); - const USHORT nStartCoverageIndex = GetUShort( pCoverage+4 ); - DBG_ASSERT( aSubstVector.size() == nStartCoverageIndex, "coverage index mismatch"); - (void)nStartCoverageIndex; + const UINT32 nGlyph0 = GetUShort( pCoverage+0 ); + const UINT32 nGlyph1 = GetUShort( pCoverage+2 ); + const USHORT nCovIdx = GetUShort( pCoverage+4 ); pCoverage += 6; - for( USHORT j = nGlyph0; j <= nGlyph1; ++j ) - aSubstVector.push_back( GlyphSubst( j, 0 ) ); + for( UINT32 j = nGlyph0; j <= nGlyph1; ++j ) + aSubstVector.push_back( GlyphSubst( static_cast<USHORT>(j + nCovIdx), 0 ) ); } } break; @@ -2537,3 +2535,4 @@ bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD ) } // ======================================================================= + diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx index 34e2f5f5bbe3..6c9d97e356b1 100644 --- a/vcl/source/glyphs/graphite_adaptors.cxx +++ b/vcl/source/glyphs/graphite_adaptors.cxx @@ -171,7 +171,7 @@ GraphiteFontAdaptor::~GraphiteFontAdaptor() throw() mpFeatures = NULL; } -void GraphiteFontAdaptor::UniqueCacheInfo(std::wstring & face_name_out, bool & bold_out, bool & italic_out) +void GraphiteFontAdaptor::UniqueCacheInfo(sil_std::wstring & face_name_out, bool & bold_out, bool & italic_out) { face_name_out = maFontProperties.szFaceName; bold_out = maFontProperties.fBold; diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx index 8c514c611d2c..a2c245e21774 100644 --- a/vcl/source/glyphs/graphite_cache.cxx +++ b/vcl/source/glyphs/graphite_cache.cxx @@ -36,8 +36,10 @@ #include <tools/debug.hxx> #include <vcl/sallayout.hxx> +#include "pregraphitestl.h" #include <graphite/GrClient.h> #include <graphite/Segment.h> +#include "postgraphitestl.h" #include <rtl/ustring.hxx> #include <vcl/graphite_layout.hxx> diff --git a/vcl/source/glyphs/graphite_features.cxx b/vcl/source/glyphs/graphite_features.cxx index dae1bfc2866e..b26397aa43e5 100644 --- a/vcl/source/glyphs/graphite_features.cxx +++ b/vcl/source/glyphs/graphite_features.cxx @@ -91,7 +91,7 @@ GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, co gr::isocode aLang = maLang; for (size_t i = pos; i < nFeatEnd; i++) aLang.rgch[i-pos] = features[i]; - std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported + sil_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported = font.getSupportedLanguages(); gr::LanguageIterator iL = aSupported.first; while (iL != aSupported.second) @@ -142,7 +142,7 @@ void GrFeatureParser::setLang(gr::Font & font, const std::string & lang) if (lang[i] == '-') break; aLang.rgch[i] = lang[i]; } - std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported + sil_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported = font.getSupportedLanguages(); gr::LanguageIterator iL = aSupported.first; while (iL != aSupported.second) @@ -189,7 +189,7 @@ bool GrFeatureParser::isValid(gr::Font & font, gr::FeatureSetting & setting) { return false; } - std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator > + sil_std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator > validValues = font.getFeatureSettings(i); gr::FeatureSettingIterator j = validValues.first; while (j != validValues.second) diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index 86dee2749efa..6f4e13c7985f 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -66,11 +66,13 @@ #include <unicode/uscript.h> // Graphite Libraries (must be after vcl headers on windows) +#include "pregraphitestl.h" #include <graphite/GrClient.h> #include <graphite/Font.h> #include <graphite/ITextSource.h> #include <graphite/Segment.h> #include <graphite/SegmentPainter.h> +#include "postgraphitestl.h" #include <vcl/graphite_layout.hxx> #include <vcl/graphite_features.hxx> @@ -105,8 +107,8 @@ FILE * grLog() namespace { - typedef std::pair<gr::GlyphIterator, gr::GlyphIterator> glyph_range_t; - typedef std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t; + typedef sil_std::pair<gr::GlyphIterator, gr::GlyphIterator> glyph_range_t; + typedef sil_std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t; inline long round(const float n) { return long(n + (n < 0 ? -0.5 : 0.5)); @@ -171,7 +173,7 @@ GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, bool bRtl, long &rWidth, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs) { // Create a glyph item for each of the glyph and append it to the base class glyph list. - typedef std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet; + typedef sil_std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet; int nChar = rArgs.mnEndCharPos - rArgs.mnMinCharPos; glyph_range_t iGlyphs = rSegment.glyphs(); int nGlyphs = iGlyphs.second - iGlyphs.first; @@ -586,7 +588,7 @@ public: sal_Int32 hashCode(const grutils::GrFeatureParser * mpFeatures) { // is this sufficient? - std::wstring aFace; + sil_std::wstring aFace; bool bBold; bool bItalic; UniqueCacheInfo(aFace, bBold, bItalic); @@ -720,6 +722,7 @@ bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment) #ifdef GRCACHE_REUSE_VECTORS // if we have an exact match, then we can reuse the glyph vectors from before if (pSegRecord && (pSegRecord->glyphs().size() > 0) && + (pSegRecord->fontScale() == mfScaling) && !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) ) { mnWidth = pSegRecord->width(); @@ -765,7 +768,8 @@ bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment) !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)) { pSegRecord->setGlyphVectors(mnWidth, mvGlyphs, mvCharDxs, - mvChar2BaseGlyph, mvGlyph2Char); + mvChar2BaseGlyph, mvGlyph2Char, + mfScaling); } #endif #endif diff --git a/vcl/source/glyphs/graphite_textsrc.cxx b/vcl/source/glyphs/graphite_textsrc.cxx index adc2ae99c4f8..cbbd386e734a 100644 --- a/vcl/source/glyphs/graphite_textsrc.cxx +++ b/vcl/source/glyphs/graphite_textsrc.cxx @@ -138,16 +138,16 @@ gr::isocode TextSourceAdaptor::getLanguage(gr::toffset) return unknown; } -std::pair<gr::toffset, gr::toffset> TextSourceAdaptor::propertyRange(gr::toffset nCharIdx) +sil_std::pair<gr::toffset, gr::toffset> TextSourceAdaptor::propertyRange(gr::toffset nCharIdx) { if (nCharIdx < unsigned(maLayoutArgs.mnMinCharPos)) - return std::make_pair(0, maLayoutArgs.mnMinCharPos); + return sil_std::make_pair(0, maLayoutArgs.mnMinCharPos); if (nCharIdx < mnEnd) - return std::make_pair(maLayoutArgs.mnMinCharPos, mnEnd); + return sil_std::make_pair(maLayoutArgs.mnMinCharPos, mnEnd); - return std::make_pair(mnEnd, maLayoutArgs.mnLength); + return sil_std::make_pair(mnEnd, maLayoutArgs.mnLength); } size_t TextSourceAdaptor::getFontFeatures(gr::toffset, gr::FeatureSetting * settings) @@ -159,7 +159,7 @@ size_t TextSourceAdaptor::getFontFeatures(gr::toffset, gr::FeatureSetting * sett bool TextSourceAdaptor::sameSegment(gr::toffset char_idx1, gr::toffset char_idx2) { - const std::pair<gr::toffset, gr::toffset> + const sil_std::pair<gr::toffset, gr::toffset> range1 = propertyRange(char_idx1), range2 = propertyRange(char_idx2); diff --git a/vcl/source/glyphs/graphite_textsrc.hxx b/vcl/source/glyphs/graphite_textsrc.hxx index 6f701988bb01..62d951c3f950 100644 --- a/vcl/source/glyphs/graphite_textsrc.hxx +++ b/vcl/source/glyphs/graphite_textsrc.hxx @@ -62,9 +62,11 @@ #include "vcl/dllapi.h" // Libraries +#include "pregraphitestl.h" #include <graphite/GrClient.h> #include <graphite/Font.h> #include <graphite/ITextSource.h> +#include "postgraphitestl.h" // Module type definitions and forward declarations. // @@ -91,7 +93,7 @@ public: virtual float getVerticalOffset(gr::toffset ich); virtual gr::isocode getLanguage(gr::toffset ich); - virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich); + virtual sil_std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich); virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset); virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2); diff --git a/vcl/source/window/dlgctrl.cxx b/vcl/source/window/dlgctrl.cxx index c6f64d74c5fc..a332c89dc9be 100644 --- a/vcl/source/window/dlgctrl.cxx +++ b/vcl/source/window/dlgctrl.cxx @@ -36,6 +36,7 @@ #include <vcl/svapp.hxx> #include <vcl/tabpage.hxx> #include <vcl/tabctrl.hxx> +#include <vcl/tabdlg.hxx> #include <vcl/button.hxx> #include <vcl/window.h> @@ -888,6 +889,20 @@ BOOL Window::ImplDlgCtrl( const KeyEvent& rKEvt, BOOL bKeyInput ) return TRUE; } + // if we have come here (and therefore the strange "formular" logic above + // turned up no result, then let's try to find a customer for Ctrl-TAB + if ( nKeyCode == KEY_TAB && aKeyCode.IsMod1() && ! aKeyCode.IsMod2() ) + { + TabDialog* pDlg = dynamic_cast<TabDialog*>(this); + if( pDlg ) + { + TabControl* pTabCtrl = pDlg->ImplGetFirstTabControl(); + NotifyEvent aEvt( bKeyInput ? EVENT_KEYINPUT : EVENT_KEYUP, + pTabCtrl, &rKEvt ); + return pTabCtrl->ImplHandleNotifyEvent( aEvt ); + } + } + return FALSE; } diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk index 21b8efe4c586..8b3c01f5721e 100644 --- a/vcl/source/window/makefile.mk +++ b/vcl/source/window/makefile.mk @@ -70,6 +70,7 @@ SLOFILES= \ $(SLO)$/mnemonic.obj \ $(SLO)$/mnemonicengine.obj \ $(SLO)$/msgbox.obj \ + $(SLO)$/popupmenuwindow.obj \ $(SLO)$/scrwnd.obj \ $(SLO)$/printdlg.obj \ $(SLO)$/seleng.obj \ diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index c9e0c23e7f16..5b99cd084360 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -5578,6 +5578,17 @@ BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu n = pMenu->GetItemCount()-1; } + // handling gtk like (aka mbOpenMenuOnF10) + // do not highlight an item when opening a sub menu + // unless there already was a higlighted sub menu item + bool bWasHighlight = false; + if( pActivePopup ) + { + MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow()); + if( pSubWindow ) + bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID); + } + USHORT nLoop = n; if( nCode == KEY_HOME ) @@ -5604,7 +5615,10 @@ BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n ); if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) ) { - ChangeHighlightItem( n, TRUE ); + BOOL bDoSelect = TRUE; + if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 ) + bDoSelect = bWasHighlight; + ChangeHighlightItem( n, bDoSelect ); break; } } while ( n != nLoop ); diff --git a/vcl/source/window/popupmenuwindow.cxx b/vcl/source/window/popupmenuwindow.cxx new file mode 100644 index 000000000000..29d60a7cc02d --- /dev/null +++ b/vcl/source/window/popupmenuwindow.cxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: floatwin.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "vcl/popupmenuwindow.hxx" + +#include <limits> + +struct PopupMenuFloatingWindow::ImplData +{ + sal_uInt16 mnMenuStackLevel; // Store the stack level of a popup menu. 0 = top-level menu. + + ImplData(); + ~ImplData(); +}; + +PopupMenuFloatingWindow::ImplData::ImplData() : + mnMenuStackLevel( ::std::numeric_limits<sal_uInt16>::max() ) +{ +} + +PopupMenuFloatingWindow::ImplData::~ImplData() +{ +} + +// ============================================================================ + +PopupMenuFloatingWindow::PopupMenuFloatingWindow( Window* pParent, WinBits nStyle ) : + FloatingWindow(pParent, nStyle), + mpImplData(new ImplData) +{ +} + +PopupMenuFloatingWindow::~PopupMenuFloatingWindow() +{ + delete mpImplData; +} + +sal_uInt16 PopupMenuFloatingWindow::GetMenuStackLevel() const +{ + return mpImplData->mnMenuStackLevel; +} + +void PopupMenuFloatingWindow::SetMenuStackLevel( sal_uInt16 nLevel ) +{ + mpImplData->mnMenuStackLevel = nLevel; +} + +bool PopupMenuFloatingWindow::IsPopupMenu() const +{ + return mpImplData->mnMenuStackLevel != ::std::numeric_limits<sal_uInt16>::max(); +} + diff --git a/vcl/source/window/status.cxx b/vcl/source/window/status.cxx index ede3bcc107aa..8d986f691963 100644 --- a/vcl/source/window/status.cxx +++ b/vcl/source/window/status.cxx @@ -156,6 +156,7 @@ void StatusBar::ImplInit( Window* pParent, WinBits nStyle ) mbProgressMode = FALSE; mbInUserDraw = FALSE; mbBottomBorder = FALSE; + mnItemsWidth = STATUSBAR_OFFSET_X; mnDX = 0; mnDY = 0; mnCalcHeight = 0; diff --git a/vcl/source/window/tabdlg.cxx b/vcl/source/window/tabdlg.cxx index 95fb404d24af..217533c8d6b7 100644 --- a/vcl/source/window/tabdlg.cxx +++ b/vcl/source/window/tabdlg.cxx @@ -276,3 +276,21 @@ void TabDialog::AdjustLayout() { ImplPosControls(); } + +// ----------------------------------------------------------------------- + +TabControl* TabDialog::ImplGetFirstTabControl() const +{ + Window* pChild = GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild ) + { + if ( pChild->IsVisible() && (pChild != mpViewWindow) ) + { + if ( pChild->GetType() == WINDOW_TABCONTROL ) + return (TabControl*)pChild; + } + pChild = pChild->GetWindow( WINDOW_NEXT ); + } + return NULL; +} + diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index ca0ebb10a4e9..5689972e69d6 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -699,6 +699,7 @@ void Window::ImplInitWindowData( WindowType nType ) mpWindowImpl->mbDisableAccessibleLabelForRelation = FALSE; // TRUE: do not set LabelFor relation on accessible objects mpWindowImpl->mbDisableAccessibleLabeledByRelation = FALSE; // TRUE: do not set LabeledBy relation on accessible objects mpWindowImpl->mbHelpTextDynamic = FALSE; // TRUE: append help id in HELP_DEBUG case + mpWindowImpl->mbFakeFocusSet = FALSE; // TRUE: pretend as if the window has focus. mbEnableRTL = Application::GetSettings().GetLayoutRTL(); // TRUE: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active } @@ -3915,6 +3916,20 @@ void Window::ImplCallFocusChangeActivate( Window* pNewOverlapWindow, } } +static bool IsWindowFocused(const WindowImpl& rWinImpl) +{ + if (rWinImpl.mpSysObj) + return true; + + if (rWinImpl.mpFrameData->mbHasFocus) + return true; + + if (rWinImpl.mbFakeFocusSet) + return true; + + return false; +} + // ----------------------------------------------------------------------- void Window::ImplGrabFocus( USHORT nFlags ) { @@ -3986,9 +4001,7 @@ void Window::ImplGrabFocus( USHORT nFlags ) pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame; } - BOOL bHasFocus = TRUE; - if ( !mpWindowImpl->mpSysObj && !mpWindowImpl->mpFrameData->mbHasFocus ) - bHasFocus = FALSE; + bool bHasFocus = IsWindowFocused(*mpWindowImpl); BOOL bMustNotGrabFocus = FALSE; // #100242#, check parent hierarchy if some floater prohibits grab focus @@ -4759,7 +4772,10 @@ void Window::doLazyDelete() SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this); DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(this); if( pSysWin || ( pDockWin && pDockWin->IsFloatingMode() ) ) + { + Show( FALSE ); SetParent( ImplGetDefaultWindow() ); + } vcl::LazyDeletor<Window>::Delete( this ); } @@ -5381,6 +5397,11 @@ void Window::CallEventListeners( ULONG nEvent, void* pData ) } } +void Window::FireVclEvent( VclSimpleEvent* pEvent ) +{ + ImplGetSVData()->mpApp->ImplCallEventListeners(pEvent); +} + // ----------------------------------------------------------------------- void Window::AddEventListener( const Link& rEventListener ) @@ -7756,6 +7777,11 @@ void Window::GrabFocusToDocument() } } +void Window::SetFakeFocus( bool bFocus ) +{ + ImplGetWindowImpl()->mbFakeFocusSet = bFocus; +} + // ----------------------------------------------------------------------- BOOL Window::HasChildPathFocus( BOOL bSystemWindow ) const |