2022-07-04 02:30:12 +08:00
/*
Copyright ( c ) 2008 - 2022 Jan W . Krieger ( < jan @ jkrieger . de > )
This software is free software : you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License ( LGPL ) as published by
the Free Software Foundation , either version 2.1 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License ( LGPL ) for more details .
You should have received a copy of the GNU Lesser General Public License ( LGPL )
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "jkqtmathtext/nodes/jkqtmathtextwhitespacenode.h"
# include "jkqtmathtext/jkqtmathtexttools.h"
# include "jkqtmathtext/nodes/jkqtmathtextnode.h"
# include "jkqtmathtext/jkqtmathtext.h"
# include "jkqtcommon/jkqtpcodestructuring.h"
# include "jkqtcommon/jkqtpstringtools.h"
# include <cmath>
# include <QFontMetricsF>
# include <QDebug>
# include <QFontDatabase>
# include <QFontInfo>
# include <QApplication>
# include <QFont>
JKQTMathTextWhitespaceNode : : JKQTMathTextWhitespaceNode ( Types type , JKQTMathText * _parent ) :
JKQTMathTextWhitespaceNode ( type , 1 , _parent )
{
}
JKQTMathTextWhitespaceNode : : JKQTMathTextWhitespaceNode ( JKQTMathText * _parent ) :
JKQTMathTextWhitespaceNode ( WSTNormal , 1 , _parent )
{
}
JKQTMathTextWhitespaceNode : : JKQTMathTextWhitespaceNode ( const QString & _type , JKQTMathText * parent ) :
JKQTMathTextWhitespaceNode ( parent )
{
fillSupportedInstructions ( ) ;
whitespace = supportedInstructions [ _type ] ;
}
JKQTMathTextWhitespaceNode : : JKQTMathTextWhitespaceNode ( const QString & _type , size_t count , JKQTMathText * parent ) :
JKQTMathTextWhitespaceNode ( parent )
{
fillSupportedInstructions ( ) ;
whitespace = supportedInstructions [ _type ] ;
whitespace . count = whitespace . count * count ;
}
JKQTMathTextWhitespaceNode : : JKQTMathTextWhitespaceNode ( Types type , size_t count , JKQTMathText * parent ) :
JKQTMathTextNode ( parent ) ,
whitespace ( type , count )
{
fillSupportedInstructions ( ) ;
}
JKQTMathTextWhitespaceNode : : ~ JKQTMathTextWhitespaceNode ( ) {
}
QString JKQTMathTextWhitespaceNode : : getTypeName ( ) const
{
return QLatin1String ( " JKQTMathTextWhitespaceNode( " ) + Type2String ( whitespace . type ) + " , count= " + QString : : number ( whitespace . count ) + " ) " ;
}
2022-08-17 05:05:04 +08:00
bool JKQTMathTextWhitespaceNode : : toHtml ( QString & html , JKQTMathTextEnvironment /*currentEv*/ , JKQTMathTextEnvironment /*defaultEv*/ ) const {
2022-07-04 02:30:12 +08:00
for ( size_t i = 0 ; i < whitespace . count ; i + + ) {
html = html + Type2HTML ( whitespace . type ) ;
}
return true ;
}
JKQTMathTextWhitespaceNode : : WhitespaceProps : : WhitespaceProps ( JKQTMathTextWhitespaceNode : : Types _type , size_t _count ) :
type ( _type ) , count ( _count )
{
}
2022-08-14 22:59:03 +08:00
JKQTMathTextWhitespaceNode : : WhitespaceProps : : WhitespaceProps ( const WhitespaceProps & other ) :
type ( other . type ) , count ( other . count )
{
}
JKQTMathTextWhitespaceNode : : WhitespaceProps & JKQTMathTextWhitespaceNode : : WhitespaceProps : : operator = ( const WhitespaceProps & other )
{
type = other . type ;
count = other . count ;
return * this ;
}
2022-07-04 02:30:12 +08:00
JKQTMathTextWhitespaceNode : : Types JKQTMathTextWhitespaceNode : : getWhitespaceType ( ) const
{
return whitespace . type ;
}
size_t JKQTMathTextWhitespaceNode : : getWhitespaceCount ( ) const
{
return whitespace . count ;
}
2022-08-17 05:05:04 +08:00
double JKQTMathTextWhitespaceNode : : draw ( QPainter & painter , double x , double y , JKQTMathTextEnvironment currentEv ) const
2022-07-04 02:30:12 +08:00
{
2022-08-17 05:05:04 +08:00
const JKQTMathTextNodeSize s = getSize ( painter , currentEv ) ;
doDrawBoxes ( painter , x , y , s ) ;
return x + s . width ;
2022-07-04 02:30:12 +08:00
}
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize JKQTMathTextWhitespaceNode : : getSizeInternal ( QPainter & painter , JKQTMathTextEnvironment currentEv ) const
2022-07-04 02:30:12 +08:00
{
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize s ;
2022-07-05 03:02:43 +08:00
const double singelWidthPIX = Type2PixelWidth ( whitespace . type , currentEv , painter . device ( ) ) ;
2023-07-01 21:57:57 +08:00
const QFontMetricsF fm ( currentEv . getFont ( parentMathText ) , painter . device ( ) ) ;
2022-08-17 05:05:04 +08:00
s . width = singelWidthPIX * static_cast < double > ( whitespace . count ) ;
s . baselineHeight = 0 ;
s . overallHeight = 0 ;
s . strikeoutPos = fm . strikeOutPos ( ) ;
return s ;
2022-07-04 02:30:12 +08:00
}
QHash < QString , JKQTMathTextWhitespaceNode : : WhitespaceProps > JKQTMathTextWhitespaceNode : : supportedInstructions ;
void JKQTMathTextWhitespaceNode : : fillSupportedInstructions ( )
{
2023-06-30 19:52:17 +08:00
static std : : mutex sMutex ;
std : : lock_guard < std : : mutex > lock ( sMutex ) ;
2022-07-04 02:30:12 +08:00
if ( supportedInstructions . size ( ) = = 0 ) {
supportedInstructions [ " " ] = WhitespaceProps ( WSTthicker , 1 ) ;
supportedInstructions [ " nbsp " ] = WhitespaceProps ( WSTNonbreaking , 1 ) ;
2022-08-14 22:59:03 +08:00
supportedInstructions [ " enspace " ] = WhitespaceProps ( WST1en , 1 ) ;
supportedInstructions [ " enskip " ] = WhitespaceProps ( WST1en , 1 ) ;
supportedInstructions [ " quad " ] = WhitespaceProps ( WSTQuad , 1 ) ;
supportedInstructions [ " emspace " ] = WhitespaceProps ( WSTQuad , 1 ) ;
2022-07-04 02:30:12 +08:00
supportedInstructions [ " qquad " ] = WhitespaceProps ( WSTQuad , 2 ) ;
2022-08-14 22:59:03 +08:00
supportedInstructions [ " , " ] = WhitespaceProps ( WSTthin , 1 ) ;
supportedInstructions [ " thinspace " ] = WhitespaceProps ( WSTthin , 1 ) ;
supportedInstructions [ " : " ] = WhitespaceProps ( WSTmedium , 1 ) ;
supportedInstructions [ " medspace " ] = WhitespaceProps ( WSTmedium , 1 ) ;
supportedInstructions [ " ; " ] = WhitespaceProps ( WSTthick , 1 ) ;
supportedInstructions [ " thickspace " ] = WhitespaceProps ( WSTthick , 1 ) ;
supportedInstructions [ " ! " ] = WhitespaceProps ( WSTnegthin , 1 ) ;
supportedInstructions [ " negthinspace " ] = WhitespaceProps ( WSTnegthin , 1 ) ;
2022-07-04 02:30:12 +08:00
supportedInstructions [ " negmedspace " ] = WhitespaceProps ( WSTnegmedium , 1 ) ;
supportedInstructions [ " negthickspace " ] = WhitespaceProps ( WSTnegthick , 1 ) ;
}
}
QString JKQTMathTextWhitespaceNode : : Type2String ( Types type )
{
switch ( type ) {
case WSTNormal : return " WSTNormal " ;
case WSTNonbreaking : return " WSTNonbreaking " ;
case WST1en : return " WST1en " ;
case WST1em : return " WST1em " ;
case WSThair : return " WSThair " ;
case WSTthin : return " WSTthin " ;
case WSTnegthin : return " WSTnegthin " ;
case WSTmedium : return " WSTmedium " ;
case WSTnegmedium : return " WSTnegmedium " ;
case WSTthick : return " WSTthick " ;
case WSTnegthick : return " WSTnegthick " ;
case WSTthicker : return " WSTthicker " ;
}
return " ??? " ;
}
2022-07-05 03:02:43 +08:00
double JKQTMathTextWhitespaceNode : : Type2PixelWidth ( Types type , JKQTMathTextEnvironment currentEv , QPaintDevice * pd ) const
2022-07-04 02:30:12 +08:00
{
2022-07-05 03:02:43 +08:00
const QFontMetricsF fm ( currentEv . getFont ( parentMathText ) , pd ) ;
2022-07-06 02:14:51 +08:00
# if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
2022-07-05 03:02:43 +08:00
const double em = fm . horizontalAdvance ( QChar ( 0x2003 ) ) ; //currentEv.fontSize;
2022-07-06 02:14:51 +08:00
const double sp = fm . horizontalAdvance ( ' ' ) ; //currentEv.fontSize;
2022-07-05 03:02:43 +08:00
# else
const double em = fm . width ( QChar ( 0x2003 ) ) ; //currentEv.fontSize;
2022-07-06 02:14:51 +08:00
const double sp = fm . width ( ' ' ) ; //currentEv.fontSize;
2022-07-05 03:02:43 +08:00
# endif
2022-07-04 02:30:12 +08:00
const double en = em / 2.0 ;
switch ( type ) {
2022-07-06 02:14:51 +08:00
case WSTNormal : return sp ;
case WSTNonbreaking : return sp ;
2022-07-04 02:30:12 +08:00
case WST1en : return en ;
case WST1em : return em ;
case WSThair : return em / 12.0 ;
case WSTthin : return em / 6.0 ;
case WSTnegthin : return - em / 6.0 ;
case WSTmedium : return em * 2.0 / 9.0 ;
case WSTnegmedium : return - em * 2.0 / 9.0 ;
case WSTthick : return em * 5.0 / 18.0 ;
case WSTnegthick : return - em * 5.0 / 18.0 ;
case WSTthicker : return em / 3.0 ;
}
return 0.0 ;
}
bool JKQTMathTextWhitespaceNode : : supportsInstructionName ( const QString & instruction )
{
fillSupportedInstructions ( ) ;
return supportedInstructions . contains ( instruction ) ;
}
QString JKQTMathTextWhitespaceNode : : Type2HTML ( Types type )
{
switch ( type ) {
case WSTNonbreaking : return " " ;
case WST1en : return "   " ;
case WST1em : return "   " ;
case WSThair : return " &hairsp " ;
case WSTthin : return "   " ;
case WSTnegthin : return " " ;
case WSTmedium : return "   " ;
case WSTnegmedium : return " " ;
case WSTthick : return "   " ;
case WSTnegthick : return " " ;
case WSTthicker : return "    " ;
case WSTNormal :
default :
return " " ;
}
return " " ;
}
2022-08-03 15:55:45 +08:00
QString JKQTMathTextEmptyBoxNode : : Units2String ( Units type )
{
switch ( type ) {
case EBUem : return " em " ;
case EBUex : return " ex " ;
}
return " ? " ;
}
JKQTMathTextEmptyBoxNode : : Units JKQTMathTextEmptyBoxNode : : String2Units ( QString type )
{
type = type . toLower ( ) . trimmed ( ) ;
if ( type = = " ex " ) return EBUex ;
if ( type = = " em " ) return EBUem ;
return EBUem ;
}
double JKQTMathTextEmptyBoxNode : : Units2PixelWidth ( double value , Units unit , JKQTMathTextEnvironment currentEv , QPaintDevice * pd ) const
{
2022-08-07 23:50:38 +08:00
QFont f = currentEv . getFont ( parentMathText ) ;
f . setStyleStrategy ( QFont : : PreferDefault ) ;
const QFontMetricsF fm ( f , pd ) ;
2022-08-03 15:55:45 +08:00
if ( unit = = EBUem ) {
# if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
const double em = fm . horizontalAdvance ( QChar ( 0x2003 ) ) ; //currentEv.fontSize;
# else
const double em = fm . width ( QChar ( 0x2003 ) ) ; //currentEv.fontSize;
# endif
2022-08-07 23:50:38 +08:00
//qDebug()<<"em="<<em<<"pix";
2022-08-03 15:55:45 +08:00
return value * em ;
} else if ( unit = = EBUex ) {
2023-07-01 21:57:57 +08:00
const double ex = JKQTMathTextGetTightBoundingRect ( f , " x " , pd ) . height ( ) ;
2022-08-07 23:50:38 +08:00
//qDebug()<<"ex="<<ex<<"pix";
2022-08-03 15:55:45 +08:00
return value * ex ;
2022-08-07 23:50:38 +08:00
} else {
//qDebug()<<"JKQTMathTextEmptyBoxNode::Units2PixelWidth(): UNKOWN UNIT";
2022-08-03 15:55:45 +08:00
}
return 0 ;
}
JKQTMathTextEmptyBoxNode : : JKQTMathTextEmptyBoxNode ( JKQTMathText * parent , double width_ , Units widthUnit_ , double height_ , Units heightUnit_ ) :
JKQTMathTextNode ( parent ) ,
width ( width_ ) , widthUnit ( widthUnit_ ) ,
height ( height_ ) , heightUnit ( heightUnit_ )
{
}
JKQTMathTextEmptyBoxNode : : ~ JKQTMathTextEmptyBoxNode ( )
{
}
QString JKQTMathTextEmptyBoxNode : : getTypeName ( ) const
{
return QString ( " JKQTMathTextEmptyBoxNode(%1%2 x %3%4) " ).arg(getWidth()).arg(JKQTMathTextEmptyBoxNode::Units2String(getWidthUnit())).arg(getHeight()).arg(JKQTMathTextEmptyBoxNode::Units2String(getHeightUnit())) ;
}
2022-08-17 05:05:04 +08:00
bool JKQTMathTextEmptyBoxNode : : toHtml ( QString & html , JKQTMathTextEnvironment currentEv , JKQTMathTextEnvironment defaultEv ) const
2022-08-03 15:55:45 +08:00
{
2022-08-17 05:05:04 +08:00
return false ;
2022-08-03 15:55:45 +08:00
}
JKQTMathTextEmptyBoxNode : : Units JKQTMathTextEmptyBoxNode : : getWidthUnit ( ) const
{
return widthUnit ;
}
double JKQTMathTextEmptyBoxNode : : getWidth ( ) const
{
return width ;
}
JKQTMathTextEmptyBoxNode : : Units JKQTMathTextEmptyBoxNode : : getHeightUnit ( ) const
{
return heightUnit ;
}
double JKQTMathTextEmptyBoxNode : : getHeight ( ) const
{
return height ;
}
2022-08-17 05:05:04 +08:00
double JKQTMathTextEmptyBoxNode : : draw ( QPainter & painter , double x , double y , JKQTMathTextEnvironment currentEv ) const
2022-08-03 15:55:45 +08:00
{
2022-08-07 23:50:38 +08:00
const auto s = getSize ( painter , currentEv ) ;
2022-08-17 05:05:04 +08:00
doDrawBoxes ( painter , x , y , s ) ;
2022-08-07 23:50:38 +08:00
return x + s . width ;
2022-08-03 15:55:45 +08:00
}
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode : : getSizeInternal ( QPainter & painter , JKQTMathTextEnvironment currentEv ) const
2022-08-03 15:55:45 +08:00
{
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize s ;
2022-08-03 15:55:45 +08:00
const QFontMetricsF fm ( currentEv . getFont ( parentMathText ) , painter . device ( ) ) ;
2022-08-17 05:05:04 +08:00
s . width = Units2PixelWidth ( width , widthUnit , currentEv , painter . device ( ) ) ;
s . overallHeight = Units2PixelWidth ( height , heightUnit , currentEv , painter . device ( ) ) ;
2022-08-03 15:55:45 +08:00
if ( height > 0 ) {
2022-08-17 05:05:04 +08:00
s . baselineHeight = s . overallHeight ;
2022-08-03 15:55:45 +08:00
} else {
2022-08-17 05:05:04 +08:00
s . baselineHeight = 0 ;
2022-08-03 15:55:45 +08:00
}
2022-08-17 05:05:04 +08:00
s . strikeoutPos = fm . strikeOutPos ( ) ;
return s ;
2022-08-03 15:55:45 +08:00
}
2022-08-10 20:36:16 +08:00
QString JKQTMathTextPhantomNode : : Mode2Instruction ( Mode mode )
{
switch ( mode ) {
case FMwidthAndHeight : return " phantom " ;
case FMwidth : return " hphantom " ;
case FMheight : return " vphantom " ;
}
return " phantom " ;
}
JKQTMathTextPhantomNode : : JKQTMathTextPhantomNode ( JKQTMathText * parent , const QString & mode , JKQTMathTextNode * child ) :
JKQTMathTextInstruction1Node ( parent , mode , child )
{
fillInstructions ( ) ;
}
JKQTMathTextPhantomNode : : JKQTMathTextPhantomNode ( JKQTMathText * _parent , Mode mode , JKQTMathTextNode * child ) :
JKQTMathTextInstruction1Node ( _parent , Mode2Instruction ( mode ) , child )
{
fillInstructions ( ) ;
}
JKQTMathTextPhantomNode : : ~ JKQTMathTextPhantomNode ( ) {
}
QString JKQTMathTextPhantomNode : : getTypeName ( ) const
{
return QLatin1String ( " JKQTMathTextPhantomNode( " ) + instructionName + " ) " ;
}
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize JKQTMathTextPhantomNode : : getSizeInternal ( QPainter & painter , JKQTMathTextEnvironment currentEv ) const {
2022-08-10 20:36:16 +08:00
fillInstructions ( ) ;
2022-08-17 05:05:04 +08:00
JKQTMathTextNodeSize s = getChild ( ) - > getSize ( painter , currentEv ) ;
2022-08-10 20:36:16 +08:00
switch ( instructions [ getInstructionName ( ) ] ) {
case FMwidth :
2022-08-17 05:05:04 +08:00
s . overallHeight = 0 ;
s . baselineHeight = 0 ;
s . strikeoutPos = 0 ;
2022-08-10 20:36:16 +08:00
break ;
case FMwidthAndHeight :
break ;
case FMheight :
2022-08-17 05:05:04 +08:00
s . width = 0 ;
2022-08-10 20:36:16 +08:00
break ;
}
2022-08-17 05:05:04 +08:00
return s ;
2022-08-10 20:36:16 +08:00
}
2022-08-17 05:05:04 +08:00
double JKQTMathTextPhantomNode : : draw ( QPainter & painter , double x , double y , JKQTMathTextEnvironment currentEv ) const {
2022-08-10 20:36:16 +08:00
const JKQTMathTextNodeSize s = getSize ( painter , currentEv ) ;
2022-08-17 05:05:04 +08:00
doDrawBoxes ( painter , x , y , s ) ;
2022-08-10 20:36:16 +08:00
return x + s . width ;
}
2022-08-17 05:05:04 +08:00
bool JKQTMathTextPhantomNode : : toHtml ( QString & html , JKQTMathTextEnvironment currentEv , JKQTMathTextEnvironment defaultEv ) const {
2022-08-10 20:36:16 +08:00
JKQTMathTextEnvironment ev = currentEv ;
fillInstructions ( ) ;
return " " ;
}
bool JKQTMathTextPhantomNode : : supportsInstructionName ( const QString & instructionName )
{
fillInstructions ( ) ;
return instructions . contains ( instructionName ) ;
}
QHash < QString , JKQTMathTextPhantomNode : : Mode > JKQTMathTextPhantomNode : : instructions ;
void JKQTMathTextPhantomNode : : fillInstructions ( )
{
2023-06-30 19:52:17 +08:00
static std : : mutex sMutex ;
std : : lock_guard < std : : mutex > lock ( sMutex ) ;
if ( instructions . size ( ) > 0 ) return ;
2022-08-10 20:36:16 +08:00
instructions [ " phantom " ] = FMwidthAndHeight ;
instructions [ " hphantom " ] = FMwidth ;
instructions [ " vphantom " ] = FMheight ;
}