/* This file is part of the KDE project
   Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
   Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <tqpainter.h>
#include <tqpen.h>
#include <tqfontdatabase.h>
#include <tqapplication.h>

#include <kstaticdeleter.h>
#include <tdelocale.h>
#include <tdestandarddirs.h>
#include <tdeio/netaccess.h>
#include <tdeio/job.h>
#include <tdemessagebox.h>

#include "fontstyle.h"


KFORMULA_NAMESPACE_BEGIN

#include "unicodetable.cpp"

bool FontStyle::m_installed = false;

bool FontStyle::init( ContextStyle* style, bool install )
{
    if (!m_installed && install)
        installFonts();
    m_symbolTable.init( style->getMathFont() );

    return true;
}

// Cache the family list from TQFontDatabase after fixing it up (no foundry, lowercase)
class FontList {
public:
    FontList() {
        TQFontDatabase db;
        const TQStringList lst = db.families();
        for ( TQStringList::const_iterator it = lst.begin(), end = lst.end() ; it != end ; ++it ) {
            const TQString name = *it;
            int i = name.find('[');
            TQString family = name;
            // Remove foundry
            if ( i > -1 ) {
                const int li = name.findRev(']');
                if (i < li) {
                    if (name[i - 1] == ' ')
                        i--;
                    family = name.left(i);
                }
            }
            m_fontNames.append( family.lower() );
        }
    }
    bool hasFont( const TQString& fontName ) const {
        return m_fontNames.find( fontName ) != m_fontNames.end();
    }
    TQStringList m_fontNames;
};
static FontList* s_fontList = 0;
static KStaticDeleter<FontList> s_fontList_sd;

void FontStyle::testFont( TQStringList& missing, const TQString& fontName ) {
    if ( !s_fontList )
        s_fontList_sd.setObject( s_fontList, new FontList() );
    if ( !s_fontList->hasFont( fontName ) )  {
        kdWarning(39001) << "Font '" << fontName << "' not found" << endl;
        missing.append( fontName );
    }
}


TQStringList FontStyle::missingFonts( bool install )
{
    if (!m_installed && install)
        installFonts();

    TQStringList missing = missingFontsInternal();
    return missing;
}

TQStringList FontStyle::missingFontsInternal()
{
    TQStringList missing;

    testFont( missing, "cmex10" );
    testFont( missing, "arev sans");

    return missing;
}

void FontStyle::installFonts()
{
    if (m_installed)
        return;
    TQStringList missing = missingFontsInternal();
    if (!missing.isEmpty())
    {
        TQStringList urlList;
        for (TQStringList::iterator it = missing.begin(); it != missing.end(); ++it)
        {
            if ( *it == "arev sans" ) {
                if (!TDEIO::NetAccess::exists("fonts:/Personal/Arev.ttf", true, NULL))
                    urlList.append(locate("data", "kformula/fonts/Arev.ttf"));
                if (!TDEIO::NetAccess::exists("fonts:/Personal/ArevIt.ttf", true, NULL))
                    urlList.append(locate("data", "kformula/fonts/ArevIt.ttf"));
                if (!TDEIO::NetAccess::exists("fonts:/Personal/ArevBd.ttf", true, NULL))
                    urlList.append(locate("data", "kformula/fonts/ArevBd.ttf"));
                if (!TDEIO::NetAccess::exists("fonts:/Personal/ArevBI.ttf", true, NULL))
                    urlList.append(locate("data", "kformula/fonts/ArevBI.ttf"));
            }
            else {
                if (!TDEIO::NetAccess::exists("fonts:/Personal/" + *it + ".ttf", true, NULL))
                    urlList.append(locate("data", "kformula/fonts/" + *it + ".ttf"));
            }
        }
        TDEIO::copy(urlList, "fonts:/Personal/", false);
        KMessageBox::information(tqApp->mainWidget(), 
                                 i18n("Some fonts have been installed to assure that symbols in formulas are properly visualized. You must restart the application in order so that changes take effect"));
    }
    m_installed = true;
}

Artwork* FontStyle::createArtwork( SymbolType type ) const
{
    return new Artwork( type );
}

// We claim that all chars come from the same font.
// It's up to the font tables to ensure this.
const TQChar leftRoundBracket[] = {
    0x30, // uppercorner
    0x40, // lowercorner
    0x42  // line
};
const TQChar leftSquareBracket[] = {
    0x32, // uppercorner
    0x34, // lowercorner
    0x36  // line
};
const TQChar leftCurlyBracket[] = {
    0x38, // uppercorner
    0x3A, // lowercorner
    0x3E, // line
    0x3C  // middle
};

const TQChar leftLineBracket[] = {
    0x36, // line
    0x36, // line
    0x36  // line
};
const TQChar rightLineBracket[] = {
    0x37, // line
    0x37, // line
    0x37  // line
};

const TQChar rightRoundBracket[] = {
    0x31, // uppercorner
    0x41, // lowercorner
    0x43  // line
};
const TQChar rightSquareBracket[] = {
    0x33, // uppercorner
    0x35, // lowercorner
    0x37  // line
};
const TQChar rightCurlyBracket[] = {
    0x39, // uppercorner
    0x3B, // lowercorner
    0x3E, // line
    0x3D  // middle
};


static const char cmex_LeftSquareBracket = 163;
static const char cmex_RightSquareBracket = 164;
static const char cmex_LeftCurlyBracket = 169;
static const char cmex_RightCurlyBracket = 170;
static const char cmex_LeftCornerBracket = 173;
static const char cmex_RightCornerBracket = 174;
static const char cmex_LeftRoundBracket = 161;
static const char cmex_RightRoundBracket = 162;
static const char cmex_SlashBracket = 177;
static const char cmex_BackSlashBracket = 178;
//static const char cmex_LeftLineBracket = 0x4b;
//static const char cmex_RightLineBracket = 0x4b;

// use the big symbols here
static const char cmex_Int = 90;
static const char cmex_Sum = 88;
static const char cmex_Prod = 89;


// cmex is a special font with symbols in four sizes.
static short cmex_nextchar( short ch )
{
    switch ( ch ) {
    case 161: return 179;
    case 162: return 180;
    case 163: return 104;
    case 164: return 105;
    case 169: return 110;
    case 170: return 111;
    case 165: return 106;
    case 166: return 107;
    case 167: return 108;
    case 168: return 109;
    case 173: return 68;
    case 174: return 69;
    case 177: return 46;
    case 178: return 47;

    case 179: return 181;
    case 180: return 182;
    case 104: return 183;
    case 105: return 184;
    case 110: return 189;
    case 111: return 190;
    case 106: return 185;
    case 107: return 186;
    case 108: return 187;
    case 109: return 188;
    case 68: return 191;
    case 69: return 192;
    case 46: return 193;
    case 47: return 194;

    case 181: return 195;
    case 182: return 33;
    case 183: return 34;
    case 184: return 35;
    case 189: return 40;
    case 190: return 41;
    case 185: return 36;
    case 186: return 37;
    case 187: return 38;
    case 188: return 39;
    case 191: return 42;
    case 192: return 43;
    case 193: return 44;
    case 194: return 45;
    }
    return 0;
}

bool Artwork::calcCMDelimiterSize( const ContextStyle& context,
                                     uchar c,
                                     luPt fontSize,
                                     luPt parentSize )
{
    TQFont f( "cmex10" );
    f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
    TQFontMetrics fm( f );

    for ( char i=1; c != 0; ++i ) {
        LuPixelRect bound = fm.boundingRect( c );

        luPt height = context.ptToLayoutUnitPt( bound.height() );
        if ( height >= parentSize ) {
            luPt width = context.ptToLayoutUnitPt( fm.width( c ) );
            luPt baseline = context.ptToLayoutUnitPt( -bound.top() );

            cmChar = c;

            setHeight( height );
            setWidth( width );
            setBaseline( baseline );

            return true;
        }
        c = cmex_nextchar( c );
    }

    // Build it up from pieces.
    return false;
}


void Artwork::calcLargest( const ContextStyle& context,
                             uchar c, luPt fontSize )
{
    TQFont f( "cmex10" );
    f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
    TQFontMetrics fm( f );

    cmChar = c;
    for ( ;; ) {
        c = cmex_nextchar( c );
        if ( c == 0 ) {
            break;
        }
        cmChar = c;
    }

    LuPixelRect bound = fm.boundingRect( cmChar );

    luPt height = context.ptToLayoutUnitPt( bound.height() );
    luPt width = context.ptToLayoutUnitPt( fm.width( cmChar ) );
    luPt baseline = context.ptToLayoutUnitPt( -bound.top() );

    setHeight( height );
    setWidth( width );
    setBaseline( baseline );
}


void Artwork::drawCMDelimiter( TQPainter& painter, const ContextStyle& style,
                                 luPixel x, luPixel y,
                                 luPt height )
{
    TQFont f( "cmex10" );
    f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );

    painter.setFont( f );
    painter.drawText( style.layoutUnitToPixelX( x ),
                      style.layoutUnitToPixelY( y + getBaseline() ),
                      TQString( TQChar( cmChar ) ) );

    // Debug
#if 0
    TQFontMetrics fm( f );
    LuPixelRect bound = fm.boundingRect( cmChar );
    painter.setBrush(TQt::NoBrush);
    painter.setPen(TQt::green);
    painter.drawRect( style.layoutUnitToPixelX( x ),
                      style.layoutUnitToPixelY( y ),
                      fm.width( cmChar ),
                      bound.height() );
#endif
}


Artwork::Artwork(SymbolType t)
    : baseline( -1 ), type(t)
{
}


void Artwork::calcSizes( const ContextStyle& style,
                           ContextStyle::TextStyle tstyle,
                           double factor,
                           luPt parentSize )
{
    setBaseline( -1 );
    cmChar = -1;
    luPt mySize = style.getAdjustedSize( tstyle, factor );
    switch (getType()) {
    case LeftSquareBracket:
        if ( calcCMDelimiterSize( style, cmex_LeftSquareBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcRoundBracket( style, leftSquareBracket, parentSize, mySize );
        break;
    case RightSquareBracket:
        if ( calcCMDelimiterSize( style, cmex_RightSquareBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcRoundBracket( style, rightSquareBracket, parentSize, mySize );
        break;
    case LeftLineBracket:
        calcRoundBracket( style, leftLineBracket, parentSize, mySize );
        setWidth( getWidth()/2 );
        break;
    case RightLineBracket:
        calcRoundBracket( style, rightLineBracket, parentSize, mySize );
        setWidth( getWidth()/2 );
        break;
    case SlashBracket:
        if ( calcCMDelimiterSize( style, cmex_SlashBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcLargest( style, cmex_SlashBracket, mySize );
        break;
    case BackSlashBracket:
        if ( calcCMDelimiterSize( style, cmex_BackSlashBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcLargest( style, cmex_BackSlashBracket, mySize );
        break;
    case LeftCornerBracket:
        if ( calcCMDelimiterSize( style, cmex_LeftCornerBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcLargest( style, cmex_LeftCornerBracket, mySize );
        break;
    case RightCornerBracket:
        if ( calcCMDelimiterSize( style, cmex_RightCornerBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcLargest( style, cmex_RightCornerBracket, mySize );
        break;
    case LeftRoundBracket:
        if ( calcCMDelimiterSize( style, cmex_LeftRoundBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcRoundBracket( style, leftRoundBracket, parentSize, mySize );
        break;
    case RightRoundBracket:
        if ( calcCMDelimiterSize( style, cmex_RightRoundBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcRoundBracket( style, rightRoundBracket, parentSize, mySize );
        break;
    case EmptyBracket:
        setHeight(parentSize);
        //setWidth(style.getEmptyRectWidth());
        setWidth(0);
        break;
    case LeftCurlyBracket:
        if ( calcCMDelimiterSize( style, cmex_LeftCurlyBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcCurlyBracket( style, leftCurlyBracket, parentSize, mySize );
        break;
    case RightCurlyBracket:
        if ( calcCMDelimiterSize( style, cmex_RightCurlyBracket,
                                  mySize, parentSize ) ) {
            return;
        }
        calcCurlyBracket( style, rightCurlyBracket, parentSize, mySize );
        break;
    case Integral:
        calcCharSize( style, style.getBracketFont(), mySize, cmex_Int );
        break;
    case Sum:
        calcCharSize( style, style.getBracketFont(), mySize, cmex_Sum );
        break;
    case Product:
        calcCharSize( style, style.getBracketFont(), mySize, cmex_Prod );
        break;
    }
}

void Artwork::calcSizes( const ContextStyle& style,
                         ContextStyle::TextStyle tstyle,
                         double factor )
{
    luPt mySize = style.getAdjustedSize( tstyle, factor );
    switch (type) {
    case LeftSquareBracket:
        calcCharSize(style, mySize, leftSquareBracketChar);
        break;
    case RightSquareBracket:
        calcCharSize(style, mySize, rightSquareBracketChar);
        break;
    case LeftLineBracket:
    case RightLineBracket:
        calcCharSize(style, mySize, verticalLineChar);
        break;
    case SlashBracket:
        calcCharSize(style, mySize, slashChar);
        break;
    case BackSlashBracket:
        calcCharSize(style, mySize, backSlashChar);
        break;
    case LeftCornerBracket:
        calcCharSize(style, mySize, leftAngleBracketChar);
        break;
    case RightCornerBracket:
        calcCharSize(style, mySize, rightAngleBracketChar);
        break;
    case LeftRoundBracket:
        calcCharSize(style, mySize, leftParenthesisChar);
        break;
    case RightRoundBracket:
        calcCharSize(style, mySize, rightParenthesisChar);
        break;
    case EmptyBracket:
        //calcCharSize(style, mySize, spaceChar);
        setHeight(0);
        //setWidth(style.getEmptyRectWidth());
        setWidth(0);
        break;
    case LeftCurlyBracket:
        calcCharSize(style, mySize, leftCurlyBracketChar);
        break;
    case RightCurlyBracket:
        calcCharSize(style, mySize, rightCurlyBracketChar);
        break;
    case Integral:
    case Sum:
    case Product:
        break;
    }
}


void Artwork::draw(TQPainter& painter, const LuPixelRect& /*r*/,
                   const ContextStyle& context, ContextStyle::TextStyle tstyle,
                   StyleAttributes& style, const LuPixelPoint& parentOrigin)
{
    luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
    luPixel myX = parentOrigin.x() + getX();
    luPixel myY = parentOrigin.y() + getY();
    /*
    if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
        return;
    */

    painter.setPen(context.getDefaultColor());

    switch (type) {
    case LeftSquareBracket:
        drawCharacter(painter, context, myX, myY, mySize, leftSquareBracketChar);
        break;
    case RightSquareBracket:
        drawCharacter(painter, context, myX, myY, mySize, rightSquareBracketChar);
        break;
    case LeftCurlyBracket:
        drawCharacter(painter, context, myX, myY, mySize, leftCurlyBracketChar);
        break;
    case RightCurlyBracket:
        drawCharacter(painter, context, myX, myY, mySize, rightCurlyBracketChar);
        break;
    case LeftLineBracket:
    case RightLineBracket:
        drawCharacter(painter, context, myX, myY, mySize, verticalLineChar);
        break;
    case SlashBracket:
        drawCharacter(painter, context, myX, myY, mySize, slashChar);
        break;
    case BackSlashBracket:
        drawCharacter(painter, context, myX, myY, mySize, backSlashChar);
        break;
    case LeftCornerBracket:
        drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
        break;
    case RightCornerBracket:
        drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
        break;
    case LeftRoundBracket:
        drawCharacter(painter, context, myX, myY, mySize, leftParenthesisChar);
        break;
    case RightRoundBracket:
        drawCharacter(painter, context, myX, myY, mySize, rightParenthesisChar);
        break;
    case EmptyBracket:
        break;
    case Integral:
    case Sum:
    case Product:
        break;
    }
}

void Artwork::draw(TQPainter& painter, const LuPixelRect& ,
                     const ContextStyle& context, ContextStyle::TextStyle tstyle,
                     StyleAttributes& style, luPt , const LuPixelPoint& origin)
{
    luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
    luPixel myX = origin.x() + getX();
    luPixel myY = origin.y() + getY();
    /*
    if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
        return;
    */

    painter.setPen(context.getDefaultColor());

    switch (getType()) {
    case LeftSquareBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigRoundBracket( painter, context, leftSquareBracket, myX, myY, mySize );
        }
        break;
    case RightSquareBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigRoundBracket( painter, context, rightSquareBracket, myX, myY, mySize );
        }
        break;
    case LeftCurlyBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigCurlyBracket( painter, context, leftCurlyBracket, myX, myY, mySize );
        }
        break;
    case RightCurlyBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigCurlyBracket( painter, context, rightCurlyBracket, myX, myY, mySize );
        }
        break;
    case LeftLineBracket: {
        luPixel halfWidth = getWidth()/2;
        drawBigRoundBracket( painter, context, leftLineBracket,
                             myX-halfWidth, myY, mySize );
    }
        break;
    case RightLineBracket: {
        luPixel halfWidth = getWidth()/2;
        drawBigRoundBracket( painter, context, rightLineBracket,
                             myX-halfWidth, myY, mySize );
    }
        break;
    case SlashBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        break;
    case BackSlashBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        break;
    case LeftCornerBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
        break;
    case RightCornerBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
        break;
    case LeftRoundBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigRoundBracket( painter, context, leftRoundBracket, myX, myY, mySize );
        }
        break;
    case RightRoundBracket:
        if ( cmChar != -1 ) {
            drawCMDelimiter( painter, context, myX, myY, mySize );
        }
        else {
            drawBigRoundBracket( painter, context, rightRoundBracket, myX, myY, mySize );
        }
        break;
    case EmptyBracket:
        break;
    case Integral:
        drawCharacter(painter, context, TQFont( "cmex10" ), myX, myY, mySize, cmex_Int);
        break;
    case Sum:
        drawCharacter(painter, context, TQFont( "cmex10" ), myX, myY, mySize, cmex_Sum);
        break;
    case Product:
        drawCharacter(painter, context, TQFont( "cmex10" ), myX, myY, mySize, cmex_Prod);
        break;
    }

    // debug
//     painter.setBrush(TQt::NoBrush);
//     painter.setPen(TQt::green);
//     painter.drawRect( context.layoutUnitToPixelX( myX ),
//                       context.layoutUnitToPixelY( myY ),
//                       context.layoutUnitToPixelX( getWidth() ),
//                       context.layoutUnitToPixelY( getHeight() ) );
}

void Artwork::calcCharSize( const ContextStyle& style, luPt height, TQChar ch )
{
    calcCharSize( style, style.getMathFont(), height, ch );
}


void Artwork::drawCharacter( TQPainter& painter, const ContextStyle& style,
                             luPixel x, luPixel y,
                             luPt height, TQChar ch )
{
    drawCharacter( painter, style, style.getMathFont(), x, y, height, ch );
}


void Artwork::calcCharSize( const ContextStyle& style, TQFont f,
                            luPt height, TQChar c )
{
    f.setPointSizeFloat( style.layoutUnitPtToPt( height ) );
    //f.setPointSize( height );
    TQFontMetrics fm(f);
    setWidth( style.ptToLayoutUnitPt( fm.width( c ) ) );
    LuPixelRect bound = fm.boundingRect( c );
    setHeight( style.ptToLayoutUnitPt( bound.height() ) );
    setBaseline( style.ptToLayoutUnitPt( -bound.top() ) );
}


void Artwork::drawCharacter( TQPainter& painter, const ContextStyle& style,
                             TQFont f,
                             luPixel x, luPixel y, luPt height, uchar c )
{
    f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );

    painter.setFont( f );
    painter.drawText( style.layoutUnitToPixelX( x ),
                      style.layoutUnitToPixelY( y+getBaseline() ),
                      TQString( TQChar( c ) ) );
}


void Artwork::calcRoundBracket( const ContextStyle& style, const TQChar chars[],
                                luPt height, luPt charHeight )
{
    uchar uppercorner = chars[0];
    uchar lowercorner = chars[1];
    //uchar line = style.symbolTable().character( chars[2] );

    TQFont f = style.getBracketFont();
    f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
    TQFontMetrics fm( f );
    LuPtRect upperBound = fm.boundingRect( uppercorner );
    LuPtRect lowerBound = fm.boundingRect( lowercorner );
    //LuPtRect lineBound = fm.boundingRect( line );

    setWidth( style.ptToLayoutUnitPt( fm.width( TQChar( uppercorner ) ) ) );
    luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+lowerBound.height() );
    //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );

    //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
    setHeight( TQMAX( edgeHeight, height ) );
}

void Artwork::drawBigRoundBracket( TQPainter& p, const ContextStyle& style, const TQChar chars[],
                                   luPixel x, luPixel y, luPt charHeight )
{
    uchar uppercorner = chars[0];
    uchar lowercorner = chars[1];
    uchar line = chars[2];

    TQFont f = style.getBracketFont();
    f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
    p.setFont(f);

    TQFontMetrics fm(f);
    TQRect upperBound = fm.boundingRect(uppercorner);
    TQRect lowerBound = fm.boundingRect(lowercorner);
    TQRect lineBound = fm.boundingRect(line);

    pixel ptX = style.layoutUnitToPixelX( x );
    pixel ptY = style.layoutUnitToPixelY( y );
    pixel height = style.layoutUnitToPixelY( getHeight() );

//     p.setPen( TQt::red );
//     //p.drawRect( ptX, ptY, upperBound.width(), upperBound.height() + lowerBound.height() );
//     p.drawRect( ptX, ptY, style.layoutUnitToPixelX( getWidth() ),
//                 style.layoutUnitToPixelY( getHeight() ) );

//     p.setPen( TQt::black );
    p.drawText( ptX, ptY-upperBound.top(), TQString( TQChar( uppercorner ) ) );
    p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
                TQString( TQChar( lowercorner ) ) );

    // for printing
    //pt safety = lineBound.height() / 10.0;
    pixel safety = 0;

    pixel gap = height - upperBound.height() - lowerBound.height();
    pixel lineHeight = lineBound.height() - safety;
    int lineCount = tqRound( static_cast<double>( gap ) / lineHeight );
    pixel start = upperBound.height()-lineBound.top() - safety;

    for (int i = 0; i < lineCount; i++) {
        p.drawText( ptX, ptY+start+i*lineHeight, TQString(TQChar(line)));
    }
    pixel remaining = gap - lineCount*lineHeight;
    pixel dist = ( lineHeight - remaining ) / 2;
    p.drawText( ptX, ptY+height-upperBound.height()+dist-lineBound.height()-lineBound.top(),
                TQString( TQChar( line ) ) );
}

void Artwork::calcCurlyBracket( const ContextStyle& style, const TQChar chars[],
                                luPt height, luPt charHeight )
{
    uchar uppercorner = chars[0];
    uchar lowercorner = chars[1];
    //uchar line = style.symbolTable().character( chars[2] );
    uchar middle = chars[3];

    TQFont f = style.getBracketFont();
    f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
    TQFontMetrics fm( f );
    LuPtRect upperBound = fm.boundingRect( uppercorner );
    LuPtRect lowerBound = fm.boundingRect( lowercorner );
    //LuPtRect lineBound = fm.boundingRect( line );
    LuPtRect middleBound = fm.boundingRect( middle );

    setWidth( style.ptToLayoutUnitPt( fm.width( TQChar( uppercorner ) ) ) );
    luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+
                                              lowerBound.height()+
                                              middleBound.height() );
    //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );

    //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
    setHeight( TQMAX( edgeHeight, height ) );
}

void Artwork::drawBigCurlyBracket( TQPainter& p, const ContextStyle& style, const TQChar chars[],
                                   luPixel x, luPixel y, luPt charHeight )
{
    //TQFont f = style.getSymbolFont();
    TQFont f = style.getBracketFont();
    f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
    p.setFont(f);

    uchar uppercorner = chars[0];
    uchar lowercorner = chars[1];
    uchar line = chars[2];
    uchar middle = chars[3];

    TQFontMetrics fm(p.fontMetrics());
    TQRect upperBound = fm.boundingRect(uppercorner);
    TQRect lowerBound = fm.boundingRect(lowercorner);
    TQRect middleBound = fm.boundingRect(middle);
    TQRect lineBound = fm.boundingRect(line);

    pixel ptX = style.layoutUnitToPixelX( x );
    pixel ptY = style.layoutUnitToPixelY( y );
    pixel height = style.layoutUnitToPixelY( getHeight() );

    //p.setPen(TQt::gray);
    //p.drawRect(x, y, upperBound.width() + offset, height);

    p.drawText( ptX, ptY-upperBound.top(), TQString( TQChar( uppercorner ) ) );
    p.drawText( ptX, ptY+(height-middleBound.height())/2-middleBound.top(),
                TQString( TQChar( middle ) ) );
    p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
                TQString( TQChar( lowercorner ) ) );

    // for printing
    // If the world was perfect and the urw-symbol font correct
    // this could be 0.
    //lu safety = lineBound.height() / 10;
    pixel safety = 0;

    pixel lineHeight = lineBound.height() - safety;
    pixel gap = height/2 - upperBound.height() - middleBound.height() / 2;

    if (gap > 0) {
        TQString ch = TQString(TQChar(line));
        int lineCount = tqRound( gap / lineHeight ) + 1;

        pixel start = (height - middleBound.height()) / 2 + safety;
        for (int i = 0; i < lineCount; i++) {
            p.drawText( ptX, ptY-lineBound.top()+TQMAX( start-(i+1)*lineHeight,
                                                       upperBound.width() ),
                        ch );
        }

        start = (height + middleBound.height()) / 2 - safety;
        for (int i = 0; i < lineCount; i++) {
            p.drawText( ptX, ptY-lineBound.top()+TQMIN( start+i*lineHeight,
                                                       height-upperBound.width()-lineBound.height() ),
                        ch );
        }
    }
}

KFORMULA_NAMESPACE_END
