/* Copyright (c) 2008-2022 Jan W. Krieger () 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 . */ #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 #include #include #include #include #include #include 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)+")"; } bool JKQTMathTextWhitespaceNode::toHtml(QString &html, JKQTMathTextEnvironment /*currentEv*/, JKQTMathTextEnvironment /*defaultEv*/) const { for (size_t i=0; i(whitespace.count); s.baselineHeight=0; s.overallHeight=0; s.strikeoutPos=fm.strikeOutPos(); return s; } QHash JKQTMathTextWhitespaceNode::supportedInstructions; void JKQTMathTextWhitespaceNode::fillSupportedInstructions() { static std::mutex sMutex; std::lock_guard lock(sMutex); if (supportedInstructions.size()==0) { supportedInstructions[" "]=WhitespaceProps(WSTthicker, 1); supportedInstructions["nbsp"]=WhitespaceProps(WSTNonbreaking, 1); supportedInstructions["enspace"]=WhitespaceProps(WST1en, 1); supportedInstructions["enskip"]=WhitespaceProps(WST1en, 1); supportedInstructions["quad"]=WhitespaceProps(WSTQuad, 1); supportedInstructions["emspace"]=WhitespaceProps(WSTQuad, 1); supportedInstructions["qquad"]=WhitespaceProps(WSTQuad, 2); 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); 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 "???"; } double JKQTMathTextWhitespaceNode::Type2PixelWidth(Types type, JKQTMathTextEnvironment currentEv, QPaintDevice* pd) const { const QFontMetricsF fm(currentEv.getFont(parentMathText), pd); #if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0)) const double em=fm.horizontalAdvance(QChar(0x2003));//currentEv.fontSize; 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; switch (type) { case WSTNormal: return sp; case WSTNonbreaking: return sp; 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 " "; } 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 { QFont f=currentEv.getFont(parentMathText); f.setStyleStrategy(QFont::PreferDefault); const QFontMetricsF fm(f, pd); 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 //qDebug()<<"em="<0) { s.baselineHeight=s.overallHeight; } else { s.baselineHeight=0; } s.strikeoutPos=fm.strikeOutPos(); return s; } 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+")"; } JKQTMathTextNodeSize JKQTMathTextPhantomNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv) const { fillInstructions(); JKQTMathTextNodeSize s=getChild()->getSize(painter, currentEv); switch(instructions[getInstructionName()]) { case FMwidth: s.overallHeight=0; s.baselineHeight=0; s.strikeoutPos=0; break; case FMwidthAndHeight: break; case FMheight: s.width=0; break; } return s; } double JKQTMathTextPhantomNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const { const JKQTMathTextNodeSize s=getSize(painter, currentEv); doDrawBoxes(painter, x, y, s); return x+s.width; } bool JKQTMathTextPhantomNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) const { JKQTMathTextEnvironment ev=currentEv; fillInstructions(); return " "; } bool JKQTMathTextPhantomNode::supportsInstructionName(const QString &instructionName) { fillInstructions(); return instructions.contains(instructionName); } QHash JKQTMathTextPhantomNode::instructions; void JKQTMathTextPhantomNode::fillInstructions() { static std::mutex sMutex; std::lock_guard lock(sMutex); if (instructions.size()>0) return; instructions["phantom"] = FMwidthAndHeight; instructions["hphantom"] = FMwidth; instructions["vphantom"] = FMheight; }