/**************************************************************
 * 
 * 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 <stdio.h>

#include <rtl/ustring.hxx>
#include <osl/module.h>

#include <unx/salunx.h>
#include <unx/saldata.hxx>
#include <unx/saldisp.hxx>

#include <xrender_peer.hxx>

using namespace rtl;

// ---------------------------------------------------------------------------

XRenderPeer::XRenderPeer()
:   mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ),
    mpStandardFormatA8( NULL ),
    mnRenderVersion( 0 ),
    mpRenderLib( NULL )
#ifndef XRENDER_LINK
,   mpXRenderCompositeTrapezoids( NULL )
,   mpXRenderAddTraps( NULL )
#endif // XRENDER_LINK
{
    InitRenderLib();
}

// ---------------------------------------------------------------------------

XRenderPeer::~XRenderPeer()
{
    osl_unloadModule( mpRenderLib );
}

// ---------------------------------------------------------------------------

XRenderPeer& XRenderPeer::GetInstance()
{
    static XRenderPeer aPeer;
    return aPeer;
}

// ---------------------------------------------------------------------------

void XRenderPeer::InitRenderLib()
{
    int nDummy;
    if( !XQueryExtension( mpDisplay, "RENDER", &nDummy, &nDummy, &nDummy ) )
        return;

#ifndef XRENDER_LINK
    // we don't know if we are running on a system with xrender library
    // we don't want to install system libraries ourselves
    // => load them dynamically when they are there
    static const char aLibName[] = "libXrender.so.1";
    mpRenderLib = osl_loadAsciiModule( aLibName, SAL_LOADMODULE_DEFAULT );
    if( !mpRenderLib ) {
#ifdef DEBUG
        fprintf( stderr, "Display can do XRender, but no %s installed.\n"
            "Please install for improved display performance\n", aLibName );
#endif
        return;
    }

    oslGenericFunction pFunc;
    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryExtension" );
    if( !pFunc ) return;
    mpXRenderQueryExtension = (Bool(*)(Display*,int*,int*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryVersion" );
    if( !pFunc ) return;
    mpXRenderQueryVersion = (void(*)(Display*,int*,int*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindVisualFormat" );
    if( !pFunc ) return;
    mpXRenderFindVisualFormat = (XRenderPictFormat*(*)(Display*,Visual*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindStandardFormat" );
    if( !pFunc ) return;
    mpXRenderFindStandardFormat = (XRenderPictFormat*(*)(Display*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindFormat" );
    if( !pFunc ) return;
    mpXRenderFindFormat = (XRenderPictFormat*(*)(Display*,unsigned long,
        const XRenderPictFormat*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreateGlyphSet" );
    if( !pFunc ) return;
    mpXRenderCreateGlyphSet = (GlyphSet(*)(Display*,const XRenderPictFormat*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphSet" );
    if( !pFunc ) return;
    mpXRenderFreeGlyphSet = (void(*)(Display*,GlyphSet))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddGlyphs" );
    if( !pFunc ) return;
    mpXRenderAddGlyphs = (void(*)(Display*,GlyphSet,Glyph*,const XGlyphInfo*,
        int,const char*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphs" );
    if( !pFunc ) return;
    mpXRenderFreeGlyphs = (void(*)(Display*,GlyphSet,Glyph*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeString32" );
    if( !pFunc ) return;
    mpXRenderCompositeString32 = (void(*)(Display*,int,Picture,Picture,
        const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreatePicture" );
    if( !pFunc ) return;
    mpXRenderCreatePicture = (Picture(*)(Display*,Drawable,const XRenderPictFormat*,
        unsigned long,const XRenderPictureAttributes*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderChangePicture" );
    if( !pFunc ) return;
    mpXRenderChangePicture = (void(*)(Display*,Picture,unsigned long,const XRenderPictureAttributes*))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderSetPictureClipRegion" );
    if( !pFunc ) return;
    mpXRenderSetPictureClipRegion = (void(*)(Display*,Picture,XLIB_Region))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreePicture" );
    if( !pFunc ) return;
    mpXRenderFreePicture = (void(*)(Display*,Picture))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderComposite" );
    if( !pFunc ) return;
    mpXRenderComposite = (void(*)(Display*,int,Picture,Picture,Picture,
        int,int,int,int,int,int,unsigned,unsigned))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFillRectangle" );
    if( !pFunc ) return;
    mpXRenderFillRectangle = (void(*)(Display*,int,Picture,const XRenderColor*,
        int,int,unsigned int,unsigned int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeTrapezoids" );
#if 0 // not having trapezoid support is supported
    if( !pFunc ) return;
#endif
    mpXRenderCompositeTrapezoids = (void(*)(Display*,int,Picture,Picture,
        const XRenderPictFormat*,int,int,const XTrapezoid*,int))pFunc;

    pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddTraps" );
#if 0 // not having trapezoid support is supported
    if( !pFunc ) return;
#endif
    mpXRenderAddTraps = (void(*)(Display*,Picture,int,int,const _XTrap*,int))pFunc;

#endif // XRENDER_LINK

    // needed to initialize libXrender internals, we already know its there
#ifdef XRENDER_LINK
    XRenderQueryExtension( mpDisplay, &nDummy, &nDummy );
#else
    (*mpXRenderQueryExtension)( mpDisplay, &nDummy, &nDummy );
#endif

    int nMajor, nMinor;
#ifdef XRENDER_LINK
    XRenderQueryVersion( mpDisplay, &nMajor, &nMinor );
#else
    (*mpXRenderQueryVersion)( mpDisplay, &nMajor, &nMinor );
#endif
    mnRenderVersion = 16*nMajor + nMinor;

    // the 8bit alpha mask format must be there
    XRenderPictFormat aPictFormat={0,0,8,{0,0,0,0,0,0,0,0xFF},0};
    mpStandardFormatA8 = FindPictureFormat( PictFormatAlphaMask|PictFormatDepth, aPictFormat );
}

// ---------------------------------------------------------------------------

// return mask of screens capable of XRENDER text
sal_uInt32 XRenderPeer::InitRenderText()
{
    if( mnRenderVersion < 0x01 )
        return 0;

    // #93033# disable XRENDER for old RENDER versions if XINERAMA is present
    int nDummy;
    if( XQueryExtension( mpDisplay, "XINERAMA", &nDummy, &nDummy, &nDummy ) )
        if( mnRenderVersion < 0x02 )
            return 0;

    if( !mpStandardFormatA8 )
        return 0;

    // and the visual must be supported too on at least one screen
    sal_uInt32 nRetMask = 0;
    SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
    const int nScreenCount = pSalDisp->GetScreenCount();
    XRenderPictFormat* pVisualFormat = NULL;
    int nMaxDepth = 0;
    for( int nScreen = 0; nScreen < nScreenCount; ++nScreen )
    {
        Visual* pXVisual = pSalDisp->GetVisual( nScreen ).GetVisual();
        pVisualFormat = FindVisualFormat( pXVisual );
        if( pVisualFormat != NULL )
        {
            int nVDepth = pSalDisp->GetVisual( nScreen ).GetDepth();
            if( nVDepth > nMaxDepth )
                nMaxDepth = nVDepth;
            nRetMask |= 1U << nScreen;
        }
    }

    // #97763# disable XRENDER on <15bit displays for XFree<=4.2.0
    if( mnRenderVersion <= 0x02 )
        if( nMaxDepth < 15 )
            nRetMask = 0;

    return nRetMask;
}

// ---------------------------------------------------------------------------
