Implement Level 3.5 bold and italic font style
Proportional font attributes are tracked within the decoder, but the effect is not rendered.
This commit is contained in:
79
decode.cpp
79
decode.cpp
@@ -113,6 +113,7 @@ void TeletextPageDecode::Invocation::buildMap(int level)
|
|||||||
case 0x23: // Background colour
|
case 0x23: // Background colour
|
||||||
case 0x27: // Additional flash functions
|
case 0x27: // Additional flash functions
|
||||||
case 0x2c: // Display attributes
|
case 0x2c: // Display attributes
|
||||||
|
case 0x2e: // Font style
|
||||||
m_attributeMap.insert(qMakePair(targetRow, targetColumn), triplet);
|
m_attributeMap.insert(qMakePair(targetRow, targetColumn), triplet);
|
||||||
m_rightMostColumn.insert(targetRow, targetColumn);
|
m_rightMostColumn.insert(targetRow, targetColumn);
|
||||||
break;
|
break;
|
||||||
@@ -143,8 +144,15 @@ TeletextPageDecode::textPainter TeletextPageDecode::s_blankPainter;
|
|||||||
TeletextPageDecode::TeletextPageDecode()
|
TeletextPageDecode::TeletextPageDecode()
|
||||||
{
|
{
|
||||||
if (s_instances == 0) {
|
if (s_instances == 0) {
|
||||||
for (int c=0; c<72; c++)
|
for (int c=0; c<72; c++) {
|
||||||
s_blankPainter.bottomHalfCell[c].character.code = 0x00;
|
s_blankPainter.bottomHalfCell[c].character.code = 0x00;
|
||||||
|
s_blankPainter.setProportionalRows[c] = 0;
|
||||||
|
s_blankPainter.clearProportionalRows[c] = 0;
|
||||||
|
s_blankPainter.setBoldRows[c] = 0;
|
||||||
|
s_blankPainter.clearBoldRows[c] = 0;
|
||||||
|
s_blankPainter.setItalicRows[c] = 0;
|
||||||
|
s_blankPainter.clearItalicRows[c] = 0;
|
||||||
|
}
|
||||||
s_blankPainter.rightHalfCell.character.code = 0x00;
|
s_blankPainter.rightHalfCell.character.code = 0x00;
|
||||||
}
|
}
|
||||||
s_instances++;
|
s_instances++;
|
||||||
@@ -495,6 +503,7 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
bool adapBackground = false;
|
bool adapBackground = false;
|
||||||
bool adapFlash = false;
|
bool adapFlash = false;
|
||||||
bool adapDisplayAttrs = false;
|
bool adapDisplayAttrs = false;
|
||||||
|
bool adapStyle = false;
|
||||||
|
|
||||||
for (int c=0; c<72; c++) {
|
for (int c=0; c<72; c++) {
|
||||||
textCell previousCellContents = m_cell[r][c];
|
textCell previousCellContents = m_cell[r][c];
|
||||||
@@ -512,6 +521,9 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
m_level1ActivePainter.attribute.display.conceal = false;
|
m_level1ActivePainter.attribute.display.conceal = false;
|
||||||
m_level1ActivePainter.attribute.display.invert = false;
|
m_level1ActivePainter.attribute.display.invert = false;
|
||||||
m_level1ActivePainter.attribute.display.underlineSeparated = false;
|
m_level1ActivePainter.attribute.display.underlineSeparated = false;
|
||||||
|
m_level1ActivePainter.attribute.style.proportional = false;
|
||||||
|
m_level1ActivePainter.attribute.style.bold = false;
|
||||||
|
m_level1ActivePainter.attribute.style.italic = false;
|
||||||
|
|
||||||
if (m_level >= 2) {
|
if (m_level >= 2) {
|
||||||
m_level1ActivePainter.attribute.foregroundCLUT = 7 | m_foregroundRemap[m_levelOnePage->colourTableRemap()];
|
m_level1ActivePainter.attribute.foregroundCLUT = 7 | m_foregroundRemap[m_levelOnePage->colourTableRemap()];
|
||||||
@@ -599,6 +611,41 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
|
|
||||||
painter = (t == 0) ? &m_level1ActivePainter : &m_adapPassPainter[t-1][i];
|
painter = (t == 0) ? &m_level1ActivePainter : &m_adapPassPainter[t-1][i];
|
||||||
|
|
||||||
|
if (m_level == 3) {
|
||||||
|
// Reset font style "row spread" at start of row and side panels
|
||||||
|
if (c == 0 || c == 40 || c == 56)
|
||||||
|
painter->styleSpreadRows = 0;
|
||||||
|
|
||||||
|
// Apply any font style attributes from previous rows
|
||||||
|
// For m_level1ActivePainter, ensure we deal with font style row counters only once
|
||||||
|
if (t >= 1 || i == 0) {
|
||||||
|
if (painter->clearProportionalRows[c] != 0) {
|
||||||
|
painter->attribute.style.proportional = false;
|
||||||
|
painter->clearProportionalRows[c]--;
|
||||||
|
}
|
||||||
|
if (painter->setProportionalRows[c] != 0) {
|
||||||
|
painter->attribute.style.proportional = true;
|
||||||
|
painter->setProportionalRows[c]--;
|
||||||
|
}
|
||||||
|
if (painter->clearBoldRows[c] != 0) {
|
||||||
|
painter->attribute.style.bold = false;
|
||||||
|
painter->clearBoldRows[c]--;
|
||||||
|
}
|
||||||
|
if (painter->setBoldRows[c] != 0) {
|
||||||
|
painter->attribute.style.bold = true;
|
||||||
|
painter->setBoldRows[c]--;
|
||||||
|
}
|
||||||
|
if (painter->clearItalicRows[c] != 0) {
|
||||||
|
painter->attribute.style.italic = false;
|
||||||
|
painter->clearItalicRows[c]--;
|
||||||
|
}
|
||||||
|
if (painter->setItalicRows[c] != 0) {
|
||||||
|
painter->attribute.style.italic = true;
|
||||||
|
painter->setItalicRows[c]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adaptive Invocation painter: pick up the attributes we're NOT adapting from
|
// Adaptive Invocation painter: pick up the attributes we're NOT adapting from
|
||||||
// m_level1ActivePainter, which by now has taken into account all the attributes
|
// m_level1ActivePainter, which by now has taken into account all the attributes
|
||||||
// from the Level 1 page, Active Objects and the Local Enhancement Data
|
// from the Level 1 page, Active Objects and the Local Enhancement Data
|
||||||
@@ -611,6 +658,8 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
painter->attribute.flash = m_level1ActivePainter.attribute.flash;
|
painter->attribute.flash = m_level1ActivePainter.attribute.flash;
|
||||||
if (!adapDisplayAttrs)
|
if (!adapDisplayAttrs)
|
||||||
painter->attribute.display = m_level1ActivePainter.attribute.display;
|
painter->attribute.display = m_level1ActivePainter.attribute.display;
|
||||||
|
if (!adapStyle)
|
||||||
|
painter->attribute.style = m_level1ActivePainter.attribute.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
// QMultiMap::values returns QList with most recent value first...
|
// QMultiMap::values returns QList with most recent value first...
|
||||||
@@ -668,10 +717,36 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
if (t == 0 && !painter->attribute.display.underlineSeparated)
|
if (t == 0 && !painter->attribute.display.underlineSeparated)
|
||||||
level1SeparatedMosaics = false;
|
level1SeparatedMosaics = false;
|
||||||
break;
|
break;
|
||||||
|
case 0x2e: // Font style
|
||||||
|
if (m_level != 3)
|
||||||
|
break;
|
||||||
|
if (applyAdapt)
|
||||||
|
adapStyle = true;
|
||||||
|
painter->attribute.style.proportional = triplet.data() & 0x01;
|
||||||
|
painter->attribute.style.bold = triplet.data() & 0x02;
|
||||||
|
painter->attribute.style.italic = triplet.data() & 0x04;
|
||||||
|
painter->styleSpreadRows = triplet.data() >> 4;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->result.attribute = painter->attribute;
|
painter->result.attribute = painter->attribute;
|
||||||
|
|
||||||
|
// Font style attribute that spreads across more than one row
|
||||||
|
if (m_level == 3 && painter->styleSpreadRows != 0) {
|
||||||
|
if (painter->attribute.style.proportional)
|
||||||
|
painter->setProportionalRows[c] = painter->styleSpreadRows;
|
||||||
|
else
|
||||||
|
painter->clearProportionalRows[c] = painter->styleSpreadRows;
|
||||||
|
if (painter->attribute.style.bold)
|
||||||
|
painter->setBoldRows[c] = painter->styleSpreadRows;
|
||||||
|
else
|
||||||
|
painter->clearBoldRows[c] = painter->styleSpreadRows;
|
||||||
|
if (painter->attribute.style.italic)
|
||||||
|
painter->setItalicRows[c] = painter->styleSpreadRows;
|
||||||
|
else
|
||||||
|
painter->clearItalicRows[c] = painter->styleSpreadRows;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -875,7 +950,7 @@ void TeletextPageDecode::decodeRow(int r)
|
|||||||
m_adapPassPainter[0][adapInvokeAttrs].attribute.display.doubleHeight = false;
|
m_adapPassPainter[0][adapInvokeAttrs].attribute.display.doubleHeight = false;
|
||||||
m_adapPassPainter[0][adapInvokeAttrs].attribute.display.doubleWidth = false;
|
m_adapPassPainter[0][adapInvokeAttrs].attribute.display.doubleWidth = false;
|
||||||
adapInvokeAttrs = -1;
|
adapInvokeAttrs = -1;
|
||||||
adapForeground = adapBackground = adapFlash = adapDisplayAttrs = false;
|
adapForeground = adapBackground = adapFlash = adapDisplayAttrs = adapStyle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Level 1 set-after spacing attributes
|
// Level 1 set-after spacing attributes
|
||||||
|
|||||||
22
decode.h
22
decode.h
@@ -58,6 +58,9 @@ public:
|
|||||||
bool cellBoxed(int r, int c) const { return m_cell[r][c].attribute.display.boxingWindow; };
|
bool cellBoxed(int r, int c) const { return m_cell[r][c].attribute.display.boxingWindow; };
|
||||||
bool cellConceal(int r, int c) const { return m_cell[r][c].attribute.display.conceal; };
|
bool cellConceal(int r, int c) const { return m_cell[r][c].attribute.display.conceal; };
|
||||||
bool cellUnderlined(int r, int c) const { return cellCharacterSet(r, c) < 24 ? m_cell[r][c].attribute.display.underlineSeparated : false; };
|
bool cellUnderlined(int r, int c) const { return cellCharacterSet(r, c) < 24 ? m_cell[r][c].attribute.display.underlineSeparated : false; };
|
||||||
|
bool cellBold(int r, int c) const { return m_cell[r][c].attribute.style.bold; };
|
||||||
|
bool cellItalic(int r, int c) const { return m_cell[r][c].attribute.style.italic; };
|
||||||
|
bool cellProportional(int r, int c) const { return m_cell[r][c].attribute.style.proportional; };
|
||||||
|
|
||||||
bool level1MosaicAttribute(int r, int c) const { return m_cellLevel1Mosaic[r][c]; };
|
bool level1MosaicAttribute(int r, int c) const { return m_cellLevel1Mosaic[r][c]; };
|
||||||
int level1CharSet(int r, int c) const { return m_cellLevel1CharSet[r][c]; };
|
int level1CharSet(int r, int c) const { return m_cellLevel1CharSet[r][c]; };
|
||||||
@@ -109,7 +112,7 @@ private:
|
|||||||
int mode=0;
|
int mode=0;
|
||||||
int ratePhase=0;
|
int ratePhase=0;
|
||||||
int phase2HzShown=0;
|
int phase2HzShown=0;
|
||||||
} flash;
|
};
|
||||||
|
|
||||||
struct displayAttributes {
|
struct displayAttributes {
|
||||||
bool doubleHeight=false;
|
bool doubleHeight=false;
|
||||||
@@ -120,6 +123,12 @@ private:
|
|||||||
bool underlineSeparated=false;
|
bool underlineSeparated=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fontStyle {
|
||||||
|
bool proportional=false;
|
||||||
|
bool bold=false;
|
||||||
|
bool italic=false;
|
||||||
|
};
|
||||||
|
|
||||||
friend inline bool operator!=(const displayAttributes &lhs, const displayAttributes &rhs)
|
friend inline bool operator!=(const displayAttributes &lhs, const displayAttributes &rhs)
|
||||||
{
|
{
|
||||||
return lhs.doubleHeight != rhs.doubleHeight ||
|
return lhs.doubleHeight != rhs.doubleHeight ||
|
||||||
@@ -135,6 +144,7 @@ private:
|
|||||||
int backgroundCLUT=0;
|
int backgroundCLUT=0;
|
||||||
flashFunctions flash;
|
flashFunctions flash;
|
||||||
displayAttributes display;
|
displayAttributes display;
|
||||||
|
fontStyle style;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend inline bool operator!=(const textAttributes &lhs, const textAttributes &rhs)
|
friend inline bool operator!=(const textAttributes &lhs, const textAttributes &rhs)
|
||||||
@@ -144,7 +154,10 @@ private:
|
|||||||
lhs.flash.mode != rhs.flash.mode ||
|
lhs.flash.mode != rhs.flash.mode ||
|
||||||
lhs.flash.ratePhase != rhs.flash.ratePhase ||
|
lhs.flash.ratePhase != rhs.flash.ratePhase ||
|
||||||
lhs.flash.phase2HzShown != rhs.flash.phase2HzShown ||
|
lhs.flash.phase2HzShown != rhs.flash.phase2HzShown ||
|
||||||
lhs.display != rhs.display;
|
lhs.display != rhs.display ||
|
||||||
|
lhs.style.proportional != rhs.style.proportional ||
|
||||||
|
lhs.style.bold != rhs.style.bold ||
|
||||||
|
lhs.style.italic != rhs.style.italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct textCell {
|
struct textCell {
|
||||||
@@ -165,6 +178,11 @@ private:
|
|||||||
textCell result;
|
textCell result;
|
||||||
textCell rightHalfCell;
|
textCell rightHalfCell;
|
||||||
textCell bottomHalfCell[72];
|
textCell bottomHalfCell[72];
|
||||||
|
|
||||||
|
int styleSpreadRows=0;
|
||||||
|
int setProportionalRows[72], clearProportionalRows[72];
|
||||||
|
int setBoldRows[72], clearBoldRows[72];
|
||||||
|
int setItalicRows[72], clearItalicRows[72];
|
||||||
};
|
};
|
||||||
|
|
||||||
const QMap<int, int> m_g0CharacterMap {
|
const QMap<int, int> m_g0CharacterMap {
|
||||||
|
|||||||
67
render.cpp
67
render.cpp
@@ -73,6 +73,39 @@ void TeletextPageRender::setDecoder(TeletextPageDecode *decoder)
|
|||||||
m_decoder = decoder;
|
m_decoder = decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void TeletextPageRender::drawFromBitmap(QPainter &pixmapPainter, int r, int c, const QBitmap bitmap, TeletextPageDecode::CharacterFragment characterFragment)
|
||||||
|
{
|
||||||
|
switch (characterFragment) {
|
||||||
|
case TeletextPageDecode::NormalSize:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, bitmap);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleHeightTopHalf:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 0, 0, 12, 5);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleHeightBottomHalf:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 0, 5, 12, 5);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleWidthLeftHalf:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 0, 0, 6, 10);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleWidthRightHalf:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 6, 0, 6, 10);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleSizeTopLeftQuarter:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 0, 0, 6, 5);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleSizeTopRightQuarter:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 6, 0, 6, 5);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleSizeBottomLeftQuarter:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 0, 5, 6, 5);
|
||||||
|
break;
|
||||||
|
case TeletextPageDecode::DoubleSizeBottomRightQuarter:
|
||||||
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, bitmap, 6, 5, 6, 5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void TeletextPageRender::drawFromFontBitmap(QPainter &pixmapPainter, int r, int c, unsigned char characterCode, int characterSet, TeletextPageDecode::CharacterFragment characterFragment)
|
inline void TeletextPageRender::drawFromFontBitmap(QPainter &pixmapPainter, int r, int c, unsigned char characterCode, int characterSet, TeletextPageDecode::CharacterFragment characterFragment)
|
||||||
{
|
{
|
||||||
switch (characterFragment) {
|
switch (characterFragment) {
|
||||||
@@ -152,6 +185,8 @@ inline void TeletextPageRender::drawCharacter(QPainter &pixmapPainter, int r, in
|
|||||||
pixmapPainter.fillRect(c*12, r*10, 12, 10, pixmapPainter.background().color());
|
pixmapPainter.fillRect(c*12, r*10, 12, 10, pixmapPainter.background().color());
|
||||||
else if (characterCode == 0x7f && characterSet == 24)
|
else if (characterCode == 0x7f && characterSet == 24)
|
||||||
pixmapPainter.fillRect(c*12, r*10, 12, 10, pixmapPainter.pen().color());
|
pixmapPainter.fillRect(c*12, r*10, 12, 10, pixmapPainter.pen().color());
|
||||||
|
else if ((m_decoder->cellBold(r, c) || m_decoder->cellItalic(r, c)) && characterSet < 24)
|
||||||
|
drawBoldOrItalicCharacter(pixmapPainter, r, c, characterCode, characterSet, characterFragment);
|
||||||
else
|
else
|
||||||
drawFromFontBitmap(pixmapPainter, r, c, characterCode, characterSet, characterFragment);
|
drawFromFontBitmap(pixmapPainter, r, c, characterCode, characterSet, characterFragment);
|
||||||
|
|
||||||
@@ -182,6 +217,38 @@ inline void TeletextPageRender::drawCharacter(QPainter &pixmapPainter, int r, in
|
|||||||
pixmapPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
pixmapPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void TeletextPageRender::drawBoldOrItalicCharacter(QPainter &pixmapPainter, int r, int c, unsigned char characterCode, int characterSet, TeletextPageDecode::CharacterFragment characterFragment)
|
||||||
|
{
|
||||||
|
QBitmap bitmap = QBitmap(12, 10);
|
||||||
|
QPainter bitmapPainter;
|
||||||
|
|
||||||
|
// TODO italic glyph-making is VERY slow!
|
||||||
|
if (m_decoder->cellItalic(r, c)) {
|
||||||
|
bitmap.clear();
|
||||||
|
|
||||||
|
bitmapPainter.begin(&bitmap);
|
||||||
|
bitmapPainter.setBackgroundMode(Qt::OpaqueMode);
|
||||||
|
bitmapPainter.drawPixmap(1, 0, *m_fontBitmap.rawBitmap(), (characterCode-32)*12, characterSet*10, 11, 3);
|
||||||
|
bitmapPainter.drawPixmap(0, 3, *m_fontBitmap.rawBitmap(), (characterCode-32)*12, characterSet*10+3, 12, 3);
|
||||||
|
bitmapPainter.drawPixmap(0, 6, *m_fontBitmap.rawBitmap(), (characterCode-32)*12+1, characterSet*10+6, 11, 4);
|
||||||
|
bitmapPainter.end();
|
||||||
|
} else
|
||||||
|
bitmap = m_fontBitmap.rawBitmap()->copy((characterCode-32)*12, characterSet*10, 12, 10);
|
||||||
|
|
||||||
|
if (m_decoder->cellBold(r, c)) {
|
||||||
|
QBitmap boldeningBitmap;
|
||||||
|
|
||||||
|
boldeningBitmap = bitmap.copy();
|
||||||
|
bitmapPainter.begin(&bitmap);
|
||||||
|
// No idea why we need this setPen workaround when character is made italic first?!
|
||||||
|
if (!m_decoder->cellItalic(r, c))
|
||||||
|
bitmapPainter.setPen(Qt::color0);
|
||||||
|
bitmapPainter.drawPixmap(1, 0, boldeningBitmap);
|
||||||
|
bitmapPainter.end();
|
||||||
|
}
|
||||||
|
drawFromBitmap(pixmapPainter, r, c, bitmap, characterFragment);
|
||||||
|
}
|
||||||
|
|
||||||
void TeletextPageRender::renderPage(bool force)
|
void TeletextPageRender::renderPage(bool force)
|
||||||
{
|
{
|
||||||
for (int r=0; r<25; r++)
|
for (int r=0; r<25; r++)
|
||||||
|
|||||||
2
render.h
2
render.h
@@ -70,8 +70,10 @@ protected:
|
|||||||
int m_flashingRow[25];
|
int m_flashingRow[25];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
inline void drawFromBitmap(QPainter &, int, int, const QBitmap, TeletextPageDecode::CharacterFragment);
|
||||||
inline void drawFromFontBitmap(QPainter &, int, int, unsigned char, int, TeletextPageDecode::CharacterFragment);
|
inline void drawFromFontBitmap(QPainter &, int, int, unsigned char, int, TeletextPageDecode::CharacterFragment);
|
||||||
inline void drawCharacter(QPainter &, int, int, unsigned char, int, int, TeletextPageDecode::CharacterFragment);
|
inline void drawCharacter(QPainter &, int, int, unsigned char, int, int, TeletextPageDecode::CharacterFragment);
|
||||||
|
inline void drawBoldOrItalicCharacter(QPainter &, int, int, unsigned char, int, TeletextPageDecode::CharacterFragment);
|
||||||
void renderRow(int, int, bool force=false);
|
void renderRow(int, int, bool force=false);
|
||||||
void setRowFlashStatus(int, int);
|
void setRowFlashStatus(int, int);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user