lib

fontstyle.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
00003    Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qpainter.h>
00022 #include <qpen.h>
00023 #include <qfontdatabase.h>
00024 #include <qapplication.h>
00025 
00026 #include <kstaticdeleter.h>
00027 #include <klocale.h>
00028 #include <kstandarddirs.h>
00029 #include <kio/netaccess.h>
00030 #include <kio/job.h>
00031 #include <kmessagebox.h>
00032 
00033 #include "fontstyle.h"
00034 
00035 
00036 KFORMULA_NAMESPACE_BEGIN
00037 
00038 #include "unicodetable.cc"
00039 
00040 bool FontStyle::m_installed = false;
00041 
00042 bool FontStyle::init( ContextStyle* style, bool install )
00043 {
00044     if (!m_installed && install)
00045         installFonts();
00046     m_symbolTable.init( style->getMathFont() );
00047 
00048     return true;
00049 }
00050 
00051 // Cache the family list from QFontDatabase after fixing it up (no foundry, lowercase)
00052 class FontList {
00053 public:
00054     FontList() {
00055         QFontDatabase db;
00056         const QStringList lst = db.families();
00057         for ( QStringList::const_iterator it = lst.begin(), end = lst.end() ; it != end ; ++it ) {
00058             const QString name = *it;
00059             int i = name.find('[');
00060             QString family = name;
00061             // Remove foundry
00062             if ( i > -1 ) {
00063                 const int li = name.findRev(']');
00064                 if (i < li) {
00065                     if (name[i - 1] == ' ')
00066                         i--;
00067                     family = name.left(i);
00068                 }
00069             }
00070             m_fontNames.append( family.lower() );
00071         }
00072     }
00073     bool hasFont( const QString& fontName ) const {
00074         return m_fontNames.find( fontName ) != m_fontNames.end();
00075     }
00076     QStringList m_fontNames;
00077 };
00078 static FontList* s_fontList = 0;
00079 static KStaticDeleter<FontList> s_fontList_sd;
00080 
00081 void FontStyle::testFont( QStringList& missing, const QString& fontName ) {
00082     if ( !s_fontList )
00083         s_fontList_sd.setObject( s_fontList, new FontList() );
00084     if ( !s_fontList->hasFont( fontName ) )  {
00085         kdWarning(39001) << "Font '" << fontName << "' not found" << endl;
00086         missing.append( fontName );
00087     }
00088 }
00089 
00090 
00091 QStringList FontStyle::missingFonts( bool install )
00092 {
00093     if (!m_installed && install)
00094         installFonts();
00095 
00096     QStringList missing = missingFontsInternal();
00097     return missing;
00098 }
00099 
00100 QStringList FontStyle::missingFontsInternal()
00101 {
00102     QStringList missing;
00103 
00104     testFont( missing, "cmex10" );
00105     testFont( missing, "arev sans");
00106 
00107     return missing;
00108 }
00109 
00110 void FontStyle::installFonts()
00111 {
00112     if (m_installed)
00113         return;
00114     QStringList missing = missingFontsInternal();
00115     if (!missing.isEmpty())
00116     {
00117         QStringList urlList;
00118         for (QStringList::iterator it = missing.begin(); it != missing.end(); ++it)
00119         {
00120             if ( *it == "arev sans" ) {
00121                 if (!KIO::NetAccess::exists("fonts:/Personal/Arev.ttf", true, NULL))
00122                     urlList.append(locate("data", "kformula/fonts/Arev.ttf"));
00123                 if (!KIO::NetAccess::exists("fonts:/Personal/ArevIt.ttf", true, NULL))
00124                     urlList.append(locate("data", "kformula/fonts/ArevIt.ttf"));
00125                 if (!KIO::NetAccess::exists("fonts:/Personal/ArevBd.ttf", true, NULL))
00126                     urlList.append(locate("data", "kformula/fonts/ArevBd.ttf"));
00127                 if (!KIO::NetAccess::exists("fonts:/Personal/ArevBI.ttf", true, NULL))
00128                     urlList.append(locate("data", "kformula/fonts/ArevBI.ttf"));
00129             }
00130             else {
00131                 if (!KIO::NetAccess::exists("fonts:/Personal/" + *it + ".ttf", true, NULL))
00132                     urlList.append(locate("data", "kformula/fonts/" + *it + ".ttf"));
00133             }
00134         }
00135         KIO::copy(urlList, "fonts:/Personal/", false);
00136         KMessageBox::information(qApp->mainWidget(), 
00137                                  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"));
00138     }
00139     m_installed = true;
00140 }
00141 
00142 Artwork* FontStyle::createArtwork( SymbolType type ) const
00143 {
00144     return new Artwork( type );
00145 }
00146 
00147 // We claim that all chars come from the same font.
00148 // It's up to the font tables to ensure this.
00149 const QChar leftRoundBracket[] = {
00150     0x30, // uppercorner
00151     0x40, // lowercorner
00152     0x42  // line
00153 };
00154 const QChar leftSquareBracket[] = {
00155     0x32, // uppercorner
00156     0x34, // lowercorner
00157     0x36  // line
00158 };
00159 const QChar leftCurlyBracket[] = {
00160     0x38, // uppercorner
00161     0x3A, // lowercorner
00162     0x3E, // line
00163     0x3C  // middle
00164 };
00165 
00166 const QChar leftLineBracket[] = {
00167     0x36, // line
00168     0x36, // line
00169     0x36  // line
00170 };
00171 const QChar rightLineBracket[] = {
00172     0x37, // line
00173     0x37, // line
00174     0x37  // line
00175 };
00176 
00177 const QChar rightRoundBracket[] = {
00178     0x31, // uppercorner
00179     0x41, // lowercorner
00180     0x43  // line
00181 };
00182 const QChar rightSquareBracket[] = {
00183     0x33, // uppercorner
00184     0x35, // lowercorner
00185     0x37  // line
00186 };
00187 const QChar rightCurlyBracket[] = {
00188     0x39, // uppercorner
00189     0x3B, // lowercorner
00190     0x3E, // line
00191     0x3D  // middle
00192 };
00193 
00194 
00195 static const char cmex_LeftSquareBracket = 163;
00196 static const char cmex_RightSquareBracket = 164;
00197 static const char cmex_LeftCurlyBracket = 169;
00198 static const char cmex_RightCurlyBracket = 170;
00199 static const char cmex_LeftCornerBracket = 173;
00200 static const char cmex_RightCornerBracket = 174;
00201 static const char cmex_LeftRoundBracket = 161;
00202 static const char cmex_RightRoundBracket = 162;
00203 static const char cmex_SlashBracket = 177;
00204 static const char cmex_BackSlashBracket = 178;
00205 //static const char cmex_LeftLineBracket = 0x4b;
00206 //static const char cmex_RightLineBracket = 0x4b;
00207 
00208 // use the big symbols here
00209 static const char cmex_Int = 90;
00210 static const char cmex_Sum = 88;
00211 static const char cmex_Prod = 89;
00212 
00213 
00214 // cmex is a special font with symbols in four sizes.
00215 static short cmex_nextchar( short ch )
00216 {
00217     switch ( ch ) {
00218     case 161: return 179;
00219     case 162: return 180;
00220     case 163: return 104;
00221     case 164: return 105;
00222     case 169: return 110;
00223     case 170: return 111;
00224     case 165: return 106;
00225     case 166: return 107;
00226     case 167: return 108;
00227     case 168: return 109;
00228     case 173: return 68;
00229     case 174: return 69;
00230     case 177: return 46;
00231     case 178: return 47;
00232 
00233     case 179: return 181;
00234     case 180: return 182;
00235     case 104: return 183;
00236     case 105: return 184;
00237     case 110: return 189;
00238     case 111: return 190;
00239     case 106: return 185;
00240     case 107: return 186;
00241     case 108: return 187;
00242     case 109: return 188;
00243     case 68: return 191;
00244     case 69: return 192;
00245     case 46: return 193;
00246     case 47: return 194;
00247 
00248     case 181: return 195;
00249     case 182: return 33;
00250     case 183: return 34;
00251     case 184: return 35;
00252     case 189: return 40;
00253     case 190: return 41;
00254     case 185: return 36;
00255     case 186: return 37;
00256     case 187: return 38;
00257     case 188: return 39;
00258     case 191: return 42;
00259     case 192: return 43;
00260     case 193: return 44;
00261     case 194: return 45;
00262     }
00263     return 0;
00264 }
00265 
00266 bool Artwork::calcCMDelimiterSize( const ContextStyle& context,
00267                                      uchar c,
00268                                      luPt fontSize,
00269                                      luPt parentSize )
00270 {
00271     QFont f( "cmex10" );
00272     f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
00273     QFontMetrics fm( f );
00274 
00275     for ( char i=1; c != 0; ++i ) {
00276         LuPixelRect bound = fm.boundingRect( c );
00277 
00278         luPt height = context.ptToLayoutUnitPt( bound.height() );
00279         if ( height >= parentSize ) {
00280             luPt width = context.ptToLayoutUnitPt( fm.width( c ) );
00281             luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
00282 
00283             cmChar = c;
00284 
00285             setHeight( height );
00286             setWidth( width );
00287             setBaseline( baseline );
00288 
00289             return true;
00290         }
00291         c = cmex_nextchar( c );
00292     }
00293 
00294     // Build it up from pieces.
00295     return false;
00296 }
00297 
00298 
00299 void Artwork::calcLargest( const ContextStyle& context,
00300                              uchar c, luPt fontSize )
00301 {
00302     QFont f( "cmex10" );
00303     f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
00304     QFontMetrics fm( f );
00305 
00306     cmChar = c;
00307     for ( ;; ) {
00308         c = cmex_nextchar( c );
00309         if ( c == 0 ) {
00310             break;
00311         }
00312         cmChar = c;
00313     }
00314 
00315     LuPixelRect bound = fm.boundingRect( cmChar );
00316 
00317     luPt height = context.ptToLayoutUnitPt( bound.height() );
00318     luPt width = context.ptToLayoutUnitPt( fm.width( cmChar ) );
00319     luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
00320 
00321     setHeight( height );
00322     setWidth( width );
00323     setBaseline( baseline );
00324 }
00325 
00326 
00327 void Artwork::drawCMDelimiter( QPainter& painter, const ContextStyle& style,
00328                                  luPixel x, luPixel y,
00329                                  luPt height )
00330 {
00331     QFont f( "cmex10" );
00332     f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
00333 
00334     painter.setFont( f );
00335     painter.drawText( style.layoutUnitToPixelX( x ),
00336                       style.layoutUnitToPixelY( y + getBaseline() ),
00337                       QString( QChar( cmChar ) ) );
00338 
00339     // Debug
00340 #if 0
00341     QFontMetrics fm( f );
00342     LuPixelRect bound = fm.boundingRect( cmChar );
00343     painter.setBrush(Qt::NoBrush);
00344     painter.setPen(Qt::green);
00345     painter.drawRect( style.layoutUnitToPixelX( x ),
00346                       style.layoutUnitToPixelY( y ),
00347                       fm.width( cmChar ),
00348                       bound.height() );
00349 #endif
00350 }
00351 
00352 
00353 Artwork::Artwork(SymbolType t)
00354     : baseline( -1 ), type(t)
00355 {
00356 }
00357 
00358 
00359 void Artwork::calcSizes( const ContextStyle& style,
00360                            ContextStyle::TextStyle tstyle,
00361                            double factor,
00362                            luPt parentSize )
00363 {
00364     setBaseline( -1 );
00365     cmChar = -1;
00366     luPt mySize = style.getAdjustedSize( tstyle, factor );
00367     switch (getType()) {
00368     case LeftSquareBracket:
00369         if ( calcCMDelimiterSize( style, cmex_LeftSquareBracket,
00370                                   mySize, parentSize ) ) {
00371             return;
00372         }
00373         calcRoundBracket( style, leftSquareBracket, parentSize, mySize );
00374         break;
00375     case RightSquareBracket:
00376         if ( calcCMDelimiterSize( style, cmex_RightSquareBracket,
00377                                   mySize, parentSize ) ) {
00378             return;
00379         }
00380         calcRoundBracket( style, rightSquareBracket, parentSize, mySize );
00381         break;
00382     case LeftLineBracket:
00383         calcRoundBracket( style, leftLineBracket, parentSize, mySize );
00384         setWidth( getWidth()/2 );
00385         break;
00386     case RightLineBracket:
00387         calcRoundBracket( style, rightLineBracket, parentSize, mySize );
00388         setWidth( getWidth()/2 );
00389         break;
00390     case SlashBracket:
00391         if ( calcCMDelimiterSize( style, cmex_SlashBracket,
00392                                   mySize, parentSize ) ) {
00393             return;
00394         }
00395         calcLargest( style, cmex_SlashBracket, mySize );
00396         break;
00397     case BackSlashBracket:
00398         if ( calcCMDelimiterSize( style, cmex_BackSlashBracket,
00399                                   mySize, parentSize ) ) {
00400             return;
00401         }
00402         calcLargest( style, cmex_BackSlashBracket, mySize );
00403         break;
00404     case LeftCornerBracket:
00405         if ( calcCMDelimiterSize( style, cmex_LeftCornerBracket,
00406                                   mySize, parentSize ) ) {
00407             return;
00408         }
00409         calcLargest( style, cmex_LeftCornerBracket, mySize );
00410         break;
00411     case RightCornerBracket:
00412         if ( calcCMDelimiterSize( style, cmex_RightCornerBracket,
00413                                   mySize, parentSize ) ) {
00414             return;
00415         }
00416         calcLargest( style, cmex_RightCornerBracket, mySize );
00417         break;
00418     case LeftRoundBracket:
00419         if ( calcCMDelimiterSize( style, cmex_LeftRoundBracket,
00420                                   mySize, parentSize ) ) {
00421             return;
00422         }
00423         calcRoundBracket( style, leftRoundBracket, parentSize, mySize );
00424         break;
00425     case RightRoundBracket:
00426         if ( calcCMDelimiterSize( style, cmex_RightRoundBracket,
00427                                   mySize, parentSize ) ) {
00428             return;
00429         }
00430         calcRoundBracket( style, rightRoundBracket, parentSize, mySize );
00431         break;
00432     case EmptyBracket:
00433         setHeight(parentSize);
00434         //setWidth(style.getEmptyRectWidth());
00435         setWidth(0);
00436         break;
00437     case LeftCurlyBracket:
00438         if ( calcCMDelimiterSize( style, cmex_LeftCurlyBracket,
00439                                   mySize, parentSize ) ) {
00440             return;
00441         }
00442         calcCurlyBracket( style, leftCurlyBracket, parentSize, mySize );
00443         break;
00444     case RightCurlyBracket:
00445         if ( calcCMDelimiterSize( style, cmex_RightCurlyBracket,
00446                                   mySize, parentSize ) ) {
00447             return;
00448         }
00449         calcCurlyBracket( style, rightCurlyBracket, parentSize, mySize );
00450         break;
00451     case Integral:
00452         calcCharSize( style, style.getBracketFont(), mySize, cmex_Int );
00453         break;
00454     case Sum:
00455         calcCharSize( style, style.getBracketFont(), mySize, cmex_Sum );
00456         break;
00457     case Product:
00458         calcCharSize( style, style.getBracketFont(), mySize, cmex_Prod );
00459         break;
00460     }
00461 }
00462 
00463 void Artwork::calcSizes( const ContextStyle& style,
00464                          ContextStyle::TextStyle tstyle,
00465                          double factor )
00466 {
00467     luPt mySize = style.getAdjustedSize( tstyle, factor );
00468     switch (type) {
00469     case LeftSquareBracket:
00470         calcCharSize(style, mySize, leftSquareBracketChar);
00471         break;
00472     case RightSquareBracket:
00473         calcCharSize(style, mySize, rightSquareBracketChar);
00474         break;
00475     case LeftLineBracket:
00476     case RightLineBracket:
00477         calcCharSize(style, mySize, verticalLineChar);
00478         break;
00479     case SlashBracket:
00480         calcCharSize(style, mySize, slashChar);
00481         break;
00482     case BackSlashBracket:
00483         calcCharSize(style, mySize, backSlashChar);
00484         break;
00485     case LeftCornerBracket:
00486         calcCharSize(style, mySize, leftAngleBracketChar);
00487         break;
00488     case RightCornerBracket:
00489         calcCharSize(style, mySize, rightAngleBracketChar);
00490         break;
00491     case LeftRoundBracket:
00492         calcCharSize(style, mySize, leftParenthesisChar);
00493         break;
00494     case RightRoundBracket:
00495         calcCharSize(style, mySize, rightParenthesisChar);
00496         break;
00497     case EmptyBracket:
00498         //calcCharSize(style, mySize, spaceChar);
00499         setHeight(0);
00500         //setWidth(style.getEmptyRectWidth());
00501         setWidth(0);
00502         break;
00503     case LeftCurlyBracket:
00504         calcCharSize(style, mySize, leftCurlyBracketChar);
00505         break;
00506     case RightCurlyBracket:
00507         calcCharSize(style, mySize, rightCurlyBracketChar);
00508         break;
00509     case Integral:
00510     case Sum:
00511     case Product:
00512         break;
00513     }
00514 }
00515 
00516 
00517 void Artwork::draw(QPainter& painter, const LuPixelRect& /*r*/,
00518                    const ContextStyle& context, ContextStyle::TextStyle tstyle,
00519                    StyleAttributes& style, const LuPixelPoint& parentOrigin)
00520 {
00521     luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
00522     luPixel myX = parentOrigin.x() + getX();
00523     luPixel myY = parentOrigin.y() + getY();
00524     /*
00525     if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
00526         return;
00527     */
00528 
00529     painter.setPen(context.getDefaultColor());
00530 
00531     switch (type) {
00532     case LeftSquareBracket:
00533         drawCharacter(painter, context, myX, myY, mySize, leftSquareBracketChar);
00534         break;
00535     case RightSquareBracket:
00536         drawCharacter(painter, context, myX, myY, mySize, rightSquareBracketChar);
00537         break;
00538     case LeftCurlyBracket:
00539         drawCharacter(painter, context, myX, myY, mySize, leftCurlyBracketChar);
00540         break;
00541     case RightCurlyBracket:
00542         drawCharacter(painter, context, myX, myY, mySize, rightCurlyBracketChar);
00543         break;
00544     case LeftLineBracket:
00545     case RightLineBracket:
00546         drawCharacter(painter, context, myX, myY, mySize, verticalLineChar);
00547         break;
00548     case SlashBracket:
00549         drawCharacter(painter, context, myX, myY, mySize, slashChar);
00550         break;
00551     case BackSlashBracket:
00552         drawCharacter(painter, context, myX, myY, mySize, backSlashChar);
00553         break;
00554     case LeftCornerBracket:
00555         drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
00556         break;
00557     case RightCornerBracket:
00558         drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
00559         break;
00560     case LeftRoundBracket:
00561         drawCharacter(painter, context, myX, myY, mySize, leftParenthesisChar);
00562         break;
00563     case RightRoundBracket:
00564         drawCharacter(painter, context, myX, myY, mySize, rightParenthesisChar);
00565         break;
00566     case EmptyBracket:
00567         break;
00568     case Integral:
00569     case Sum:
00570     case Product:
00571         break;
00572     }
00573 }
00574 
00575 void Artwork::draw(QPainter& painter, const LuPixelRect& ,
00576                      const ContextStyle& context, ContextStyle::TextStyle tstyle,
00577                      StyleAttributes& style, luPt , const LuPixelPoint& origin)
00578 {
00579     luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
00580     luPixel myX = origin.x() + getX();
00581     luPixel myY = origin.y() + getY();
00582     /*
00583     if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
00584         return;
00585     */
00586 
00587     painter.setPen(context.getDefaultColor());
00588 
00589     switch (getType()) {
00590     case LeftSquareBracket:
00591         if ( cmChar != -1 ) {
00592             drawCMDelimiter( painter, context, myX, myY, mySize );
00593         }
00594         else {
00595             drawBigRoundBracket( painter, context, leftSquareBracket, myX, myY, mySize );
00596         }
00597         break;
00598     case RightSquareBracket:
00599         if ( cmChar != -1 ) {
00600             drawCMDelimiter( painter, context, myX, myY, mySize );
00601         }
00602         else {
00603             drawBigRoundBracket( painter, context, rightSquareBracket, myX, myY, mySize );
00604         }
00605         break;
00606     case LeftCurlyBracket:
00607         if ( cmChar != -1 ) {
00608             drawCMDelimiter( painter, context, myX, myY, mySize );
00609         }
00610         else {
00611             drawBigCurlyBracket( painter, context, leftCurlyBracket, myX, myY, mySize );
00612         }
00613         break;
00614     case RightCurlyBracket:
00615         if ( cmChar != -1 ) {
00616             drawCMDelimiter( painter, context, myX, myY, mySize );
00617         }
00618         else {
00619             drawBigCurlyBracket( painter, context, rightCurlyBracket, myX, myY, mySize );
00620         }
00621         break;
00622     case LeftLineBracket: {
00623         luPixel halfWidth = getWidth()/2;
00624         drawBigRoundBracket( painter, context, leftLineBracket,
00625                              myX-halfWidth, myY, mySize );
00626     }
00627         break;
00628     case RightLineBracket: {
00629         luPixel halfWidth = getWidth()/2;
00630         drawBigRoundBracket( painter, context, rightLineBracket,
00631                              myX-halfWidth, myY, mySize );
00632     }
00633         break;
00634     case SlashBracket:
00635         if ( cmChar != -1 ) {
00636             drawCMDelimiter( painter, context, myX, myY, mySize );
00637         }
00638         break;
00639     case BackSlashBracket:
00640         if ( cmChar != -1 ) {
00641             drawCMDelimiter( painter, context, myX, myY, mySize );
00642         }
00643         break;
00644     case LeftCornerBracket:
00645         if ( cmChar != -1 ) {
00646             drawCMDelimiter( painter, context, myX, myY, mySize );
00647         }
00648         else drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
00649         break;
00650     case RightCornerBracket:
00651         if ( cmChar != -1 ) {
00652             drawCMDelimiter( painter, context, myX, myY, mySize );
00653         }
00654         else drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
00655         break;
00656     case LeftRoundBracket:
00657         if ( cmChar != -1 ) {
00658             drawCMDelimiter( painter, context, myX, myY, mySize );
00659         }
00660         else {
00661             drawBigRoundBracket( painter, context, leftRoundBracket, myX, myY, mySize );
00662         }
00663         break;
00664     case RightRoundBracket:
00665         if ( cmChar != -1 ) {
00666             drawCMDelimiter( painter, context, myX, myY, mySize );
00667         }
00668         else {
00669             drawBigRoundBracket( painter, context, rightRoundBracket, myX, myY, mySize );
00670         }
00671         break;
00672     case EmptyBracket:
00673         break;
00674     case Integral:
00675         drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Int);
00676         break;
00677     case Sum:
00678         drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Sum);
00679         break;
00680     case Product:
00681         drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Prod);
00682         break;
00683     }
00684 
00685     // debug
00686 //     painter.setBrush(Qt::NoBrush);
00687 //     painter.setPen(Qt::green);
00688 //     painter.drawRect( context.layoutUnitToPixelX( myX ),
00689 //                       context.layoutUnitToPixelY( myY ),
00690 //                       context.layoutUnitToPixelX( getWidth() ),
00691 //                       context.layoutUnitToPixelY( getHeight() ) );
00692 }
00693 
00694 void Artwork::calcCharSize( const ContextStyle& style, luPt height, QChar ch )
00695 {
00696     calcCharSize( style, style.getMathFont(), height, ch );
00697 }
00698 
00699 
00700 void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
00701                              luPixel x, luPixel y,
00702                              luPt height, QChar ch )
00703 {
00704     drawCharacter( painter, style, style.getMathFont(), x, y, height, ch );
00705 }
00706 
00707 
00708 void Artwork::calcCharSize( const ContextStyle& style, QFont f,
00709                             luPt height, QChar c )
00710 {
00711     f.setPointSizeFloat( style.layoutUnitPtToPt( height ) );
00712     //f.setPointSize( height );
00713     QFontMetrics fm(f);
00714     setWidth( style.ptToLayoutUnitPt( fm.width( c ) ) );
00715     LuPixelRect bound = fm.boundingRect( c );
00716     setHeight( style.ptToLayoutUnitPt( bound.height() ) );
00717     setBaseline( style.ptToLayoutUnitPt( -bound.top() ) );
00718 }
00719 
00720 
00721 void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
00722                              QFont f,
00723                              luPixel x, luPixel y, luPt height, uchar c )
00724 {
00725     f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
00726 
00727     painter.setFont( f );
00728     painter.drawText( style.layoutUnitToPixelX( x ),
00729                       style.layoutUnitToPixelY( y+getBaseline() ),
00730                       QString( QChar( c ) ) );
00731 }
00732 
00733 
00734 void Artwork::calcRoundBracket( const ContextStyle& style, const QChar chars[],
00735                                 luPt height, luPt charHeight )
00736 {
00737     uchar uppercorner = chars[0];
00738     uchar lowercorner = chars[1];
00739     //uchar line = style.symbolTable().character( chars[2] );
00740 
00741     QFont f = style.getBracketFont();
00742     f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
00743     QFontMetrics fm( f );
00744     LuPtRect upperBound = fm.boundingRect( uppercorner );
00745     LuPtRect lowerBound = fm.boundingRect( lowercorner );
00746     //LuPtRect lineBound = fm.boundingRect( line );
00747 
00748     setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
00749     luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+lowerBound.height() );
00750     //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
00751 
00752     //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
00753     setHeight( QMAX( edgeHeight, height ) );
00754 }
00755 
00756 void Artwork::drawBigRoundBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
00757                                    luPixel x, luPixel y, luPt charHeight )
00758 {
00759     uchar uppercorner = chars[0];
00760     uchar lowercorner = chars[1];
00761     uchar line = chars[2];
00762 
00763     QFont f = style.getBracketFont();
00764     f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
00765     p.setFont(f);
00766 
00767     QFontMetrics fm(f);
00768     QRect upperBound = fm.boundingRect(uppercorner);
00769     QRect lowerBound = fm.boundingRect(lowercorner);
00770     QRect lineBound = fm.boundingRect(line);
00771 
00772     pixel ptX = style.layoutUnitToPixelX( x );
00773     pixel ptY = style.layoutUnitToPixelY( y );
00774     pixel height = style.layoutUnitToPixelY( getHeight() );
00775 
00776 //     p.setPen( Qt::red );
00777 //     //p.drawRect( ptX, ptY, upperBound.width(), upperBound.height() + lowerBound.height() );
00778 //     p.drawRect( ptX, ptY, style.layoutUnitToPixelX( getWidth() ),
00779 //                 style.layoutUnitToPixelY( getHeight() ) );
00780 
00781 //     p.setPen( Qt::black );
00782     p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
00783     p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
00784                 QString( QChar( lowercorner ) ) );
00785 
00786     // for printing
00787     //pt safety = lineBound.height() / 10.0;
00788     pixel safety = 0;
00789 
00790     pixel gap = height - upperBound.height() - lowerBound.height();
00791     pixel lineHeight = lineBound.height() - safety;
00792     int lineCount = qRound( static_cast<double>( gap ) / lineHeight );
00793     pixel start = upperBound.height()-lineBound.top() - safety;
00794 
00795     for (int i = 0; i < lineCount; i++) {
00796         p.drawText( ptX, ptY+start+i*lineHeight, QString(QChar(line)));
00797     }
00798     pixel remaining = gap - lineCount*lineHeight;
00799     pixel dist = ( lineHeight - remaining ) / 2;
00800     p.drawText( ptX, ptY+height-upperBound.height()+dist-lineBound.height()-lineBound.top(),
00801                 QString( QChar( line ) ) );
00802 }
00803 
00804 void Artwork::calcCurlyBracket( const ContextStyle& style, const QChar chars[],
00805                                 luPt height, luPt charHeight )
00806 {
00807     uchar uppercorner = chars[0];
00808     uchar lowercorner = chars[1];
00809     //uchar line = style.symbolTable().character( chars[2] );
00810     uchar middle = chars[3];
00811 
00812     QFont f = style.getBracketFont();
00813     f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
00814     QFontMetrics fm( f );
00815     LuPtRect upperBound = fm.boundingRect( uppercorner );
00816     LuPtRect lowerBound = fm.boundingRect( lowercorner );
00817     //LuPtRect lineBound = fm.boundingRect( line );
00818     LuPtRect middleBound = fm.boundingRect( middle );
00819 
00820     setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
00821     luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+
00822                                               lowerBound.height()+
00823                                               middleBound.height() );
00824     //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
00825 
00826     //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
00827     setHeight( QMAX( edgeHeight, height ) );
00828 }
00829 
00830 void Artwork::drawBigCurlyBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
00831                                    luPixel x, luPixel y, luPt charHeight )
00832 {
00833     //QFont f = style.getSymbolFont();
00834     QFont f = style.getBracketFont();
00835     f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
00836     p.setFont(f);
00837 
00838     uchar uppercorner = chars[0];
00839     uchar lowercorner = chars[1];
00840     uchar line = chars[2];
00841     uchar middle = chars[3];
00842 
00843     QFontMetrics fm(p.fontMetrics());
00844     QRect upperBound = fm.boundingRect(uppercorner);
00845     QRect lowerBound = fm.boundingRect(lowercorner);
00846     QRect middleBound = fm.boundingRect(middle);
00847     QRect lineBound = fm.boundingRect(line);
00848 
00849     pixel ptX = style.layoutUnitToPixelX( x );
00850     pixel ptY = style.layoutUnitToPixelY( y );
00851     pixel height = style.layoutUnitToPixelY( getHeight() );
00852 
00853     //p.setPen(Qt::gray);
00854     //p.drawRect(x, y, upperBound.width() + offset, height);
00855 
00856     p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
00857     p.drawText( ptX, ptY+(height-middleBound.height())/2-middleBound.top(),
00858                 QString( QChar( middle ) ) );
00859     p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
00860                 QString( QChar( lowercorner ) ) );
00861 
00862     // for printing
00863     // If the world was perfect and the urw-symbol font correct
00864     // this could be 0.
00865     //lu safety = lineBound.height() / 10;
00866     pixel safety = 0;
00867 
00868     pixel lineHeight = lineBound.height() - safety;
00869     pixel gap = height/2 - upperBound.height() - middleBound.height() / 2;
00870 
00871     if (gap > 0) {
00872         QString ch = QString(QChar(line));
00873         int lineCount = qRound( gap / lineHeight ) + 1;
00874 
00875         pixel start = (height - middleBound.height()) / 2 + safety;
00876         for (int i = 0; i < lineCount; i++) {
00877             p.drawText( ptX, ptY-lineBound.top()+QMAX( start-(i+1)*lineHeight,
00878                                                        upperBound.width() ),
00879                         ch );
00880         }
00881 
00882         start = (height + middleBound.height()) / 2 - safety;
00883         for (int i = 0; i < lineCount; i++) {
00884             p.drawText( ptX, ptY-lineBound.top()+QMIN( start+i*lineHeight,
00885                                                        height-upperBound.width()-lineBound.height() ),
00886                         ch );
00887         }
00888     }
00889 }
00890 
00891 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys