| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include "rtl/ustring.hxx" |
| #include "osl/module.h" |
| #include "osl/thread.h" |
| |
| #include "unx/saldisp.hxx" |
| #include "unx/saldata.hxx" |
| #include "unx/salgdi.h" |
| |
| #include "gcach_xpeer.hxx" |
| #include "xrender_peer.hxx" |
| |
| // =========================================================================== |
| |
| // all glyph specific data needed by the XGlyphPeer is quite trivial |
| // with one exception: if multiple screens are involved and non-antialiased |
| // glyph rendering is active, then we need screen specific pixmaps |
| struct MultiScreenGlyph |
| { |
| const RawBitmap* mpRawBitmap; |
| Glyph maXRGlyphId; |
| Pixmap maPixmaps[1]; // [mnMaxScreens] |
| }; |
| |
| // =========================================================================== |
| |
| X11GlyphPeer::X11GlyphPeer() |
| : mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ) |
| , mnMaxScreens(0) |
| , mnDefaultScreen(0) |
| , mnExtByteCount(0) |
| , mnForcedAA(0) |
| , mnUsingXRender(0) |
| { |
| maRawBitmap.mnAllocated = 0; |
| maRawBitmap.mpBits = NULL; |
| if( !mpDisplay ) |
| return; |
| |
| SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay(); |
| mpDisplay = rSalDisplay.GetDisplay(); |
| mnMaxScreens = rSalDisplay.GetScreenCount(); |
| if( mnMaxScreens > MAX_GCACH_SCREENS ) |
| mnMaxScreens = MAX_GCACH_SCREENS; |
| // if specific glyph data has to be kept for many screens |
| // then prepare the allocation of MultiScreenGlyph objects |
| if( mnMaxScreens > 1 ) |
| mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1); |
| mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber(); |
| |
| InitAntialiasing(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| X11GlyphPeer::~X11GlyphPeer() |
| { |
| SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); |
| Display* const pX11Disp = pSalDisp->GetDisplay(); |
| XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); |
| for( int i = 0; i < mnMaxScreens; i++ ) |
| { |
| SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i ); |
| for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it ) |
| { |
| if( it->second.m_aPixmap ) |
| ::XFreePixmap( pX11Disp, it->second.m_aPixmap ); |
| if( it->second.m_aPicture ) |
| rRenderPeer.FreePicture( it->second.m_aPicture ); |
| } |
| rMap.clear(); |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphPeer::InitAntialiasing() |
| { |
| int nEnvAntiAlias = 0; |
| const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" ); |
| if( pEnvAntiAlias ) |
| { |
| nEnvAntiAlias = atoi( pEnvAntiAlias ); |
| if( nEnvAntiAlias == 0 ) |
| return; |
| } |
| |
| mnUsingXRender = 0; |
| mnForcedAA = 0; |
| |
| // enable XRENDER accelerated aliasing on screens that support it |
| // unless it explicitly disabled by an environment variable |
| if( (nEnvAntiAlias & 2) == 0 ) |
| mnUsingXRender = XRenderPeer::GetInstance().InitRenderText(); |
| |
| // else enable client side antialiasing for these screens |
| // unless it is explicitly disabled by an environment variable |
| if( (nEnvAntiAlias & 1) != 0 ) |
| return; |
| |
| // enable client side antialiasing for screen visuals that are suitable |
| // mnForcedAA is a bitmask of screens enabled for client side antialiasing |
| mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender; |
| SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay(); |
| for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen) |
| { |
| Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual(); |
| XVisualInfo aXVisualInfo; |
| aXVisualInfo.visualid = pVisual->visualid; |
| int nVisuals = 0; |
| XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals ); |
| for( int i = nVisuals; --i >= 0; ) |
| { |
| if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24)) |
| && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) ) |
| mnForcedAA &= ~(1U << nScreen); |
| } |
| if( pXVisualInfo != NULL ) |
| XFree( pXVisualInfo ); |
| } |
| } |
| |
| // =========================================================================== |
| |
| enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN }; |
| static const Glyph NO_GLYPHID = 0; |
| static RawBitmap* const NO_RAWBMP = NULL; |
| static const Pixmap NO_PIXMAP = ~0; |
| |
| // --------------------------------------------------------------------------- |
| |
| MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const |
| { |
| // prepare to store screen specific pixmaps |
| MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ]; |
| |
| // init the glyph formats |
| pMSGlyph->mpRawBitmap = NO_RAWBMP; |
| pMSGlyph->maXRGlyphId = NO_GLYPHID; |
| for( int i = 0; i < mnMaxScreens; ++i ) |
| pMSGlyph->maPixmaps[i] = NO_PIXMAP; |
| // reuse already available glyph formats |
| if( rEGD.meInfo == INFO_XRENDER ) |
| pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData); |
| else if( rEGD.meInfo == INFO_RAWBMP ) |
| pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData); |
| else if( rEGD.meInfo == INFO_PIXMAP ) |
| { |
| Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData); |
| if( aPixmap != None ) |
| // pixmap for the default screen is available |
| pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap; |
| else // empty pixmap for all screens is available |
| for( int i = 0; i < mnMaxScreens; ++i ) |
| pMSGlyph->maPixmaps[ i ] = None; |
| } |
| // enable use of multiscreen glyph |
| rEGD.mpData = (void*)pMSGlyph; |
| rEGD.meInfo = INFO_MULTISCREEN; |
| |
| return pMSGlyph; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const |
| { |
| Glyph aGlyphId = NO_GLYPHID; |
| const ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| if( rEGD.meInfo == INFO_XRENDER ) |
| aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData); |
| else if( rEGD.meInfo == INFO_MULTISCREEN ) |
| aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId; |
| return aGlyphId; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const |
| { |
| ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| switch( rEGD.meInfo ) |
| { |
| case INFO_EMPTY: |
| rEGD.meInfo = INFO_XRENDER; |
| // fall through |
| case INFO_XRENDER: |
| rEGD.mpData = reinterpret_cast<void*>(aGlyphId); |
| break; |
| case INFO_PIXMAP: |
| case INFO_RAWBMP: |
| PrepareForMultiscreen( rEGD ); |
| // fall through |
| case INFO_MULTISCREEN: |
| reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId; |
| break; |
| default: |
| break; // cannot happen... |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const |
| { |
| const RawBitmap* pRawBitmap = NO_RAWBMP; |
| const ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| if( rEGD.meInfo == INFO_RAWBMP ) |
| pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData); |
| else if( rEGD.meInfo == INFO_MULTISCREEN ) |
| pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap; |
| return pRawBitmap; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const |
| { |
| ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| switch( rEGD.meInfo ) |
| { |
| case INFO_EMPTY: |
| rEGD.meInfo = INFO_RAWBMP; |
| // fall through |
| case INFO_RAWBMP: |
| rEGD.mpData = (void*)pRawBitmap; |
| break; |
| case INFO_PIXMAP: |
| case INFO_XRENDER: |
| PrepareForMultiscreen( rEGD ); |
| // fall through |
| case INFO_MULTISCREEN: |
| reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap; |
| break; |
| default: |
| // cannot happen... |
| break; |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const |
| { |
| Pixmap aPixmap = NO_PIXMAP; |
| const ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) ) |
| aPixmap = (Pixmap)rEGD.mpData; |
| else if( rEGD.meInfo == INFO_MULTISCREEN ) |
| aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]); |
| return aPixmap; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const |
| { |
| if( aPixmap == NO_PIXMAP ) |
| aPixmap = None; |
| |
| ExtGlyphData& rEGD = rGD.ExtDataRef(); |
| if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) ) |
| { |
| rEGD.meInfo = INFO_PIXMAP; |
| rEGD.mpData = (void*)aPixmap; |
| } |
| else |
| { |
| MultiScreenGlyph* pMSGlyph; |
| if( rEGD.meInfo == INFO_MULTISCREEN ) |
| pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData); |
| else |
| pMSGlyph = PrepareForMultiscreen( rEGD ); |
| |
| pMSGlyph->maPixmaps[ nScreen ] = aPixmap; |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphPeer::RemovingFont( ServerFont& rServerFont ) |
| { |
| void* pFontExt = rServerFont.GetExtPointer(); |
| switch( rServerFont.GetExtInfo() ) |
| { |
| case INFO_PIXMAP: |
| case INFO_RAWBMP: |
| // nothing to do |
| break; |
| case INFO_MULTISCREEN: |
| // cannot happen... |
| break; |
| |
| case INFO_XRENDER: |
| XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt ); |
| break; |
| } |
| |
| rServerFont.SetExtended( INFO_EMPTY, NULL ); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| // notification to clean up GlyphPeer resources for this glyph |
| void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, sal_GlyphId /*aGlyphId*/ ) |
| { |
| // nothing to do if the GlyphPeer hasn't allocated resources for the glyph |
| if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY ) |
| return; |
| |
| const GlyphMetric& rGM = rGlyphData.GetMetric(); |
| const int nWidth = rGM.GetSize().Width(); |
| const int nHeight = rGM.GetSize().Height(); |
| |
| void* pGlyphExt = rGlyphData.ExtDataRef().mpData; |
| switch( rGlyphData.ExtDataRef().meInfo ) |
| { |
| case INFO_PIXMAP: |
| { |
| Pixmap aPixmap = (Pixmap)pGlyphExt; |
| if( aPixmap != None ) |
| { |
| XFreePixmap( mpDisplay, aPixmap ); |
| mnBytesUsed -= nHeight * ((nWidth + 7) >> 3); |
| } |
| } |
| break; |
| |
| case INFO_MULTISCREEN: |
| { |
| MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt); |
| for( int i = 0; i < mnMaxScreens; ++i) |
| { |
| if( pMSGlyph->maPixmaps[i] == NO_PIXMAP ) |
| continue; |
| if( pMSGlyph->maPixmaps[i] == None ) |
| continue; |
| XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] ); |
| mnBytesUsed -= nHeight * ((nWidth + 7) >> 3); |
| } |
| delete pMSGlyph->mpRawBitmap; |
| // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer(); |
| // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph ); |
| delete[] pMSGlyph; // it was allocated with new char[] |
| } |
| break; |
| |
| case INFO_RAWBMP: |
| { |
| RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt; |
| if( pRawBitmap != NULL ) |
| { |
| mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight; |
| mnBytesUsed -= sizeof(RawBitmap); |
| delete pRawBitmap; |
| } |
| } |
| break; |
| |
| case INFO_XRENDER: |
| { |
| // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer(); |
| // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph ); |
| mnBytesUsed -= nHeight * ((nWidth + 3) & ~3); |
| } |
| break; |
| } |
| |
| if( mnBytesUsed < 0 ) // TODO: eliminate nBytesUsed calc mismatch |
| mnBytesUsed = 0; |
| |
| rGlyphData.ExtDataRef() = ExtGlyphData(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const |
| { |
| bool bForceOk = rServerFont.GetAntialiasAdvice(); |
| // maximum size for antialiasing is 250 pixels |
| bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250); |
| return (bForceOk && ((mnForcedAA >> nScreen) & 1)); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen ) |
| { |
| if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 ) |
| return 0; |
| |
| GlyphSet aGlyphSet; |
| |
| switch( rServerFont.GetExtInfo() ) |
| { |
| case INFO_XRENDER: |
| aGlyphSet = (GlyphSet)rServerFont.GetExtPointer(); |
| break; |
| |
| case INFO_EMPTY: |
| { |
| // antialiasing for reasonable font heights only |
| // => prevents crashes caused by X11 requests >= 256k |
| // => prefer readablity of hinted glyphs at small sizes |
| // => prefer "grey clouds" to "black clouds" at very small sizes |
| int nHeight = rServerFont.GetFontSelData().mnHeight; |
| if( nHeight<250 && rServerFont.GetAntialiasAdvice() ) |
| { |
| aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet(); |
| rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet ); |
| } |
| else |
| aGlyphSet = 0; |
| } |
| break; |
| |
| default: |
| aGlyphSet = 0; |
| break; |
| } |
| |
| return aGlyphSet; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, sal_GlyphId aGlyphId, int nReqScreen ) |
| { |
| if( rServerFont.IsGlyphInvisible( aGlyphId ) ) |
| return None; |
| |
| GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); |
| Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen ); |
| if( aPixmap == NO_PIXMAP ) |
| { |
| aPixmap = None; |
| if( rServerFont.GetGlyphBitmap1( aGlyphId, maRawBitmap ) ) |
| { |
| // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163 |
| sal_uLong nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1; |
| nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth ); |
| |
| rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) ); |
| rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset ); |
| |
| const sal_uLong nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize; |
| if( nBytes > 0 ) |
| { |
| // conversion table LSB<->MSB (for XCreatePixmapFromData) |
| static const unsigned char lsb2msb[256] = |
| { |
| 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, |
| 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, |
| 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, |
| 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, |
| 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, |
| 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, |
| 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, |
| 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, |
| 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, |
| 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, |
| 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, |
| 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, |
| 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, |
| 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, |
| 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, |
| 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, |
| 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, |
| 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, |
| 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, |
| 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, |
| 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, |
| 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, |
| 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, |
| 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, |
| 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, |
| 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, |
| 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, |
| 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, |
| 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, |
| 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, |
| 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, |
| 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF |
| }; |
| |
| unsigned char* pTemp = maRawBitmap.mpBits; |
| for( int i = nBytes; --i >= 0; ++pTemp ) |
| *pTemp = lsb2msb[ *pTemp ]; |
| |
| // often a glyph pixmap is only needed on the default screen |
| // => optimize for this common case |
| int nMinScreen = 0; |
| int nEndScreen = mnMaxScreens; |
| if( nReqScreen == mnDefaultScreen ) { |
| nMinScreen = mnDefaultScreen; |
| nEndScreen = mnDefaultScreen + 1; |
| } |
| // prepare glyph pixmaps for the different screens |
| for( int i = nMinScreen; i < nEndScreen; ++i ) |
| { |
| // don't bother if the pixmap is already there |
| if( GetPixmap( rGlyphData, i ) != NO_PIXMAP ) |
| continue; |
| // create the glyph pixmap |
| Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay, |
| RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits, |
| nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 ); |
| // and cache it as glyph specific data |
| SetPixmap( rGlyphData, aScreenPixmap, i ); |
| mnBytesUsed += nBytes; |
| if( i == nReqScreen ) |
| aPixmap = aScreenPixmap; |
| } |
| } |
| } |
| else |
| { |
| // fall back to .notdef glyph |
| if( aGlyphId != 0 ) // recurse only once |
| aPixmap = GetPixmap( rServerFont, 0, nReqScreen ); |
| |
| if( aPixmap == NO_PIXMAP ) |
| aPixmap = None; |
| } |
| } |
| |
| return aPixmap; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont, sal_GlyphId aGlyphId ) |
| { |
| if( rServerFont.IsGlyphInvisible( aGlyphId ) ) |
| return NO_RAWBMP; |
| |
| GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); |
| |
| const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData ); |
| if( pRawBitmap == NO_RAWBMP ) |
| { |
| RawBitmap* pNewBitmap = new RawBitmap; |
| if( rServerFont.GetGlyphBitmap8( aGlyphId, *pNewBitmap ) ) |
| { |
| pRawBitmap = pNewBitmap; |
| mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight; |
| mnBytesUsed += sizeof(pNewBitmap); |
| } |
| else |
| { |
| delete pNewBitmap; |
| // fall back to .notdef glyph |
| if( aGlyphId != 0 ) // recurse only once |
| pRawBitmap = GetRawBitmap( rServerFont, 0 ); |
| } |
| |
| SetRawBitmap( rGlyphData, pRawBitmap ); |
| } |
| |
| return pRawBitmap; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| XRenderGlyph X11GlyphPeer::GetXRGlyph( ServerFont& rServerFont, sal_GlyphId aGlyphId ) |
| { |
| if( rServerFont.IsGlyphInvisible( aGlyphId ) ) |
| return NO_GLYPHID; |
| |
| GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); |
| |
| XRenderGlyph nXRGlyph = GetRenderGlyph( rGlyphData ); |
| if( nXRGlyph == NO_GLYPHID ) |
| { |
| // prepare GlyphInfo and Bitmap |
| if( rServerFont.GetGlyphBitmap8( aGlyphId, maRawBitmap ) ) |
| { |
| XGlyphInfo aGlyphInfo; |
| aGlyphInfo.width = maRawBitmap.mnWidth; |
| aGlyphInfo.height = maRawBitmap.mnHeight; |
| aGlyphInfo.x = -maRawBitmap.mnXOffset; |
| aGlyphInfo.y = -maRawBitmap.mnYOffset; |
| |
| rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) ); |
| rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset ); |
| |
| const GlyphMetric& rGM = rGlyphData.GetMetric(); |
| aGlyphInfo.xOff = +rGM.GetDelta().X(); |
| aGlyphInfo.yOff = +rGM.GetDelta().Y(); |
| |
| // upload glyph bitmap to server |
| GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 ); |
| |
| nXRGlyph = aGlyphId & 0x00FFFFFF; |
| const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight; |
| XRenderPeer::GetInstance().AddGlyph( aGlyphSet, nXRGlyph, |
| aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes ); |
| mnBytesUsed += nBytes; |
| } |
| else |
| { |
| // fall back to .notdef glyph |
| if( nXRGlyph != 0 ) // recurse only once |
| nXRGlyph = GetXRGlyph( rServerFont, 0 ); |
| } |
| |
| SetRenderGlyph( rGlyphData, nXRGlyph ); |
| } |
| |
| return nXRGlyph; |
| } |
| |
| // =========================================================================== |
| |
| X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer ) |
| : GlyphCache( rPeer ) |
| { |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| static X11GlyphPeer* pX11GlyphPeer = NULL; |
| static X11GlyphCache* pX11GlyphCache = NULL; |
| |
| X11GlyphCache& X11GlyphCache::GetInstance() |
| { |
| if( !pX11GlyphCache ) |
| { |
| pX11GlyphPeer = new X11GlyphPeer(); |
| pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer ); |
| } |
| return *pX11GlyphCache; |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| void X11GlyphCache::KillInstance() |
| { |
| delete pX11GlyphCache; |
| delete pX11GlyphPeer; |
| pX11GlyphCache = NULL; |
| pX11GlyphPeer = NULL; |
| } |
| |
| // =========================================================================== |
| |
| void X11SalGraphics::releaseGlyphPeer() |
| { |
| X11GlyphCache::KillInstance(); |
| } |
| |
| // =========================================================================== |
| |