00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qfont.h"
00025 #include "qpaintdevice.h"
00026 #include "qfontdatabase.h"
00027 #include "qfontmetrics.h"
00028 #include "qfontinfo.h"
00029 #include "qpainter.h"
00030 #include "qhash.h"
00031 #include "qdatastream.h"
00032 #include "qapplication.h"
00033 #include "qstringlist.h"
00034
00035 #include "qthread.h"
00036
00037 #include <private/qunicodetables_p.h>
00038 #include "qfont_p.h"
00039 #include <private/qfontengine_p.h>
00040 #include <private/qpainter_p.h>
00041 #include <private/qtextengine_p.h>
00042
00043 #ifdef Q_WS_X11
00044 #include "qx11info_x11.h"
00045 extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
00046 #endif
00047 #ifdef Q_WS_QWS
00048 #include "qscreen_qws.h"
00049 #endif
00050
00051
00052 #ifdef QFONTCACHE_DEBUG
00053 # define FC_DEBUG qDebug
00054 #else
00055 # define FC_DEBUG if (false) qDebug
00056 #endif
00057
00058
00059 bool QFontDef::exactMatch(const QFontDef &other) const
00060 {
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 if (pixelSize != -1 && other.pixelSize != -1) {
00080 if (pixelSize != other.pixelSize)
00081 return false;
00082 } else if (pointSize != -1 && other.pointSize != -1) {
00083 if (pointSize != other.pointSize)
00084 return false;
00085 } else {
00086 return false;
00087 }
00088
00089 if (!ignorePitch && !other.ignorePitch && fixedPitch != other.fixedPitch)
00090 return false;
00091
00092 if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
00093 return false;
00094
00095 QString this_family, this_foundry, other_family, other_foundry;
00096 QFontDatabase::parseFontName(family, this_foundry, this_family);
00097 QFontDatabase::parseFontName(other.family, other_foundry, other_family);
00098
00099 return (styleHint == other.styleHint
00100 && styleStrategy == other.styleStrategy
00101 && weight == other.weight
00102 && style == other.style
00103 && this_family == other_family
00104 && (this_foundry.isEmpty()
00105 || other_foundry.isEmpty()
00106 || this_foundry == other_foundry)
00107 #ifdef Q_WS_X11
00108 && addStyle == other.addStyle
00109 #endif
00110 );
00111 }
00112
00113 #ifdef Q_WS_WIN
00114 extern HDC shared_dc;
00115 #endif
00116
00117 extern bool qt_is_gui_used;
00118
00119 Q_GUI_EXPORT int qt_defaultDpi()
00120 {
00121 if (!qt_is_gui_used)
00122 return 75;
00123
00124 int dpi;
00125 #ifdef Q_WS_X11
00126 dpi = QX11Info::appDpiY();
00127 #elif defined(Q_WS_WIN)
00128 dpi = GetDeviceCaps(shared_dc,LOGPIXELSY);
00129 #elif defined(Q_WS_MAC)
00130 short hr;
00131 short mdpi;
00132 ScreenRes(&hr, &mdpi);
00133 dpi = int(mdpi);
00134 #elif defined(Q_WS_QWS)
00135 if (!qt_screen)
00136 return 72;
00137 QScreen *screen = qt_screen;
00138 const QList<QScreen*> subScreens = qt_screen->subScreens();
00139 if (!subScreens.isEmpty())
00140 screen = subScreens.at(0);
00141 dpi = qRound(screen->height() / double(screen->physicalHeight() / 25.4));
00142 #endif // Q_WS_X11
00143
00144 return dpi;
00145 }
00146
00147 QFontPrivate::QFontPrivate()
00148 : engineData(0), dpi(qt_defaultDpi()), screen(0),
00149 rawMode(false), underline(false), overline(false), strikeOut(false), kerning(true)
00150 {
00151 ref = 1;
00152 #ifdef Q_WS_X11
00153 screen = QX11Info::appScreen();
00154 #endif
00155 #ifdef Q_WS_WIN
00156 hdc = 0;
00157 #endif
00158 }
00159
00160 QFontPrivate::QFontPrivate(const QFontPrivate &other)
00161 : request(other.request), engineData(0), dpi(other.dpi), screen(other.screen),
00162 rawMode(other.rawMode), underline(other.underline), overline(other.overline),
00163 strikeOut(other.strikeOut), kerning(other.kerning)
00164 {
00165 ref = 1;
00166 #ifdef Q_WS_WIN
00167 hdc = other.hdc;
00168 #endif
00169 }
00170
00171 QFontPrivate::~QFontPrivate()
00172 {
00173 if (engineData)
00174 engineData->ref.deref();
00175 engineData = 0;
00176 }
00177
00178 void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
00179 {
00180 Q_ASSERT(other != 0);
00181
00182 dpi = other->dpi;
00183
00184 if ((mask & Complete) == Complete) return;
00185
00186
00187 if (! (mask & Family))
00188 request.family = other->request.family;
00189
00190 if (! (mask & Size)) {
00191 request.pointSize = other->request.pointSize;
00192 request.pixelSize = other->request.pixelSize;
00193 }
00194
00195 if (! (mask & StyleHint))
00196 request.styleHint = other->request.styleHint;
00197
00198 if (! (mask & StyleStrategy))
00199 request.styleStrategy = other->request.styleStrategy;
00200
00201 if (! (mask & Weight))
00202 request.weight = other->request.weight;
00203
00204 if (! (mask & Style))
00205 request.style = other->request.style;
00206
00207 if (! (mask & FixedPitch))
00208 request.fixedPitch = other->request.fixedPitch;
00209
00210 if (! (mask & Stretch))
00211 request.stretch = other->request.stretch;
00212
00213 if (! (mask & Underline))
00214 underline = other->underline;
00215
00216 if (! (mask & Overline))
00217 overline = other->overline;
00218
00219 if (! (mask & StrikeOut))
00220 strikeOut = other->strikeOut;
00221
00222 if (! (mask & Kerning))
00223 kerning = other->kerning;
00224 }
00225
00226
00227
00228
00229 QFontEngineData::QFontEngineData()
00230 {
00231 ref = 1;
00232 #if defined(Q_WS_X11) || defined(Q_WS_WIN)
00233 memset(engines, 0, QUnicodeTables::ScriptCount * sizeof(QFontEngine *));
00234 #else
00235 engine = 0;
00236 #endif // Q_WS_X11 || Q_WS_WIN
00237 }
00238
00239 QFontEngineData::~QFontEngineData()
00240 {
00241 #if defined(Q_WS_X11) || defined(Q_WS_WIN)
00242 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
00243 if (engines[i])
00244 engines[i]->ref.deref();
00245 engines[i] = 0;
00246 }
00247 #else
00248 if (engine)
00249 engine->ref.deref();
00250 engine = 0;
00251 #endif // Q_WS_X11 || Q_WS_WIN
00252 }
00253
00254
00255
00256
00435 void qt_font_tread_test()
00436 {
00437 if (QApplication::instance() && QThread::currentThread() != QApplication::instance()->thread())
00438 qWarning("QFont: It is not safe to use text and fonts outside the GUI thread");
00439 }
00440
00444 QFont::QFont(const QFont &font, QPaintDevice *pd)
00445 : resolve_mask(font.resolve_mask)
00446 {
00447 Q_ASSERT(pd != 0);
00448 int dpi = pd->logicalDpiY();
00449 #ifdef Q_WS_X11
00450 const QX11Info *info = qt_x11Info(pd);
00451 int screen = info ? info->screen() : 0;
00452 #else
00453 const int screen = 0;
00454 #endif
00455 if (font.d->dpi != dpi || font.d->screen != screen ) {
00456 d = new QFontPrivate(*font.d);
00457 d->dpi = dpi;
00458 d->screen = screen;
00459 } else {
00460 d = font.d;
00461 d->ref.ref();
00462 }
00463 #ifdef Q_WS_WIN
00464 if (pd->devType() == QInternal::Printer && pd->getDC())
00465 d->hdc = pd->getDC();
00466 #endif
00467 }
00468
00472 QFont::QFont(QFontPrivate *data)
00473 : resolve_mask(QFontPrivate::Complete)
00474 {
00475 qt_font_tread_test();
00476
00477 d = data;
00478 d->ref.ref();
00479 }
00480
00484 void QFont::detach()
00485 {
00486 if (d->ref == 1) {
00487 if (d->engineData)
00488 d->engineData->ref.deref();
00489 d->engineData = 0;
00490 return;
00491 }
00492
00493 qAtomicDetach(d);
00494 }
00495
00501 QFont::QFont()
00502 :d(QApplication::font().d), resolve_mask(0)
00503 {
00504 d->ref.ref();
00505 }
00506
00523 QFont::QFont(const QString &family, int pointSize, int weight, bool italic)
00524 :d(new QFontPrivate)
00525 {
00526 qt_font_tread_test();
00527
00528 resolve_mask = QFontPrivate::Family;
00529
00530 if (pointSize <= 0) {
00531 pointSize = 12;
00532 } else {
00533 resolve_mask |= QFontPrivate::Size;
00534 }
00535
00536 if (weight < 0) {
00537 weight = Normal;
00538 } else {
00539 resolve_mask |= QFontPrivate::Weight | QFontPrivate::Style;
00540 }
00541
00542 d->request.family = family;
00543 d->request.pointSize = qreal(pointSize);
00544 d->request.pixelSize = -1;
00545 d->request.weight = weight;
00546 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
00547 }
00548
00552 QFont::QFont(const QFont &font)
00553 {
00554 d = font.d;
00555 d->ref.ref();
00556 resolve_mask = font.resolve_mask;
00557 }
00558
00562 QFont::~QFont()
00563 {
00564 if (!d->ref.deref())
00565 delete d;
00566 }
00567
00571 QFont &QFont::operator=(const QFont &font)
00572 {
00573 qAtomicAssign(d, font.d);
00574 resolve_mask = font.resolve_mask;
00575 return *this;
00576 }
00577
00584 QString QFont::family() const
00585 {
00586 return d->request.family;
00587 }
00588
00602 void QFont::setFamily(const QString &family)
00603 {
00604 detach();
00605
00606 d->request.family = family;
00607 #if defined(Q_WS_X11)
00608 d->request.addStyle.clear();
00609 #endif // Q_WS_X11
00610
00611 resolve_mask |= QFontPrivate::Family;
00612 }
00613
00620 int QFont::pointSize() const
00621 {
00622 return qRound(d->request.pointSize);
00623 }
00624
00631 void QFont::setPointSize(int pointSize)
00632 {
00633 Q_ASSERT_X (pointSize > 0, "QFont::setPointSize", "point size must be greater than 0");
00634
00635 detach();
00636
00637 d->request.pointSize = qreal(pointSize);
00638 d->request.pixelSize = -1;
00639
00640 resolve_mask |= QFontPrivate::Size;
00641 }
00642
00650 void QFont::setPointSizeF(qreal pointSize)
00651 {
00652 Q_ASSERT_X(pointSize > 0.0, "QFont::setPointSizeF", "point size must be greater than 0");
00653
00654 detach();
00655
00656 d->request.pointSize = pointSize;
00657 d->request.pixelSize = -1;
00658
00659 resolve_mask |= QFontPrivate::Size;
00660 }
00661
00668 qreal QFont::pointSizeF() const
00669 {
00670 return d->request.pointSize;
00671 }
00672
00682 void QFont::setPixelSize(int pixelSize)
00683 {
00684 if (pixelSize <= 0) {
00685 qWarning("QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
00686 return;
00687 }
00688
00689 detach();
00690
00691 d->request.pixelSize = pixelSize;
00692 d->request.pointSize = -1;
00693
00694 resolve_mask |= QFontPrivate::Size;
00695 }
00696
00704 int QFont::pixelSize() const
00705 {
00706 return d->request.pixelSize;
00707 }
00708
00709 #ifdef QT3_SUPPORT
00710
00715 void QFont::setPixelSizeFloat(qreal pixelSize)
00716 {
00717 setPixelSize((int)pixelSize);
00718 }
00719 #endif
00720
00743 QFont::Style QFont::style() const
00744 {
00745 return (QFont::Style)d->request.style;
00746 }
00747
00748
00754 void QFont::setStyle(Style style)
00755 {
00756 detach();
00757
00758 d->request.style = style;
00759 resolve_mask |= QFontPrivate::Style;
00760 }
00761
00768 int QFont::weight() const
00769 {
00770 return d->request.weight;
00771 }
00772
00795 void QFont::setWeight(int weight)
00796 {
00797 Q_ASSERT_X(weight >= 0 && weight <= 99, "QFont::setWeight", "Weight must be between 0 and 99");
00798
00799 detach();
00800
00801 d->request.weight = weight;
00802 resolve_mask |= QFontPrivate::Weight;
00803 }
00804
00831 bool QFont::underline() const
00832 {
00833 return d->underline;
00834 }
00835
00842 void QFont::setUnderline(bool enable)
00843 {
00844 detach();
00845
00846 d->underline = enable;
00847 resolve_mask |= QFontPrivate::Underline;
00848 }
00849
00855 bool QFont::overline() const
00856 {
00857 return d->overline;
00858 }
00859
00865 void QFont::setOverline(bool enable)
00866 {
00867 detach();
00868
00869 d->overline = enable;
00870 resolve_mask |= QFontPrivate::Overline;
00871 }
00872
00878 bool QFont::strikeOut() const
00879 {
00880 return d->strikeOut;
00881 }
00882
00889 void QFont::setStrikeOut(bool enable)
00890 {
00891 detach();
00892
00893 d->strikeOut = enable;
00894 resolve_mask |= QFontPrivate::StrikeOut;
00895 }
00896
00902 bool QFont::fixedPitch() const
00903 {
00904 return d->request.fixedPitch;
00905 }
00906
00913 void QFont::setFixedPitch(bool enable)
00914 {
00915 detach();
00916
00917 d->request.fixedPitch = enable;
00918 d->request.ignorePitch = false;
00919 resolve_mask |= QFontPrivate::FixedPitch;
00920 }
00921
00927 bool QFont::kerning() const
00928 {
00929 return d->kerning;
00930 }
00931
00943 void QFont::setKerning(bool enable)
00944 {
00945 detach();
00946 d->kerning = enable;
00947 resolve_mask |= QFontPrivate::Kerning;
00948 }
00949
00958 QFont::StyleStrategy QFont::styleStrategy() const
00959 {
00960 return (StyleStrategy) d->request.styleStrategy;
00961 }
00962
00971 QFont::StyleHint QFont::styleHint() const
00972 {
00973 return (StyleHint) d->request.styleHint;
00974 }
00975
01046 void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
01047 {
01048 detach();
01049
01050 if ((resolve_mask & (QFontPrivate::StyleHint | QFontPrivate::StyleStrategy)) &&
01051 (StyleHint) d->request.styleHint == hint &&
01052 (StyleStrategy) d->request.styleStrategy == strategy)
01053 return;
01054
01055 d->request.styleHint = hint;
01056 d->request.styleStrategy = strategy;
01057 resolve_mask |= QFontPrivate::StyleHint;
01058 resolve_mask |= QFontPrivate::StyleStrategy;
01059
01060 #if defined(Q_WS_X11)
01061 d->request.addStyle.clear();
01062 #endif // Q_WS_X11
01063 }
01064
01070 void QFont::setStyleStrategy(StyleStrategy s)
01071 {
01072 detach();
01073
01074 if ((resolve_mask & QFontPrivate::StyleStrategy) &&
01075 s == (StyleStrategy)d->request.styleStrategy)
01076 return;
01077
01078 d->request.styleStrategy = s;
01079 resolve_mask |= QFontPrivate::StyleStrategy;
01080 }
01081
01082
01107 int QFont::stretch() const
01108 {
01109 return d->request.stretch;
01110 }
01111
01130 void QFont::setStretch(int factor)
01131 {
01132 if (factor < 1 || factor > 4000) {
01133 qWarning("QFont::setStretch: Parameter '%d' out of range", factor);
01134 return;
01135 }
01136
01137 detach();
01138
01139 if ((resolve_mask & QFontPrivate::Stretch) &&
01140 d->request.stretch == (uint)factor)
01141 return;
01142
01143 d->request.stretch = (uint)factor;
01144 resolve_mask |= QFontPrivate::Stretch;
01145 }
01146
01164 void QFont::setRawMode(bool enable)
01165 {
01166 detach();
01167
01168 if ((bool) d->rawMode == enable) return;
01169
01170 d->rawMode = enable;
01171 }
01172
01179 bool QFont::exactMatch() const
01180 {
01181 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01182 Q_ASSERT(engine != 0);
01183 return (d->rawMode
01184 ? engine->type() != QFontEngine::Box
01185 : d->request.exactMatch(engine->fontDef));
01186 }
01187
01198 bool QFont::operator==(const QFont &f) const
01199 {
01200 return (f.d == d
01201 || (f.d->request == d->request
01202 && f.d->request.pointSize == d->request.pointSize
01203 && f.d->underline == d->underline
01204 && f.d->overline == d->overline
01205 && f.d->strikeOut == d->strikeOut
01206 && f.d->kerning == d->kerning));
01207 }
01208
01209
01221 bool QFont::operator<(const QFont &f) const
01222 {
01223 if (f.d == d) return false;
01224
01225 QFontDef &r1 = f.d->request;
01226 QFontDef &r2 = d->request;
01227 if (r1.pointSize != r2.pointSize) return r1.pointSize < r2.pointSize;
01228 if (r1.pixelSize != r2.pixelSize) return r1.pixelSize < r2.pixelSize;
01229 if (r1.weight != r2.weight) return r1.weight < r2.weight;
01230 if (r1.style != r2.style) return r1.style < r2.style;
01231 if (r1.stretch != r2.stretch) return r1.stretch < r2.stretch;
01232 if (r1.styleHint != r2.styleHint) return r1.styleHint < r2.styleHint;
01233 if (r1.styleStrategy != r2.styleStrategy) return r1.styleStrategy < r2.styleStrategy;
01234 if (r1.family != r2.family) return r1.family < r2.family;
01235 #ifdef Q_WS_X11
01236 if (r1.addStyle != r2.addStyle) return r1.addStyle < r2.addStyle;
01237 #endif // Q_WS_X11
01238
01239 int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
01240 int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
01241 return f1attrs < f2attrs;
01242 }
01243
01244
01255 bool QFont::operator!=(const QFont &f) const
01256 {
01257 return !(operator==(f));
01258 }
01259
01263 QFont::operator QVariant() const
01264 {
01265 return QVariant(QVariant::Font, this);
01266 }
01267
01275 bool QFont::isCopyOf(const QFont & f) const
01276 {
01277 return d == f.d;
01278 }
01279
01286 bool QFont::rawMode() const
01287 {
01288 return d->rawMode;
01289 }
01290
01295 QFont QFont::resolve(const QFont &other) const
01296 {
01297 if (*this == other
01298 && (resolve_mask == other.resolve_mask || resolve_mask == 0)
01299 && d->dpi == other.d->dpi) {
01300 QFont o = other;
01301 o.resolve_mask = resolve_mask;
01302 return o;
01303 }
01304
01305 QFont font(*this);
01306 font.detach();
01307 font.d->resolve(resolve_mask, other.d);
01308
01309 return font;
01310 }
01311
01322 #ifdef QT3_SUPPORT
01323
01328 QFont QFont::defaultFont()
01329 {
01330 return QApplication::font();
01331 }
01332
01337 void QFont::setDefaultFont(const QFont &f)
01338 {
01339 QApplication::setFont(f);
01340 }
01341
01355 #endif
01356
01357
01358
01359
01360
01361
01362
01363
01364 typedef QHash<QString, QStringList> QFontSubst;
01365 Q_GLOBAL_STATIC(QFontSubst, globalFontSubst)
01366
01367
01368 static void initFontSubst()
01369 {
01370
01371 static const char *initTbl[] = {
01372
01373 #if defined(Q_WS_X11)
01374 "arial", "helvetica",
01375 "times new roman", "times",
01376 "courier new", "courier",
01377 "sans serif", "helvetica",
01378 #elif defined(Q_WS_WIN)
01379 "times", "times new roman",
01380 "courier", "courier new",
01381 "helvetica", "arial",
01382 "sans serif", "arial",
01383 #endif
01384
01385 0, 0
01386 };
01387
01388 QFontSubst *fontSubst = globalFontSubst();
01389 Q_ASSERT(fontSubst != 0);
01390 if (!fontSubst->isEmpty())
01391 return;
01392
01393 for (int i=0; initTbl[i] != 0; i += 2) {
01394 QStringList &list = (*fontSubst)[QString::fromLatin1(initTbl[i])];
01395 list.append(QString::fromLatin1(initTbl[i+1]));
01396 }
01397 }
01398
01399
01411 QString QFont::substitute(const QString &familyName)
01412 {
01413 initFontSubst();
01414
01415 QFontSubst *fontSubst = globalFontSubst();
01416 Q_ASSERT(fontSubst != 0);
01417 QFontSubst::ConstIterator it = fontSubst->constFind(familyName.toLower());
01418 if (it != fontSubst->constEnd() && !(*it).isEmpty())
01419 return (*it).first();
01420
01421 return familyName;
01422 }
01423
01424
01434 QStringList QFont::substitutes(const QString &familyName)
01435 {
01436 initFontSubst();
01437
01438 QFontSubst *fontSubst = globalFontSubst();
01439 Q_ASSERT(fontSubst != 0);
01440 return fontSubst->value(familyName.toLower(), QStringList());
01441 }
01442
01443
01450 void QFont::insertSubstitution(const QString &familyName,
01451 const QString &substituteName)
01452 {
01453 initFontSubst();
01454
01455 QFontSubst *fontSubst = globalFontSubst();
01456 Q_ASSERT(fontSubst != 0);
01457 QStringList &list = (*fontSubst)[familyName.toLower()];
01458 QString s = substituteName.toLower();
01459 if (!list.contains(s))
01460 list.append(s);
01461 }
01462
01463
01470 void QFont::insertSubstitutions(const QString &familyName,
01471 const QStringList &substituteNames)
01472 {
01473 initFontSubst();
01474
01475 QFontSubst *fontSubst = globalFontSubst();
01476 Q_ASSERT(fontSubst != 0);
01477 QStringList &list = (*fontSubst)[familyName.toLower()];
01478 QStringList::ConstIterator it = substituteNames.constBegin();
01479 while (it != substituteNames.constEnd()) {
01480 QString s = (*it).toLower();
01481 if (!list.contains(s))
01482 list.append(s);
01483 it++;
01484 }
01485 }
01486
01487
01493 void QFont::removeSubstitution(const QString &familyName)
01494 {
01495
01496 initFontSubst();
01497
01498 QFontSubst *fontSubst = globalFontSubst();
01499 Q_ASSERT(fontSubst != 0);
01500 fontSubst->remove(familyName.toLower());
01501 }
01502
01503
01509 QStringList QFont::substitutions()
01510 {
01511 initFontSubst();
01512
01513 QFontSubst *fontSubst = globalFontSubst();
01514 Q_ASSERT(fontSubst != 0);
01515 QStringList ret;
01516 QFontSubst::ConstIterator it = fontSubst->constBegin();
01517
01518 while (it != fontSubst->constEnd()) {
01519 ret.append(it.key());
01520 ++it;
01521 }
01522
01523 ret.sort();
01524 return ret;
01525 }
01526
01527
01528
01529
01530
01531
01532 static quint8 get_font_bits(int version, const QFontPrivate *f)
01533 {
01534 Q_ASSERT(f != 0);
01535 quint8 bits = 0;
01536 if (f->request.style)
01537 bits |= 0x01;
01538 if (f->underline)
01539 bits |= 0x02;
01540 if (f->overline)
01541 bits |= 0x40;
01542 if (f->strikeOut)
01543 bits |= 0x04;
01544 if (f->request.fixedPitch)
01545 bits |= 0x08;
01546
01547
01548 if (f->rawMode)
01549 bits |= 0x20;
01550 if (version >= QDataStream::Qt_4_0) {
01551 if (f->kerning)
01552 bits |= 0x10;
01553 }
01554 if (f->request.style == QFont::StyleOblique)
01555 bits |= 0x80;
01556 return bits;
01557 }
01558
01559
01560 #ifndef QT_NO_DATASTREAM
01561
01562
01563
01564
01565
01566 static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
01567 {
01568 Q_ASSERT(f != 0);
01569 f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
01570 f->underline = (bits & 0x02) != 0;
01571 f->overline = (bits & 0x40) != 0;
01572 f->strikeOut = (bits & 0x04) != 0;
01573 f->request.fixedPitch = (bits & 0x08) != 0;
01574
01575 f->rawMode = (bits & 0x20) != 0;
01576 if (version >= QDataStream::Qt_4_0)
01577 f->kerning = (bits & 0x10) != 0;
01578 if ((bits & 0x80) != 0)
01579 f->request.style = QFont::StyleOblique;
01580 }
01581
01582 #endif
01583
01584
01591 QString QFont::key() const
01592 {
01593 return toString();
01594 }
01595
01603 QString QFont::toString() const
01604 {
01605 const QChar comma(QLatin1Char(','));
01606 return family() + comma +
01607 QString::number( pointSizeF()) + comma +
01608 QString::number( pixelSize()) + comma +
01609 QString::number((int) styleHint()) + comma +
01610 QString::number( weight()) + comma +
01611 QString::number((int) style()) + comma +
01612 QString::number((int) underline()) + comma +
01613 QString::number((int) strikeOut()) + comma +
01614 QString::number((int)fixedPitch()) + comma +
01615 QString::number((int) rawMode());
01616 }
01617
01618
01626 bool QFont::fromString(const QString &descrip)
01627 {
01628 QStringList l(descrip.split(QLatin1Char(',')));
01629
01630 int count = l.count();
01631 if (!count || (count > 2 && count < 9) || count > 11) {
01632 qWarning("QFont::fromString: Invalid description '%s'",
01633 descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
01634 return false;
01635 }
01636
01637 setFamily(l[0]);
01638 if (count > 1 && l[1].toDouble() > 0.0)
01639 setPointSizeF(l[1].toDouble());
01640 if (count == 9) {
01641 setStyleHint((StyleHint) l[2].toInt());
01642 setWeight(qMax(qMin(99, l[3].toInt()), 0));
01643 setItalic(l[4].toInt());
01644 setUnderline(l[5].toInt());
01645 setStrikeOut(l[6].toInt());
01646 setFixedPitch(l[7].toInt());
01647 setRawMode(l[8].toInt());
01648 } else if (count == 10) {
01649 if (l[2].toInt() > 0)
01650 setPixelSize(l[2].toInt());
01651 setStyleHint((StyleHint) l[3].toInt());
01652 setWeight(qMax(qMin(99, l[4].toInt()), 0));
01653 setStyle((QFont::Style)l[5].toInt());
01654 setUnderline(l[6].toInt());
01655 setStrikeOut(l[7].toInt());
01656 setFixedPitch(l[8].toInt());
01657 setRawMode(l[9].toInt());
01658 }
01659
01660 return true;
01661 }
01662
01663 #if !defined(Q_WS_QWS)
01664
01668 void QFont::cacheStatistics()
01669 {
01670
01671
01672 }
01673 #endif // !Q_WS_QWS
01674
01675
01676
01677
01678
01679
01680 #ifndef QT_NO_DATASTREAM
01681
01690 QDataStream &operator<<(QDataStream &s, const QFont &font)
01691 {
01692 if (s.version() == 1) {
01693 s << font.d->request.family.toLatin1();
01694 } else {
01695 s << font.d->request.family;
01696 }
01697
01698 if (s.version() >= QDataStream::Qt_4_0) {
01699
01700 double pointSize = font.d->request.pointSize;
01701 qint32 pixelSize = font.d->request.pixelSize;
01702 s << pointSize;
01703 s << pixelSize;
01704 } else if (s.version() <= 3) {
01705 qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
01706 if (pointSize < 0) {
01707 #ifdef Q_WS_X11
01708 pointSize = (qint16)(font.d->request.pixelSize*720/QX11Info::appDpiY());
01709 #else
01710 pointSize = (qint16)QFontInfo(font).pointSize() * 10;
01711 #endif
01712 }
01713 s << pointSize;
01714 } else {
01715 s << (qint16) (font.d->request.pointSize * 10);
01716 s << (qint16) font.d->request.pixelSize;
01717 }
01718
01719 s << (quint8) font.d->request.styleHint;
01720 if (s.version() >= 5)
01721 s << (quint8) font.d->request.styleStrategy;
01722 return s << (quint8) 0
01723 << (quint8) font.d->request.weight
01724 << get_font_bits(s.version(), font.d);
01725 }
01726
01727
01736 QDataStream &operator>>(QDataStream &s, QFont &font)
01737 {
01738 if (!font.d->ref.deref())
01739 delete font.d;
01740
01741 font.d = new QFontPrivate;
01742 font.resolve_mask = QFontPrivate::Complete;
01743
01744 quint8 styleHint, styleStrategy = QFont::PreferDefault, charSet, weight, bits;
01745
01746 if (s.version() == 1) {
01747 QByteArray fam;
01748 s >> fam;
01749 font.d->request.family = QString::fromLatin1(fam);
01750 } else {
01751 s >> font.d->request.family;
01752 }
01753
01754 if (s.version() >= QDataStream::Qt_4_0) {
01755
01756 double pointSize;
01757 qint32 pixelSize;
01758 s >> pointSize;
01759 s >> pixelSize;
01760 font.d->request.pointSize = qreal(pointSize);
01761 font.d->request.pixelSize = pixelSize;
01762 } else {
01763 qint16 pointSize, pixelSize = -1;
01764 s >> pointSize;
01765 if (s.version() >= 4)
01766 s >> pixelSize;
01767 font.d->request.pointSize = qreal(pointSize / 10.);
01768 font.d->request.pixelSize = pixelSize;
01769 }
01770 s >> styleHint;
01771 if (s.version() >= 5)
01772 s >> styleStrategy;
01773 s >> charSet;
01774 s >> weight;
01775 s >> bits;
01776
01777 font.d->request.styleHint = styleHint;
01778 font.d->request.styleStrategy = styleStrategy;
01779 font.d->request.weight = weight;
01780
01781 set_font_bits(s.version(), bits, font.d);
01782
01783 return s;
01784 }
01785
01786 #endif // QT_NO_DATASTREAM
01787
01788
01789
01790
01791
01792
01853 QFontInfo::QFontInfo(const QFont &font)
01854 : d(font.d)
01855 { d->ref.ref(); }
01856
01860 QFontInfo::QFontInfo(const QFontInfo &fi)
01861 : d(fi.d)
01862 { d->ref.ref(); }
01863
01867 QFontInfo::~QFontInfo()
01868 {
01869 if (!d->ref.deref())
01870 delete d;
01871 }
01872
01876 QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
01877 {
01878 qAtomicAssign(d, fi.d);
01879 return *this;
01880 }
01881
01887 QString QFontInfo::family() const
01888 {
01889 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01890 Q_ASSERT(engine != 0);
01891 return engine->fontDef.family;
01892 }
01893
01899 int QFontInfo::pointSize() const
01900 {
01901 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01902 Q_ASSERT(engine != 0);
01903 return qRound(engine->fontDef.pointSize);
01904 }
01905
01911 qreal QFontInfo::pointSizeF() const
01912 {
01913 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01914 Q_ASSERT(engine != 0);
01915 return engine->fontDef.pointSize;
01916 }
01917
01923 int QFontInfo::pixelSize() const
01924 {
01925 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01926 Q_ASSERT(engine != 0);
01927 return engine->fontDef.pixelSize;
01928 }
01929
01935 bool QFontInfo::italic() const
01936 {
01937 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01938 Q_ASSERT(engine != 0);
01939 return engine->fontDef.style != QFont::StyleNormal;
01940 }
01941
01947 QFont::Style QFontInfo::style() const
01948 {
01949 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01950 Q_ASSERT(engine != 0);
01951 return (QFont::Style)engine->fontDef.style;
01952 }
01953
01959 int QFontInfo::weight() const
01960 {
01961 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
01962 Q_ASSERT(engine != 0);
01963 return engine->fontDef.weight;
01964
01965 }
01966
01986 bool QFontInfo::underline() const
01987 {
01988 return d->underline;
01989 }
01990
02001 bool QFontInfo::overline() const
02002 {
02003 return d->overline;
02004 }
02005
02014 bool QFontInfo::strikeOut() const
02015 {
02016 return d->strikeOut;
02017 }
02018
02024 bool QFontInfo::fixedPitch() const
02025 {
02026 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
02027 Q_ASSERT(engine != 0);
02028 #ifdef Q_OS_MAC
02029 if (!engine->fontDef.fixedPitchComputed) {
02030 QChar ch[2] = { QChar('i'), QChar('m') };
02031 QGlyphLayout g[2];
02032 int l = 2;
02033 engine->stringToCMap(ch, 2, g, &l, 0);
02034 engine->fontDef.fixedPitch = g[0].advance.x == g[1].advance.x;
02035 engine->fontDef.fixedPitchComputed = true;
02036 }
02037 #endif
02038 return engine->fontDef.fixedPitch;
02039 }
02040
02048 QFont::StyleHint QFontInfo::styleHint() const
02049 {
02050 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
02051 Q_ASSERT(engine != 0);
02052 return (QFont::StyleHint) engine->fontDef.styleHint;
02053 }
02054
02065 bool QFontInfo::rawMode() const
02066 {
02067 return d->rawMode;
02068 }
02069
02076 bool QFontInfo::exactMatch() const
02077 {
02078 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
02079 Q_ASSERT(engine != 0);
02080 return (d->rawMode
02081 ? engine->type() != QFontEngine::Box
02082 : d->request.exactMatch(engine->fontDef));
02083 }
02084
02085
02086
02087
02088
02089
02090
02091
02092 #ifdef QFONTCACHE_DEBUG
02093
02094 static const int fast_timeout = 1000;
02095 static const int slow_timeout = 5000;
02096 #else
02097 static const int fast_timeout = 10000;
02098 static const int slow_timeout = 300000;
02099 #endif // QFONTCACHE_DEBUG
02100
02101 QFontCache *QFontCache::instance = 0;
02102 const uint QFontCache::min_cost = 4*1024;
02103
02104
02105 QFontCache::QFontCache()
02106 : QObject(qApp), total_cost(0), max_cost(min_cost),
02107 current_timestamp(0), fast(false), timer_id(-1)
02108 {
02109 Q_ASSERT(instance == 0);
02110 instance = this;
02111 }
02112
02113 QFontCache::~QFontCache()
02114 {
02115 {
02116 EngineDataCache::Iterator it = engineDataCache.begin(),
02117 end = engineDataCache.end();
02118 while (it != end) {
02119 if (it.value()->ref == 0)
02120 delete it.value();
02121 else
02122 FC_DEBUG("QFontCache::~QFontCache: engineData %p still has refcount %d",
02123 it.value(), it.value()->ref.atomic);
02124 ++it;
02125 }
02126 }
02127 EngineCache::Iterator it = engineCache.begin(),
02128 end = engineCache.end();
02129 while (it != end) {
02130 if (--it.value().data->cache_count == 0) {
02131 if (it.value().data->ref == 0) {
02132 FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %d %d %d %d)",
02133 it.value().data, it.key().script, it.key().def.pointSize,
02134 it.key().def.pixelSize, it.key().def.weight, it.key().def.style,
02135 it.key().def.fixedPitch);
02136
02137 delete it.value().data;
02138 } else {
02139 FC_DEBUG("QFontCache::~QFontCache: engine = %p still has refcount %d",
02140 it.value().data, it.value().data->ref.atomic);
02141 }
02142 }
02143 ++it;
02144 }
02145 instance = 0;
02146 }
02147
02148 void QFontCache::clear()
02149 {
02150 {
02151 EngineDataCache::Iterator it = engineDataCache.begin(),
02152 end = engineDataCache.end();
02153 while (it != end) {
02154 QFontEngineData *data = it.value();
02155 #if defined(Q_WS_X11) || defined(Q_WS_WIN)
02156 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
02157 if (data->engines[i]) {
02158 data->engines[i]->ref.deref();
02159 data->engines[i] = 0;
02160 }
02161 }
02162 #else
02163 if (data->engine) {
02164 data->engine->ref.deref();
02165 data->engine = 0;
02166 }
02167 #endif
02168 ++it;
02169 }
02170 }
02171
02172 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
02173 it != end; ++it) {
02174 if (it->data->ref == 0) {
02175 delete it->data;
02176 it->data = 0;
02177 }
02178 }
02179
02180 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
02181 it != end; ++it) {
02182 if (it->data && it->data->ref == 0) {
02183 delete it->data;
02184 it->data = 0;
02185 }
02186 }
02187
02188 engineCache.clear();
02189 }
02190
02191 QFontEngineData *QFontCache::findEngineData(const Key &key) const
02192 {
02193 EngineDataCache::ConstIterator it = engineDataCache.find(key),
02194 end = engineDataCache.end();
02195 if (it == end) return 0;
02196
02197
02198 return it.value();
02199 }
02200
02201 void QFontCache::insertEngineData(const Key &key, QFontEngineData *engineData)
02202 {
02203 FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
02204
02205 engineDataCache.insert(key, engineData);
02206 increaseCost(sizeof(QFontEngineData));
02207 }
02208
02209 QFontEngine *QFontCache::findEngine(const Key &key)
02210 {
02211 EngineCache::Iterator it = engineCache.find(key),
02212 end = engineCache.end();
02213 if (it == end) return 0;
02214
02215
02216 it.value().hits++;
02217 it.value().timestamp = ++current_timestamp;
02218
02219 FC_DEBUG("QFontCache: found font engine\n"
02220 " %p: timestamp %4u hits %3u ref %2d/%2d, type '%s'",
02221 it.value().data, it.value().timestamp, it.value().hits,
02222 it.value().data->ref.atomic, it.value().data->cache_count,
02223 it.value().data->name());
02224
02225 return it.value().data;
02226 }
02227
02228 void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
02229 {
02230 FC_DEBUG("QFontCache: inserting new engine %p", engine);
02231
02232 Engine data(engine);
02233 data.timestamp = ++current_timestamp;
02234
02235 engineCache.insert(key, data);
02236
02237
02238 if (engine->cache_count == 0)
02239 increaseCost(engine->cache_cost);
02240
02241 ++engine->cache_count;
02242 }
02243
02244 void QFontCache::increaseCost(uint cost)
02245 {
02246 cost = (cost + 512) / 1024;
02247 cost = cost > 0 ? cost : 1;
02248 total_cost += cost;
02249
02250 FC_DEBUG(" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
02251 cost, total_cost, max_cost);
02252
02253 if (total_cost > max_cost) {
02254 max_cost = total_cost;
02255
02256 if (timer_id == -1 || ! fast) {
02257 FC_DEBUG(" TIMER: starting fast timer (%d ms)", fast_timeout);
02258
02259 if (timer_id != -1) killTimer(timer_id);
02260 timer_id = startTimer(fast_timeout);
02261 fast = true;
02262 }
02263 }
02264 }
02265
02266 void QFontCache::decreaseCost(uint cost)
02267 {
02268 cost = (cost + 512) / 1024;
02269 cost = cost > 0 ? cost : 1;
02270 Q_ASSERT(cost <= total_cost);
02271 total_cost -= cost;
02272
02273 FC_DEBUG(" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
02274 cost, total_cost, max_cost);
02275 }
02276
02277 #if defined(Q_WS_WIN) || defined (Q_WS_QWS)
02278 void QFontCache::cleanupPrinterFonts()
02279 {
02280 FC_DEBUG("QFontCache::cleanupPrinterFonts");
02281
02282 {
02283 FC_DEBUG(" CLEAN engine data:");
02284
02285
02286 EngineDataCache::Iterator it = engineDataCache.begin(),
02287 end = engineDataCache.end();
02288 while (it != end) {
02289 if (it.key().screen == 0) {
02290 ++it;
02291 continue;
02292 }
02293
02294 if(it.value()->ref != 0) {
02295 #ifdef Q_WS_WIN
02296 for(int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
02297 if(it.value()->engines[i]) {
02298 it.value()->engines[i]->ref.deref();
02299 it.value()->engines[i] = 0;
02300 }
02301 }
02302 #else
02303 if (it.value()->engine) {
02304 it.value()->engine->ref.deref();
02305 it.value()->engine = 0;
02306 }
02307 #endif
02308 ++it;
02309 } else {
02310
02311 EngineDataCache::Iterator rem = it++;
02312
02313 decreaseCost(sizeof(QFontEngineData));
02314
02315 FC_DEBUG(" %p", rem.value());
02316
02317 delete rem.value();
02318 engineDataCache.erase(rem);
02319 }
02320 }
02321 }
02322
02323 EngineCache::Iterator it = engineCache.begin(),
02324 end = engineCache.end();
02325 while(it != end) {
02326 if (it.value().data->ref != 0 || it.key().screen == 0) {
02327 ++it;
02328 continue;
02329 }
02330
02331 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
02332 it.value().data, it.value().timestamp, it.value().hits,
02333 it.value().data->ref.atomic, it.value().data->cache_count,
02334 it.value().data->name());
02335
02336 if (--it.value().data->cache_count == 0) {
02337 FC_DEBUG(" DELETE: last occurrence in cache");
02338
02339 decreaseCost(it.value().data->cache_cost);
02340 delete it.value().data;
02341 }
02342
02343 engineCache.erase(it++);
02344 }
02345 }
02346 #endif
02347
02348 void QFontCache::timerEvent(QTimerEvent *)
02349 {
02350 FC_DEBUG("QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
02351 current_timestamp);
02352
02353 if (total_cost <= max_cost && max_cost <= min_cost) {
02354 FC_DEBUG(" cache redused sufficiently, stopping timer");
02355
02356 killTimer(timer_id);
02357 timer_id = -1;
02358 fast = false;
02359
02360 return;
02361 }
02362
02363
02364 uint in_use_cost = 0;
02365
02366 {
02367 FC_DEBUG(" SWEEP engine data:");
02368
02369
02370 const uint engine_data_cost =
02371 sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
02372
02373 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
02374 end = engineDataCache.constEnd();
02375 for (; it != end; ++it) {
02376 #ifdef QFONTCACHE_DEBUG
02377 FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref));
02378
02379 # if defined(Q_WS_X11) || defined(Q_WS_WIN)
02380
02381 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
02382 if (! it.value()->engines[i])
02383 continue;
02384 FC_DEBUG(" contains %p", it.value()->engines[i]);
02385 }
02386 # endif // Q_WS_X11 || Q_WS_WIN
02387 #endif // QFONTCACHE_DEBUG
02388
02389 if (it.value()->ref != 0)
02390 in_use_cost += engine_data_cost;
02391 }
02392 }
02393
02394 {
02395 FC_DEBUG(" SWEEP engine:");
02396
02397 EngineCache::ConstIterator it = engineCache.constBegin(),
02398 end = engineCache.constEnd();
02399 for (; it != end; ++it) {
02400 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
02401 it.value().data, it.value().timestamp, it.value().hits,
02402 it.value().data->ref.atomic, it.value().data->cache_count,
02403 it.value().data->cache_cost);
02404
02405 if (it.value().data->ref != 0)
02406 in_use_cost += it.value().data->cache_cost / it.value().data->cache_count;
02407 }
02408
02409
02410 in_use_cost += engineCache.size();
02411 }
02412
02413 in_use_cost = (in_use_cost + 512) / 1024;
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423 uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
02424
02425 FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
02426 in_use_cost, total_cost, max_cost, new_max_cost);
02427
02428 if (new_max_cost == max_cost) {
02429 if (fast) {
02430 FC_DEBUG(" cannot shrink cache, slowing timer");
02431
02432 killTimer(timer_id);
02433 timer_id = startTimer(slow_timeout);
02434 fast = false;
02435 }
02436
02437 return;
02438 } else if (! fast) {
02439 FC_DEBUG(" dropping into passing gear");
02440
02441 killTimer(timer_id);
02442 timer_id = startTimer(fast_timeout);
02443 fast = true;
02444 }
02445
02446 max_cost = new_max_cost;
02447
02448 {
02449 FC_DEBUG(" CLEAN engine data:");
02450
02451
02452 EngineDataCache::Iterator it = engineDataCache.begin(),
02453 end = engineDataCache.end();
02454 while (it != end) {
02455 if (it.value()->ref != 0) {
02456 ++it;
02457 continue;
02458 }
02459
02460 EngineDataCache::Iterator rem = it++;
02461
02462 decreaseCost(sizeof(QFontEngineData));
02463
02464 FC_DEBUG(" %p", rem.value());
02465
02466 delete rem.value();
02467 engineDataCache.erase(rem);
02468 }
02469 }
02470
02471
02472 uint current_cost;
02473 do {
02474 current_cost = total_cost;
02475
02476 EngineCache::Iterator it = engineCache.begin(),
02477 end = engineCache.end();
02478
02479 uint oldest = ~0u;
02480 uint least_popular = ~0u;
02481
02482 for (; it != end; ++it) {
02483 if (it.value().data->ref != 0)
02484 continue;
02485
02486 if (it.value().timestamp < oldest &&
02487 it.value().hits <= least_popular) {
02488 oldest = it.value().timestamp;
02489 least_popular = it.value().hits;
02490 }
02491 }
02492
02493 FC_DEBUG(" oldest %u least popular %u", oldest, least_popular);
02494
02495 for (it = engineCache.begin(); it != end; ++it) {
02496 if (it.value().data->ref == 0 &&
02497 it.value().timestamp == oldest &&
02498 it.value().hits == least_popular)
02499 break;
02500 }
02501
02502 if (it != end) {
02503 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
02504 it.value().data, it.value().timestamp, it.value().hits,
02505 it.value().data->ref.atomic, it.value().data->cache_count,
02506 it.value().data->name());
02507
02508 if (--it.value().data->cache_count == 0) {
02509 FC_DEBUG(" DELETE: last occurrence in cache");
02510
02511 decreaseCost(it.value().data->cache_cost);
02512 delete it.value().data;
02513 } else {
02514
02515
02516
02517
02518
02519 current_cost = 0;
02520 }
02521
02522 engineCache.erase(it);
02523 }
02524 } while (current_cost != total_cost && total_cost > max_cost);
02525 }