NEW/REWORKED: extended the set of functions like JKQTMathTextGetTightBoundingRect(): These use an internal, thread-safe cache and capsule calls to QFontMetricsF-instances. This significantly improves speed in (parallelized) plotting.

This commit is contained in:
jkriege2 2024-01-08 17:16:31 +01:00
parent 3fee9609fb
commit 09e07cb12a
27 changed files with 761 additions and 361 deletions

View File

@ -97,10 +97,10 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):
<b>VERSION:</b> 5.0.0 <b>VERSION:</b> 5.0.0
<b>BUILD MODE:</b> Release <b>BUILD MODE:</b> Release
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 1896.0ms<br/>single runtimes = (236.9 +/- 379.1) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/> <u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 3399.6ms<br/>single runtimes = (141.6 +/- 366.9) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
<u><b>PARALLEL RESULTS:</b></u><br/> <u><b>PARALLEL RESULTS:</b></u><br/>
runtime, overall = 624.7ms<br/>single runtimes = (564.3 +/- 107.7) ms<br/>speedup = 7.23x<br/>threads / available = 8 / 16<br/><br/><b>speedup vs. serial = 3.0x</b> runtime, overall = 526.7ms<br/>single runtimes = (166.4 +/- 9.9) ms<br/>speedup = 7.58x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 6.5x</b>
[comment]:RESULTS_END [comment]:RESULTS_END
@ -108,8 +108,9 @@ runtime, overall = 624.7ms<br/>single runtimes = (564.3 +/- 107.7) ms<br/>speedu
From this data you can observe: From this data you can observe:
- The plotting parallelizes nicely, i.e. the speedup ist >7x on a 8-core-machine. This is the speedup calculated as sum of runtimes of each thread, divided by the runtime of all threads in parallel. - The plotting parallelizes nicely, i.e. the speedup ist >7x on a 8-core-machine. This is the speedup calculated as sum of runtimes of each thread, divided by the runtime of all threads in parallel.
- BUT: the speedup of serialized plotting vs. parallel plotting is way smaller: It is only 2-3x. Also the runtime in each thread is about 3x longer than in the serialized example. This can be explained by the (significant) overhead due to shared caches (and therefore synchronization) between the plotters. This may be reworked in future! - BUT: the speedup of serialized plotting vs. parallel plotting is a biz smaller: It is only 6-7x. Also the runtime in each thread is a bit longer than in the serialized example. This can be explained by the overhead due to shared caches (and therefore synchronization) between the plotters (e.g. using JKQTMathTextGetBoundingRect() within JKQTMathText).
- The variance in runtimes in the (initial) serial test-run is larger than in the parallel run. This is due to filling of the internal caches during the first plotting! - The variance in runtimes in the (initial) serial test-run is larger than in the parallel run. This is due to filling of the internal caches during the first plotting!
- NOTE: The parallel vs. serial speedup significantly depends on the complexity of the text rendering (i.e. usage of JKQTMathText). Therefore rendinering more complex textxs with more and more complex LaTeX markup, will result in smalle speedups!
. .
Finally the application displays the plots: Finally the application displays the plots:

View File

@ -21,6 +21,7 @@
#define NUM_PLOTS 8 #define NUM_PLOTS 8
#define NUM_GRAPHS 6 #define NUM_GRAPHS 6
#define NUM_DATAPOINTS 1000 #define NUM_DATAPOINTS 1000
#define NUM_REPEATS 3
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@ -33,11 +34,21 @@ int main(int argc, char* argv[])
mainWin->setCentralWidget(main=new QWidget(mainWin)); mainWin->setCentralWidget(main=new QWidget(mainWin));
QString markdownFile=""; QString markdownFile="";
QString labelTemplate="Plot %1: $f(x)=\\cos\\left(x+\\sfrac{%1\\pi}{8}\\right)$";
QByteArray mdMATCH="RESULTS";
for (int i=1; i<argc; i++) { for (int i=1; i<argc; i++) {
if (QString(argv[i]).startsWith("--mdfile=")) { if (QString(argv[i]).startsWith("--mdfile=")) {
markdownFile=QString::fromLatin1(argv[i]).right(QString::fromLatin1(argv[i]).size()-9); markdownFile=QString::fromLatin1(argv[i]).right(QString::fromLatin1(argv[i]).size()-9);
if (markdownFile.startsWith('"')) markdownFile.remove('"'); if (markdownFile.startsWith('"')) markdownFile.remove('"');
} }
if (QString(argv[i]).startsWith("--complexlabel")) {
labelTemplate="Plot %1: $f(x)=\\cos\\left(x+\\sfrac{%1\\pi}{8}\\right)$";
mdMATCH="COMPLEXRESULTS";
}
if (QString(argv[i]).startsWith("--simplelabel")) {
labelTemplate="Plot %1: $f(x)=\\cos(x+%1\\pi/8)$";
mdMATCH="COMPLEXRESULTS";
}
} }
@ -72,23 +83,27 @@ int main(int argc, char* argv[])
lay_serial->addWidget(pic_serial.last(), 1); lay_serial->addWidget(pic_serial.last(), 1);
lay_parallel->addWidget(pic_parallel.last(), 1); lay_parallel->addWidget(pic_parallel.last(), 1);
} }
QList<double> runtimesParallel;
QList<double> runtimesSerial;
double durSerialNano=0;
double durParallelNano=0;
for (int run=0; run<NUM_REPEATS; run++) {
filenamesParallel.clear();
QElapsedTimer timer; QElapsedTimer timer;
QList<double> runtimesSerial;
timer.start(); timer.start();
for (int i=0; i<NUM_PLOTS; i++) { for (int i=0; i<NUM_PLOTS; i++) {
double dur=0; double dur=0;
filenamesSerial<<PlottingThread::plotAndSave("serial", i, NUM_GRAPHS, NUM_DATAPOINTS, &dur); filenamesSerial<<PlottingThread::plotAndSave("serial", i, NUM_GRAPHS, NUM_DATAPOINTS, labelTemplate, &dur);
runtimesSerial<<dur/1e6; runtimesSerial<<dur/1e6;
} }
const double durSerialNano=timer.nsecsElapsed(); durSerialNano+=timer.nsecsElapsed();
qDebug()<<"durSerial = "<<durSerialNano/1e6<<"ms"; qDebug()<<"durSerial = "<<durSerialNano/1e6<<"ms";
QList<double> runtimesParallel;
QList<QSharedPointer<PlottingThread>> threads; QList<QSharedPointer<PlottingThread>> threads;
for (int i=0; i<NUM_PLOTS; i++) { for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" creating thread "<<i; qDebug()<<" creating thread "<<i;
threads.append(QSharedPointer<PlottingThread>::create("parallel",i, NUM_GRAPHS, NUM_DATAPOINTS, nullptr)); threads.append(QSharedPointer<PlottingThread>::create("parallel",i, NUM_GRAPHS, NUM_DATAPOINTS, labelTemplate, nullptr));
} }
timer.start(); timer.start();
for (int i=0; i<NUM_PLOTS; i++) { for (int i=0; i<NUM_PLOTS; i++) {
@ -102,10 +117,11 @@ int main(int argc, char* argv[])
runtimesParallel<<threads[i]->getRuntimeNanosends()/1e6; runtimesParallel<<threads[i]->getRuntimeNanosends()/1e6;
} }
} }
const double durParallelNano=timer.nsecsElapsed(); durParallelNano+=timer.nsecsElapsed();
qDebug()<<"durParallel = "<<durParallelNano/1e6<<"ms"; qDebug()<<"durParallel["<<run+1<<"] = "<<durParallelNano/1e6<<"ms";
threads.clear(); threads.clear();
}
for (int ii=0; ii<NUM_SHOWN_PLOTS; ii++) { for (int ii=0; ii<NUM_SHOWN_PLOTS; ii++) {
int i=ii; int i=ii;
@ -114,8 +130,8 @@ int main(int argc, char* argv[])
pic_parallel[ii]->setPixmap(QPixmap(filenamesParallel[i], "PNG")); pic_parallel[ii]->setPixmap(QPixmap(filenamesParallel[i], "PNG"));
} }
QString ser_result, par_result; QString ser_result, par_result;
labSerialResult->setText(ser_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/> ").arg(durSerialNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatSum(runtimesSerial.begin(), runtimesSerial.end())/(durSerialNano/1e6),0,'f',2).arg(1).arg(std::thread::hardware_concurrency())); labSerialResult->setText(ser_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/><br/> ").arg(durSerialNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatSum(runtimesSerial.begin(), runtimesSerial.end())/(durSerialNano/1e6),0,'f',2).arg(1).arg(std::thread::hardware_concurrency()));
labParallelResult->setText(par_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/><b>speedup vs. serial = %7x</b>").arg(durParallelNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatSum(runtimesParallel.begin(), runtimesParallel.end())/(durParallelNano/1e6),0,'f',2).arg(NUM_PLOTS).arg(std::thread::hardware_concurrency()).arg(durSerialNano/durParallelNano,0,'f',1)); labParallelResult->setText(par_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/>batch runs = %8<br/><br/><b>speedup vs. serial = %7x</b>").arg(durParallelNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatSum(runtimesParallel.begin(), runtimesParallel.end())/(durParallelNano/1e6),0,'f',2).arg(NUM_PLOTS).arg(std::thread::hardware_concurrency()).arg(durSerialNano/durParallelNano,0,'f',1).arg(NUM_REPEATS));
mainWin->show(); mainWin->show();
if (!markdownFile.isEmpty()) { if (!markdownFile.isEmpty()) {
@ -126,11 +142,11 @@ int main(int argc, char* argv[])
md=f.readAll(); md=f.readAll();
qDebug()<<" read "<<md.size()<<" bytes"; qDebug()<<" read "<<md.size()<<" bytes";
f.close(); f.close();
const auto istart=md.indexOf("[comment]:RESULTS"); const auto istart=md.indexOf("[comment]:"+mdMATCH);
const auto iend=md.indexOf("[comment]:RESULTS_END"); const auto iend=md.indexOf("[comment]:"+mdMATCH+"_END");
qDebug()<<" istart="<<istart<<", iend="<<iend; qDebug()<<" istart="<<istart<<", iend="<<iend;
if (istart>=0 && iend>istart) { if (istart>=0 && iend>istart) {
const QByteArray newResults="[comment]:RESULTS\n\n<b>VERSION:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_VERSION) const QByteArray newResults="[comment]:"+mdMATCH+"\n\n<b>VERSION:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_VERSION)
+"\n<b>BUILD MODE:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_BUILDTYPE) +"\n<b>BUILD MODE:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_BUILDTYPE)
+"\n\n<u><b>SERIAL RESULTS:</b></u><br/>"+ser_result.toUtf8() +"\n\n<u><b>SERIAL RESULTS:</b></u><br/>"+ser_result.toUtf8()
+"\n\n<u><b>PARALLEL RESULTS:</b></u><br/>\n"+par_result.toUtf8()+"\n\n"; +"\n\n<u><b>PARALLEL RESULTS:</b></u><br/>\n"+par_result.toUtf8()+"\n\n";

View File

@ -14,17 +14,18 @@
class PlottingThread: public QThread { class PlottingThread: public QThread {
Q_OBJECT Q_OBJECT
public: public:
inline PlottingThread(const QString& filenamepart, int plotindex, int NUM_GRAPHS, int NUM_DATAPOINTS, QObject* parent): inline PlottingThread(const QString& filenamepart, int plotindex, int NUM_GRAPHS, int NUM_DATAPOINTS, const QString& labeltemplate, QObject* parent):
QThread(parent), QThread(parent),
m_plotindex(plotindex), m_plotindex(plotindex),
m_runtimeNanoseconds(0), m_runtimeNanoseconds(0),
m_filenamepart(filenamepart), m_filenamepart(filenamepart),
m_filename(), m_filename(),
m_NUM_GRAPHS(NUM_GRAPHS), m_NUM_GRAPHS(NUM_GRAPHS),
m_NUM_DATAPOINTS(NUM_DATAPOINTS) m_NUM_DATAPOINTS(NUM_DATAPOINTS),
m_labeltemplate(labeltemplate)
{} {}
inline static QString plotAndSave(const QString& filenamepart, int plotIndex, int NUM_GRAPHS, int NUM_DATAPOINTS, double* runtimeNanoseconds=nullptr) { inline static QString plotAndSave(const QString& filenamepart, int plotIndex, int NUM_GRAPHS, int NUM_DATAPOINTS, const QString& labeltemplate, double* runtimeNanoseconds=nullptr) {
QElapsedTimer timer; QElapsedTimer timer;
timer.start(); timer.start();
const QString filename=QDir(QDir::tempPath()).absoluteFilePath(QString("testimg_%1_%2.png").arg(filenamepart).arg(plotIndex)); const QString filename=QDir(QDir::tempPath()).absoluteFilePath(QString("testimg_%1_%2.png").arg(filenamepart).arg(plotIndex));
@ -36,15 +37,15 @@ public:
JKQTPXYLineGraph* g; JKQTPXYLineGraph* g;
plot.addGraph(g=new JKQTPXYLineGraph(&plot)); plot.addGraph(g=new JKQTPXYLineGraph(&plot));
g->setXColumn(colX); g->setXColumn(colX);
g->setYColumn(plot.getDatastore()->addColumnCalculatedFromColumn(colX, [&](double x) { return cos(x+double(i)/8.0*JKQTPSTATISTICS_PI)+rng.generateDouble()*0.2-0.1;})); g->setYColumn(plot.getDatastore()->addColumnCalculatedFromColumn(colX, [&](double x) { return cos(x+double(i+plotIndex)/8.0*JKQTPSTATISTICS_PI)+rng.generateDouble()*0.2-0.1;}));
g->setTitle(QString("Plot %1: $f(x)=\\cos\\leftx+\\frac{%1\\pi}{8}\\right)").arg(i+1)); g->setTitle(labeltemplate.arg(i+plotIndex+1));
g->setDrawLine(true); g->setDrawLine(true);
g->setSymbolType(JKQTPNoSymbol); g->setSymbolType(JKQTPNoSymbol);
} }
plot.setPlotLabel(QString("Test Plot %1").arg(plotIndex+1)); plot.setPlotLabel(QString("Test Plot %1 (%2)").arg(plotIndex+1).arg(filenamepart));
plot.getXAxis()->setAxisLabel("x-axis"); plot.getXAxis()->setAxisLabel("x-axis $x$");
plot.getYAxis()->setAxisLabel("y-axis"); plot.getYAxis()->setAxisLabel("y-axis $f(x)$");
plot.zoomToFit(); plot.zoomToFit();
plot.saveAsPixelImage(filename, false, "PNG"); plot.saveAsPixelImage(filename, false, "PNG");
@ -59,15 +60,16 @@ public:
} }
protected: protected:
inline virtual void run() { inline virtual void run() {
m_filename=plotAndSave(m_filenamepart, m_plotindex, m_NUM_GRAPHS, m_NUM_DATAPOINTS, &m_runtimeNanoseconds); m_filename=plotAndSave(m_filenamepart, m_plotindex, m_NUM_GRAPHS, m_NUM_DATAPOINTS, m_labeltemplate, &m_runtimeNanoseconds);
} }
int m_plotindex; int m_plotindex;
double m_runtimeNanoseconds; double m_runtimeNanoseconds;
QString m_filename; QString m_filename;
QString m_filenamepart; const QString m_filenamepart;
const int m_NUM_GRAPHS; const int m_NUM_GRAPHS;
const int m_NUM_DATAPOINTS; const int m_NUM_DATAPOINTS;
const QString m_labeltemplate;
}; };
#endif // MULTITHREADED_THREAD_H #endif // MULTITHREADED_THREAD_H

View File

@ -71,6 +71,14 @@ class JKQTMathTextVerticalListNode; // forward
- \ref jkqtmathtext_supportedlatex for a description of the supported LaTeX subset - \ref jkqtmathtext_supportedlatex for a description of the supported LaTeX subset
. .
\section JKQTMathTextUsageThreadSafety Thread-Safety/Re-Entrancy Guarantees
All functions in this class are reentrant. Therefore different instances off JKQTMathtext can be used in parallel in different threads.
DO NOT however use the same instance from multiple threads, as the functions are not thread-safe!
Also note that there are certain caches that reuse information (e.g. about fonts) from previous runs, which allow different instances
(also over different threads) to profit from each other. On the other hand, this strategy requires a bit of overhead due to synchronization,
but usually the speedup outweighs the overhead significantly!
\section JKQTMathTextUsage Usage \section JKQTMathTextUsage Usage

View File

@ -22,6 +22,7 @@
#include "jkqtmathtext/jkqtmathtexttools.h" #include "jkqtmathtext/jkqtmathtexttools.h"
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpcachingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -29,6 +30,7 @@
#include <QFontInfo> #include <QFontInfo>
#include <QApplication> #include <QApplication>
#include <QFont> #include <QFont>
#include <QReadWriteLock>
#include <mutex> #include <mutex>
@ -877,13 +879,13 @@ QPainterPath JKQTMathTextMakeHBracePath(double x, double ybrace, double width, d
} }
JKQTMathTextTBRData::JKQTMathTextTBRData(const QFont &f, const QString &text, QPaintDevice *pd):
fm(f, pd) namespace {
struct JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextCacheKeyBase(const QFont& f_, QPaintDevice *pd):
f(f_)
{ {
this->text=text;
this->tbr=this->fm.tightBoundingRect(text);
this->f=f;
//this->pd=pd;
if (pd) { if (pd) {
ldpiX=pd->logicalDpiX(); ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY(); ldpiY=pd->logicalDpiY();
@ -896,62 +898,220 @@ JKQTMathTextTBRData::JKQTMathTextTBRData(const QFont &f, const QString &text, Q
pdpiY=0; pdpiY=0;
} }
} }
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
bool JKQTMathTextTBRData::operator==(const JKQTMathTextTBRData &other) const inline bool operator==(const JKQTMathTextCacheKeyBase& other) const{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && pdpiX==other.pdpiX && pdpiY==other.pdpiY && f==other.f;
};
};
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
inline size_t qHash(const JKQTMathTextCacheKeyBase& data, size_t seed=0) {
#else
inline uint qHash(const JKQTMathTextCacheKeyBase& data) {
const size_t seed=0;
#endif
return qHash(data.f)+::qHash(data.ldpiX,seed)+::qHash(data.ldpiY)+::qHash(data.pdpiX)+::qHash(data.pdpiY);
}
struct JKQTMathTextCacheKeyBaseExt: public JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextCacheKeyBaseExt(const QFont& f_, QPaintDevice *pd_):
JKQTMathTextCacheKeyBase(f_,pd_), pd(pd_)
{}
QPaintDevice *pd;
};
template <class TText=QString>
struct JKQTMathTextTBRDataH: public JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextTBRDataH(const QFont& f_, const TText& text_, QPaintDevice *pd):
JKQTMathTextCacheKeyBase(f_, pd), text(text_)
{ {
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f;
}
TText text;
inline bool operator==(const JKQTMathTextTBRDataH& other) const{
return JKQTMathTextCacheKeyBase::operator==(other) && text==other.text;
};
};
template <class TText=QString>
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
inline size_t qHash(const JKQTMathTextTBRDataH<TText>& data, size_t /*seed=0*/) {
#else
inline uint qHash(const JKQTMathTextTBRDataH<TText>& data) {
#endif
return qHash(data.f)+qHash(data.text)+::qHash(data.ldpiX)+::qHash(data.ldpiY)+::qHash(data.pdpiX)+::qHash(data.pdpiY);
}
template <class TText=QString>
struct JKQTMathTextTBRDataHExt: public JKQTMathTextTBRDataH<TText> {
inline explicit JKQTMathTextTBRDataHExt(const QFont& f_, const TText& text_, QPaintDevice *pd_):
JKQTMathTextTBRDataH<TText>(f_,text_,pd_), pd(pd_)
{}
QPaintDevice *pd;
};
} }
JKQTMathTextTBRDataH::JKQTMathTextTBRDataH(const QFont &f, const QString &text, QPaintDevice *pd)
QRectF JKQTMathTextGetTightBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
{ {
this->text=text; //thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
this->f=f; static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
if (pd) { [](const JKQTMathTextTBRDataHExt<QString>& key) {
ldpiX=pd->logicalDpiX(); const QFontMetricsF fm(key.f, key.pd);
ldpiY=pd->logicalDpiY(); return fm.tightBoundingRect(key.text);
pdpiX=pd->physicalDpiX(); });
pdpiY=pd->physicalDpiY();
} else { return cache.get_inline(f, text, pd);
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
} }
bool JKQTMathTextTBRDataH::operator==(const JKQTMathTextTBRDataH &other) const QRectF JKQTMathTextGetBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
{ {
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f; //thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
[](const JKQTMathTextTBRDataHExt<QString>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.boundingRect(key.text);
});
return cache.get_inline(f, text, pd);
} }
qreal JKQTMathTextGetHorAdvance(const QFont &f, const QString &text, QPaintDevice *pd)
QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm, const QString &text, QPaintDevice *pd)
{ {
thread_local QList<JKQTMathTextTBRData> JKQTMathText_tbrs=QList<JKQTMathTextTBRData>(); //thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
thread_local QHash<JKQTMathTextTBRDataH, QRectF> JKQTMathText_tbrh=QHash<JKQTMathTextTBRDataH, QRectF>(); static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
[](const JKQTMathTextTBRDataHExt<QString>& key) {
const QFontMetricsF fm(key.f, key.pd);
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
return fm.horizontalAdvance(key.text);
#else
return fm.width(key.text);
#endif
});
return cache.get_inline(f, text, pd);
JKQTMathTextTBRDataH dh(fm, text, pd);
if (pd) {
if (JKQTMathText_tbrh.contains(dh)) return JKQTMathText_tbrh[dh];
/*for (int i=0; i<tbrs.size(); i++) {
if (tbrs[i].f==fm && tbrs[i].text==text && (tbrs[i].ldpiX==pd->logicalDpiX() && tbrs[i].ldpiY==pd->logicalDpiY() && tbrs[i].pdpiX==pd->physicalDpiX() && tbrs[i].pdpiY==pd->physicalDpiY())) {
//qDebug()<<" ### "<<fm<<pd<<tbrs[i].text<<tbrs[i].tbr;
return tbrs[i].tbr;
} }
}*/
} else { qreal JKQTMathTextGetRightBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
//qDebug()<<"warning no pd"; {
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
[](const JKQTMathTextTBRDataHExt<QChar>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.rightBearing(key.text);
});
return cache.get_inline(f, text, pd);
} }
JKQTMathTextTBRData d(fm, text, pd);
JKQTMathText_tbrs.append(d); qreal JKQTMathTextGetLeftBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
JKQTMathText_tbrh[dh]=d.tbr; {
//qDebug()<<"TBRs lits: "<<tbrs.size(); //thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
//qDebug()<<"+++ "<<fm<<pd<<d.text<<d.tbr; static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
return d.tbr; [](const JKQTMathTextTBRDataHExt<QChar>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.leftBearing(key.text);
});
return cache.get_inline(f, text, pd);
}
qreal JKQTMathTextGetFontAscent(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.ascent();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontDescent(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.descent();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontHeight(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.height();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLineWidth(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.lineWidth();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLeading(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.leading();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLineSpacing(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.lineSpacing();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontStrikoutPos(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.strikeOutPos();
});
return cache.get_inline(f, pd);
} }
QFont JKQTMathTextGetNonItalic(const QFont &font) QFont JKQTMathTextGetNonItalic(const QFont &font)
@ -1048,12 +1208,12 @@ JKQTMathTextBlackboradDrawingMode String2JKQTMathTextBlackboradDrawingMode(QStri
void JKQTMathTextDrawStringSimBlackboard(QPainter &painter, const QFont &f, const QColor& color, double x, double y, const QString &txt) void JKQTMathTextDrawStringSimBlackboard(QPainter &painter, const QFont &f, const QColor& color, double x, double y, const QString &txt)
{ {
const QFontMetricsF fm(f, painter.device()); const qreal lw=JKQTMathTextGetFontLineWidth(f, painter.device());
const QPen p(color, fm.lineWidth()/4.0, Qt::SolidLine); const QPen p(color, lw/4.0, Qt::SolidLine);
painter.setPen(p); painter.setPen(p);
QPainterPath path; QPainterPath path;
path.addText(QPointF(x, y), f, txt); path.addText(QPointF(x, y), f, txt);
path.addText(QPointF(x+fm.lineWidth()/2.0, y), f, txt); path.addText(QPointF(x+lw/2.0, y), f, txt);
painter.drawPath(path); painter.drawPath(path);
} }
@ -1074,3 +1234,4 @@ JKQTMathTextLineSpacingMode String2JKQTMathTextLineSpacingMode(QString tokenName
if (tokenName=="minimal" || tokenName=="min" || tokenName=="minimum") return MTSMMinimalSpacing; if (tokenName=="minimal" || tokenName=="min" || tokenName=="minimum") return MTSMMinimalSpacing;
return MTSMDefaultSpacing; return MTSMDefaultSpacing;
} }

View File

@ -42,7 +42,8 @@
#include <QHash> #include <QHash>
#include <QPainterPath> #include <QPainterPath>
#include <QtMath> #include <QtMath>
#include <QFontMetrics>
#include <QFontMetricsF>
class JKQTMathText; // forward class JKQTMathText; // forward
@ -471,41 +472,173 @@ JKQTMATHTEXT_LIB_EXPORT QPainterPath JKQTMathTextMakeDArrow(double x, double y,
*/ */
JKQTMATHTEXT_LIB_EXPORT void JKQTMathTextDrawStringSimBlackboard(QPainter& painter, const QFont& f, const QColor &color, double x, double y, const QString& txt); JKQTMATHTEXT_LIB_EXPORT void JKQTMathTextDrawStringSimBlackboard(QPainter& painter, const QFont& f, const QColor &color, double x, double y, const QString& txt);
struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTBRData {
explicit JKQTMathTextTBRData(const QFont& f, const QString& text, QPaintDevice *pd);
QFontMetricsF fm;
QString text;
QRectF tbr;
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
//QPaintDevice *pd;
bool operator==(const JKQTMathTextTBRData& other) const;
};
struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTBRDataH {
explicit JKQTMathTextTBRDataH(const QFont& f, const QString& text, QPaintDevice *pd);
QString text;
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
bool operator==(const JKQTMathTextTBRDataH& other) const;
};
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) /** \brief calculates the tight bounding rectangle around \a text
inline size_t qHash(const JKQTMathTextTBRDataH& data, size_t /*seed=0*/) { * (from <a href="https://doc.qt.io/qt/qfontmetricsf.html#tightBoundingRect">QFontMetricsF::tightBoundingRect()</a>),
#else * uses internal (thread-local) hashing to not redo a calculation that has already been performed
inline uint qHash(const JKQTMathTextTBRDataH& data) {
#endif
return qHash(data.f.family())+qHash(data.text);
}
/** \brief calculates the tight bounding rectangle around \a text, uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools * \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/ */
JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm, const QString& text, QPaintDevice *pd); JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the bounding rectangle around \a text
* (from (using <a href="https://doc.qt.io/qt/qfontmetricsf.html#boundingRect">QFontMetricsF::boundingRect()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetBoundingRect(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the horizontal advance of \a text
* (from <a href="https://doc.qt.io/qt/qfontmetricsf.html#horizontalAdvance">QFontMetricsF::horizontalAdvance()</a>
* or \c QFontMetricsF::width() if it is not yet available in your Qt version),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetHorAdvance(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the left bearing of \a text
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#leftBearing">QFontMetricsF::leftBearing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the character of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetLeftBearing(const QFont &fm, const QChar& text, QPaintDevice *pd);
/** \brief calculates the right bearing of \a text
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#rightBearing">QFontMetricsF::rightBearing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the character of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetRightBearing(const QFont &fm, const QChar& text, QPaintDevice *pd);
/** \brief calculates the strikeout-pos of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#strikeoutPos">QFontMetricsF::strikeoutPos()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontStrikoutPos(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the line width of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#lineWidth">QFontMetricsF::lineWidth()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLineWidth(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the ascent of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#ascent">QFontMetricsF::ascent()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontAscent(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the descent of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#descent">QFontMetricsF::descent()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontDescent(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the height of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#height">QFontMetricsF::height()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontHeight(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the leading of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#leading">QFontMetricsF::leading()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLeading(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the line spacing of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#lineSpacing">QFontMetricsF::lineSpacing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLineSpacing(const QFont &fm, QPaintDevice *pd);
/** \brief returns a copy of \a f, but with the italic-property set to \c false /** \brief returns a copy of \a f, but with the italic-property set to \c false
* \ingroup jkqtmathtext_tools * \ingroup jkqtmathtext_tools
*/ */

View File

@ -24,8 +24,8 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF>
#include <QDebug> #include <QDebug>
#include <QFontDatabase> #include <QFontDatabase>
#include <QFontInfo> #include <QFontInfo>
@ -60,9 +60,9 @@ JKQTMathTextNodeSize JKQTMathTextBoxInstructionNode::getSizeInternal(QPainter& p
inst.modifier(ev, getParameters()); inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText); const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText); const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText)), painter.device()); const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
const double lw=p.widthF(); const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width(); const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
JKQTMathTextNodeSize s; JKQTMathTextNodeSize s;
@ -74,6 +74,9 @@ JKQTMathTextNodeSize JKQTMathTextBoxInstructionNode::getSizeInternal(QPainter& p
} }
double JKQTMathTextBoxInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextBoxInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBoxInstructionNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
@ -81,10 +84,10 @@ double JKQTMathTextBoxInstructionNode::draw(QPainter& painter, double x, double
inst.modifier(ev, getParameters()); inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText); const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText); const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText)), painter.device()); const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
const double lw=p.widthF(); const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width(); const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const double rr=inst.roundingFactor*fmNonItalic.tightBoundingRect("x").width(); const double rr=inst.roundingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
{ {
@ -116,10 +119,10 @@ bool JKQTMathTextBoxInstructionNode::toHtml(QString &html, JKQTMathTextEnvironme
inst.modifier(ev, getParameters()); inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText); const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText); const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText))); const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
//const double lw=p.widthF(); //const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width(); const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", nullptr).width();
//const double rr=inst.roundingFactor*fmNonItalic.tightBoundingRect("x").width(); //const double rr=inst.roundingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
QString s=QString("padding: %1px").arg(padding); QString s=QString("padding: %1px").arg(padding);
if (p!=Qt::NoPen) { if (p!=Qt::NoPen) {
if (s.size()>0 && s.right(2)!="; ") s=s+"; "; if (s.size()>0 && s.right(2)!="; ") s=s+"; ";
@ -310,7 +313,7 @@ JKQTMathTextBoxInstructionNode::InstructionProperties::ModifyEnvironmentFunctor
[](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/){}; [](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/){};
JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::DefaultPen= JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::DefaultPen=
[](JKQTMathTextEnvironment& ev, const QStringList& /*parameters*/, JKQTMathText* parent){ return QPen(ev.color, QFontMetricsF(ev.getFont(parent)).lineWidth(), Qt::SolidLine); }; [](JKQTMathTextEnvironment& ev, const QStringList& /*parameters*/, JKQTMathText* parent){ return QPen(ev.color, JKQTMathTextGetFontLineWidth(ev.getFont(parent),nullptr), Qt::SolidLine); };
JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::NoPen= JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::NoPen=
[](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/, JKQTMathText* /*parent*/){ return Qt::NoPen; }; [](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/, JKQTMathText* /*parent*/){ return Qt::NoPen; };

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -55,8 +56,8 @@ JKQTMathTextBraceNode::NodeSize JKQTMathTextBraceNode::getSizeInternalAndBrace(Q
{ {
NodeSize s; NodeSize s;
const NodeSize childSize=getChild()->getSize(painter, currentEv); const NodeSize childSize=getChild()->getSize(painter, currentEv);
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device()); const QFont f=currentEv.getFont(parentMathText);
const double minChildHeight=fm.tightBoundingRect("l").height(); const double minChildHeight=JKQTMathTextGetTightBoundingRect(f, "l", painter.device()).height();
double cAscentAboveStrike=0; double cAscentAboveStrike=0;
double cDescentBelowStrike=0; double cDescentBelowStrike=0;
@ -84,13 +85,16 @@ JKQTMathTextBraceNode::NodeSize JKQTMathTextBraceNode::getSizeInternalAndBrace(Q
} }
double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBraceNode[]::draw()"));
#endif
//std::cout<<"drawing brace-node: '"<<openbrace.toStdString()<<"' ... '"<<closebrace.toStdString()<<"'\n"; //std::cout<<"drawing brace-node: '"<<openbrace.toStdString()<<"' ... '"<<closebrace.toStdString()<<"'\n";
const NodeSize nodesize=getSizeInternalAndBrace(painter, currentEv); const NodeSize nodesize=getSizeInternalAndBrace(painter, currentEv);
doDrawBoxes(painter, x, y, nodesize); doDrawBoxes(painter, x, y, nodesize);
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device()); const QFont f=currentEv.getFont(parentMathText);
const double lw=fm.lineWidth(); const double lw=JKQTMathTextGetFontLineWidth(f, painter.device());
double xnew=x; double xnew=x;
@ -360,7 +364,6 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
} }
} }
//qDebug()<<" ==> "<<bc<<fm.boundingRect(bc).width();
return xnew; return xnew;
} }
@ -466,20 +469,20 @@ JKQTMathTextBraceNode::NodeSize::NodeSize(const NodeSize &other):
void JKQTMathTextBraceNode::calcBraceSizes(NodeSize& out, QPainter &painter, const JKQTMathTextEnvironment &ev, const JKQTMathTextNodeSize &childSize) const void JKQTMathTextBraceNode::calcBraceSizes(NodeSize& out, QPainter &painter, const JKQTMathTextEnvironment &ev, const JKQTMathTextNodeSize &childSize) const
{ {
const QFontMetricsF fm(ev.getFont(parentMathText), painter.device()); const QFont f=ev.getFont(parentMathText);
const QSizeF openBraceS=calcBraceSize(fm, openbrace, childSize); const QSizeF openBraceS=calcBraceSize(f, painter.device(), openbrace, childSize);
const QSizeF closeBraceS=calcBraceSize(fm, closebrace, childSize); const QSizeF closeBraceS=calcBraceSize(f, painter.device(), closebrace, childSize);
out.openBraceWidth=openBraceS.width(); out.openBraceWidth=openBraceS.width();
out.openBraceHeight=openBraceS.width(); out.openBraceHeight=openBraceS.width();
out.closeBraceWidth=closeBraceS.width(); out.closeBraceWidth=closeBraceS.width();
out.closeBraceHeight=closeBraceS.width(); out.closeBraceHeight=closeBraceS.width();
} }
QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFontMetricsF &fm, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFont &f, QPaintDevice *pd, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const
{ {
double braceWidth=0.0; double braceWidth=0.0;
double braceHeight=0.0; double braceHeight=0.0;
const double lw=fm.lineWidth(); const double lw=JKQTMathTextGetFontLineWidth(f, pd);
const double dblline_distance=2.0*lw; const double dblline_distance=2.0*lw;
braceHeight=childSize.overallHeight*parentMathText->getBraceFactor(); braceHeight=childSize.overallHeight*parentMathText->getBraceFactor();
braceWidth=lw*5.0; braceWidth=lw*5.0;
@ -489,7 +492,7 @@ QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFontMetricsF &fm, JKQTMathTex
if (bracetype==MTBTSingleLine) braceWidth=3.0*lw; if (bracetype==MTBTSingleLine) braceWidth=3.0*lw;
if (bracetype==MTBTSquareBracket || bracetype==MTBTCeilBracket || bracetype==MTBTFloorBracket) braceWidth=7.0*lw; if (bracetype==MTBTSquareBracket || bracetype==MTBTCeilBracket || bracetype==MTBTFloorBracket) braceWidth=7.0*lw;
const double overSizeFactor=braceHeight/fm.height(); const double overSizeFactor=braceHeight/JKQTMathTextGetFontHeight(f, pd);
if (overSizeFactor>1.2) braceWidth=braceWidth*sqrt(overSizeFactor); if (overSizeFactor>1.2) braceWidth=braceWidth*sqrt(overSizeFactor);
return QSizeF(braceWidth, braceHeight); return QSizeF(braceWidth, braceHeight);

View File

@ -101,7 +101,7 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceNode: public JKQTMathTextSingleCh
* *
* \return width and hieght of the brace * \return width and hieght of the brace
*/ */
QSizeF calcBraceSize(const QFontMetricsF& fm, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const; QSizeF calcBraceSize(const QFont& fm, QPaintDevice* pd, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const;
}; };
#endif // JKQTMATHTEXTBRACENODE_H #endif // JKQTMATHTEXTBRACENODE_H

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -133,15 +134,15 @@ JKQTMathTextNodeSize JKQTMathTextDecoratedNode::getSizeInternal(QPainter& painte
JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const double cDescent=cs.getDescent(); const double cDescent=cs.getDescent();
const QFont font=ev.getFont(parentMathText); const QFont font=ev.getFont(parentMathText);
const QFontMetricsF fm(font, painter.device()); const double fascent=JKQTMathTextGetFontAscent(font, painter.device());
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fm.ascent(); const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fascent;
const double deco_height=parentMathText->getDecorationHeightFactor()*fm.ascent(); const double deco_height=parentMathText->getDecorationHeightFactor()*fascent;
const double deco_ypos=cs.baselineHeight+decoSeparation; const double deco_ypos=cs.baselineHeight+decoSeparation;
const double decoAboveAscent_ypos=fm.ascent()+decoSeparation; const double decoAboveAscent_ypos=fascent+decoSeparation;
const double decobelow_ypos=cDescent+decoSeparation; const double decobelow_ypos=cDescent+decoSeparation;
const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild()); const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild());
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?fm.boundingRect("~").width():fm.boundingRect("^").width())-italic_xcorrection; const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?JKQTMathTextGetBoundingRect(font,"~",painter.device()).width():JKQTMathTextGetBoundingRect(font,"^",painter.device()).width())-italic_xcorrection;
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, fm.lineWidth()); const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, JKQTMathTextGetFontLineWidth(font, painter.device()));
@ -227,20 +228,24 @@ const QHash<QString, JKQTMathTextDecoratedNode::DecorationType>& JKQTMathTextDec
} }
double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextDecoratedNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
auto cs=getChild()->getSize(painter, ev); auto cs=getChild()->getSize(painter, ev);
const double cDescent=cs.overallHeight-cs.baselineHeight; const double cDescent=cs.overallHeight-cs.baselineHeight;
const QFont font=ev.getFont(parentMathText); const QFont font=ev.getFont(parentMathText);
const QFontMetricsF fm(font, painter.device()); const QFontMetricsF fm(font, painter.device());
const double width_X=fm.boundingRect("X").width(); const double width_X=JKQTMathTextGetBoundingRect(font,"X",painter.device()).width();
const double width_x=fm.boundingRect("x").width(); const double width_x=JKQTMathTextGetBoundingRect(font,"x",painter.device()).width();
const double width_dot=fm.boundingRect(".").width()/2.0; const double width_dot=JKQTMathTextGetBoundingRect(font,".",painter.device()).width()/2.0;
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fm.ascent(); const double ascent=JKQTMathTextGetFontLineWidth(font, painter.device());
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, fm.lineWidth()); const double decoSeparation=parentMathText->getDecorationSeparationFactor()*ascent;
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, JKQTMathTextGetFontLineWidth(font, painter.device()));
const double linewidthArrow=linewidth*0.65; const double linewidthArrow=linewidth*0.65;
const double deco_height=parentMathText->getDecorationHeightFactor()*fm.ascent(); const double deco_height=parentMathText->getDecorationHeightFactor()*ascent;
const double decoAboveAscent_ypos=y-fm.ascent()-decoSeparation; const double decoAboveAscent_ypos=y-ascent-decoSeparation;
const double strike_ypos=y-cs.baselineHeight/2.0; const double strike_ypos=y-cs.baselineHeight/2.0;
const double decobelow_ypos=y+cDescent+decoSeparation; const double decobelow_ypos=y+cDescent+decoSeparation;
const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild()); const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild());
@ -249,7 +254,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
const double deco_vecwidth=width_x*0.25; const double deco_vecwidth=width_x*0.25;
const double deco_vecheight=deco_height*0.5; const double deco_vecheight=deco_height*0.5;
const double deco_accentwidth=deco_height/4.0; const double deco_accentwidth=deco_height/4.0;
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?fm.boundingRect("j").width():fm.boundingRect("^").width())-italic_xcorrection; const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?JKQTMathTextGetBoundingRect(font,"~",painter.device()).width():JKQTMathTextGetBoundingRect(font,"^",painter.device()).width())-italic_xcorrection;
const double decotop_xcenter=x+italic_xcorrection+(cs.width-italic_xcorrection)/2.0; const double decotop_xcenter=x+italic_xcorrection+(cs.width-italic_xcorrection)/2.0;
const double decotop_xstart=decotop_xcenter-deco_width/2.0+linewidth/2.0; const double decotop_xstart=decotop_xcenter-deco_width/2.0+linewidth/2.0;
const double decotop_xend=decotop_xcenter+deco_width/2.0-linewidth/2.0; const double decotop_xend=decotop_xcenter+deco_width/2.0-linewidth/2.0;
@ -280,7 +285,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
auto fDrawFontAccent=[&](QChar aDirect=QChar(), QChar aFallback=QChar()) -> bool { auto fDrawFontAccent=[&](QChar aDirect=QChar(), QChar aFallback=QChar()) -> bool {
if (!aDirect.isNull() && fm.inFont(aDirect)) { if (!aDirect.isNull() && fm.inFont(aDirect)) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
const QRectF tbra=fm.tightBoundingRect(aDirect); const QRectF tbra=JKQTMathTextGetBoundingRect(font, aDirect, painter.device());
painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0); painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0);
//painter.setPen("red"); //painter.setPen("red");
//painter.drawEllipse(0-2,0-2,4,4); //painter.drawEllipse(0-2,0-2,4,4);
@ -298,7 +303,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
} }
if (!aFallback.isNull() && fm.inFont(aFallback)) { if (!aFallback.isNull() && fm.inFont(aFallback)) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
const QRectF tbra=fm.tightBoundingRect(aFallback); const QRectF tbra=JKQTMathTextGetBoundingRect(font, aFallback, painter.device());
painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0); painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0);
//painter.setPen("yellow"); //painter.setPen("yellow");
//painter.drawEllipse(0-2,0-2,4,4); //painter.drawEllipse(0-2,0-2,4,4);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -128,15 +129,14 @@ JKQTMathTextNodeSize JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JK
if (fracmode==MTFMsfrac) fracmode=MTFMstfrac; if (fracmode==MTFMsfrac) fracmode=MTFMstfrac;
} }
const QFont f=currentEv.getFont(parentMathText); const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment ev1=currentEv; JKQTMathTextEnvironment ev1=currentEv;
JKQTMathTextEnvironment ev2=currentEv; JKQTMathTextEnvironment ev2=currentEv;
const double xheight=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height(); const double xheight=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height();
const double line_ascent=xheight/2.0; const double line_ascent=xheight/2.0;
//const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent(); //const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();
const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width(); const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent(); const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();
const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor(); const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor();
const double braceseparation=xheight*parentMathText->getUnderbraceSeparationXFactor(); const double braceseparation=xheight*parentMathText->getUnderbraceSeparationXFactor();
@ -152,11 +152,11 @@ JKQTMathTextNodeSize JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JK
ev2.fontSize=ev2.fontSize*getFracScalingFactor()*0.7; ev2.fontSize=ev2.fontSize*getFracScalingFactor()*0.7;
} }
const QFontMetricsF fmev1(ev1.getFont(parentMathText), painter.device()); const QFont fev1=ev1.getFont(parentMathText);
const QRectF AeTBR1=fmev1.tightBoundingRect("A"); const QRectF AeTBR1=JKQTMathTextGetBoundingRect(fev1, "A", painter.device());
const double asc1=AeTBR1.height(); const double asc1=AeTBR1.height();
const QFontMetricsF fmev2(ev2.getFont(parentMathText), painter.device()); const QFont fev2=ev2.getFont(parentMathText);
const QRectF AeTBR2=fmev2.tightBoundingRect("A"); const QRectF AeTBR2=JKQTMathTextGetBoundingRect(fev2, "A", painter.device());
const double asc2=AeTBR2.height(); const double asc2=AeTBR2.height();
JKQTMathTextNodeSize size1=child1->getSize(painter, ev1); JKQTMathTextNodeSize size1=child1->getSize(painter, ev1);
@ -243,6 +243,9 @@ double JKQTMathTextFracNode::getFracScalingFactor() const
} }
double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextFracNode[]::draw()"));
#endif
FracType fracmode=this->mode; FracType fracmode=this->mode;
if (currentEv.isMathTextStyle()) { if (currentEv.isMathTextStyle()) {
if (fracmode==MTFMfrac) fracmode=MTFMtfrac; if (fracmode==MTFMfrac) fracmode=MTFMtfrac;
@ -251,14 +254,13 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
const QFont f=currentEv.getFont(parentMathText); const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment ev1=currentEv; JKQTMathTextEnvironment ev1=currentEv;
JKQTMathTextEnvironment ev2=currentEv; JKQTMathTextEnvironment ev2=currentEv;
const QRectF tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double xheight=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height(); const double xheight=tbr_x.height();
const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width(); const double xwidth=tbr_x.width();
const double linewideth=fm.lineWidth(); const double linewideth=JKQTMathTextGetFontLineWidth(f, painter.device());
const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent(); const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent(); const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent();
const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor(); const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor();
@ -277,13 +279,14 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
} }
const QFontMetricsF fmev1(ev1.getFont(parentMathText), painter.device()); const QFont fev1=ev1.getFont(parentMathText);
const QRectF AeTBR1=fmev1.tightBoundingRect("A"); const QRectF AeTBR1=JKQTMathTextGetBoundingRect(fev1, "A", painter.device());
const double asc1=AeTBR1.height(); const double asc1=AeTBR1.height();
const QFontMetricsF fmev2(ev2.getFont(parentMathText), painter.device()); const QFont fev2=ev2.getFont(parentMathText);
const QRectF AeTBR2=fmev2.tightBoundingRect("A"); const QRectF AeTBR2=JKQTMathTextGetBoundingRect(fev2, "A", painter.device());
const double asc2=AeTBR2.height(); const double asc2=AeTBR2.height();
JKQTMathTextNodeSize size1=child1->getSize(painter, ev1); JKQTMathTextNodeSize size1=child1->getSize(painter, ev1);
JKQTMathTextNodeSize size2=child2->getSize(painter, ev2); JKQTMathTextNodeSize size2=child2->getSize(painter, ev2);
if (asc1>size1.baselineHeight) { if (asc1>size1.baselineHeight) {

View File

@ -27,6 +27,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -63,12 +64,12 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
//bool wasBrace=false; //bool wasBrace=false;
for (int i=0; i<nodes.size(); i++) { for (int i=0; i<nodes.size(); i++) {
const QFont f=currentEv.getFont(parentMathText); const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device()); const auto tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double subsupershift=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height()*parentMathText->getOperatorsubsuperDistanceFactor(); const double subsupershift=tbr_x.height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=fm.boundingRect('x').width()*parentMathText->getOperatorsubsuperExtraSpaceFactor(); const double subsuperextrawidth=tbr_x.width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=fm.ascent()*parentMathText->getSubsuperModeSelectionBySizeFactor(); const double subsuperSpecialModeAscent=JKQTMathTextGetFontAscent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=fm.descent()*parentMathText->getSubsuperModeSelectionBySizeFactor(); const double subsuperSpecialModeDecent=JKQTMathTextGetFontDescent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double spaceWidth=fm.boundingRect(' ').width(); const double spaceWidth=JKQTMathTextGetBoundingRect(f, " ", painter.device()).width();
JKQTMathTextSymbolNode::NodeSize prevNodeSize; JKQTMathTextSymbolNode::NodeSize prevNodeSize;
JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr; JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr;
@ -85,7 +86,7 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize; if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize;
if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize; if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize;
} }
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+fm.lineWidth()*0.5; const double subscript_xcorrection=prevNodeSize.baselineXCorrection+JKQTMathTextGetFontLineWidth(f, painter.device())*0.5;
JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]); JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]);
JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]); JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]);
@ -327,6 +328,9 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
} }
double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const { double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextHorizontalListNode[]::draw()"));
#endif
JKQTMathTextEnvironment currentEv=ev; JKQTMathTextEnvironment currentEv=ev;
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
double ynew=y; double ynew=y;
@ -335,11 +339,11 @@ double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double
for (int i=0; i<nodes.size(); i++) { for (int i=0; i<nodes.size(); i++) {
bool doDraw=true; bool doDraw=true;
const QFont f=currentEv.getFont(parentMathText); const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device()); const auto tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double subsupershift=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height()*parentMathText->getOperatorsubsuperDistanceFactor(); const double subsupershift=tbr_x.height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=fm.boundingRect('x').width()*parentMathText->getOperatorsubsuperExtraSpaceFactor(); const double subsuperextrawidth=tbr_x.width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=fm.ascent()*parentMathText->getSubsuperModeSelectionBySizeFactor(); const double subsuperSpecialModeAscent=JKQTMathTextGetFontAscent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=fm.descent()*parentMathText->getSubsuperModeSelectionBySizeFactor(); const double subsuperSpecialModeDecent=JKQTMathTextGetFontDescent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
JKQTMathTextSymbolNode::NodeSize prevNodeSize; JKQTMathTextSymbolNode::NodeSize prevNodeSize;
JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr; JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr;
@ -359,7 +363,7 @@ double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double
if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize; if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize;
if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize; if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize;
} }
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+fm.lineWidth()*0.5; const double subscript_xcorrection=prevNodeSize.baselineXCorrection+JKQTMathTextGetFontLineWidth(f, painter.device())*0.5;
JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]); JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]);
JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]); JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]);

View File

@ -82,9 +82,8 @@ double JKQTMathTextSimpleInstructionNode::draw(QPainter &painter, double x, doub
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
QFont f=currentEv.getFont(parentMathText); QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault); f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, painter.device());
const QString txt=executeInstruction(); const QString txt=executeInstruction();
const QRectF bb=fm.boundingRect(txt); const QRectF bb=JKQTMathTextGetBoundingRect(f, txt, painter.device());
painter.setPen(currentEv.color); painter.setPen(currentEv.color);
painter.setFont(f); painter.setFont(f);
painter.drawText(x,y,txt); painter.drawText(x,y,txt);
@ -123,14 +122,13 @@ JKQTMathTextNodeSize JKQTMathTextSimpleInstructionNode::getSizeInternal(QPainter
{ {
QFont f=currentEv.getFont(parentMathText); QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault); f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, painter.device());
const QString txt=executeInstruction(); const QString txt=executeInstruction();
const QRectF bb=fm.boundingRect(txt); const QRectF bb=JKQTMathTextGetBoundingRect(f, txt, painter.device());
JKQTMathTextNodeSize s; JKQTMathTextNodeSize s;
s.width=bb.width(); s.width=bb.width();
s.baselineHeight=-bb.y(); s.baselineHeight=-bb.y();
s.overallHeight=bb.height(); s.overallHeight=bb.height();
s.strikeoutPos=fm.strikeOutPos(); s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
return s; return s;
} }

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -318,10 +319,10 @@ JKQTMathTextMatrixNode::LayoutInfo JKQTMathTextMatrixNode::calcLayout(QPainter &
JKQTMathTextEnvironment ev1=currentEv; JKQTMathTextEnvironment ev1=currentEv;
const QFontMetricsF fm(ev1.getFont(parentMathText), painter.device()); const QFont font=ev1.getFont(parentMathText);
const double strikepos=fm.strikeOutPos(); const double strikepos=JKQTMathTextGetFontStrikoutPos(font, painter.device());
const double xwidth=fm.boundingRect("x").width(); const double xwidth=JKQTMathTextGetBoundingRect(font,"f",painter.device()).width();
const double lw=fm.lineWidth()*1.5; const double lw=JKQTMathTextGetFontLineWidth(font, painter.device())*1.5;
const double XPadding=parentMathText->getMatrixXPaddingFactor()*xwidth; const double XPadding=parentMathText->getMatrixXPaddingFactor()*xwidth;
const double YPadding=parentMathText->getMatrixYPaddingFactor()*xwidth; const double YPadding=parentMathText->getMatrixYPaddingFactor()*xwidth;
const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth; const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth;
@ -372,21 +373,25 @@ JKQTMathTextNodeSize JKQTMathTextMatrixNode::getSizeInternal(QPainter& painter,
} }
double JKQTMathTextMatrixNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextMatrixNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextMatrixNode[]::draw()"));
#endif
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device()); const QFont font=currentEv.getFont(parentMathText);
JKQTMathTextEnvironment ev1=currentEv; JKQTMathTextEnvironment ev1=currentEv;
const LayoutInfo l=calcLayout(painter, currentEv); const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l); doDrawBoxes(painter, x, y, l);
const double xwidth=fm.boundingRect("x").width(); const double xwidth=JKQTMathTextGetBoundingRect(font,"f",painter.device()).width();
const double fontlw=JKQTMathTextGetFontLineWidth(font, painter.device());
const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth; const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth;
const double YSeparation=parentMathText->getMatrixYSeparationFactor()*xwidth; const double YSeparation=parentMathText->getMatrixYSeparationFactor()*xwidth;
const double yTop=y-l.baselineHeight+l.topPadding; const double yTop=y-l.baselineHeight+l.topPadding;
const double xLeft=x+l.leftPadding; const double xLeft=x+l.leftPadding;
const double linewidth=parentMathText->getMatrixLinewidthThinFactor()*fm.lineWidth(); const double linewidth=parentMathText->getMatrixLinewidthThinFactor()*fontlw;
const double linewidthThick=parentMathText->getMatrixLinewidthHeavyFactor()*fm.lineWidth(); const double linewidthThick=parentMathText->getMatrixLinewidthHeavyFactor()*fontlw;
const double lineSeparation=parentMathText->getMatrixLineSeparationFactor()*fm.lineWidth(); const double lineSeparation=parentMathText->getMatrixLineSeparationFactor()*fontlw;
double leftlineX=xLeft-l.leftPadding/2.0; double leftlineX=xLeft-l.leftPadding/2.0;
double rightlineX=x+l.width-l.rightPadding/2.0; double rightlineX=x+l.width-l.rightPadding/2.0;
double toplineY=yTop-l.topPadding/2.0; double toplineY=yTop-l.topPadding/2.0;

View File

@ -23,6 +23,7 @@
#include "jkqtmathtext/jkqtmathtexttools.h" #include "jkqtmathtext/jkqtmathtexttools.h"
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -58,6 +59,9 @@ JKQTMathTextNodeSize JKQTMathTextModifiedTextPropsInstructionNode::getSizeIntern
} }
double JKQTMathTextModifiedTextPropsInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextModifiedTextPropsInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextModifiedTextPropsInstructionNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;

View File

@ -22,6 +22,7 @@
#include "jkqtmathtext/nodes/jkqtmathtextnoopnode.h" #include "jkqtmathtext/nodes/jkqtmathtextnoopnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextnode.h" #include "jkqtmathtext/nodes/jkqtmathtextnode.h"
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
@ -67,6 +68,9 @@ QString JKQTMathTextBlockNode::getTypeName() const
double JKQTMathTextBlockNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextBlockNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBlockNode[]::draw()"));
#endif
return child->draw(painter, x, y, currentEv); return child->draw(painter, x, y, currentEv);
} }

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -52,16 +53,16 @@ JKQTMathTextSqrtNode::~JKQTMathTextSqrtNode() {
JKQTMathTextNodeSize JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv) const { JKQTMathTextNodeSize JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv) const {
JKQTMathTextNodeSize s; JKQTMathTextNodeSize s;
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device()); const QFont f=currentEv.getFont(parentMathText);
JKQTMathTextEnvironment evSmall=currentEv; JKQTMathTextEnvironment evSmall=currentEv;
evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor(); evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor();
evSmall.italic=false; evSmall.italic=false;
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv);
const double descent=cs.getDescent(); const double descent=cs.getDescent();
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor(); const double sqrtwidth=JKQTMathTextGetBoundingRect(f, "X", painter.device()).width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent()); const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontAscent(f, painter.device()));
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent()); const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontDescent(f, painter.device()));
s.overallHeight=newAscent+newDescent; s.overallHeight=newAscent+newDescent;
s.baselineHeight=newAscent; s.baselineHeight=newAscent;
@ -76,20 +77,22 @@ JKQTMathTextNodeSize JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JK
} }
double JKQTMathTextSqrtNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextSqrtNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSqrtNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
const QFont f=currentEv.getFont(parentMathText); const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment evSmall=currentEv; JKQTMathTextEnvironment evSmall=currentEv;
evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor(); evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor();
evSmall.italic=false; evSmall.italic=false;
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv);
const double descent=cs.overallHeight-cs.baselineHeight; const double descent=cs.overallHeight-cs.baselineHeight;
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor(); const double sqrtwidth=JKQTMathTextGetBoundingRect(f, "X", painter.device()).width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent()); const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontAscent(f, painter.device()));
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent()); const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontDescent(f, painter.device()));
const double linewidth=fm.lineWidth(); const double linewidth=JKQTMathTextGetFontLineWidth(f, painter.device());
const double tinyhookSize=sqrtwidth*0.1; const double tinyhookSize=sqrtwidth*0.1;
const double smalltextIndent=0.6*sqrtwidth; const double smalltextIndent=0.6*sqrtwidth;

View File

@ -24,6 +24,10 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -50,7 +54,6 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeWithSpecialPlacement(QP
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor(); ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const QFont fnt=currentEv.getFont(parentMathText); const QFont fnt=currentEv.getFont(parentMathText);
const QFontMetricsF fm(fnt, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device()); //const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const double childDescent=cs.getDescent(); const double childDescent=cs.getDescent();
@ -67,7 +70,7 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeWithSpecialPlacement(QP
s.baselineHeight=s.overallHeight=cs.overallHeight+shiftToChildBottom; s.baselineHeight=s.overallHeight=cs.overallHeight+shiftToChildBottom;
s.width=cs.width; s.width=cs.width;
if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos; if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos;
else s.strikeoutPos=fm.strikeOutPos(); else s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(fnt, painter.device());
return s; return s;
} }
@ -77,13 +80,15 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeInternal(QPainter &pain
} }
double JKQTMathTextSuperscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const { double JKQTMathTextSuperscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSuperscriptNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor(); ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const QFont fnt=currentEv.getFont(parentMathText); const QFont fnt=currentEv.getFont(parentMathText);
const QFontMetricsF fm(fnt, painter.device());
const QRectF tbr=JKQTMathTextGetTightBoundingRect(fnt, "x", painter.device()); const QRectF tbr=JKQTMathTextGetTightBoundingRect(fnt, "x", painter.device());
const double xh=tbr.height(); const double xh=tbr.height();
//qDebug()<<"x="<<x<<" prevNodeSizeForSpecialPlacement="<<prevNodeSizeForSpecialPlacement<<" font="<<currentEv.getFont(parentMathText); //qDebug()<<"x="<<x<<" prevNodeSizeForSpecialPlacement="<<prevNodeSizeForSpecialPlacement<<" font="<<currentEv.getFont(parentMathText);
@ -98,11 +103,14 @@ double JKQTMathTextSuperscriptNode::drawWithSpecialPlacement(QPainter& painter,
double xx=x; double xx=x;
return getChild()->draw(painter, xx, y-(shiftToChildBottom+childDescent), ev);//+0.5*fm.boundingRect("A").width(); return getChild()->draw(painter, xx, y-(shiftToChildBottom+childDescent), ev);
} }
double JKQTMathTextSuperscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextSuperscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSuperscriptNode[]::draw()"));
#endif
return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr); return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr);
} }
@ -141,7 +149,6 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeWithSpecialPlacement(QPai
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor(); ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const QFont f(ev.getFont(parentMathText)); const QFont f(ev.getFont(parentMathText));
const QFontMetricsF fm(f, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device()); //const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
@ -159,7 +166,7 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeWithSpecialPlacement(QPai
s.baselineHeight=cs.baselineHeight-shift_to_childBaseline; s.baselineHeight=cs.baselineHeight-shift_to_childBaseline;
s.overallHeight=cs.overallHeight; s.overallHeight=cs.overallHeight;
if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos; if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos;
else s.strikeoutPos=fm.strikeOutPos(); else s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
s.width=cs.width; s.width=cs.width;
return s; return s;
} }
@ -170,11 +177,13 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeInternal(QPainter &painte
} }
double JKQTMathTextSubscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const { double JKQTMathTextSubscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSubscriptNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv; JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor(); ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
QFont f=ev.getFont(parentMathText); QFont f=ev.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device()); //const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev); const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
@ -191,11 +200,14 @@ double JKQTMathTextSubscriptNode::drawWithSpecialPlacement(QPainter& painter, do
//qDebug()<<"baselineHeight="<<baselineHeight<<", overallHeight="<<overallHeight<<", strikeoutPos="<<strikeoutPos; //qDebug()<<"baselineHeight="<<baselineHeight<<", overallHeight="<<overallHeight<<", strikeoutPos="<<strikeoutPos;
//qDebug()<<"shift="<<shift<<", yshift="<<yshift; //qDebug()<<"shift="<<shift<<", yshift="<<yshift;
double xx=x; double xx=x;
return getChild()->draw(painter, xx, y+shift_to_childBaseline, ev);//+0.5*fm.boundingRect("A").width(); return getChild()->draw(painter, xx, y+shift_to_childBaseline, ev);
} }
double JKQTMathTextSubscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextSubscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSubscriptNode[]::draw()"));
#endif
return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr); return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr);
} }

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -54,14 +55,17 @@ JKQTMathTextNodeSize JKQTMathTextSymbolNode::getSizeInternal(QPainter& painter,
return getSymbolSize(painter, currentEv); return getSymbolSize(painter, currentEv);
} }
QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFontMetricsF &fm, const QString &text, GlobalSymbolFlags globalFlags) QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFont &f, const QString &text, GlobalSymbolFlags globalFlags, QPaintDevice *pd)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getBoundingRect()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) { if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' '); const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i"); const QRectF brSp=JKQTMathTextGetBoundingRect(f,"i",pd);
QRectF br; QRectF br;
for (int i=0; i<str.size(); i++) { for (int i=0; i<str.size(); i++) {
const QRectF lbr=fm.boundingRect(str[i]); const QRectF lbr=JKQTMathTextGetBoundingRect(f,str[i],pd);
if (i==0) br=lbr; if (i==0) br=lbr;
else { else {
br.setWidth(br.width()+brSp.width()/2.0+lbr.width()); br.setWidth(br.width()+brSp.width()/2.0+lbr.width());
@ -75,18 +79,21 @@ QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFontMetricsF &fm, const QS
} }
return br; return br;
} else { } else {
return fm.boundingRect(text); return JKQTMathTextGetBoundingRect(f,text,pd);
} }
} }
QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFontMetricsF &fm, const QString &text, GlobalSymbolFlags globalFlags) QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFont &f, const QString &text, GlobalSymbolFlags globalFlags, QPaintDevice* pd)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getTightBoundingRect()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) { if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' '); const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i"); const QRectF brSp=JKQTMathTextGetBoundingRect(f,"i",pd);
QRectF br; QRectF br;
for (int i=0; i<str.size(); i++) { for (int i=0; i<str.size(); i++) {
const QRectF lbr=fm.tightBoundingRect(str[i]); const QRectF lbr=JKQTMathTextGetTightBoundingRect(f,str[i],pd);
if (i==0) br=lbr; if (i==0) br=lbr;
else { else {
br.setWidth(br.width()+brSp.width()/2.0+lbr.width()); br.setWidth(br.width()+brSp.width()/2.0+lbr.width());
@ -100,23 +107,25 @@ QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFontMetricsF &fm, con
} }
return br; return br;
} else { } else {
return fm.tightBoundingRect(text); return JKQTMathTextGetTightBoundingRect(f,text,pd);
} }
} }
void JKQTMathTextSymbolNode::drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags) void JKQTMathTextSymbolNode::drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags)
{ {
const QFontMetricsF fm(p.font(), p.device()); #ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::drawText()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) { if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' '); const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i"); const QRectF brSp=JKQTMathTextGetBoundingRect(p.font(), "i", p.device());
double x=0; double x=0;
for (int i=0; i<str.size(); i++) { for (int i=0; i<str.size(); i++) {
p.drawText(QPointF(x,0), str[i]); p.drawText(QPointF(x,0), str[i]);
x=x+fm.boundingRect(str[i]).width()+brSp.width()/2.0; x=x+JKQTMathTextGetBoundingRect(p.font(), str[i], p.device()).width()+brSp.width()/2.0;
} }
} else { } else {
const QRectF tbr=fm.tightBoundingRect(text); const QRectF tbr=JKQTMathTextGetBoundingRect(p.font(), text, p.device());
p.save(); auto __finalpaint=JKQTPFinally([&p]() {p.restore();}); p.save(); auto __finalpaint=JKQTPFinally([&p]() {p.restore();});
p.translate(tbr.center()); p.translate(tbr.center());
if (has(symflags, RotateSymbol90)) { if (has(symflags, RotateSymbol90)) {
@ -138,6 +147,9 @@ void JKQTMathTextSymbolNode::drawText(QPainter &p, const QString &text, GlobalSy
double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::draw()"));
#endif
const NodeSize s=getSymbolSize(painter, currentEv); const NodeSize s=getSymbolSize(painter, currentEv);
doDrawBoxes(painter, x, y, s); doDrawBoxes(painter, x, y, s);
@ -146,20 +158,18 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter); const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter);
const QFont f=drawProps.first; const QFont f=drawProps.first;
const QFont fnonItalic=JKQTMathTextGetNonItalic(drawProps.first); const QFont fnonItalic=JKQTMathTextGetNonItalic(drawProps.first);
const QFontMetricsF fm(f, painter.device());
const QFontMetricsF fmNonItalic(fnonItalic, painter.device());
const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second; const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second;
const SymbolFlags symflags=symprops.flags; const SymbolFlags symflags=symprops.flags;
const QString sym=symprops.symbol; const QString sym=symprops.symbol;
const QRectF tbr=getTightBoundingRect(fm, sym, globalFlags); const QRectF tbr=getTightBoundingRect(f, sym, globalFlags, painter.device());
const QRectF tbrNonItalic=getTightBoundingRect(fmNonItalic, sym, globalFlags); const QRectF tbrNonItalic=getTightBoundingRect(fnonItalic, sym, globalFlags, painter.device());
//const QRectF br=getBoundingRect(fm, sym, globalFlags); //const QRectF br=getBoundingRect(fm, sym, globalFlags);
const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device()); const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device());
const double yShift=symprops.yShiftFactor*tbr.height(); const double yShift=symprops.yShiftFactor*tbr.height();
const double xShift=(s.width-tbr.width())/2.0; const double xShift=(s.width-tbr.width())/2.0;
const QPointF x0(x+xShift-tbr.x(), y+yShift); const QPointF x0(x+xShift-tbr.x(), y+yShift);
double italic_xcorrection=fabs(tbr.width()-tbrNonItalic.width()); double italic_xcorrection=fabs(tbr.width()-tbrNonItalic.width());
if (fabs(italic_xcorrection)<1e-6) italic_xcorrection=double(fm.boundingRect(' ').width())*0.4; if (fabs(italic_xcorrection)<1e-6) italic_xcorrection=double(JKQTMathTextGetBoundingRect(f, " ", painter.device()).width())*0.4;
//std::cout<<"SYMB::draw(): symbolName="<<symbolName.toStdString()<<" font="<<f.family().toStdString()<<" sym="<<sym.toStdString()<<"(0x"<<std::hex<<((sym.size()==0)?uint64_t(0):uint64_t(sym[0].unicode()))<<") yShiftFactor="<<symprops.yShiftFactor<<"\n"; //std::cout<<"SYMB::draw(): symbolName="<<symbolName.toStdString()<<" font="<<f.family().toStdString()<<" sym="<<sym.toStdString()<<"(0x"<<std::hex<<((sym.size()==0)?uint64_t(0):uint64_t(sym[0].unicode()))<<") yShiftFactor="<<symprops.yShiftFactor<<"\n";
@ -173,7 +183,7 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
if (has(symflags, DrawLeftHBar) || has (symflags, DrawRightHBar)) { if (has(symflags, DrawLeftHBar) || has (symflags, DrawRightHBar)) {
//qDebug()<<" -> DrawLeftHBar or DrawRightHBar"; //qDebug()<<" -> DrawLeftHBar or DrawRightHBar";
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth())); painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
const double xh=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height(); const double xh=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height();
const double ybar=-xh*1.1; const double ybar=-xh*1.1;
const double deltaybar=xh*0.2; const double deltaybar=xh*0.2;
@ -184,7 +194,7 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
if (has(symflags, DrawVertLine)) { if (has(symflags, DrawVertLine)) {
//qDebug()<<" -> DrawVertLine"; //qDebug()<<" -> DrawVertLine";
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth())); painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
const double ybar=tbr.top(); const double ybar=tbr.top();
const double xbarstart=italic_xcorrection+tbrNonItalic.width()/2.0; const double xbarstart=italic_xcorrection+tbrNonItalic.width()/2.0;
const double xbarend=tbrNonItalic.width()/2.0; const double xbarend=tbrNonItalic.width()/2.0;
@ -192,22 +202,16 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
} }
if (has(symflags, DrawSlash)) { if (has(symflags, DrawSlash)) {
//qDebug()<<" -> DrawSlash"; //qDebug()<<" -> DrawSlash";
painter.drawText(QPointF((s.width-fm.boundingRect('/').width())/2.0,0),"/"); painter.drawText(QPointF((s.width-JKQTMathTextGetBoundingRect(f, "/", painter.device()).width())/2.0,0),"/");
} }
if (has(symflags, DrawBackSlash)) { if (has(symflags, DrawBackSlash)) {
//qDebug()<<" -> DrawBackSlash"; //qDebug()<<" -> DrawBackSlash";
painter.drawText(QPointF((s.width-fm.boundingRect('\\').width())/2.0,0),"\\"); painter.drawText(QPointF((s.width-JKQTMathTextGetBoundingRect(f, "\\", painter.device()).width())/2.0,0),"\\");
} }
/*painter.save();
painter.setPen(QPen(QColor("red"), 0.5, Qt::DotLine));
painter.drawEllipse(0,0,5,5);
painter.drawRect(tbr);
painter.setPen(QPen(QColor("blue"), 0.5, Qt::DashLine));
painter.drawRect(br);
painter.restore();*/
} else { // draw a box to indicate an unavailable symbol } else { // draw a box to indicate an unavailable symbol
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth())); painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
painter.drawRect(QRectF(x0.x(), x0.y()-tbrNoSymbol.height(), tbrNoSymbol.width(), tbrNoSymbol.height())); painter.drawRect(QRectF(x0.x(), x0.y()-tbrNoSymbol.height(), tbrNoSymbol.width(), tbrNoSymbol.height()));
} }
@ -232,18 +236,20 @@ QString JKQTMathTextSymbolNode::getSymbolName() const {
JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter &painter, JKQTMathTextEnvironment currentEv) const JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter &painter, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getSymbolSize()"));
#endif
NodeSize s; NodeSize s;
const auto fullProps=symbols().value(symbolName, SymbolFullProps()); const auto fullProps=symbols().value(symbolName, SymbolFullProps());
const GlobalSymbolFlags globalFlags=fullProps.globalFlags; const GlobalSymbolFlags globalFlags=fullProps.globalFlags;
const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter); const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter);
const QFont f=drawProps.first; const QFont f=drawProps.first;
const QFontMetricsF fm(f, painter.device());
const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second; const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second;
const SymbolFlags symflags=symprops.flags; const SymbolFlags symflags=symprops.flags;
const QString sym=symprops.symbol; const QString sym=symprops.symbol;
const QRectF tbr=getTightBoundingRect(fm, sym, globalFlags); const QRectF tbr=getTightBoundingRect(f, sym, globalFlags, painter.device());
const QRectF br=getBoundingRect(fm, sym, globalFlags); const QRectF br=getBoundingRect(f, sym, globalFlags, painter.device());
const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device()); const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device());
const QRectF mintbr=JKQTMathTextGetTightBoundingRect(f, "(", painter.device()); const QRectF mintbr=JKQTMathTextGetTightBoundingRect(f, "(", painter.device());
const QRectF dottbr=JKQTMathTextGetTightBoundingRect(f, ".", painter.device()); const QRectF dottbr=JKQTMathTextGetTightBoundingRect(f, ".", painter.device());
@ -272,13 +278,13 @@ JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter
const double oldDescent=s.overallHeight-s.baselineHeight; const double oldDescent=s.overallHeight-s.baselineHeight;
if (has(symflags, HeightIsAscent)) { if (has(symflags, HeightIsAscent)) {
s.baselineHeight=fm.ascent(); s.baselineHeight=JKQTMathTextGetFontAscent(f, painter.device());
s.overallHeight=s.baselineHeight+oldDescent; s.overallHeight=s.baselineHeight+oldDescent;
} }
if (has(symflags, RotateSymbol90)) { if (has(symflags, RotateSymbol90)) {
s.width=qMax(s.overallHeight, s.width); s.width=qMax(s.overallHeight, s.width);
} }
s.strikeoutPos=fm.strikeOutPos(); s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
if (has(globalFlags, IntLikeSymbolCorrection)) { if (has(globalFlags, IntLikeSymbolCorrection)) {
if (has(globalFlags, SubSuperscriptBelowAboveSymbol)) { if (has(globalFlags, SubSuperscriptBelowAboveSymbol)) {
@ -288,7 +294,7 @@ JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter
s.topXCorrection=dottbr.width(); s.topXCorrection=dottbr.width();
} }
if (has(globalFlags, SubscriptCorrection) && sym.size()>0) { if (has(globalFlags, SubscriptCorrection) && sym.size()>0) {
s.baselineXCorrection=fm.rightBearing(sym[sym.size()-1]); s.baselineXCorrection=JKQTMathTextGetRightBearing(f,sym[sym.size()-1],painter.device());
} }
return s; return s;
@ -384,7 +390,7 @@ const QHash<QString, JKQTMathTextSymbolNode::SymbolFullProps> &JKQTMathTextSymbo
* STANDARD Symbols available in all standard fonts * STANDARD Symbols available in all standard fonts
**************************************************************************************/ **************************************************************************************/
symbols["#"]=SimpleTextSymbol("#", "&num;"); symbols["#"]=SimpleTextSymbol("#", "&num;");
symbols["%"]=SimpleTextSymbol("%", "&NestedGreaterGreater;"); symbols["%"]=SimpleTextSymbol("%", "&percent;");
symbols["&"]=SimpleTextSymbol("&", "&amp;"); symbols["&"]=SimpleTextSymbol("&", "&amp;");
symbols["("]=SimpleUprightTextSymbol("("); symbols["("]=SimpleUprightTextSymbol("(");
symbols[")"]=SimpleUprightTextSymbol(")"); symbols[")"]=SimpleUprightTextSymbol(")");

View File

@ -156,9 +156,9 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextSymbolNode: public JKQTMathTextNode {
friend inline bool has(GlobalSymbolFlags a, GlobalSymbolFlags b) { return (a&b)==b; } friend inline bool has(GlobalSymbolFlags a, GlobalSymbolFlags b) { return (a&b)==b; }
/** \brief calculates the bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */ /** \brief calculates the bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */
static QRectF getBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags); static QRectF getBoundingRect(const QFont &fm, const QString& text, GlobalSymbolFlags globalFlags, QPaintDevice *pd);
/** \brief calculates the tight bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */ /** \brief calculates the tight bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */
static QRectF getTightBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags); static QRectF getTightBoundingRect(const QFont& fm, const QString& text, GlobalSymbolFlags globalFlags, QPaintDevice *pd);
/** \brief draw \a text at (0,0) using QPainter \a p and taking the flags from \a globalFlags into account */ /** \brief draw \a text at (0,0) using QPainter \a p and taking the flags from \a globalFlags into account */
static void drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags); static void drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -141,15 +142,7 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
const QFont fUpright=JKQTMathTextGetNonItalic(f); const QFont fUpright=JKQTMathTextGetNonItalic(f);
const QFont fFallbackSym=currentEv.exchangedFontFor(MTEFallbackSymbols).getFont(parentMathText); const QFont fFallbackSym=currentEv.exchangedFontFor(MTEFallbackSymbols).getFont(parentMathText);
const QFont fRoman=currentEv.exchangedFontForRoman().getFont(parentMathText); const QFont fRoman=currentEv.exchangedFontForRoman().getFont(parentMathText);
const QFontMetricsF fmUpright(fUpright, painter.device()); const double sp=JKQTMathTextGetHorAdvance(f, " ", painter.device());
const QFontMetricsF fm(f, painter.device());
const QFontMetricsF fmFallbackSym(fFallbackSym, painter.device());
const QFontMetricsF fmRoman(fRoman, painter.device());
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
const double sp=fm.horizontalAdvance(' ');
#else
const double sp=fm.width(' ');
#endif
l.width=0; l.width=0;
double ascent=0; double ascent=0;
double descent=0; double descent=0;
@ -160,23 +153,23 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
switch(l.fontMode[i]) { switch(l.fontMode[i]) {
case FMasDefined: case FMasDefined:
case FMasDefinedOutline: case FMasDefinedOutline:
br=fm.boundingRect(l.textpart[i]); br=JKQTMathTextGetBoundingRect(f, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(f, l.textpart[i], painter.device()); tbr=JKQTMathTextGetTightBoundingRect(f, l.textpart[i], painter.device());
if (f.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fm.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1)); if (f.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(f,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break; break;
case FMasDefinedForceUpright: case FMasDefinedForceUpright:
br=fmUpright.boundingRect(l.textpart[i]); br=JKQTMathTextGetBoundingRect(fUpright, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fUpright, l.textpart[i], painter.device()); tbr=JKQTMathTextGetTightBoundingRect(fUpright, l.textpart[i], painter.device());
break; break;
case FMroman: case FMroman:
br=fmRoman.boundingRect(l.textpart[i]); br=JKQTMathTextGetBoundingRect(fRoman, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fRoman, l.textpart[i], painter.device()); tbr=JKQTMathTextGetTightBoundingRect(fRoman, l.textpart[i], painter.device());
if (fRoman.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fmRoman.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1)); if (fRoman.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(fRoman,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break; break;
case FMfallbackSymbol: case FMfallbackSymbol:
br=fmFallbackSym.boundingRect(l.textpart[i]); br=JKQTMathTextGetBoundingRect(fFallbackSym, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fFallbackSym, l.textpart[i], painter.device()); tbr=JKQTMathTextGetTightBoundingRect(fFallbackSym, l.textpart[i], painter.device());
if (fFallbackSym.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fmFallbackSym.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1)); if (fFallbackSym.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(fFallbackSym,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break; break;
} }
l.textpartXPos.append(l.width); l.textpartXPos.append(l.width);
@ -193,7 +186,7 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
} }
l.overallHeight=(ascent+descent); //fm.height(); l.overallHeight=(ascent+descent); //fm.height();
l.baselineHeight=ascent; l.baselineHeight=ascent;
l.strikeoutPos=fm.strikeOutPos(); l.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
return l; return l;
} }
@ -285,6 +278,9 @@ void JKQTMathTextTextNode::splitTextForLayout(QPainter &painter, JKQTMathTextEnv
} }
double JKQTMathTextTextNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextTextNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextTextNode[]::draw()"));
#endif
const LayoutInfo l=calcLayout(painter, currentEv); const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l); doDrawBoxes(painter, x, y, l);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -81,6 +82,9 @@ size_t JKQTMathTextVerbatimNode::getTabSize() const
double JKQTMathTextVerbatimNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextVerbatimNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextVerbatimNode[]::draw()"));
#endif
transformEnvironment(currentEv); transformEnvironment(currentEv);
const LayoutInfo l=calcLayout(painter, currentEv); const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l); doDrawBoxes(painter, x, y, l);
@ -134,10 +138,10 @@ JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPaint
QFont f=currentEv.getFont(parentMathText); QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault); f.setStyleStrategy(QFont::PreferDefault);
f.setFixedPitch(true); f.setFixedPitch(true);
const QFontMetricsF fm(f, painter.device()); const qreal fascent=JKQTMathTextGetFontAscent(f, painter.device());
const double linespacing=fm.lineSpacing()*lineSpacingFactor; const double linespacing=JKQTMathTextGetFontLineSpacing(f, painter.device())*lineSpacingFactor;
const double fleading=fm.leading(); const double fleading=JKQTMathTextGetFontLeading(f, painter.device());
const double synLeading=fm.lineWidth(); const double synLeading=JKQTMathTextGetFontLineWidth(f, painter.device());
const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor; const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor;
if (text.size()<=0) { if (text.size()<=0) {
@ -154,18 +158,18 @@ JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPaint
for (int i=0; i<l.lines.size(); i++) { for (int i=0; i<l.lines.size(); i++) {
if (i==0) { if (i==0) {
heightSum=fm.ascent(); heightSum=fascent;
} else if (i>0) { } else if (i>0) {
const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fm.ascent()); const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fascent);
heightSum=heightSum+deltaLine; heightSum=heightSum+deltaLine;
y=y+deltaLine; y=y+deltaLine;
} }
widths<<fm.boundingRect(l.lines[i]).width(); widths<<JKQTMathTextGetBoundingRect(f,l.lines[i],painter.device()).width();
l.width=qMax(l.width, widths.last()); l.width=qMax(l.width, widths.last());
heights<<fm.height(); heights<<JKQTMathTextGetFontHeight(f, painter.device());
ascents<<fm.ascent(); ascents<<fascent;
descents<<fm.descent(); descents<<JKQTMathTextGetFontDescent(f, painter.device());
strikeouts<<fm.strikeOutPos(); strikeouts<<JKQTMathTextGetFontStrikoutPos(f, painter.device());
ysFromFirstLine<<y; ysFromFirstLine<<y;
} }
heightSum+=descents.last(); heightSum+=descents.last();

View File

@ -27,6 +27,7 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -76,10 +77,10 @@ JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayou
QList<double> ysFromFirstLine; // y-position of each line, where the first line is always at y=0 (i.e. ysFromFirstLine[0]==0) QList<double> ysFromFirstLine; // y-position of each line, where the first line is always at y=0 (i.e. ysFromFirstLine[0]==0)
double y=0; double y=0;
for (int i=0; i<nodes.size(); i++) { for (int i=0; i<nodes.size(); i++) {
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device()); const QFont f=currentEv.getFont(parentMathText);
const double linespacing=fm.lineSpacing()*lineSpacingFactor; const double linespacing=JKQTMathTextGetFontLineSpacing(f, painter.device())*lineSpacingFactor;
const double fleading=fm.leading(); const double fleading=JKQTMathTextGetFontLeading(f, painter.device());
const double synLeading=fm.lineWidth(); const double synLeading=JKQTMathTextGetFontLineWidth(f, painter.device());
const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor; const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor;
const JKQTMathTextNodeSize loc=nodes[i]->getSize(painter, currentEv); const JKQTMathTextNodeSize loc=nodes[i]->getSize(painter, currentEv);
@ -145,6 +146,9 @@ JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayou
} }
double JKQTMathTextVerticalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const { double JKQTMathTextVerticalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextVerticalListNode[]::draw()"));
#endif
JKQTMathTextEnvironment currentEv=ev; JKQTMathTextEnvironment currentEv=ev;
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
const LayoutInfo l=calcLayout(painter, currentEv); const LayoutInfo l=calcLayout(painter, currentEv);

View File

@ -25,6 +25,9 @@
#include "jkqtmathtext/jkqtmathtext.h" #include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath> #include <cmath>
#include <QFontMetricsF> #include <QFontMetricsF>
#include <QDebug> #include <QDebug>
@ -114,6 +117,9 @@ size_t JKQTMathTextWhitespaceNode::getWhitespaceCount() const
double JKQTMathTextWhitespaceNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextWhitespaceNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextWhitespaceNode[]::draw()"));
#endif
const JKQTMathTextNodeSize s=getSize(painter, currentEv); const JKQTMathTextNodeSize s=getSize(painter, currentEv);
doDrawBoxes(painter, x,y,s); doDrawBoxes(painter, x,y,s);
return x+s.width; return x+s.width;
@ -123,11 +129,10 @@ JKQTMathTextNodeSize JKQTMathTextWhitespaceNode::getSizeInternal(QPainter &paint
{ {
JKQTMathTextNodeSize s; JKQTMathTextNodeSize s;
const double singelWidthPIX=Type2PixelWidth(whitespace.type, currentEv, painter.device()); const double singelWidthPIX=Type2PixelWidth(whitespace.type, currentEv, painter.device());
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
s.width=singelWidthPIX*static_cast<double>(whitespace.count); s.width=singelWidthPIX*static_cast<double>(whitespace.count);
s.baselineHeight=0; s.baselineHeight=0;
s.overallHeight=0; s.overallHeight=0;
s.strikeoutPos=fm.strikeOutPos(); s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(currentEv.getFont(parentMathText), painter.device());
return s; return s;
} }
@ -179,14 +184,9 @@ QString JKQTMathTextWhitespaceNode::Type2String(Types type)
double JKQTMathTextWhitespaceNode::Type2PixelWidth(Types type, JKQTMathTextEnvironment currentEv, QPaintDevice* pd) const double JKQTMathTextWhitespaceNode::Type2PixelWidth(Types type, JKQTMathTextEnvironment currentEv, QPaintDevice* pd) const
{ {
const QFontMetricsF fm(currentEv.getFont(parentMathText), pd); const QFont f=currentEv.getFont(parentMathText);
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0)) const double sp=JKQTMathTextGetHorAdvance(f, " ", pd);
const double em=fm.horizontalAdvance(QChar(0x2003));//currentEv.fontSize; const double em=JKQTMathTextGetHorAdvance(f, QChar(0x2003), pd);
const double sp=fm.horizontalAdvance(' ');//currentEv.fontSize;
#else
const double em=fm.width(QChar(0x2003));//currentEv.fontSize;
const double sp=fm.width(' ');//currentEv.fontSize;
#endif
const double en=em/2.0; const double en=em/2.0;
switch (type) { switch (type) {
case WSTNormal: return sp; case WSTNormal: return sp;
@ -255,13 +255,8 @@ double JKQTMathTextEmptyBoxNode::Units2PixelWidth(double value, Units unit, JKQT
{ {
QFont f=currentEv.getFont(parentMathText); QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault); f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, pd);
if (unit==EBUem) { if (unit==EBUem) {
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0)) const double em=JKQTMathTextGetHorAdvance(f, QChar(0x2003), pd);
const double em=fm.horizontalAdvance(QChar(0x2003));//currentEv.fontSize;
#else
const double em=fm.width(QChar(0x2003));//currentEv.fontSize;
#endif
//qDebug()<<"em="<<em<<"pix"; //qDebug()<<"em="<<em<<"pix";
return value*em; return value*em;
} else if (unit==EBUex) { } else if (unit==EBUex) {
@ -319,6 +314,9 @@ double JKQTMathTextEmptyBoxNode::getHeight() const
double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextEmptyBoxNode[]::draw()"));
#endif
const auto s=getSize(painter, currentEv); const auto s=getSize(painter, currentEv);
doDrawBoxes(painter, x,y,s); doDrawBoxes(painter, x,y,s);
return x+s.width; return x+s.width;
@ -327,7 +325,6 @@ double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQ
JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv) const JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv) const
{ {
JKQTMathTextNodeSize s; JKQTMathTextNodeSize s;
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
s.width=Units2PixelWidth(width, widthUnit, currentEv, painter.device()); s.width=Units2PixelWidth(width, widthUnit, currentEv, painter.device());
s.overallHeight=Units2PixelWidth(height, heightUnit, currentEv, painter.device()); s.overallHeight=Units2PixelWidth(height, heightUnit, currentEv, painter.device());
if (height>0) { if (height>0) {
@ -335,7 +332,7 @@ JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode::getSizeInternal(QPainter &painter
} else { } else {
s.baselineHeight=0; s.baselineHeight=0;
} }
s.strikeoutPos=fm.strikeOutPos(); s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(currentEv.getFont(parentMathText), painter.device());
return s; return s;
} }
@ -400,6 +397,9 @@ JKQTMathTextNodeSize JKQTMathTextPhantomNode::getSizeInternal(QPainter& painter,
} }
double JKQTMathTextPhantomNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { double JKQTMathTextPhantomNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextPhantomNode[]::draw()"));
#endif
const JKQTMathTextNodeSize s=getSize(painter, currentEv); const JKQTMathTextNodeSize s=getSize(painter, currentEv);
doDrawBoxes(painter, x, y, s); doDrawBoxes(painter, x, y, s);
return x+s.width; return x+s.width;

View File

@ -63,13 +63,15 @@ void JKQTPBaseKey::saveSettings(QSettings& settings, const QString& group) const
void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, const KeySizeDescription& layout) void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, const KeySizeDescription& layout)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::drawKey()").arg(objectName()));
#endif
if (!keyStyle().visible) return; if (!keyStyle().visible) return;
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize); QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device()); const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal Xwid=kfm.boundingRect('X').width(); const qreal FHeight=JKQTMathTextGetFontHeight(kf, painter.device());
const qreal FHeight=kfm.height();
// determine layouting info and size // determine layouting info and size
QPointF internalOffset(0,0); QPointF internalOffset(0,0);
@ -130,6 +132,7 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
// draw key table/contents // draw key table/contents
x0=x0+internalOffset; x0=x0+internalOffset;
QPointF xi=x0; QPointF xi=x0;
int ic=0;
for (const auto& c: layout.d->columns) { for (const auto& c: layout.d->columns) {
xi.setY(x0.y()); xi.setY(x0.y());
int ir=0; int ir=0;
@ -137,12 +140,22 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
const QRectF sampleRect(xi, QSizeF(keyStyle().sampleLineLength*Xwid, keyStyle().sampleHeight*FHeight)); const QRectF sampleRect(xi, QSizeF(keyStyle().sampleLineLength*Xwid, keyStyle().sampleHeight*FHeight));
const double rowHeight=layout.d->calcRowHeight(ir, sampleRect.height()); const double rowHeight=layout.d->calcRowHeight(ir, sampleRect.height());
const QRectF textRect(xi+QPointF((keyStyle().sampleLineLength+keyStyle().xSeparation)*Xwid, 0), QSize(r.size.width(), rowHeight)); const QRectF textRect(xi+QPointF((keyStyle().sampleLineLength+keyStyle().xSeparation)*Xwid, 0), QSize(r.size.width(), rowHeight));
drawEntrySample(r.id, painter, sampleRect), drawEntrySample(r.id, painter, sampleRect);
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaatmt(QString("JKQTPBaseKey[%1]::drawKey()::drawEntryText(r=%2,c=%3)::parse").arg(objectName()).arg(ir).arg(ic));
#endif
getParentMathText()->setFontColor(keyStyle().textColor); getParentMathText()->setFontColor(keyStyle().textColor);
getParentMathText()->setFontPointSize(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); getParentMathText()->setFontPointSize(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
getParentMathText()->setFontSpecial(keyStyle().fontName); getParentMathText()->setFontSpecial(keyStyle().fontName);
getParentMathText()->parse(r.text); getParentMathText()->parse(r.text);
}
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaatmt(QString("JKQTPBaseKey[%1]::drawKey()::drawEntryText(r=%2,c=%3)::parse").arg(objectName()).arg(ir).arg(ic));
#endif
getParentMathText()->draw(painter, Qt::AlignLeft|Qt::AlignVCenter, textRect, getParent()->isDebugShowTextBoxesEnabled()); getParentMathText()->draw(painter, Qt::AlignLeft|Qt::AlignVCenter, textRect, getParent()->isDebugShowTextBoxesEnabled());
}
if (drawDebugRects) { if (drawDebugRects) {
painter.save(); auto __finalpaintinner=JKQTPFinally([&painter]() {painter.restore();}); painter.save(); auto __finalpaintinner=JKQTPFinally([&painter]() {painter.restore();});
@ -160,6 +173,7 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
ir++; ir++;
} }
xi.setX(xi.x()+c.calcColumnWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid)+keyStyle().columnSeparation*Xwid); xi.setX(xi.x()+c.calcColumnWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid)+keyStyle().columnSeparation*Xwid);
ic++;
} }
} }
@ -167,13 +181,15 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
JKQTPBaseKey::KeySizeDescription JKQTPBaseKey::getSize(JKQTPEnhancedPainter &painter) JKQTPBaseKey::KeySizeDescription JKQTPBaseKey::getSize(JKQTPEnhancedPainter &painter)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::getSize()").arg(objectName()));
#endif
KeySizeDescription size; KeySizeDescription size;
if (!keyStyle().visible) return size; if (!keyStyle().visible) return size;
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize); QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device()); const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal Xwid=kfm.boundingRect('X').width();
// calculate layout of the "table" of samples and labels // calculate layout of the "table" of samples and labels
const KeyLayoutDescription layout=getKeyLayout(painter); const KeyLayoutDescription layout=getKeyLayout(painter);
@ -190,9 +206,8 @@ void JKQTPBaseKey::calcLayoutSize(JKQTPEnhancedPainter &painter, KeySizeDescript
{ {
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize); QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device()); const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal Xwid=kfm.boundingRect('X').width(); const qreal FHeight=JKQTMathTextGetFontHeight(kf, painter.device());
const qreal FHeight=kfm.height();
layout.requiredSize=extendLayoutSize(QSizeF(layout.d->calcOverallWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid, keyStyle().columnSeparation*Xwid), layout.requiredSize=extendLayoutSize(QSizeF(layout.d->calcOverallWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid, keyStyle().columnSeparation*Xwid),
layout.d->calcOverallHeight(keyStyle().ySeparation*FHeight, keyStyle().sampleHeight*FHeight)), painter); layout.d->calcOverallHeight(keyStyle().ySeparation*FHeight, keyStyle().sampleHeight*FHeight)), painter);
@ -207,6 +222,9 @@ void JKQTPBaseKey::calcLayoutSize(JKQTPEnhancedPainter &painter, KeySizeDescript
void JKQTPBaseKey::modifySize(JKQTPEnhancedPainter &painter, KeySizeDescription &currentKeyLayout, QSizeF preliminaryPlotSize) void JKQTPBaseKey::modifySize(JKQTPEnhancedPainter &painter, KeySizeDescription &currentKeyLayout, QSizeF preliminaryPlotSize)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::modifySize()").arg(objectName()));
#endif
const auto lay=getLayout(); const auto lay=getLayout();
if (lay==JKQTPKeyLayoutMultiColumn || lay==JKQTPKeyLayoutMultiRow) { if (lay==JKQTPKeyLayoutMultiColumn || lay==JKQTPKeyLayoutMultiRow) {
std::function<bool(QSizeF, QSizeF)> fCompare=[](const QSizeF& requiredSize, const QSizeF& preliminaryPlotSize) { std::function<bool(QSizeF, QSizeF)> fCompare=[](const QSizeF& requiredSize, const QSizeF& preliminaryPlotSize) {
@ -264,11 +282,13 @@ void JKQTPBaseKey::setCurrentKeyStyle(const JKQTPKeyStyle &style)
JKQTPBaseKey::KeyLayoutDescription JKQTPBaseKey::getKeyLayout(JKQTPEnhancedPainter &painter) JKQTPBaseKey::KeyLayoutDescription JKQTPBaseKey::getKeyLayout(JKQTPEnhancedPainter &painter)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::getKeyLayout()").arg(objectName()));
#endif
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize); QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
QFontMetricsF kfm(kf, painter.device()); //const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
//const qreal Xwid=kfm.boundingRect('X').width(); const qreal Fheight=JKQTMathTextGetFontHeight(kf, painter.device());
const qreal Fheight=kfm.height();
//const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier())); //const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier()));
@ -303,10 +323,12 @@ JKQTPBaseKey::KeyLayoutDescription JKQTPBaseKey::getKeyLayout(JKQTPEnhancedPaint
QSizeF JKQTPBaseKey::extendLayoutSize(QSizeF rawLayoutSize, JKQTPEnhancedPainter& painter, QPointF *offset) const QSizeF JKQTPBaseKey::extendLayoutSize(QSizeF rawLayoutSize, JKQTPEnhancedPainter& painter, QPointF *offset) const
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::extendLayoutSize()").arg(objectName()));
#endif
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize); QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier()); kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
QFontMetricsF kfm(kf, painter.device()); const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal Xwid=kfm.boundingRect('X').width();
const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier())); const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier()));
if (rawLayoutSize.width()>0) rawLayoutSize.setWidth(rawLayoutSize.width()+2.0*keyStyle().xMargin*Xwid+2.0*frameWidth); if (rawLayoutSize.width()>0) rawLayoutSize.setWidth(rawLayoutSize.width()+2.0*keyStyle().xMargin*Xwid+2.0*frameWidth);
@ -531,6 +553,9 @@ QColor JKQTPMainKey::getEntryColor(int item) const
void JKQTPMainKey::drawEntrySample(int item, JKQTPEnhancedPainter &painter, const QRectF &rect) void JKQTPMainKey::drawEntrySample(int item, JKQTPEnhancedPainter &painter, const QRectF &rect)
{ {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::drawEntrySammple(%2)").arg(objectName()).arg(item));
#endif
auto g=getPlotElement(item); auto g=getPlotElement(item);
if (g) g->drawKeyMarker(painter, rect); if (g) g->drawKeyMarker(painter, rect);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB