font.cpp 7.27 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/**
 * This file is part of the html renderer for KDE.
 *
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2000 Dirk Mueller (mueller@kde.org)
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

#include "font.h"
#include "khtml_factory.h"
#include "khtml_settings.h"

#include <kdebug.h>
#include <kglobal.h>

#include <qpainter.h>
#include <qfontdatabase.h>
#include <qpaintdevicemetrics.h>

hyatt's avatar
hyatt committed
36 37
#include <algorithm>

38 39 40 41 42
using namespace khtml;

void Font::drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, int len,
        int toAdd, QPainter::TextDirection d, int from, int to, QColor bg ) const
{
43
#if APPLE_CHANGES
44
    p->drawText(x, y, str + pos, std::min(slen - pos, len), from, to, toAdd, bg, d, letterSpacing, wordSpacing);
darin's avatar
darin committed
45
#else
darin's avatar
darin committed
46 47
    QString qstr = QConstString(str, slen).string();

48 49 50 51 52 53 54 55 56
    //fprintf (stdout, "x %d, y %d, pos %d, qstr.length() %d, len %d, toAdd %d, from %d, to %d, str \"%s\"\n", x, y, pos, qstr.length(), len, toAdd, from, to, qstr.ascii());
    // hack for fonts that don't have a welldefined nbsp
    if ( !fontDef.hasNbsp ) {
        // str.setLength() always does a deep copy, so the replacement code below is safe.
        qstr.setLength( slen );
        QChar *uc = (QChar *)qstr.unicode();
        for( int i = 0; i < slen; i++ )
            if ( (uc+i)->unicode() == 0xa0 )
            *(uc+i) = ' ';
darin's avatar
darin committed
57
    }
darin's avatar
darin committed
58

59 60
    // ### fixme for RTL
    if ( !letterSpacing && !wordSpacing && !toAdd && from==-1 ) {
61 62
        // simply draw it
        p->drawText( x, y, qstr, pos, len, d );
63
    } else {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
        int numSpaces = 0;
        if ( toAdd ) {
            for( int i = 0; i < len; i++ )
            if ( str[i+pos].direction() == QChar::DirWS )
                numSpaces++;
        }
    
        if ( d == QPainter::RTL ) {
            x += width( str, slen, pos, len ) + toAdd;
        }
        for( int i = 0; i < len; i++ ) {
            int chw = fm.charWidth( qstr, pos+i );
            if ( letterSpacing )
                chw += letterSpacing;
            if ( (wordSpacing || toAdd) && str[i+pos].isSpace() ) {
                chw += wordSpacing;
                if ( numSpaces ) {
                    int a = toAdd/numSpaces;
                    chw += a;
                    toAdd -= a;
                    numSpaces--;
                }
            }
            if ( d == QPainter::RTL )
                x -= chw;
89 90 91 92 93
            if ( to==-1 || (i>=from && i<to) )
            {
                if ( bg.isValid() )
                    p->fillRect( x, y-fm.ascent(), chw, fm.height(), bg );

94
                p->drawText( x, y, qstr, pos+i, 1, d );
95
            }
96 97 98
            if ( d != QPainter::RTL )
                x += chw;
        }
99
    }
100
#endif
101 102
}

103
#if APPLE_CHANGES
darin's avatar
darin committed
104

rjw's avatar
 
rjw committed
105 106
float Font::floatWidth( QChar *chs, int slen, int pos, int len ) const
{
107
    return fm.floatWidth(chs, slen, pos, len, letterSpacing, wordSpacing);
rjw's avatar
 
rjw committed
108 109 110
}


111
void Font::floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, float *buffer) const
rjw's avatar
 
rjw committed
112
{
113
    fm.floatCharacterWidths(str, slen, pos, len, toAdd, buffer, letterSpacing, wordSpacing);
rjw's avatar
 
rjw committed
114 115
}

darin's avatar
darin committed
116
#endif
rjw's avatar
 
rjw committed
117

118 119
int Font::width( QChar *chs, int slen, int pos, int len ) const
{
120
#if APPLE_CHANGES
121 122 123
#ifndef ROUND_TO_INT
#define ROUND_TO_INT(x) (unsigned int)((x)+.5)
#endif
rjw's avatar
rjw committed
124 125
    return ROUND_TO_INT(fm.floatWidth(chs+pos, slen-pos, 0, len, letterSpacing, wordSpacing));
//    return fm.width(chs + pos, len);
darin's avatar
darin committed
126
#else
darin's avatar
darin committed
127
    QString qstr = QConstString(chs+pos, len).string();
darin's avatar
darin committed
128 129 130
    // hack for fonts that don't have a welldefined nbsp
    if ( !fontDef.hasNbsp ) {
	// str.setLength() always does a deep copy, so the replacement code below is safe.
darin's avatar
darin committed
131
	qstr.setLength( len );
darin's avatar
darin committed
132
	QChar *uc = (QChar *)qstr.unicode();
darin's avatar
darin committed
133 134 135
	for( int i = 0; i < len; i++ )
	    if ( (uc+i)->unicode() == 0xa0 )
		*(uc+i) = ' ';
darin's avatar
darin committed
136 137
    }

138
    // ### might be a little inaccurate
darin's avatar
darin committed
139
    int w = fm.width( qstr );
140 141

    if ( letterSpacing )
142
	    w += len*letterSpacing;
143

darin's avatar
darin committed
144
    if ( wordSpacing )
145 146 147 148 149
        // add amount
        for( int i = 0; i < len; i++ ) {
            if( chs[i+pos].isSpace() )
            w += wordSpacing;
        }
darin's avatar
darin committed
150

151
    return w;
darin's avatar
darin committed
152
#endif
153 154 155 156
}

int Font::width( QChar *chs, int slen, int pos ) const
{
157
#if APPLE_CHANGES
rjw's avatar
rjw committed
158 159
//    return ROUND_TO_INT(fm.floatWidth(chs, slen, pos, 1, letterSpacing, wordSpacing));
    return width(chs, slen, pos, 1);
darin's avatar
darin committed
160 161 162 163 164 165
#else
    int w;
    if ( !fontDef.hasNbsp && (chs+pos)->unicode() == 0xa0 )
	w = fm.width( QChar( ' ' ) );
    else
	w = fm.charWidth( QConstString( chs, slen).string(), pos );
166 167 168 169 170 171 172

    if ( letterSpacing )
	w += letterSpacing;

    if ( wordSpacing && (chs+pos)->isSpace() )
		w += wordSpacing;
    return w;
darin's avatar
darin committed
173
#endif
174 175 176 177 178 179 180 181 182
}


void Font::update( QPaintDeviceMetrics* devMetrics ) const
{
    f.setFamily( fontDef.family.isEmpty() ? KHTMLFactory::defaultHTMLSettings()->stdFontName() : fontDef.family );
    f.setItalic( fontDef.italic );
    f.setWeight( fontDef.weight );

183
#if APPLE_CHANGES
darin's avatar
darin committed
184 185
    f.setPixelSize(fontDef.size);
#else
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    QFontDatabase db;

    int size = fontDef.size;
    int lDpiY = kMax(devMetrics->logicalDpiY(), 96);

    // ok, now some magic to get a nice unscaled font
    // all other font properties should be set before this one!!!!
    if( !db.isSmoothlyScalable(f.family(), db.styleString(f)) )
    {
        QValueList<int> pointSizes = db.smoothSizes(f.family(), db.styleString(f));
        // lets see if we find a nice looking font, which is not too far away
        // from the requested one.
        // kdDebug(6080) << "khtml::setFontSize family = " << f.family() << " size requested=" << size << endl;

        QValueList<int>::Iterator it;
        float diff = 1; // ### 100% deviation
        float bestSize = 0;
        for( it = pointSizes.begin(); it != pointSizes.end(); ++it )
        {
            float newDiff = ((*it)*(lDpiY/72.) - float(size))/float(size);
            //kdDebug( 6080 ) << "smooth font size: " << *it << " diff=" << newDiff << endl;
            if(newDiff < 0) newDiff = -newDiff;
            if(newDiff < diff)
            {
                diff = newDiff;
                bestSize = *it;
            }
        }
        //kdDebug( 6080 ) << "best smooth font size: " << bestSize << " diff=" << diff << endl;
        if ( bestSize != 0 && diff < 0.2 ) // 20% deviation, otherwise we use a scaled font...
darin's avatar
darin committed
216
            size = (int)((bestSize*lDpiY) / 72);
217 218
    }

darin's avatar
darin committed
219 220 221
    // make sure we don't bust up X11
    size = KMAX(0, KMIN(255, size));

222 223 224
//      qDebug("setting font to %s, italic=%d, weight=%d, size=%d", fontDef.family.latin1(), fontDef.italic,
//   	   fontDef.weight, size );

darin's avatar
darin committed
225

226
    f.setPixelSize( size );
darin's avatar
darin committed
227
#endif
228 229

    fm = QFontMetrics( f );
darin's avatar
darin committed
230

231
#if !APPLE_CHANGES
darin's avatar
darin committed
232 233
    fontDef.hasNbsp = fm.inFont( 0xa0 );
#endif
234
}