Ticket #10194: srt_formatting_v6.patch

File srt_formatting_v6.patch, 26.2 KB (added by Jim Stichnoth <stichnot@…>, 12 years ago)

Updated after subtitlescreen.cpp checkins.

  • mythtv/libs/libmythtv/subtitlescreen.cpp

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp
    index 9f6820c..9d5c77f 100644
    a b void SubtitleScreen::DisplayTextSubtitles(void) 
    354354    if (vo)
    355355    {
    356356        QRect oldsafe = m_safeArea;
    357         m_safeArea = m_player->GetVideoOutput()->GetSafeRect();
    358         if (oldsafe != m_safeArea)
    359         {
    360             changed = true;
    361             int height = (m_safeArea.height() * m_textFontZoom) / 2000;
    362             gTextSubFont->GetFace()->setPixelSize(height);
    363             gTextSubFont->GetFace()->setItalic(false);
    364             gTextSubFont->GetFace()->setUnderline(false);
    365             gTextSubFont->SetColor(Qt::white);
    366         }
     357        m_safeArea = vo->GetSafeRect();
     358        changed = (oldsafe != m_safeArea);
    367359    }
    368360    else
    369361    {
    void SubtitleScreen::DisplayTextSubtitles(void) 
    423415        return;
    424416    }
    425417
    426     OptimiseTextSubs(rawsubs);
    427418    subs->Unlock();
    428419    DrawTextSubtitles(rawsubs, 0, 0);
    429420}
    void SubtitleScreen::DisplayRawTextSubtitles(void) 
    439430        return;
    440431
    441432    VideoOutput *vo = m_player->GetVideoOutput();
    442     if (vo)
    443     {
    444         QRect oldsafe = m_safeArea;
    445         m_safeArea = m_player->GetVideoOutput()->GetSafeRect();
    446         if (oldsafe != m_safeArea)
    447         {
    448             int height = (m_safeArea.height() * m_textFontZoom) / 2000;
    449             gTextSubFont->GetFace()->setPixelSize(height);
    450             gTextSubFont->GetFace()->setItalic(false);
    451             gTextSubFont->GetFace()->setUnderline(false);
    452             gTextSubFont->SetColor(Qt::white);
    453         }
    454     }
    455     else
     433    if (!vo)
    456434        return;
    457435
    458436    VideoFrame *currentFrame = vo->GetLastShownFrame();
    void SubtitleScreen::DisplayRawTextSubtitles(void) 
    461439
    462440    // delete old subs that may still be on screen
    463441    DeleteAllChildren();
    464     OptimiseTextSubs(subs);
    465442    DrawTextSubtitles(subs, currentFrame->timecode, duration);
    466443}
    467444
    468 void SubtitleScreen::OptimiseTextSubs(QStringList &rawsubs)
    469 {
    470     QFontMetrics font(*(gTextSubFont->GetFace()));
    471     int maxwidth = m_safeArea.width();
    472     QStringList wrappedsubs;
    473     QString wrappedtext = "";
    474     int i = 0;
    475     while ((i < rawsubs.size()) || !wrappedtext.isEmpty())
    476     {
    477         QString nextline = wrappedtext;
    478         if (i < rawsubs.size())
    479             nextline += rawsubs[i].remove((const QRegExp&) m_removeHTML);
    480         wrappedtext = "";
    481 
    482         while (font.width(nextline) > maxwidth)
    483         {
    484             QString word = nextline.section(" ", -1, -1,
    485                                             QString::SectionSkipEmpty);
    486             if (word.isEmpty() || font.width(word) > maxwidth)
    487                 break;
    488             wrappedtext = word + " " + wrappedtext;
    489             nextline.chop(word.size() + 1);
    490         }
    491         if (!nextline.isEmpty())
    492             wrappedsubs.append(nextline);
    493         i++;
    494     }
    495     rawsubs = wrappedsubs;
    496 }
    497 
    498445void SubtitleScreen::DrawTextSubtitles(QStringList &wrappedsubs,
    499446                                       uint64_t start, uint64_t duration)
    500447{
    501     QFontMetrics font(*(gTextSubFont->GetFace()));
    502     int height = font.height() * (1 + PAD_HEIGHT);
    503     int pad_width = font.maxWidth() * PAD_WIDTH;
    504     int y = m_safeArea.height() - (height * wrappedsubs.size());
    505     int centre = m_safeArea.width() / 2;
    506     QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
    507     foreach (QString subtitle, wrappedsubs)
    508     {
    509         if (subtitle.isEmpty())
    510             continue;
    511         int width = font.width(subtitle) + pad_width * 2;
    512         int x = centre - (width / 2) - pad_width;
    513         QRect rect(x, y, width, height);
    514 
    515         if (m_useBackground)
    516         {
    517             MythUIShape *shape = new MythUIShape(this,
    518                 QString("tsubbg%1%2").arg(x).arg(y));
    519             shape->SetFillBrush(bgfill);
    520             shape->SetArea(MythRect(rect));
    521             if (duration > 0)
    522                 m_expireTimes.insert(shape, start + duration);
    523         }
    524         MythUISimpleText* text = new MythUISimpleText
    525                                  (subtitle, *gTextSubFont, rect,
    526                                   Qt::AlignCenter, this,
    527                                   QString("tsub%1%2").arg(x).arg(y));
    528         y += height;
    529         LOG(VB_PLAYBACK, LOG_INFO, LOC + subtitle);
    530         m_refreshArea = true;
    531 
    532         if (duration > 0)
    533         {
    534             m_expireTimes.insert(text, start + duration);
    535             LOG(VB_PLAYBACK, LOG_INFO, LOC +
    536                 QString("Display text subtitle for %1 ms").arg(duration));
    537         }
    538     }
     448    FormattedTextSubtitle fsub(m_safeArea);
     449    fsub.InitFromSRT(wrappedsubs, m_textFontZoom);
     450    fsub.WrapLongLines();
     451    fsub.Draw(this);
     452    m_refreshArea = true;
    539453}
    540454
    541455void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
    void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos) 
    604518/// are corresondingly updated (and the control character is stripped).
    605519static QString extract_cc608(
    606520    QString &text, bool teletextmode, int &color,
    607     bool &isItalic, bool &isUnderline, bool &showedNonControl)
     521    bool &isItalic, bool &isUnderline)
    608522{
    609523    QString result;
    610524    QString orig(text);
    static QString extract_cc608( 
    613527    {
    614528        result = text;
    615529        text = QString::null;
    616         showedNonControl = true;
    617530        return result;
    618531    }
    619532
    static QString extract_cc608( 
    651564    {
    652565        result = text;
    653566        text = QString::null;
    654         showedNonControl = true;
    655567    }
    656568    else
    657569    {
    static QString extract_cc608( 
    664576        if (text[nextControl] < (0x7000 + 0x10))
    665577            result += " ";
    666578        text = text.mid(nextControl);
    667         if (nextControl > 0)
    668             showedNonControl = true;
    669579    }
    670580
    671581    return result;
    static QString extract_cc608( 
    673583
    674584void SubtitleScreen::DisplayCC608Subtitles(void)
    675585{
    676     static const QColor clr[8] =
    677     {
    678         Qt::white,   Qt::green,   Qt::blue,    Qt::cyan,
    679         Qt::red,     Qt::yellow,  Qt::magenta, Qt::white,
    680     };
    681 
    682586    if (!InitialiseFont(m_fontStretch) || !m_608reader)
    683587        return;
    684588
    void SubtitleScreen::DisplayCC608Subtitles(void) 
    715619        return;
    716620    }
    717621
    718     vector<CC608Text*>::iterator i = textlist->buffers.begin();
    719     bool teletextmode = (*i)->teletextmode;
    720     int xscale = teletextmode ? 40 : 36;
    721     int yscale = teletextmode ? 25 : 17;
    722     gTextSubFont->GetFace()->setPixelSize(m_safeArea.height() /
    723                                           (yscale * 1.1765f));
    724     QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
    725 
    726     for (; i != textlist->buffers.end(); ++i)
    727     {
    728         CC608Text *cc = (*i);
    729         int color = 0;
    730         bool isItalic = false, isUnderline = false;
    731         bool first = true;
    732         bool showedNonControl = false;
    733         int x = 0, width = 0;
    734         QString text(cc->text);
    735 
    736         for (int chunk = 0; text != QString::null; first = false, chunk++)
    737         {
    738             QString captionText =
    739                 extract_cc608(text, cc->teletextmode,
    740                               color, isItalic, isUnderline,
    741                               showedNonControl);
    742             gTextSubFont->GetFace()->setItalic(isItalic);
    743             gTextSubFont->GetFace()->setUnderline(isUnderline);
    744             gTextSubFont->SetColor(clr[min(max(0, color), 7)]);
    745             QFontMetrics font(*(gTextSubFont->GetFace()));
    746             // XXX- could there be different heights across the same line?
    747             int height = font.height() * (1 + PAD_HEIGHT);
    748             if (first)
    749             {
    750                 x = teletextmode ? cc->y : (cc->x + 3);
    751                 x = (int)(((float)x / (float)xscale) *
    752                           (float)m_safeArea.width());
    753             }
    754             else
    755             {
    756                 x += width; // bump x by the previous width
    757             }
    758 
    759             int pad_width = font.maxWidth() * PAD_WIDTH;
    760             width = font.width(captionText) + pad_width;
    761             int y = teletextmode ? cc->x : cc->y;
    762             y = (int)(((float)y / (float)yscale) * (float)m_safeArea.height());
    763             // Sometimes a line of caption text begins with a mid-row
    764             // format control like italics or a color change.  The
    765             // spec says the mid-row control also includes a space
    766             // character.  But this looks clumsy when using a
    767             // background, so we suppress it after the placement is
    768             // calculated.
    769             if (!showedNonControl)
    770                 continue;
    771             QRect rect(x, y, width, height);
    772 
    773             if (!teletextmode && m_useBackground)
    774             {
    775                 MythUIShape *shape = new MythUIShape(this,
    776                     QString("cc608bg%1%2%3").arg(cc->x).arg(cc->y).arg(width));
    777                 shape->SetFillBrush(bgfill);
    778                 QRect bgrect(x - pad_width, y, width + pad_width, height);
    779                 shape->SetArea(MythRect(bgrect));
    780             }
    781 
    782             new MythUISimpleText(captionText, *gTextSubFont, rect,
    783                                  Qt::AlignLeft, (MythUIType*)this,
    784                                  QString("cc608txt%1%2%3%4")
    785                                      .arg(cc->x).arg(cc->y)
    786                                      .arg(width).arg(chunk));
    787 
    788             m_refreshArea = true;
    789 
    790             LOG(VB_VBI, LOG_INFO,
    791                 QString("x %1 y %2 uline=%4 ital=%5 "
    792                         "color=%6 coord=%7,%8 String: '%3'")
    793                 .arg(cc->x).arg(cc->y).arg(captionText)
    794                 .arg(isUnderline).arg(isItalic).arg(color).arg(x).arg(y));
    795         }
    796     }
     622    FormattedTextSubtitle fsub(m_safeArea);
     623    fsub.InitFromCC608(textlist->buffers);
     624    fsub.Draw(this);
     625    m_refreshArea = true;
    797626    textlist->lock.unlock();
    798627}
    799628
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    11891019    return mythfont;
    11901020}
    11911021
     1022void FormattedTextChunk::GetSize(int pixelSize, int &width, int &height) const
     1023{
     1024    QFont *font = gTextSubFont->GetFace();
     1025    font->setItalic(isItalic);
     1026    font->setBold(isBold);
     1027    font->setUnderline(isUnderline);
     1028    font->setPixelSize(pixelSize);
     1029    QFontMetrics fm(*font);
     1030    width = fm.width(text) + fm.maxWidth() * PAD_WIDTH;
     1031    height = fm.height() * (1 + PAD_HEIGHT);
     1032}
     1033
     1034void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers)
     1035{
     1036    static const QColor clr[8] =
     1037    {
     1038        Qt::white,   Qt::green,   Qt::blue,    Qt::cyan,
     1039        Qt::red,     Qt::yellow,  Qt::magenta, Qt::white,
     1040    };
     1041
     1042    if (buffers.empty())
     1043        return;
     1044    vector<CC608Text*>::iterator i = buffers.begin();
     1045    bool teletextmode = (*i)->teletextmode;
     1046    m_useBackground = m_useBackground && !teletextmode;
     1047    int xscale = teletextmode ? 40 : 36;
     1048    int yscale = teletextmode ? 25 : 17;
     1049    m_pixelSize = m_safeArea.height() / (yscale * 1.1765f);
     1050
     1051    for (; i != buffers.end(); ++i)
     1052    {
     1053        CC608Text *cc = (*i);
     1054        int color = 0;
     1055        bool isItalic = false, isUnderline = false;
     1056        const bool isBold = false;
     1057        QString text(cc->text);
     1058
     1059        int orig_x = teletextmode ? cc->y : (cc->x + 3);
     1060        int x = (int)(((float)orig_x / (float)xscale) * (float)m_safeArea.width());
     1061        int orig_y = teletextmode ? cc->x : cc->y;
     1062        int y = (int)(((float)orig_y / (float)yscale) * (float)m_safeArea.height());
     1063        FormattedTextLine line(x, y);
     1064        for (int chunk = 0; text != QString::null; chunk++)
     1065        {
     1066            QString captionText =
     1067                extract_cc608(text, cc->teletextmode,
     1068                              color, isItalic, isUnderline);
     1069            FormattedTextChunk chunk(captionText,
     1070                                     isItalic, isBold, isUnderline,
     1071                                     clr[min(max(0, color), 7)]);
     1072            line.chunks += chunk;
     1073            LOG(VB_VBI, LOG_INFO,
     1074                QString("Adding cc608 chunk: x=%1 y=%2 "
     1075                        "uline=%3 ital=%4 color=%5 text='%6'")
     1076                .arg(cc->x).arg(cc->y)
     1077                .arg(isUnderline).arg(isItalic).arg(color).arg(captionText));
     1078        }
     1079        m_lines += line;
     1080    }
     1081}
     1082
     1083void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom)
     1084{
     1085    // Does a simplistic parsing of HTML tags from the strings.
     1086    // Nesting is not implemented.  Stray whitespace may cause
     1087    // legitimate tags to be ignored.  All other HTML tags are
     1088    // stripped and ignored.
     1089    //
     1090    // <i> - enable italics
     1091    // </i> - disable italics
     1092    // <b> - enable boldface
     1093    // </b> - disable boldface
     1094    // <u> - enable underline
     1095    // </u> - disable underline
     1096    // <font color="#xxyyzz"> - change font color
     1097    // </font> - reset font color to white
     1098
     1099    m_pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     1100
     1101    bool isItalic = false;
     1102    bool isBold = false;
     1103    bool isUnderline = false;
     1104    QColor color(Qt::white);
     1105    QRegExp htmlTag("</?.+>");
     1106    QString htmlPrefix("<font color=\""), htmlSuffix("\">");
     1107    htmlTag.setMinimal(true);
     1108    foreach (QString subtitle, subs)
     1109    {
     1110        FormattedTextLine line;
     1111        QString text(subtitle);
     1112        while (!text.isEmpty())
     1113        {
     1114            int pos = text.indexOf(htmlTag);
     1115            if (pos != 0) // don't add a zero-length string
     1116            {
     1117                FormattedTextChunk chunk(text.left(pos),
     1118                                         isItalic, isBold, isUnderline, color);
     1119                line.chunks += chunk;
     1120                text = (pos < 0 ? "" : text.mid(pos));
     1121                LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk '%1'").arg(chunk.text));
     1122            }
     1123            if (pos >= 0)
     1124            {
     1125                int htmlLen = htmlTag.matchedLength();
     1126                QString html = text.left(htmlLen).toLower();
     1127                text = text.mid(htmlLen);
     1128                if (html == "<i>")
     1129                    isItalic = true;
     1130                else if (html == "</i>")
     1131                    isItalic = false;
     1132                else if (html.startsWith(htmlPrefix) &&
     1133                         html.endsWith(htmlSuffix))
     1134                {
     1135                    int colorLen = html.length() -
     1136                        (htmlPrefix.length() + htmlSuffix.length());
     1137                    QString colorString(html.mid(htmlPrefix.length(), colorLen));
     1138                    QColor newColor(colorString);
     1139                    if (newColor.isValid())
     1140                        color = newColor;
     1141                    else
     1142                        LOG(VB_VBI, LOG_INFO,
     1143                            QString("Ignoring invalid SRT color specification: "
     1144                                    "'%1'").arg(colorString));
     1145                }
     1146                else if (html == "</font>")
     1147                    color = Qt::white;
     1148                else if (html == "<b>")
     1149                    isBold = true;
     1150                else if (html == "</b>")
     1151                    isBold = false;
     1152                else if (html == "<u>")
     1153                    isUnderline = true;
     1154                else if (html == "</u>")
     1155                    isUnderline = false;
     1156                else
     1157                    LOG(VB_VBI, LOG_INFO,
     1158                        QString("Ignoring unknown SRT formatting: '%1'").arg(html));
     1159
     1160                LOG(VB_VBI, LOG_INFO,
     1161                    QString("SRT formatting change '%1', "
     1162                            "new ital=%2 bold=%3 uline=%4 color=#%5%6%7)")
     1163                    .arg(html).arg(isItalic).arg(isBold).arg(isUnderline)
     1164                    .arg(color.red(),   2, 16, QLatin1Char('0'))
     1165                    .arg(color.green(), 2, 16, QLatin1Char('0'))
     1166                    .arg(color.blue(),  2, 16, QLatin1Char('0')));
     1167            }
     1168        }
     1169        m_lines += line;
     1170    }
     1171}
     1172
     1173bool FormattedTextChunk::Split(FormattedTextChunk &newChunk)
     1174{
     1175    LOG(VB_VBI, LOG_INFO,
     1176        QString("Attempting to split chunk '%1'").arg(text));
     1177    int lastSpace = text.lastIndexOf(' ', -2); // -2 to ignore trailing space
     1178    if (lastSpace < 0)
     1179    {
     1180        LOG(VB_VBI, LOG_INFO,
     1181            QString("Failed to split chunk '%1'").arg(text));
     1182        return false;
     1183    }
     1184    newChunk.isItalic = isItalic;
     1185    newChunk.isBold = isBold;
     1186    newChunk.isUnderline = isUnderline;
     1187    newChunk.color = color;
     1188    newChunk.text = text.mid(lastSpace + 1).trimmed() + ' ';
     1189    text = text.left(lastSpace).trimmed();
     1190    LOG(VB_VBI, LOG_INFO,
     1191        QString("Split chunk into '%1' + '%2'").arg(text).arg(newChunk.text));
     1192    return true;
     1193}
     1194
     1195void FormattedTextSubtitle::WrapLongLines(void)
     1196{
     1197    int maxWidth = m_safeArea.width();
     1198    for (int i = 0; i < m_lines.size(); i++)
     1199    {
     1200        int width = m_lines[i].Width(m_pixelSize);
     1201        // Move entire chunks to the next line as necessary.  Leave at
     1202        // least one chunk on the current line.
     1203        while (width > maxWidth && m_lines[i].chunks.size() > 1)
     1204        {
     1205            width -= m_lines[i].chunks.back().Width(m_pixelSize);
     1206            // Make sure there's a next line to wrap into.
     1207            if (m_lines.size() == i + 1)
     1208                m_lines += FormattedTextLine(m_lines[i].x_indent,
     1209                                             m_lines[i].y_indent);
     1210            m_lines[i+1].chunks.prepend(m_lines[i].chunks.takeLast());
     1211            LOG(VB_VBI, LOG_INFO,
     1212                QString("Wrapping chunk to next line: '%1'")
     1213                .arg(m_lines[i+1].chunks[0].text));
     1214        }
     1215        // Split the last chunk until width is small enough or until
     1216        // no more splits are possible.
     1217        bool isSplitPossible = true;
     1218        while (width > maxWidth && isSplitPossible)
     1219        {
     1220            FormattedTextChunk newChunk;
     1221            isSplitPossible = m_lines[i].chunks.back().Split(newChunk);
     1222            if (isSplitPossible)
     1223            {
     1224                // Make sure there's a next line to split into.
     1225                if (m_lines.size() == i + 1)
     1226                    m_lines += FormattedTextLine(m_lines[i].x_indent,
     1227                                                 m_lines[i].y_indent);
     1228                m_lines[i+1].chunks.prepend(newChunk);
     1229                width = m_lines[i].Width(m_pixelSize);
     1230            }
     1231        }
     1232    }
     1233}
     1234
     1235void FormattedTextSubtitle::Draw(SubtitleScreen *parent,
     1236                                 uint64_t start, uint64_t duration) const
     1237{
     1238    bool useBackground = m_useBackground && parent->GetUseBackground();
     1239    gTextSubFont->GetFace()->setPixelSize(m_pixelSize);
     1240    QFontMetrics font(*(gTextSubFont->GetFace()));
     1241    int pad_width = font.maxWidth() * PAD_WIDTH;
     1242    QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
     1243
     1244    for (int i = 0; i < m_lines.size(); i++)
     1245    {
     1246        int x = m_lines[i].x_indent;
     1247        if (x < 0) // centering
     1248            x = (m_safeArea.width() - m_lines[i].Width(m_pixelSize)) / 2;
     1249        int y = m_lines[i].y_indent;
     1250        if (y < 0) // stack lines at bottom
     1251            y = m_safeArea.height() -
     1252                (m_lines.size() - i) * m_lines[i].Height(m_pixelSize) * 1.1765f;
     1253
     1254        if (useBackground)
     1255        {
     1256            QRect bgrect(x - pad_width, y,
     1257                         m_lines[i].Width(m_pixelSize) + pad_width,
     1258                         m_lines[i].Height(m_pixelSize));
     1259            // Special case.  If the first chunk is entirely
     1260            // whitespace, don't put a black background behind that
     1261            // chunk.
     1262            //
     1263            // This often happens when a line of cc608 caption text
     1264            // begins with a mid-row format control like italics or a
     1265            // color change.  The spec says the mid-row control
     1266            // implies a space character, which needs to be preserved
     1267            // so that the rest of the text is accurately laid out.  A
     1268            // leading space looks clumsy against the black
     1269            // background, so we adjust the background accordingly.
     1270            if (!m_lines[i].chunks.isEmpty() &&
     1271                m_lines[i].chunks[0].text.trimmed().isEmpty())
     1272            {
     1273                bgrect.setLeft(bgrect.left() +
     1274                               m_lines[i].chunks[0].Width(m_pixelSize));
     1275            }
     1276            MythUIShape *shape =
     1277                new MythUIShape(parent, QString("subbg%1_%2").arg(x).arg(y));
     1278            shape->SetFillBrush(bgfill);
     1279            shape->SetArea(MythRect(bgrect));
     1280            if (duration > 0)
     1281                parent->RegisterExpiration(shape, start + duration);
     1282        }
     1283        QList<FormattedTextChunk>::const_iterator chunk;
     1284        for (chunk = m_lines[i].chunks.constBegin();
     1285             chunk != m_lines[i].chunks.constEnd();
     1286             ++chunk)
     1287        {
     1288            // If the chunk starts with whitespace, the leading
     1289            // whitespace ultimately gets lost due to the
     1290            // text.trimmed() operation in the MythUISimpleText
     1291            // constructor.  To compensate, we manually indent the
     1292            // chunk accordingly.
     1293            int count = 0;
     1294            while (count < (*chunk).text.length() &&
     1295                   (*chunk).text.at(count) == ' ')
     1296                ++count;
     1297            int x_adjust = count * font.width(" ");
     1298            gTextSubFont->GetFace()->setItalic((*chunk).isItalic);
     1299            gTextSubFont->GetFace()->setBold((*chunk).isBold);
     1300            gTextSubFont->GetFace()->setUnderline((*chunk).isUnderline);
     1301            gTextSubFont->SetColor((*chunk).color);
     1302            QRect rect(x + x_adjust, y,
     1303                       (*chunk).Width(m_pixelSize) - x_adjust,
     1304                       (*chunk).Height(m_pixelSize));
     1305
     1306            MythUISimpleText *text =
     1307                new MythUISimpleText((*chunk).text, *gTextSubFont, rect,
     1308                                     Qt::AlignLeft, (MythUIType*)parent,
     1309                                     QString("subtxt%1x%2@%3,%4")
     1310                                     .arg((*chunk).Width(m_pixelSize))
     1311                                     .arg((*chunk).Height(m_pixelSize))
     1312                                     .arg(x).arg(y));
     1313            if (duration > 0)
     1314                parent->RegisterExpiration(text, start + duration);
     1315
     1316            LOG(VB_VBI, LOG_INFO,
     1317                QString("Drawing chunk at (%1,%2) with "
     1318                        "ital=%3 bold=%4 uline=%5 color=#%6%7%8 "
     1319                        "text='%9'")
     1320                .arg(x).arg(y)
     1321                .arg((*chunk).isItalic)
     1322                .arg((*chunk).isBold)
     1323                .arg((*chunk).isUnderline)
     1324                .arg((*chunk).color.red(),   2, 16, QLatin1Char('0'))
     1325                .arg((*chunk).color.green(), 2, 16, QLatin1Char('0'))
     1326                .arg((*chunk).color.blue(),  2, 16, QLatin1Char('0'))
     1327                .arg((*chunk).text));
     1328
     1329            x += (*chunk).Width(m_pixelSize);
     1330        }
     1331    }
     1332}
     1333
    11921334#ifdef USING_LIBASS
    11931335static void myth_libass_log(int level, const char *fmt, va_list vl, void *ctx)
    11941336{
  • mythtv/libs/libmythtv/subtitlescreen.h

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
    index f233220..da3ae19 100644
    a b class SubtitleScreen : public MythScreenType 
    3232    void ExpireSubtitles(void);
    3333    void DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos);
    3434
     35    void RegisterExpiration(MythUIType *shape, long long endTime) {
     36        m_expireTimes.insert(shape, endTime);
     37    }
     38
     39    bool GetUseBackground(void) { return m_useBackground; }
     40
    3541    // MythScreenType methods
    3642    virtual bool Create(void);
    3743    virtual void Pulse(void);
    class SubtitleScreen : public MythScreenType 
    4147    void DisplayAVSubtitles(void);
    4248    void DisplayTextSubtitles(void);
    4349    void DisplayRawTextSubtitles(void);
    44     void OptimiseTextSubs(QStringList &list);
    4550    void DrawTextSubtitles(QStringList &wrappedsubs, uint64_t start,
    4651                           uint64_t duration);
    4752    void DisplayCC608Subtitles(void);
    class SubtitleScreen : public MythScreenType 
    8590#endif // USING_LIBASS
    8691};
    8792
     93struct FormattedTextChunk
     94{
     95    FormattedTextChunk(const QString &t, bool ital, bool bold, bool uline,
     96                       QColor clr)
     97        : text(t), isItalic(ital), isBold(bold), isUnderline(uline),
     98          color(clr) {}
     99    FormattedTextChunk(void) {}
     100    int Width(int pixelSize) const {
     101        int width, height;
     102        GetSize(pixelSize, width, height);
     103        return width;
     104    }
     105    int Height(int pixelSize) const {
     106        int width, height;
     107        GetSize(pixelSize, width, height);
     108        return height;
     109    }
     110    bool Split(FormattedTextChunk &newChunk);
     111    QString text;
     112    bool isItalic;
     113    bool isBold;
     114    bool isUnderline;
     115    QColor color;
     116private:
     117    void GetSize(int pixelSize, int &width, int &height) const;
     118};
     119
     120struct FormattedTextLine
     121{
     122    FormattedTextLine(int x = -1, int y = -1) : x_indent(x), y_indent(y) {}
     123    int Height(int pixelSize) const {
     124        int result = 0;
     125        QList<FormattedTextChunk>::const_iterator it;
     126        for (it = chunks.constBegin(); it != chunks.constEnd(); ++it) {
     127            int height = (*it).Height(pixelSize);
     128            result = max(result, height);
     129        }
     130        return result;
     131    }
     132    int Width(int pixelSize) const {
     133        int result = 0;
     134        QList<FormattedTextChunk>::const_iterator it;
     135        for (it = chunks.constBegin(); it != chunks.constEnd(); ++it) {
     136            int width = (*it).Width(pixelSize);
     137            result += width;
     138        }
     139        return result;
     140    }
     141    QList<FormattedTextChunk> chunks;
     142    int x_indent; // -1 means TBD i.e. centered
     143    int y_indent; // -1 means TBD i.e. relative to bottom
     144};
     145
     146class FormattedTextSubtitle
     147{
     148public:
     149    FormattedTextSubtitle(const QRect &safearea)
     150        : m_safeArea(safearea), m_useBackground(true) {}
     151    void InitFromCC608(vector<CC608Text*> &buffers);
     152    void InitFromSRT(QStringList &subs, int textFontZoom);
     153    void WrapLongLines(void);
     154    void Draw(SubtitleScreen *parent,
     155              uint64_t start = 0, uint64_t duration = 0) const;
     156private:
     157    QVector<FormattedTextLine> m_lines;
     158    const QRect m_safeArea;
     159    bool m_useBackground;
     160    int m_pixelSize;
     161};
     162
    88163#endif // SUBTITLESCREEN_H