Ticket #10194: srt_cc708_v1.patch

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

Add cc708 captions to the refactoring. Leverage for mythccextractor.

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 40e2d39..199ddf5 100644
    a b AvFormatDecoder::AvFormatDecoder(MythPlayer *parent, 
    321321
    322322    cc608_build_parity_table(cc608_parity_table);
    323323
    324     if (gCoreContext->GetNumSetting("CCBackground", 0))
    325         CC708Window::forceWhiteOnBlackText = true;
    326 
    327324    LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("PlayerFlags: 0x%1")
    328325        .arg(playerFlags, 0, 16));
    329326}
  • mythtv/libs/libmythtv/cc708window.cpp

    diff --git a/mythtv/libs/libmythtv/cc708window.cpp b/mythtv/libs/libmythtv/cc708window.cpp
    index e133eae..b1d7c43 100644
    a b const uint k708AttrOpacityFlash = 1; 
    106106const uint k708AttrOpacityTranslucent = 2;
    107107const uint k708AttrOpacityTransparent = 3;
    108108
    109 bool CC708Window::forceWhiteOnBlackText = false;
    110 
    111109CC708Window::CC708Window()
    112110    : priority(0),              visible(0),
    113111      anchor_point(0),          relative_pos(0),
    void CC708Window::DefineWindow(int _priority, int _visible, 
    175173        for (uint i = 0; i < old_row * old_col; i++)
    176174            new_text[i] = text[i];
    177175        for (uint i = old_row * old_col; i < num; i++)
    178         {
    179176            new_text[i].attr = pen.attr;
    180             if (forceWhiteOnBlackText)
    181             {
    182                 new_text[i].attr.fg_opacity = k708AttrOpacityTransparent;
    183                 new_text[i].attr.bg_opacity = k708AttrOpacityTransparent;
    184             }
    185         }
    186177        delete [] text;
    187178        text = new_text;
    188179    }
    void CC708Window::DefineWindow(int _priority, int _visible, 
    200191        pen.column = 0;
    201192        pen.row    = 0;
    202193        for (uint i = 0; i < num; i++)
    203         {
    204194            text[i].attr = pen.attr;
    205             if (forceWhiteOnBlackText)
    206             {
    207                 text[i].attr.fg_opacity = k708AttrOpacityTransparent;
    208                 text[i].attr.bg_opacity = k708AttrOpacityTransparent;
    209             }
    210         }
    211195    }
    212196
    213197    exists  = true;
    void CC708Window::Clear(void) 
    241225    {
    242226        text[i].character = QChar(' ');
    243227        text[i].attr = pen.attr;
    244         if (forceWhiteOnBlackText)
    245         {
    246             text[i].attr.fg_opacity = k708AttrOpacityTransparent;
    247             text[i].attr.bg_opacity = k708AttrOpacityTransparent;
    248         }
    249228    }
    250229    changed = true;
    251230}
    void CC708Window::AddChar(QChar ch) 
    370349    }
    371350
    372351    GetCCChar().attr      = pen.attr;
    373     if (forceWhiteOnBlackText)
    374     {
    375         GetCCChar().attr.fg_color   = k708AttrColorWhite;
    376         GetCCChar().attr.fg_opacity = k708AttrOpacitySolid;
    377         GetCCChar().attr.bg_color   = k708AttrColorBlack;
    378         GetCCChar().attr.bg_opacity = k708AttrOpacityTranslucent;
    379         GetCCChar().attr.edge_color = k708AttrColorWhite;
    380     }
    381352    GetCCChar().character = ch;
    382353    int c = pen.column;
    383354    int r = pen.row;
    void CC708Pen::SetPenStyle(uint style) 
    534505    attr.font_tag   = style2font[style];
    535506    attr.italics    = 0;
    536507    attr.underline  = 0;
     508    attr.boldface   = 0;
    537509    attr.edge_type  = 0;
    538510    attr.fg_color   = k708AttrColorWhite;
    539511    attr.fg_opacity = k708AttrOpacitySolid;
    void CC708Pen::SetPenStyle(uint style) 
    541513    attr.bg_opacity = (style<6) ?
    542514        k708AttrOpacitySolid : k708AttrOpacityTransparent;
    543515    attr.edge_color = k708AttrColorBlack;
     516    attr.override_fg_color = false;
    544517}
    545518
    546519CC708Character::CC708Character(const CC708Window &win)
    547520{
    548521    attr = win.pen.attr;
    549     if (CC708Window::forceWhiteOnBlackText)
    550     {
    551         attr.fg_opacity = k708AttrOpacityTransparent;
    552         attr.bg_opacity = k708AttrOpacityTransparent;
    553     }
    554522    character = ' ';
    555523}
    556524
    bool CC708CharacterAttribute::operator==( 
    573541
    574542QColor CC708CharacterAttribute::ConvertToQColor(uint c)
    575543{
    576     //int X[4] = {0, 85, 170, 255}; RGB( X[(c>>4)&3], X[(c>>2)&3], X[c&3] )
    577     return QColor((c & 0x30) << 2, (c & 0x0c) << 4, (c & 0x3) << 6);
     544    static int X[] = {0, 96, 255, 255};
     545    return QColor(X[(c>>4)&3], X[(c>>2)&3], X[c&3]);
    578546}
  • mythtv/libs/libmythtv/cc708window.h

    diff --git a/mythtv/libs/libmythtv/cc708window.h b/mythtv/libs/libmythtv/cc708window.h
    index 2c1db0a..ce064ee 100644
    a b using namespace std; 
    1313
    1414#include "mythtvexp.h"
    1515
     16extern const uint k708JustifyLeft;
     17extern const uint k708JustifyRight;
     18extern const uint k708JustifyCenter;
     19extern const uint k708JustifyFull;
     20
     21extern const uint k708EffectSnap;
     22extern const uint k708EffectFade;
     23extern const uint k708EffectWipe;
     24
     25extern const uint k708BorderNone;
     26extern const uint k708BorderRaised;
     27extern const uint k708BorderDepressed;
     28extern const uint k708BorderUniform;
     29extern const uint k708BorderShadowLeft;
     30extern const uint k708BorderShadowRight;
     31
     32extern const uint k708DirLeftToRight;
     33extern const uint k708DirRightToLeft;
     34extern const uint k708DirTopToBottom;
     35extern const uint k708DirBottomToTop;
     36
     37extern const uint k708AttrSizeSmall;
     38extern const uint k708AttrSizeStandard;
     39extern const uint k708AttrSizeLarge;
     40
     41extern const uint k708AttrOffsetSubscript;
     42extern const uint k708AttrOffsetNormal;
     43extern const uint k708AttrOffsetSuperscript;
     44
     45extern const uint k708AttrFontDefault;
     46extern const uint k708AttrFontMonospacedSerif;
     47extern const uint k708AttrFontProportionalSerif;
     48extern const uint k708AttrFontMonospacedSansSerif;
     49extern const uint k708AttrFontProportionalSansSerif;
     50extern const uint k708AttrFontCasual;
     51extern const uint k708AttrFontCursive;
     52extern const uint k708AttrFontSmallCaps;
     53
     54extern const uint k708AttrEdgeNone;
     55extern const uint k708AttrEdgeRaised;
     56extern const uint k708AttrEdgeDepressed;
     57extern const uint k708AttrEdgeUniform;
     58extern const uint k708AttrEdgeLeftDropShadow;
     59extern const uint k708AttrEdgeRightDropShadow;
     60
     61extern const uint k708AttrColorBlack;
     62extern const uint k708AttrColorWhite;
     63
     64extern const uint k708AttrOpacitySolid;
     65extern const uint k708AttrOpacityFlash;
     66extern const uint k708AttrOpacityTranslucent;
     67extern const uint k708AttrOpacityTransparent;
     68
    1669class CC708CharacterAttribute
    1770{
    1871  public:
    class CC708CharacterAttribute 
    2578    uint edge_type;
    2679    uint underline;
    2780    uint italics;
     81    uint boldface;
    2882
    2983    uint fg_color;
    3084    uint fg_opacity;
    class CC708CharacterAttribute 
    3286    uint bg_opacity;
    3387    uint edge_color;
    3488
     89    bool override_fg_color; // for a color not in the 6-bit palette
     90    QColor actual_fg_color;
     91
     92    CC708CharacterAttribute(bool isItalic, bool isBold, bool isUnderline,
     93                            QColor fgColor, bool hasBackground) :
     94        pen_size(k708AttrSizeStandard),
     95        offset(k708AttrOffsetNormal),
     96        text_tag(0), // "dialog", ignored
     97        font_tag(0), // system font
     98        edge_type(k708AttrEdgeNone),
     99        underline(isUnderline),
     100        italics(isItalic),
     101        boldface(isBold),
     102        fg_color(k708AttrColorWhite), // will be overridden
     103        fg_opacity(k708AttrOpacitySolid), // solid
     104        bg_color(k708AttrColorBlack),
     105        bg_opacity(hasBackground ? k708AttrOpacitySolid :
     106                   k708AttrOpacityTransparent),
     107        edge_color(k708AttrColorBlack),
     108        override_fg_color(true),
     109        actual_fg_color(fgColor)
     110    {}
     111    CC708CharacterAttribute(void) : override_fg_color(false) {}
     112
    35113    // remove this
    36114    uint FontIndex(void) const
    37115    {
    class CC708CharacterAttribute 
    41119    static QColor ConvertToQColor(uint eia708color);
    42120    QColor GetFGColor(void) const
    43121    {
    44         QColor fg = ConvertToQColor(fg_color);
     122        QColor fg = (override_fg_color ?
     123                     actual_fg_color : ConvertToQColor(fg_color));
    45124        fg.setAlpha(GetFGAlpha());
    46125        return fg;
    47126    }
    class CC708Pen 
    88167        attr.edge_type = edge_type;
    89168        attr.underline = underline;
    90169        attr.italics   = italics;
     170        attr.boldface  = 0;
    91171    }
    92172  public:
    93173    CC708CharacterAttribute attr;
    class CC708Service 
    215295    CC708Window windows[8];
    216296};
    217297
    218 extern const uint k708JustifyLeft;
    219 extern const uint k708JustifyRight;
    220 extern const uint k708JustifyCenter;
    221 extern const uint k708JustifyFull;
    222 
    223 extern const uint k708EffectSnap;
    224 extern const uint k708EffectFade;
    225 extern const uint k708EffectWipe;
    226 
    227 extern const uint k708BorderNone;
    228 extern const uint k708BorderRaised;
    229 extern const uint k708BorderDepressed;
    230 extern const uint k708BorderUniform;
    231 extern const uint k708BorderShadowLeft;
    232 extern const uint k708BorderShadowRight;
    233 
    234 extern const uint k708DirLeftToRight;
    235 extern const uint k708DirRightToLeft;
    236 extern const uint k708DirTopToBottom;
    237 extern const uint k708DirBottomToTop;
    238 
    239 extern const uint k708AttrSizeSmall;
    240 extern const uint k708AttrSizeStandard;
    241 extern const uint k708AttrSizeLarge;
    242 
    243 extern const uint k708AttrOffsetSubscript;
    244 extern const uint k708AttrOffsetNormal;
    245 extern const uint k708AttrOffsetSuperscript;
    246 
    247 extern const uint k708AttrFontDefault;
    248 extern const uint k708AttrFontMonospacedSerif;
    249 extern const uint k708AttrFontProportionalSerif;
    250 extern const uint k708AttrFontMonospacedSansSerif;
    251 extern const uint k708AttrFontProportionalSansSerif;
    252 extern const uint k708AttrFontCasual;
    253 extern const uint k708AttrFontCursive;
    254 extern const uint k708AttrFontSmallCaps;
    255 
    256 extern const uint k708AttrEdgeNone;
    257 extern const uint k708AttrEdgeRaised;
    258 extern const uint k708AttrEdgeDepressed;
    259 extern const uint k708AttrEdgeUniform;
    260 extern const uint k708AttrEdgeLeftDropShadow;
    261 extern const uint k708AttrEdgeRightDropShadow;
    262 
    263 extern const uint k708AttrColorBlack;
    264 extern const uint k708AttrColorWhite;
    265 
    266 extern const uint k708AttrOpacitySolid;
    267 extern const uint k708AttrOpacityFlash;
    268 extern const uint k708AttrOpacityTranslucent;
    269 extern const uint k708AttrOpacityTransparent;
    270 
    271298#endif // _CC708_WINDOW_
  • mythtv/libs/libmythtv/mythccextractorplayer.cpp

    diff --git a/mythtv/libs/libmythtv/mythccextractorplayer.cpp b/mythtv/libs/libmythtv/mythccextractorplayer.cpp
    index 5173256..6ac17dc 100644
    a b using namespace std; 
    2828#include "teletextextractorreader.h"
    2929#include "mythccextractorplayer.h"
    3030#include "avformatdecoder.h"
     31#include "subtitlescreen.h"
    3132#include "srtwriter.h"
    3233
    3334
    void MythCCExtractorPlayer::Ingest608Captions(void) 
    319320                continue;
    320321            }
    321322
    322             QStringList content;
    323             vector<CC608Text*>::iterator bit = textlist->buffers.begin();
    324             for (; bit != textlist->buffers.end(); ++bit)
    325                 content += CC608Decoder::ToASCII((*bit)->text, true);
     323            FormattedTextSubtitle fsub;
     324            fsub.InitFromCC608(textlist->buffers);
     325            QStringList content = fsub.ToSRT();
    326326
    327327            textlist->lock.unlock();
    328328
    void MythCCExtractorPlayer::Ingest708Captions(void) 
    411411                    if (win.visible)
    412412                        strings = win.GetStrings();
    413413                    Ingest708Caption(it.key(), serviceIdx, windowIdx,
    414                                      win.pen.row, win.pen.column, strings);
     414                                     win.pen.row, win.pen.column, win, strings);
    415415                    while (!strings.empty())
    416416                    {
    417417                        delete strings.back();
    void MythCCExtractorPlayer::Ingest708Captions(void) 
    427427void MythCCExtractorPlayer::Ingest708Caption(
    428428    uint streamId, uint serviceIdx,
    429429    uint windowIdx, uint start_row, uint start_column,
     430    const CC708Window &win,
    430431    const vector<CC708String*> &content)
    431432{
    432     bool empty = true;
    433     QStringList winContent;
    434 
    435     vector<CC708String*>::const_iterator it = content.begin();
    436     for (; it != content.end(); ++it)
    437     {
    438         QString tmp = (*it)->str.trimmed();
    439         if (!tmp.isEmpty())
    440             winContent += tmp;
    441         empty &= tmp.isEmpty();
    442     }
     433    FormattedTextSubtitle fsub;
     434    fsub.InitFromCC708(win, windowIdx, content);
     435    QStringList winContent = fsub.ToSRT();
    443436
    444437    QMap<int, Window> &cc708win = m_cc708_windows[streamId][serviceIdx];
    445438    cc708win[windowIdx].row = start_row;
  • mythtv/libs/libmythtv/mythccextractorplayer.h

    diff --git a/mythtv/libs/libmythtv/mythccextractorplayer.h b/mythtv/libs/libmythtv/mythccextractorplayer.h
    index 88d7983..5660f39 100644
    a b class MTV_PUBLIC MythCCExtractorPlayer : public MythPlayer 
    139139    void Ingest708Captions(void);
    140140    void Ingest708Caption(uint streamId, uint serviceIdx, uint windowIdx,
    141141                          uint start_row, uint start_column,
     142                          const CC708Window &win,
    142143                          const vector<CC708String*> &content);
    143144    void Process708Captions(uint flags);
    144145
  • mythtv/libs/libmythtv/subtitlescreen.cpp

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp
    index f85c2b8..24a91c5 100644
    a b  
    1414#define PAD_WIDTH  0.20
    1515#define PAD_HEIGHT 0.04
    1616
    17 static MythFontProperties* gTextSubFont;
     17static const float LINE_SPACING = 1.1765f;
     18
    1819static QHash<int, MythFontProperties*> gCC708Fonts;
     20int SubtitleScreen::g_708fontSizes[4] = {36, 45, 60};
    1921
    2022SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name,
    2123                               int fontStretch) :
    SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name, 
    2628    m_textFontZoom(100),                    m_refreshArea(false),
    2729    m_fontStretch(fontStretch)
    2830{
    29     m_708fontSizes[0] = 36;
    30     m_708fontSizes[1] = 45;
    31     m_708fontSizes[2] = 60;
    3231    m_removeHTML.setMinimal(true);
    3332
    3433#ifdef USING_LIBASS
    void SubtitleScreen::DisplayAVSubtitles(void) 
    346345
    347346void SubtitleScreen::DisplayTextSubtitles(void)
    348347{
    349     if (!InitialiseFont(m_fontStretch) || !m_player || !m_subreader)
     348    if (!Initialise708Fonts(m_fontStretch) || !m_player || !m_subreader)
    350349        return;
    351350
    352351    bool changed = false;
    void SubtitleScreen::DisplayTextSubtitles(void) 
    421420
    422421void SubtitleScreen::DisplayRawTextSubtitles(void)
    423422{
    424     if (!InitialiseFont(m_fontStretch) || !m_player || !m_subreader)
     423    if (!Initialise708Fonts(m_fontStretch) || !m_player || !m_subreader)
    425424        return;
    426425
    427426    uint64_t duration;
    void SubtitleScreen::DisplayRawTextSubtitles(void) 
    445444void SubtitleScreen::DrawTextSubtitles(QStringList &wrappedsubs,
    446445                                       uint64_t start, uint64_t duration)
    447446{
    448     FormattedTextSubtitle fsub(m_safeArea);
     447    FormattedTextSubtitle fsub(m_safeArea, m_useBackground);
    449448    fsub.InitFromSRT(wrappedsubs, m_textFontZoom);
    450449    fsub.WrapLongLines();
    451     fsub.Draw(this);
    452     m_refreshArea = true;
     450    fsub.Layout();
     451    m_refreshArea = m_refreshArea || fsub.Draw(this, 0, start, duration);
    453452}
    454453
    455454void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
    static QString extract_cc608( 
    583582
    584583void SubtitleScreen::DisplayCC608Subtitles(void)
    585584{
    586     if (!InitialiseFont(m_fontStretch) || !m_608reader)
     585    if (!Initialise708Fonts(m_fontStretch) || !m_608reader)
    587586        return;
    588587
    589588    bool changed = false;
    void SubtitleScreen::DisplayCC608Subtitles(void) 
    619618        return;
    620619    }
    621620
    622     FormattedTextSubtitle fsub(m_safeArea);
     621    FormattedTextSubtitle fsub(m_safeArea, m_useBackground);
    623622    fsub.InitFromCC608(textlist->buffers);
    624     fsub.Draw(this);
    625     m_refreshArea = true;
     623    fsub.Layout();
     624    m_refreshArea = m_refreshArea || fsub.Draw(this);
    626625    textlist->lock.unlock();
    627626}
    628627
    void SubtitleScreen::DisplayCC708Subtitles(void) 
    643642            for (uint i = 0; i < 8; i++)
    644643                cc708service->windows[i].changed = true;
    645644            int size = (m_safeArea.height() * m_textFontZoom) / 2000;
    646             m_708fontSizes[1] = size;
    647             m_708fontSizes[0] = size * 32 / 42;
    648             m_708fontSizes[2] = size * 42 / 32;
     645            g_708fontSizes[1] = size;
     646            g_708fontSizes[0] = size * 32 / 42;
     647            g_708fontSizes[2] = size * 42 / 32;
    649648        }
    650649    }
    651650    else
    void SubtitleScreen::DisplayCC708Subtitles(void) 
    669668        QMutexLocker locker(&win.lock);
    670669        vector<CC708String*> list = win.GetStrings();
    671670        if (!list.empty())
    672             Display708Strings(win, i, video_aspect, list);
     671        {
     672            FormattedTextSubtitle fsub(m_safeArea, m_useBackground);
     673            fsub.InitFromCC708(win, i, list, video_aspect, m_textFontZoom);
     674            fsub.Layout();
     675            // Draw the window background after calculating bounding
     676            // rectangle in Layout()
     677            if (win.GetFillAlpha()) // TODO border?
     678            {
     679                QBrush fill(win.GetFillColor(), Qt::SolidPattern);
     680                MythUIShape *shape =
     681                    new MythUIShape(this, QString("cc708bg%1").arg(i));
     682                shape->SetFillBrush(fill);
     683                shape->SetArea(MythRect(fsub.m_bounds));
     684                m_708imageCache[i].append(shape);
     685                m_refreshArea = true;
     686            }
     687            m_refreshArea =
     688                m_refreshArea || fsub.Draw(this, &m_708imageCache[i]);
     689        }
    673690        for (uint j = 0; j < list.size(); j++)
    674691            delete list[j];
    675692        win.changed = false;
    void SubtitleScreen::Clear708Cache(int num) 
    686703    }
    687704}
    688705
    689 void SubtitleScreen::Display708Strings(const CC708Window &win, int num,
    690                                        float aspect, vector<CC708String*> &list)
    691 {
    692     LOG(VB_VBI, LOG_INFO,LOC +
    693         QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, "
    694                 "relative %5")
    695             .arg(num).arg(win.anchor_point).arg(win.anchor_horizontal)
    696             .arg(win.anchor_vertical).arg(win.relative_pos));
    697 
    698     bool display = false;
    699     MythFontProperties *mythfont;
    700     uint max_row_width = 0;
    701     uint total_height = 0;
    702     uint i = 0;
    703     for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
    704     {
    705         uint row_width = 0, max_row_height = 0;
    706         for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++)
    707         {
    708             if (list[i]->y < row)
    709                 continue;
    710 
    711             mythfont = Get708Font(list[i]->attr);
    712             if (!mythfont)
    713                 continue;
    714 
    715             QString text = list[i]->str.trimmed();
    716             if (!text.isEmpty())
    717                 display = true;
    718 
    719             QFontMetrics font(*(mythfont->GetFace()));
    720             uint height = (uint)font.height() * (1 + PAD_HEIGHT);
    721 
    722             row_width += font.width(list[i]->str) +
    723                          (font.maxWidth() * PAD_WIDTH * 2);
    724             max_row_height = max(max_row_height, height);
    725         }
    726 
    727         max_row_width = max(max_row_width, row_width);
    728         total_height += max_row_height;
    729     }
    730 
    731     if (!display)
    732         return;
    733 
    734     float xrange  = win.relative_pos ? 100.0f :
    735                     (aspect > 1.4f) ? 210.0f : 160.0f;
    736     float yrange  = win.relative_pos ? 100.0f : 75.0f;
    737     float xmult   = (float)m_safeArea.width() / xrange;
    738     float ymult   = (float)m_safeArea.height() / yrange;
    739     uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal);
    740     uint anchor_y = (uint)(ymult * (float)win.anchor_vertical);
    741 
    742     if (win.anchor_point % 3 == 1)
    743         anchor_x -= (((int)max_row_width) / 2);
    744     if (win.anchor_point % 3 == 2)
    745         anchor_x -= (int)max_row_width;
    746     if (win.anchor_point / 3 == 1)
    747         anchor_y -= (((int)total_height) / 2);
    748     if (win.anchor_point / 3 == 2)
    749         anchor_y -= (int)total_height;
    750 
    751     if (win.GetFillAlpha()) // TODO border?
    752     {
    753         QRect bg(anchor_x, anchor_y, max_row_width, total_height);
    754         QBrush fill(win.GetFillColor(), Qt::SolidPattern);
    755         MythUIShape *shape = new MythUIShape(this,
    756                 QString("cc708bg%1").arg(num));
    757         shape->SetFillBrush(fill);
    758         shape->SetArea(MythRect(bg));
    759         m_708imageCache[num].append(shape);
    760         m_refreshArea = true;
    761     }
    762 
    763     i = 0;
    764     int y = anchor_y;
    765     for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
    766     {
    767         uint maxheight = 0;
    768         int  x = anchor_x;
    769         bool first = true;
    770         for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++)
    771         {
    772             bool last = ((i + 1) == list.size());
    773             if (!last)
    774                 last = (list[i + 1]->y > row);
    775 
    776             QString rawstring = list[i]->str;
    777             mythfont = Get708Font(list[i]->attr);
    778 
    779             if ((list[i]->y < row) || !mythfont || rawstring.isEmpty())
    780                 continue;
    781 
    782             QString trimmed = rawstring.trimmed();
    783             if (!trimmed.size() && last)
    784                 continue;
    785 
    786             QFontMetrics font(*(mythfont->GetFace()));
    787             uint height = (uint)font.height() * (1 + PAD_HEIGHT);
    788             maxheight   = max(maxheight, height);
    789             uint spacewidth = font.width(QString(" "));
    790             uint textwidth  = font.width(trimmed);
    791 
    792             int leading  = 0;
    793             int trailing = 0;
    794             if (trimmed.size() != rawstring.size())
    795             {
    796                 if (trimmed.size())
    797                 {
    798                     leading  = rawstring.indexOf(trimmed.at(0));
    799                     trailing = rawstring.size() - trimmed.size() - leading;
    800                 }
    801                 else
    802                 {
    803                     leading = rawstring.size();
    804                 }
    805                 leading  *= spacewidth;
    806                 trailing *= spacewidth;
    807             }
    808 
    809             if (!leading)
    810                 textwidth += spacewidth * PAD_WIDTH;
    811             if (!trailing)
    812                 textwidth += spacewidth * PAD_WIDTH;
    813 
    814             bool background = list[i]->attr.GetBGAlpha();
    815             QBrush bgfill = QBrush((list[i]->attr.GetBGColor(), Qt::SolidPattern));
    816 
    817             if (leading && background && !first)
    818             {
    819                 // draw background for leading space
    820                 QRect space(x, y, leading, height);
    821                 MythUIShape *shape = new MythUIShape(this,
    822                         QString("cc708shape%1x%2lead").arg(row).arg(i));
    823                 shape->SetFillBrush(bgfill);
    824                 shape->SetArea(MythRect(space));
    825                 m_708imageCache[num].append(shape);
    826                 m_refreshArea = true;
    827             }
    828 
    829             x += leading;
    830             QRect rect(x, y, textwidth, height);
    831 
    832             if (trimmed.size() && textwidth && background)
    833             {
    834                 MythUIShape *shape = new MythUIShape(this,
    835                         QString("cc708shape%1x%2main").arg(row).arg(i));
    836                 shape->SetFillBrush(bgfill);
    837                 shape->SetArea(MythRect(rect));
    838                 m_708imageCache[num].append(shape);
    839                 m_refreshArea = true;
    840             }
    841 
    842             if (trimmed.size() && textwidth)
    843             {
    844                 MythUISimpleText *text = new MythUISimpleText
    845                                          (list[i]->str, *mythfont,
    846                                           rect, Qt::AlignCenter,
    847                                           (MythUIType*)this,
    848                                   QString("cc708text%1x%2").arg(row).arg(i));
    849                 m_708imageCache[num].append(text);
    850                 m_refreshArea = true;
    851             }
    852 
    853             x += textwidth;
    854 
    855             if (trailing && background && !last)
    856             {
    857                 // draw background for trailing space
    858                 QRect space(x, y, trailing, height);
    859                 MythUIShape *shape = new MythUIShape(this,
    860                         QString("cc708shape%1x%2trail").arg(row).arg(i));
    861                 shape->SetFillBrush(bgfill);
    862                 shape->SetArea(MythRect(space));
    863                 m_708imageCache[num].append(shape);
    864                 m_refreshArea = true;
    865             }
    866 
    867             x += trailing;
    868             first = false;
    869             LOG(VB_VBI, LOG_INFO, QString("Win %1 row %2 String '%3'")
    870                 .arg(num).arg(row).arg(list[i]->str));
    871         }
    872         y += maxheight;
    873     }
    874 }
    875 
    876706void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos)
    877707{
    878708    VideoOutput *vo = m_player->GetVideoOutput();
    void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos) 
    904734    }
    905735}
    906736
    907 bool SubtitleScreen::InitialiseFont(int fontStretch)
    908 {
    909     static bool initialised = false;
    910     QString font = gCoreContext->GetSetting("OSDSubFont", "FreeSans");
    911     if (initialised)
    912     {
    913         if (gTextSubFont->face().family() == font &&
    914             gTextSubFont->face().stretch() == fontStretch)
    915         {
    916             return true;
    917         }
    918         delete gTextSubFont;
    919     }
    920 
    921     MythFontProperties *mythfont = new MythFontProperties();
    922     if (mythfont)
    923     {
    924         QFont newfont(font);
    925         newfont.setStretch(fontStretch);
    926         font.detach();
    927         mythfont->SetFace(newfont);
    928         mythfont->SetOutline(true, Qt::black, 2, 255);
    929         gTextSubFont = mythfont;
    930     }
    931     else
    932         return false;
    933 
    934     initialised = true;
    935     LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Loaded main subtitle font '%1'")
    936         .arg(font));
    937     return true;
    938 }
    939 
    940737bool SubtitleScreen::Initialise708Fonts(int fontStretch)
    941738{
    942739    static bool initialised = false;
    bool SubtitleScreen::Initialise708Fonts(int fontStretch) 
    950747    LOG(VB_GENERAL, LOG_INFO, "Initialise708Fonts()");
    951748
    952749    QStringList fonts;
    953     fonts.append("Droid Sans Mono"); // default
     750    QString defaultFont = gCoreContext->GetSetting("OSDSubFont", "FreeSans");
     751    fonts.append(defaultFont);       // default
    954752    fonts.append("FreeMono");        // mono serif
    955753    fonts.append("DejaVu Serif");    // prop serif
    956754    fonts.append("Droid Sans Mono"); // mono sans
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    986784        return NULL;
    987785
    988786    mythfont->GetFace()->setItalic(attr.italics);
    989     mythfont->GetFace()->setPixelSize(m_708fontSizes[attr.pen_size & 0x3]);
     787    mythfont->GetFace()->setPixelSize(g_708fontSizes[attr.pen_size & 0x3]);
    990788    mythfont->GetFace()->setUnderline(attr.underline);
     789    mythfont->GetFace()->setBold(attr.boldface);
    991790    mythfont->SetColor(attr.GetFGColor());
    992791
    993     int off = m_708fontSizes[attr.pen_size & 0x3] / 20;
     792    int off = g_708fontSizes[attr.pen_size & 0x3] / 20;
    994793    QPoint shadowsz(off, off);
    995794    QColor colour = attr.GetEdgeColor();
    996795    int alpha     = attr.GetFGAlpha();
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    1019818    return mythfont;
    1020819}
    1021820
    1022 void FormattedTextChunk::GetSize(int pixelSize, int &width, int &height) const
     821static QString srtColorString(QColor color)
    1023822{
    1024     QFont *font = gTextSubFont->GetFace();
    1025     font->setItalic(isItalic);
    1026     font->setBold(isBold);
    1027     font->setUnderline(isUnderline);
    1028     font->setPixelSize(pixelSize);
     823    return QString("#%1%2%3")
     824        .arg(color.red(),   2, 16, QLatin1Char('0'))
     825        .arg(color.green(), 2, 16, QLatin1Char('0'))
     826        .arg(color.blue(),  2, 16, QLatin1Char('0'));
     827}
     828
     829void FormattedTextChunk::GetSize(int &width, int &height) const
     830{
     831    QFont *font = SubtitleScreen::Get708Font(format)->GetFace();
    1029832    QFontMetrics fm(*font);
    1030833    width = fm.width(text) + fm.maxWidth() * PAD_WIDTH;
    1031834    height = fm.height() * (1 + PAD_HEIGHT);
    void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers) 
    1043846        return;
    1044847    vector<CC608Text*>::iterator i = buffers.begin();
    1045848    bool teletextmode = (*i)->teletextmode;
    1046     m_useBackground = m_useBackground && !teletextmode;
     849    bool useBackground = m_useBackground && !teletextmode;
    1047850    int xscale = teletextmode ? 40 : 36;
    1048851    int yscale = teletextmode ? 25 : 17;
    1049     m_pixelSize = m_safeArea.height() / (yscale * 1.1765f);
     852    int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING);
     853    SubtitleScreen::g_708fontSizes[k708AttrSizeStandard] = pixelSize;
    1050854
    1051855    for (; i != buffers.end(); ++i)
    1052856    {
    void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers) 
    1060864        int x = (int)(((float)orig_x / (float)xscale) * (float)m_safeArea.width());
    1061865        int orig_y = teletextmode ? cc->x : cc->y;
    1062866        int y = (int)(((float)orig_y / (float)yscale) * (float)m_safeArea.height());
    1063         FormattedTextLine line(x, y);
     867        FormattedTextLine line(x, y, orig_x, orig_y);
    1064868        for (int chunk = 0; text != QString::null; chunk++)
    1065869        {
    1066870            QString captionText =
    1067871                extract_cc608(text, cc->teletextmode,
    1068872                              color, isItalic, isUnderline);
    1069             FormattedTextChunk chunk(captionText,
    1070                                      isItalic, isBold, isUnderline,
    1071                                      clr[min(max(0, color), 7)]);
     873            CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
     874                                         clr[min(max(0, color), 7)],
     875                                         useBackground);
     876            FormattedTextChunk chunk(captionText, attr);
    1072877            line.chunks += chunk;
    1073878            LOG(VB_VBI, LOG_INFO,
    1074879                QString("Adding cc608 chunk: x=%1 y=%2 "
    void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers) 
    1080885    }
    1081886}
    1082887
     888void FormattedTextSubtitle::InitFromCC708(const CC708Window &win, int num,
     889                                          const vector<CC708String*> &list,
     890                                          float aspect,
     891                                          int textFontZoom)
     892{
     893    int pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     894    SubtitleScreen::g_708fontSizes[k708AttrSizeSmall]    = pixelSize * 32 / 42;
     895    SubtitleScreen::g_708fontSizes[k708AttrSizeStandard] = pixelSize;
     896    SubtitleScreen::g_708fontSizes[k708AttrSizeLarge]    = pixelSize * 42 / 32;
     897
     898    float xrange  = win.relative_pos ? 100.0f :
     899                    (aspect > 1.4f) ? 210.0f : 160.0f;
     900    float yrange  = win.relative_pos ? 100.0f : 75.0f;
     901    float xmult   = (float)m_safeArea.width() / xrange;
     902    float ymult   = (float)m_safeArea.height() / yrange;
     903    uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal);
     904    uint anchor_y = (uint)(ymult * (float)win.anchor_vertical);
     905    m_xAnchorPoint = win.anchor_point % 3;
     906    m_yAnchorPoint = win.anchor_point / 3;
     907    m_xAnchor = anchor_x;
     908    m_yAnchor = anchor_y;
     909
     910    for (uint i = 0; i < list.size(); i++)
     911    {
     912        if (list[i]->y >= (uint)m_lines.size())
     913            m_lines.resize(list[i]->y + 1);
     914        if (m_useBackground)
     915        {
     916            list[i]->attr.bg_color = k708AttrColorBlack;
     917            list[i]->attr.bg_opacity = k708AttrOpacitySolid;
     918        }
     919        FormattedTextChunk chunk(list[i]->str, list[i]->attr);
     920        m_lines[list[i]->y].chunks += chunk;
     921        LOG(VB_VBI, LOG_INFO, QString("Adding 708 chunk '%1'").arg(chunk.text));
     922    }
     923}
     924
    1083925void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom)
    1084926{
    1085927    // Does a simplistic parsing of HTML tags from the strings.
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    1096938    // <font color="#xxyyzz"> - change font color
    1097939    // </font> - reset font color to white
    1098940
    1099     m_pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     941    int pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     942    SubtitleScreen::g_708fontSizes[k708AttrSizeStandard] = pixelSize;
     943    m_xAnchorPoint = 1; // center
     944    m_yAnchorPoint = 2; // bottom
     945    m_xAnchor = m_safeArea.width() / 2;
     946    m_yAnchor = m_safeArea.height();
    1100947
    1101948    bool isItalic = false;
    1102949    bool isBold = false;
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    1114961            int pos = text.indexOf(htmlTag);
    1115962            if (pos != 0) // don't add a zero-length string
    1116963            {
    1117                 FormattedTextChunk chunk(text.left(pos),
    1118                                          isItalic, isBold, isUnderline, color);
     964                CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
     965                                             color, m_useBackground);
     966                FormattedTextChunk chunk(text.left(pos), attr);
    1119967                line.chunks += chunk;
    1120968                text = (pos < 0 ? "" : text.mid(pos));
    1121969                LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk '%1'").arg(chunk.text));
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    11591007
    11601008                LOG(VB_VBI, LOG_INFO,
    11611009                    QString("SRT formatting change '%1', "
    1162                             "new ital=%2 bold=%3 uline=%4 color=#%5%6%7)")
     1010                            "new ital=%2 bold=%3 uline=%4 color=%5)")
    11631011                    .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')));
     1012                    .arg(srtColorString(color)));
    11671013            }
    11681014        }
    11691015        m_lines += line;
    bool FormattedTextChunk::Split(FormattedTextChunk &newChunk) 
    11811027            QString("Failed to split chunk '%1'").arg(text));
    11821028        return false;
    11831029    }
    1184     newChunk.isItalic = isItalic;
    1185     newChunk.isBold = isBold;
    1186     newChunk.isUnderline = isUnderline;
    1187     newChunk.color = color;
     1030    newChunk.format = format;
    11881031    newChunk.text = text.mid(lastSpace + 1).trimmed() + ' ';
    11891032    text = text.left(lastSpace).trimmed();
    11901033    LOG(VB_VBI, LOG_INFO,
    void FormattedTextSubtitle::WrapLongLines(void) 
    11971040    int maxWidth = m_safeArea.width();
    11981041    for (int i = 0; i < m_lines.size(); i++)
    11991042    {
    1200         int width = m_lines[i].Width(m_pixelSize);
     1043        int width = m_lines[i].Width();
    12011044        // Move entire chunks to the next line as necessary.  Leave at
    12021045        // least one chunk on the current line.
    12031046        while (width > maxWidth && m_lines[i].chunks.size() > 1)
    12041047        {
    1205             width -= m_lines[i].chunks.back().Width(m_pixelSize);
     1048            width -= m_lines[i].chunks.back().Width();
    12061049            // Make sure there's a next line to wrap into.
    12071050            if (m_lines.size() == i + 1)
    12081051                m_lines += FormattedTextLine(m_lines[i].x_indent,
    void FormattedTextSubtitle::WrapLongLines(void) 
    12261069                    m_lines += FormattedTextLine(m_lines[i].x_indent,
    12271070                                                 m_lines[i].y_indent);
    12281071                m_lines[i+1].chunks.prepend(newChunk);
    1229                 width = m_lines[i].Width(m_pixelSize);
     1072                width = m_lines[i].Width();
    12301073            }
    12311074        }
    12321075    }
    12331076}
    12341077
    1235 void FormattedTextSubtitle::Draw(SubtitleScreen *parent,
     1078// Resolves any TBD x_indent and y_indent values in FormattedTextLine
     1079// objects.  Calculates m_bounds.  Prunes most leading and all
     1080// trailing whitespace from each line so that displaying with a black
     1081// background doesn't look clumsy.
     1082void FormattedTextSubtitle::Layout(void)
     1083{
     1084    // Calculate dimensions of bounding rectangle
     1085    int anchor_width = 0;
     1086    int anchor_height = 0;
     1087    for (int i = 0; i < m_lines.size(); i++)
     1088    {
     1089        int width = m_lines[i].Width();
     1090        int height = m_lines[i].Height();
     1091        anchor_width = max(anchor_width, width);
     1092        anchor_height += height * LINE_SPACING;
     1093    }
     1094
     1095    // Adjust the anchor point according to actual width and height
     1096    int anchor_x = m_xAnchor;
     1097    int anchor_y = m_yAnchor;
     1098    if (m_xAnchorPoint == 1)
     1099        anchor_x -= anchor_width / 2;
     1100    else if (m_xAnchorPoint == 2)
     1101        anchor_x -= anchor_width;
     1102    if (m_yAnchorPoint == 1)
     1103        anchor_y -= anchor_height / 2;
     1104    else if (m_yAnchorPoint == 2)
     1105        anchor_y -= anchor_height;
     1106
     1107    m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height);
     1108
     1109    // Fill in missing coordinates
     1110    int y = anchor_y;
     1111    for (int i = 0; i < m_lines.size(); i++)
     1112    {
     1113        if (m_lines[i].x_indent < 0)
     1114            m_lines[i].x_indent = anchor_x;
     1115        if (m_lines[i].y_indent < 0)
     1116            m_lines[i].y_indent = y;
     1117        y += m_lines[i].Height() * LINE_SPACING;
     1118        // Prune leading all-whitespace chunks.
     1119        while (!m_lines[i].chunks.isEmpty() &&
     1120               m_lines[i].chunks.first().text.trimmed().isEmpty())
     1121        {
     1122            m_lines[i].x_indent += m_lines[i].chunks.first().Width();
     1123            m_lines[i].chunks.removeFirst();
     1124        }
     1125        // Prune trailing all-whitespace chunks.
     1126        while (!m_lines[i].chunks.isEmpty() &&
     1127               m_lines[i].chunks.last().text.trimmed().isEmpty())
     1128        {
     1129            m_lines[i].chunks.removeLast();
     1130        }
     1131        // Trim trailing whitespace from last chunk.  (Trimming
     1132        // leading whitespace from the first chunk is handled in
     1133        // the Draw() routine.)
     1134        if (!m_lines[i].chunks.isEmpty())
     1135        {
     1136            QString *str = &m_lines[i].chunks.last().text;
     1137            int idx = str->length() - 1;
     1138            while (idx >= 0 && str->at(idx) == ' ')
     1139                --idx;
     1140            str->truncate(idx + 1);
     1141        }
     1142    }
     1143}
     1144
     1145// Returns true if anything new was drawn, false if not.  The caller
     1146// should call SubtitleScreen::OptimiseDisplayedArea() if true is
     1147// returned.
     1148bool FormattedTextSubtitle::Draw(SubtitleScreen *parent,
     1149                                 QList<MythUIType*> *imageCache,
    12361150                                 uint64_t start, uint64_t duration) const
    12371151{
    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);
     1152    bool result = false;
    12431153
    12441154    for (int i = 0; i < m_lines.size(); i++)
    12451155    {
    12461156        int x = m_lines[i].x_indent;
    1247         if (x < 0) // centering
    1248             x = (m_safeArea.width() - m_lines[i].Width(m_pixelSize)) / 2;
    12491157        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;
    12531158
    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         }
     1159        int height = m_lines[i].Height();
    12831160        QList<FormattedTextChunk>::const_iterator chunk;
     1161        bool first = true;
    12841162        for (chunk = m_lines[i].chunks.constBegin();
    12851163             chunk != m_lines[i].chunks.constEnd();
    12861164             ++chunk)
    12871165        {
     1166            MythFontProperties *mythfont =
     1167                SubtitleScreen::Get708Font((*chunk).format);
     1168            if (!mythfont)
     1169                continue;
     1170            QFontMetrics font(*(mythfont->GetFace()));
     1171            int pad_width = font.maxWidth() * PAD_WIDTH;
     1172            bool background = (*chunk).format.GetBGAlpha();
     1173            QBrush bgfill = QBrush((*chunk).format.GetBGColor(), Qt::SolidPattern);
    12881174            // If the chunk starts with whitespace, the leading
    12891175            // whitespace ultimately gets lost due to the
    12901176            // text.trimmed() operation in the MythUISimpleText
    void FormattedTextSubtitle::Draw(SubtitleScreen *parent, 
    12951181                   (*chunk).text.at(count) == ' ')
    12961182                ++count;
    12971183            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);
     1184            if (background)
     1185            {
     1186                QRect bgrect(x, y, (*chunk).Width(), height);
     1187                if (first)
     1188                    bgrect.setLeft(bgrect.left() + x_adjust - pad_width);
     1189                MythUIShape *bgshape = new MythUIShape(parent,
     1190                        QString("subbg%1x%2@%3,%4")
     1191                                     .arg((*chunk).Width())
     1192                                     .arg(height)
     1193                                     .arg(x).arg(y));
     1194                bgshape->SetFillBrush(bgfill);
     1195                bgshape->SetArea(MythRect(bgrect));
     1196                if (imageCache)
     1197                    imageCache->append(bgshape);
     1198                if (duration > 0)
     1199                    parent->RegisterExpiration(bgshape, start + duration);
     1200                result = true;
     1201            }
    13021202            QRect rect(x + x_adjust, y,
    1303                        (*chunk).Width(m_pixelSize) - x_adjust,
    1304                        (*chunk).Height(m_pixelSize));
     1203                       (*chunk).Width() - x_adjust,
     1204                       height);
    13051205
    13061206            MythUISimpleText *text =
    1307                 new MythUISimpleText((*chunk).text, *gTextSubFont, rect,
     1207                new MythUISimpleText((*chunk).text, *mythfont, rect,
    13081208                                     Qt::AlignLeft, (MythUIType*)parent,
    13091209                                     QString("subtxt%1x%2@%3,%4")
    1310                                      .arg((*chunk).Width(m_pixelSize))
    1311                                      .arg((*chunk).Height(m_pixelSize))
     1210                                     .arg((*chunk).Width())
     1211                                     .arg(height)
    13121212                                     .arg(x).arg(y));
     1213            if (imageCache)
     1214                imageCache->append(text);
    13131215            if (duration > 0)
    13141216                parent->RegisterExpiration(text, start + duration);
     1217            result = true;
    13151218
    13161219            LOG(VB_VBI, LOG_INFO,
    13171220                QString("Drawing chunk at (%1,%2) with "
    1318                         "ital=%3 bold=%4 uline=%5 color=#%6%7%8 "
    1319                         "text='%9'")
     1221                        "ital=%3 bold=%4 uline=%5 color=#%6 "
     1222                        "text='%7'")
    13201223                .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);
     1224                .arg((*chunk).format.italics)
     1225                .arg((*chunk).format.boldface)
     1226                .arg((*chunk).format.underline)
     1227                .arg(srtColorString((*chunk).format.GetFGColor()))
     1228                .arg((*chunk).text.mid(count)));
     1229
     1230            x += (*chunk).Width();
     1231            first = false;
    13301232        }
    13311233    }
     1234    return result;
     1235}
     1236
     1237QStringList FormattedTextSubtitle::ToSRT(void) const
     1238{
     1239    QStringList result;
     1240    for (int i = 0; i < m_lines.size(); i++)
     1241    {
     1242        QString line;
     1243        if (m_lines[i].orig_x > 0)
     1244            line.fill(' ', m_lines[i].orig_x);
     1245        QList<FormattedTextChunk>::const_iterator chunk;
     1246        for (chunk = m_lines[i].chunks.constBegin();
     1247             chunk != m_lines[i].chunks.constEnd();
     1248             ++chunk)
     1249        {
     1250            const QString &text = (*chunk).text;
     1251            LOG(VB_GENERAL, LOG_INFO, QString("JMS chunk '%1'").arg(text));
     1252            const CC708CharacterAttribute &attr = (*chunk).format;
     1253            bool isBlank = !attr.underline && text.trimmed().isEmpty();
     1254            if (!isBlank)
     1255            {
     1256                if (attr.boldface)
     1257                    line += "<b>";
     1258                if (attr.italics)
     1259                    line += "<i>";
     1260                if (attr.underline)
     1261                    line += "<u>";
     1262                if (attr.GetFGColor() != Qt::white)
     1263                    line += QString("<font color=\"%1\">")
     1264                        .arg(srtColorString(attr.GetFGColor()));
     1265            }
     1266            line += text;
     1267            if (!isBlank)
     1268            {
     1269                if (attr.GetFGColor() != Qt::white)
     1270                    line += QString("</font>");
     1271                if (attr.underline)
     1272                    line += "</u>";
     1273                if (attr.italics)
     1274                    line += "</i>";
     1275                if (attr.boldface)
     1276                    line += "</b>";
     1277            }
     1278        }
     1279        if (!line.trimmed().isEmpty())
     1280        {
     1281            LOG(VB_GENERAL, LOG_INFO, QString("JMS line '%1'").arg(line));
     1282            result += line;
     1283        }
     1284    }
     1285    return result;
    13321286}
    13331287
    13341288#ifdef USING_LIBASS
  • mythtv/libs/libmythtv/subtitlescreen.h

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
    index da3ae19..02971c2 100644
    a b extern "C" { 
    1515
    1616class SubtitleScreen : public MythScreenType
    1717{
    18     static bool InitialiseFont(int fontStretch = QFont::Unstretched);
    1918    static bool Initialise708Fonts(int fontStretch = QFont::Unstretched);
    2019
    2120  public:
    class SubtitleScreen : public MythScreenType 
    4241    virtual bool Create(void);
    4342    virtual void Pulse(void);
    4443
     44    static int g_708fontSizes[4];
     45    static MythFontProperties* Get708Font(CC708CharacterAttribute attr);
     46
    4547  private:
    4648    void OptimiseDisplayedArea(void);
    4749    void DisplayAVSubtitles(void);
    class SubtitleScreen : public MythScreenType 
    5355    void DisplayCC708Subtitles(void);
    5456    void AddScaledImage(QImage &img, QRect &pos);
    5557    void Clear708Cache(int num);
    56     void Display708Strings(const CC708Window &win, int num,
    57                            float aspect, vector<CC708String*> &list);
    58     MythFontProperties* Get708Font(CC708CharacterAttribute attr);
    5958
    6059    MythPlayer        *m_player;
    6160    SubtitleReader    *m_subreader;
    class SubtitleScreen : public MythScreenType 
    6665    QRegExp            m_removeHTML;
    6766    int                m_subtitleType;
    6867    QHash<MythUIType*, long long> m_expireTimes;
    69     int                m_708fontSizes[3];
    70     int                m_textFontZoom;
     68    int                m_textFontZoom; // valid for 708 & text subs
    7169    bool               m_refreshArea;
    7270    QHash<int,QList<MythUIType*> > m_708imageCache;
    7371    int                m_fontStretch;
    class SubtitleScreen : public MythScreenType 
    9290
    9391struct FormattedTextChunk
    9492{
    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) {}
     93    FormattedTextChunk(const QString &t, CC708CharacterAttribute formatting)
     94        : text(t), format(formatting) {}
    9995    FormattedTextChunk(void) {}
    100     int Width(int pixelSize) const {
     96    int Width(void) const {
    10197        int width, height;
    102         GetSize(pixelSize, width, height);
     98        GetSize(width, height);
    10399        return width;
    104100    }
    105     int Height(int pixelSize) const {
     101    int Height(void) const {
    106102        int width, height;
    107         GetSize(pixelSize, width, height);
     103        GetSize(width, height);
    108104        return height;
    109105    }
    110106    bool Split(FormattedTextChunk &newChunk);
    111107    QString text;
    112     bool isItalic;
    113     bool isBold;
    114     bool isUnderline;
    115     QColor color;
     108    CC708CharacterAttribute format;
    116109private:
    117     void GetSize(int pixelSize, int &width, int &height) const;
     110    void GetSize(int &width, int &height) const;
    118111};
    119112
    120113struct FormattedTextLine
    121114{
    122     FormattedTextLine(int x = -1, int y = -1) : x_indent(x), y_indent(y) {}
    123     int Height(int pixelSize) const {
     115    FormattedTextLine(int x = -1, int y = -1, int o_x = -1, int o_y = -1)
     116        : x_indent(x), y_indent(y), orig_x(o_x), orig_y(o_y) {}
     117    int Height(void) const {
    124118        int result = 0;
    125119        QList<FormattedTextChunk>::const_iterator it;
    126120        for (it = chunks.constBegin(); it != chunks.constEnd(); ++it) {
    127             int height = (*it).Height(pixelSize);
     121            int height = (*it).Height();
    128122            result = max(result, height);
    129123        }
    130124        return result;
    131125    }
    132     int Width(int pixelSize) const {
     126    int Width(void) const {
    133127        int result = 0;
    134128        QList<FormattedTextChunk>::const_iterator it;
    135129        for (it = chunks.constBegin(); it != chunks.constEnd(); ++it) {
    136             int width = (*it).Width(pixelSize);
     130            int width = (*it).Width();
    137131            result += width;
    138132        }
    139133        return result;
    struct FormattedTextLine 
    141135    QList<FormattedTextChunk> chunks;
    142136    int x_indent; // -1 means TBD i.e. centered
    143137    int y_indent; // -1 means TBD i.e. relative to bottom
     138    int orig_x, orig_y; // original, unscaled coordinates
    144139};
    145140
    146141class FormattedTextSubtitle
    147142{
    148143public:
    149     FormattedTextSubtitle(const QRect &safearea)
    150         : m_safeArea(safearea), m_useBackground(true) {}
     144    FormattedTextSubtitle(const QRect &safearea, bool useBackground)
     145        : m_safeArea(safearea), m_useBackground(useBackground) {}
     146    FormattedTextSubtitle(void)
     147        : m_safeArea(QRect(0, 0, 640, 360)), m_useBackground(false) {}
    151148    void InitFromCC608(vector<CC608Text*> &buffers);
     149    void InitFromCC708(const CC708Window &win, int num,
     150                       const vector<CC708String*> &list,
     151                       float aspect = 1.77777f,
     152                       int textFontZoom = 100);
    152153    void InitFromSRT(QStringList &subs, int textFontZoom);
    153154    void WrapLongLines(void);
    154     void Draw(SubtitleScreen *parent,
     155    void Layout(void);
     156    bool Draw(SubtitleScreen *parent,
     157              QList<MythUIType*> *imageCache = 0,
    155158              uint64_t start = 0, uint64_t duration = 0) const;
     159    QStringList ToSRT(void) const;
     160    QRect m_bounds;
    156161private:
    157162    QVector<FormattedTextLine> m_lines;
    158163    const QRect m_safeArea;
    159     bool m_useBackground;
    160     int m_pixelSize;
     164    const bool m_useBackground;
     165    int m_xAnchorPoint; // 0=left, 1=center, 2=right
     166    int m_yAnchorPoint; // 0=top,  1=center, 2=bottom
     167    int m_xAnchor; // pixels from left
     168    int m_yAnchor; // pixels from top
    161169};
    162170
    163171#endif // SUBTITLESCREEN_H