lib

fontstyle.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qpainter.h>
00021 #include <qpen.h>
00022 #include <qfontdatabase.h>
00023 #include <kstaticdeleter.h>
00024 
00025 #include "fontstyle.h"
00026 
00027 
00028 KFORMULA_NAMESPACE_BEGIN
00029 
00030 #include "unicodenames.cc"
00031 
00032 void FontStyle::fillNameTable( SymbolTable::NameTable& names )
00033 {
00034     for ( int i=0; nameTable[i].unicode != 0; ++i ) {
00035         names[QChar( nameTable[i].unicode )] = nameTable[i].name;
00036     }
00037 }
00038 
00039 // Cache the family list from QFontDatabase after fixing it up (no foundry, lowercase)
00040 class FontList {
00041 public:
00042     FontList() {
00043         QFontDatabase db;
00044         const QStringList lst = db.families();
00045         for ( QStringList::const_iterator it = lst.begin(), end = lst.end() ; it != end ; ++it ) {
00046             const QString name = *it;
00047             int i = name.find('[');
00048             QString family = name;
00049             // Remove foundry
00050             if ( i > -1 ) {
00051                 const int li = name.findRev(']');
00052                 if (i < li) {
00053                     if (name[i - 1] == ' ')
00054                         i--;
00055                     family = name.left(i);
00056                 }
00057             }
00058             m_fontNames.append( family.lower() );
00059         }
00060     }
00061     bool hasFont( const QString& fontName ) const {
00062         return m_fontNames.find( fontName ) != m_fontNames.end();
00063     }
00064     QStringList m_fontNames;
00065 };
00066 static FontList* s_fontList = 0;
00067 static KStaticDeleter<FontList> s_fontList_sd;
00068 
00069 void FontStyle::testFont( QStringList& missing, const QString& fontName ) {
00070     if ( !s_fontList )
00071         s_fontList_sd.setObject( s_fontList, new FontList() );
00072     if ( !s_fontList->hasFont( fontName ) )  {
00073         kdWarning(39001) << "Font '" << fontName << "' not found" << endl;
00074         missing.append( fontName );
00075     }
00076 }
00077 
00078 
00079 
00080 // We claim that all chars come from the same font.
00081 // It's up to the font tables to ensure this.
00082 const QChar leftRoundBracket[] = {
00083     0xF8EB, // uppercorner
00084     0xF8ED, // lowercorner
00085     0xF8EC  // line
00086 };
00087 const QChar leftSquareBracket[] = {
00088     0xF8EE, // uppercorner
00089     0xF8F0, // lowercorner
00090     0xF8EF  // line
00091 };
00092 const QChar leftCurlyBracket[] = {
00093     0xF8F1, // uppercorner
00094     0xF8F3, // lowercorner
00095     0xF8F4, // line
00096     0xF8F2  // middle
00097 };
00098 
00099 const QChar leftLineBracket[] = {
00100     0xF8EF, // line
00101     0xF8EF, // line
00102     0xF8EF  // line
00103 };
00104 const QChar rightLineBracket[] = {
00105     0xF8FA, // line
00106     0xF8FA, // line
00107     0xF8FA  // line
00108 };
00109 
00110 const QChar rightRoundBracket[] = {
00111     0xF8F6, // uppercorner
00112     0xF8F8, // lowercorner
00113     0xF8F7  // line
00114 };
00115 const QChar rightSquareBracket[] = {
00116     0xF8F9, // uppercorner
00117     0xF8FB, // lowercorner
00118     0xF8FA  // line
00119 };
00120 const QChar rightCurlyBracket[] = {
00121     0xF8FC, // uppercorner
00122     0xF8FE, // lowercorner
00123     0xF8F4, // line
00124     0xF8FD  // middle
00125 };
00126 
00127 
00128 Artwork::Artwork(SymbolType t)
00129     : baseline( -1 ), type(t)
00130 {
00131 }
00132 
00133 
00134 void Artwork::calcSizes( const ContextStyle& style,
00135                          ContextStyle::TextStyle tstyle )
00136 {
00137     luPt mySize = style.getAdjustedSize( tstyle );
00138     switch (type) {
00139     case LeftSquareBracket:
00140         calcCharSize(style, mySize, leftSquareBracketChar);
00141         break;
00142     case RightSquareBracket:
00143         calcCharSize(style, mySize, rightSquareBracketChar);
00144         break;
00145     case LeftLineBracket:
00146     case RightLineBracket:
00147         calcCharSize(style, mySize, verticalLineChar);
00148         break;
00149     case SlashBracket:
00150         calcCharSize(style, mySize, slashChar);
00151         break;
00152     case BackSlashBracket:
00153         calcCharSize(style, mySize, backSlashChar);
00154         break;
00155     case LeftCornerBracket:
00156         calcCharSize(style, mySize, leftAngleBracketChar);
00157         break;
00158     case RightCornerBracket:
00159         calcCharSize(style, mySize, rightAngleBracketChar);
00160         break;
00161     case LeftRoundBracket:
00162         calcCharSize(style, mySize, leftParenthesisChar);
00163         break;
00164     case RightRoundBracket:
00165         calcCharSize(style, mySize, rightParenthesisChar);
00166         break;
00167     case EmptyBracket:
00168         //calcCharSize(style, mySize, spaceChar);
00169         setHeight(0);
00170         //setWidth(style.getEmptyRectWidth());
00171         setWidth(0);
00172         break;
00173     case LeftCurlyBracket:
00174         calcCharSize(style, mySize, leftCurlyBracketChar);
00175         break;
00176     case RightCurlyBracket:
00177         calcCharSize(style, mySize, rightCurlyBracketChar);
00178         break;
00179     case Integral:
00180     case Sum:
00181     case Product:
00182         break;
00183     }
00184 }
00185 
00186 
00187 void Artwork::draw(QPainter& painter, const LuPixelRect& /*r*/,
00188                    const ContextStyle& style, ContextStyle::TextStyle tstyle,
00189                    const LuPixelPoint& parentOrigin)
00190 {
00191     luPt mySize = style.getAdjustedSize( tstyle );
00192     luPixel myX = parentOrigin.x() + getX();
00193     luPixel myY = parentOrigin.y() + getY();
00194     /*
00195     if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
00196         return;
00197     */
00198 
00199     painter.setPen(style.getDefaultColor());
00200 
00201     switch (type) {
00202     case LeftSquareBracket:
00203         drawCharacter(painter, style, myX, myY, mySize, leftSquareBracketChar);
00204         break;
00205     case RightSquareBracket:
00206         drawCharacter(painter, style, myX, myY, mySize, rightSquareBracketChar);
00207         break;
00208     case LeftCurlyBracket:
00209         drawCharacter(painter, style, myX, myY, mySize, leftCurlyBracketChar);
00210         break;
00211     case RightCurlyBracket:
00212         drawCharacter(painter, style, myX, myY, mySize, rightCurlyBracketChar);
00213         break;
00214     case LeftLineBracket:
00215     case RightLineBracket:
00216         drawCharacter(painter, style, myX, myY, mySize, verticalLineChar);
00217         break;
00218     case SlashBracket:
00219         drawCharacter(painter, style, myX, myY, mySize, slashChar);
00220         break;
00221     case BackSlashBracket:
00222         drawCharacter(painter, style, myX, myY, mySize, backSlashChar);
00223         break;
00224     case LeftCornerBracket:
00225         drawCharacter(painter, style, myX, myY, mySize, leftAngleBracketChar);
00226         break;
00227     case RightCornerBracket:
00228         drawCharacter(painter, style, myX, myY, mySize, rightAngleBracketChar);
00229         break;
00230     case LeftRoundBracket:
00231         drawCharacter(painter, style, myX, myY, mySize, leftParenthesisChar);
00232         break;
00233     case RightRoundBracket:
00234         drawCharacter(painter, style, myX, myY, mySize, rightParenthesisChar);
00235         break;
00236     case EmptyBracket:
00237         break;
00238     case Integral:
00239     case Sum:
00240     case Product:
00241         break;
00242     }
00243 }
00244 
00245 
00246 void Artwork::calcCharSize( const ContextStyle& style, luPt height, QChar ch )
00247 {
00248     //QFont f = style.getSymbolFont();
00249     uchar c = style.symbolTable().character( ch );
00250     QFont f = style.symbolTable().font( ch );
00251     calcCharSize( style, f, height, c );
00252 }
00253 
00254 
00255 void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
00256                              luPixel x, luPixel y,
00257                              luPt height, QChar ch )
00258 {
00259     uchar c = style.symbolTable().character( ch );
00260     QFont f = style.symbolTable().font( ch );
00261     drawCharacter( painter, style, f, x, y, height, c );
00262 }
00263 
00264 
00265 void Artwork::calcCharSize( const ContextStyle& style, QFont f,
00266                             luPt height, uchar c )
00267 {
00268     f.setPointSizeFloat( style.layoutUnitPtToPt( height ) );
00269     //f.setPointSize( height );
00270     QFontMetrics fm(f);
00271     setWidth( style.ptToLayoutUnitPt( fm.width( c ) ) );
00272     LuPixelRect bound = fm.boundingRect( c );
00273     setHeight( style.ptToLayoutUnitPt( bound.height() ) );
00274     setBaseline( style.ptToLayoutUnitPt( -bound.top() ) );
00275 }
00276 
00277 
00278 void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
00279                              QFont f,
00280                              luPixel x, luPixel y, luPt height, uchar c )
00281 {
00282     f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
00283 
00284     painter.setFont( f );
00285     painter.drawText( style.layoutUnitToPixelX( x ),
00286                       style.layoutUnitToPixelY( y+getBaseline() ),
00287                       QString( QChar( c ) ) );
00288 }
00289 
00290 
00291 void Artwork::calcRoundBracket( const ContextStyle& style, const QChar chars[],
00292                                 luPt height, luPt charHeight )
00293 {
00294     uchar uppercorner = style.symbolTable().character( chars[0] );
00295     uchar lowercorner = style.symbolTable().character( chars[1] );
00296     //uchar line = style.symbolTable().character( chars[2] );
00297 
00298     QFont f = style.symbolTable().font( chars[0] );
00299     f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
00300     QFontMetrics fm( f );
00301     LuPtRect upperBound = fm.boundingRect( uppercorner );
00302     LuPtRect lowerBound = fm.boundingRect( lowercorner );
00303     //LuPtRect lineBound = fm.boundingRect( line );
00304 
00305     setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
00306     luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+lowerBound.height() );
00307     //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
00308 
00309     //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
00310     setHeight( QMAX( edgeHeight, height ) );
00311 }
00312 
00313 void Artwork::drawBigRoundBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
00314                                    luPixel x, luPixel y, luPt charHeight )
00315 {
00316     uchar uppercorner = style.symbolTable().character( chars[0] );
00317     uchar lowercorner = style.symbolTable().character( chars[1] );
00318     uchar line = style.symbolTable().character( chars[2] );
00319 
00320     QFont f = style.symbolTable().font( chars[0] );
00321     f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
00322     p.setFont(f);
00323 
00324     QFontMetrics fm(f);
00325     QRect upperBound = fm.boundingRect(uppercorner);
00326     QRect lowerBound = fm.boundingRect(lowercorner);
00327     QRect lineBound = fm.boundingRect(line);
00328 
00329     pixel ptX = style.layoutUnitToPixelX( x );
00330     pixel ptY = style.layoutUnitToPixelY( y );
00331     pixel height = style.layoutUnitToPixelY( getHeight() );
00332 
00333 //     p.setPen( Qt::red );
00334 //     //p.drawRect( ptX, ptY, upperBound.width(), upperBound.height() + lowerBound.height() );
00335 //     p.drawRect( ptX, ptY, style.layoutUnitToPixelX( getWidth() ),
00336 //                 style.layoutUnitToPixelY( getHeight() ) );
00337 
00338 //     p.setPen( Qt::black );
00339     p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
00340     p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
00341                 QString( QChar( lowercorner ) ) );
00342 
00343     // for printing
00344     //pt safety = lineBound.height() / 10.0;
00345     pixel safety = 0;
00346 
00347     pixel gap = height - upperBound.height() - lowerBound.height();
00348     pixel lineHeight = lineBound.height() - safety;
00349     int lineCount = qRound( static_cast<double>( gap ) / lineHeight );
00350     pixel start = upperBound.height()-lineBound.top() - safety;
00351 
00352     for (int i = 0; i < lineCount; i++) {
00353         p.drawText( ptX, ptY+start+i*lineHeight, QString(QChar(line)));
00354     }
00355     pixel remaining = gap - lineCount*lineHeight;
00356     pixel dist = ( lineHeight - remaining ) / 2;
00357     p.drawText( ptX, ptY+height-upperBound.height()+dist-lineBound.height()-lineBound.top(),
00358                 QString( QChar( line ) ) );
00359 }
00360 
00361 void Artwork::calcCurlyBracket( const ContextStyle& style, const QChar chars[],
00362                                 luPt height, luPt charHeight )
00363 {
00364     uchar uppercorner = style.symbolTable().character( chars[0] );
00365     uchar lowercorner = style.symbolTable().character( chars[1] );
00366     //uchar line = style.symbolTable().character( chars[2] );
00367     uchar middle = style.symbolTable().character( chars[3] );
00368 
00369     QFont f = style.symbolTable().font( chars[0] );
00370     f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
00371     QFontMetrics fm( f );
00372     LuPtRect upperBound = fm.boundingRect( uppercorner );
00373     LuPtRect lowerBound = fm.boundingRect( lowercorner );
00374     //LuPtRect lineBound = fm.boundingRect( line );
00375     LuPtRect middleBound = fm.boundingRect( middle );
00376 
00377     setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
00378     luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+
00379                                               lowerBound.height()+
00380                                               middleBound.height() );
00381     //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
00382 
00383     //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
00384     setHeight( QMAX( edgeHeight, height ) );
00385 }
00386 
00387 void Artwork::drawBigCurlyBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
00388                                    luPixel x, luPixel y, luPt charHeight )
00389 {
00390     //QFont f = style.getSymbolFont();
00391     QFont f = style.symbolTable().font( chars[0] );
00392     f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
00393     p.setFont(f);
00394 
00395     uchar uppercorner = style.symbolTable().character( chars[0] );
00396     uchar lowercorner = style.symbolTable().character( chars[1] );
00397     uchar line = style.symbolTable().character( chars[2] );
00398     uchar middle = style.symbolTable().character( chars[3] );
00399 
00400     QFontMetrics fm(p.fontMetrics());
00401     QRect upperBound = fm.boundingRect(uppercorner);
00402     QRect lowerBound = fm.boundingRect(lowercorner);
00403     QRect middleBound = fm.boundingRect(middle);
00404     QRect lineBound = fm.boundingRect(line);
00405 
00406     pixel ptX = style.layoutUnitToPixelX( x );
00407     pixel ptY = style.layoutUnitToPixelY( y );
00408     pixel height = style.layoutUnitToPixelY( getHeight() );
00409 
00410     //p.setPen(Qt::gray);
00411     //p.drawRect(x, y, upperBound.width() + offset, height);
00412 
00413     p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
00414     p.drawText( ptX, ptY+(height-middleBound.height())/2-middleBound.top(),
00415                 QString( QChar( middle ) ) );
00416     p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
00417                 QString( QChar( lowercorner ) ) );
00418 
00419     // for printing
00420     // If the world was perfect and the urw-symbol font correct
00421     // this could be 0.
00422     //lu safety = lineBound.height() / 10;
00423     pixel safety = 0;
00424 
00425     pixel lineHeight = lineBound.height() - safety;
00426     pixel gap = height/2 - upperBound.height() - middleBound.height() / 2;
00427 
00428     if (gap > 0) {
00429         QString ch = QString(QChar(line));
00430         int lineCount = qRound( gap / lineHeight ) + 1;
00431 
00432         pixel start = (height - middleBound.height()) / 2 + safety;
00433         for (int i = 0; i < lineCount; i++) {
00434             p.drawText( ptX, ptY-lineBound.top()+QMAX( start-(i+1)*lineHeight,
00435                                                        upperBound.width() ),
00436                         ch );
00437         }
00438 
00439         start = (height + middleBound.height()) / 2 - safety;
00440         for (int i = 0; i < lineCount; i++) {
00441             p.drawText( ptX, ptY-lineBound.top()+QMIN( start+i*lineHeight,
00442                                                        height-upperBound.width()-lineBound.height() ),
00443                         ch );
00444         }
00445     }
00446 }
00447 
00448 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys