File indexing completed on 2024-05-12 04:33:59

0001 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
0002 // TeXFont_TFM.cpp
0003 //
0004 // Part of KDVI - A DVI previewer for the KDE desktop environment
0005 //
0006 // SPDX-FileCopyrightText: 2003 Stefan Kebekus
0007 // SPDX-License-Identifier: GPL-2.0-or-later
0008 
0009 #include <config.h>
0010 
0011 #include "TeXFont_TFM.h"
0012 #include "debug_dvi.h"
0013 
0014 #include <QDataStream>
0015 #include <QFile>
0016 #include <QLoggingCategory>
0017 
0018 //#define DEBUG_TFM
0019 
0020 TeXFont_TFM::TeXFont_TFM(TeXFontDefinition *parent)
0021     : TeXFont(parent)
0022 {
0023 #ifdef DEBUG_TFM
0024     qCDebug(OkularDviDebug) << "TeXFont_TFM::TeXFont_TFM( parent=" << parent << " )";
0025 #endif
0026 
0027     QFile file(parent->filename);
0028     if (!file.open(QIODevice::ReadOnly)) {
0029         qCCritical(OkularDviDebug) << "TeXFont_TFM::TeXFont_TFM(): Could not read TFM file";
0030         return;
0031     }
0032     QDataStream stream(&file);
0033 
0034     // Data from the very beginning of the TFM file, as specified in
0035     // "The DVI Driver Standard, Level 0", section D.2.1
0036     quint16 lf, lh, bc, ec, nw, nh, nd;
0037     stream >> lf >> lh >> bc >> ec >> nw >> nh >> nd;
0038 #ifdef DEBUG_TFM
0039     qCDebug(OkularDviDebug) << "lf= " << lf << "lh= " << lh << "\nbc= " << bc << "\nec= " << ec << "\nnw= " << nw << "\nnh= " << nh << "\nnd= " << nd;
0040 #endif
0041     if ((bc > ec) || (ec >= TeXFontDefinition::max_num_of_chars_in_font)) {
0042         qCCritical(OkularDviDebug) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid bc and ec entries.";
0043         file.close();
0044         return;
0045     }
0046 
0047     // Data from the HEADER section of the TFM data.
0048     file.seek(24);
0049     stream >> checksum >> design_size_in_TeX_points.value;
0050 #ifdef DEBUG_TFM
0051     qCDebug(OkularDviDebug) << "checksum    = " << checksum << "design_size = " << design_size_in_TeX_points.toDouble() << " TeX Points\n"
0052                             << "            = " << design_size_in_TeX_points.toDouble() * 254.0 / 7227.0 << " cm";
0053 #endif
0054 
0055     // Width table
0056     fix_word widthTable_in_units_of_design_size[TeXFontDefinition::max_num_of_chars_in_font];
0057     for (fix_word &fw : widthTable_in_units_of_design_size) {
0058         fw.value = 0;
0059     }
0060 
0061     file.seek(24 + 4 * lh + 4 * (ec - bc));
0062     for (unsigned int i = 0; i < nw; i++) {
0063         stream >> widthTable_in_units_of_design_size[i].value;
0064         // Some characters, which are used as parts of glyphs, have width
0065         // 0 --the real width is calculated in a lig_kern program and
0066         // depends on the preceding character. We cannot calculate the
0067         // real width here and take 0.4 times the design size as an
0068         // approximation.
0069         if (widthTable_in_units_of_design_size[i].value == 0) {
0070             widthTable_in_units_of_design_size[i].fromDouble(0.4);
0071         }
0072     }
0073 
0074     // Height table
0075     fix_word heightTable_in_units_of_design_size[16];
0076     for (fix_word &fw : heightTable_in_units_of_design_size) {
0077         fw.value = 0;
0078     }
0079     for (unsigned int i = 0; i < nh; i++) {
0080         stream >> heightTable_in_units_of_design_size[i].value;
0081     }
0082 
0083     // Char-Info table
0084     file.seek(24 + 4 * lh);
0085     for (unsigned int characterCode = bc; characterCode < ec; characterCode++) {
0086         glyph *g = glyphtable + characterCode;
0087 
0088         quint8 byte;
0089         stream >> byte;
0090         if (byte >= nw) {
0091             qCCritical(OkularDviDebug) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table.";
0092         } else {
0093             characterWidth_in_units_of_design_size[characterCode] = widthTable_in_units_of_design_size[byte];
0094             g->dvi_advance_in_units_of_design_size_by_2e20 = widthTable_in_units_of_design_size[byte].value;
0095         }
0096 
0097         stream >> byte;
0098         byte = byte >> 4;
0099         if (byte >= nh) {
0100             qCCritical(OkularDviDebug) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table.";
0101         } else {
0102             characterHeight_in_units_of_design_size[characterCode] = heightTable_in_units_of_design_size[byte];
0103         }
0104 
0105         stream >> byte;
0106         stream >> byte;
0107     }
0108     file.close();
0109 }
0110 
0111 TeXFont_TFM::~TeXFont_TFM()
0112 {
0113 }
0114 
0115 glyph *TeXFont_TFM::getGlyph(quint16 characterCode, bool generateCharacterPixmap, const QColor &color)
0116 {
0117 #ifdef DEBUG_TFM
0118     qCDebug(OkularDviDebug) << "TeXFont_TFM::getGlyph( ch=" << ch << ", generateCharacterPixmap=" << generateCharacterPixmap << " )";
0119 #endif
0120 
0121     // Paranoia checks
0122     if (characterCode >= TeXFontDefinition::max_num_of_chars_in_font) {
0123         qCCritical(OkularDviDebug) << "TeXFont_TFM::getGlyph(): Argument is too big.";
0124         return glyphtable;
0125     }
0126 
0127     // This is the address of the glyph that will be returned.
0128     class glyph *g = glyphtable + characterCode;
0129 
0130     if ((generateCharacterPixmap == true) && ((g->shrunkenCharacter.isNull()) || (color != g->color))) {
0131         g->color = color;
0132         quint16 pixelWidth = (quint16)(parent->displayResolution_in_dpi * design_size_in_TeX_points.toDouble() * characterWidth_in_units_of_design_size[characterCode].toDouble() * 100.0 / 7227.0 + 0.5);
0133         quint16 pixelHeight = (quint16)(parent->displayResolution_in_dpi * design_size_in_TeX_points.toDouble() * characterHeight_in_units_of_design_size[characterCode].toDouble() * 100.0 / 7227.0 + 0.5);
0134 
0135         // Just make sure that weird TFM files never lead to giant
0136         // pixmaps that eat all system memory...
0137         if (pixelWidth > 50) {
0138             pixelWidth = 50;
0139         }
0140         if (pixelHeight > 50) {
0141             pixelHeight = 50;
0142         }
0143 
0144         g->shrunkenCharacter = QImage(pixelWidth, pixelHeight, QImage::Format_RGB32);
0145         g->shrunkenCharacter.fill(color.rgba());
0146         g->x2 = 0;
0147         g->y2 = pixelHeight;
0148     }
0149 
0150     return g;
0151 }