Ticket #10194: srt_cc708_v6.patch

File srt_cc708_v6.patch, 51.8 KB (added by Jim Stichnoth <stichnot@…>, 8 years ago)

Change new static fields/methods back to instance. gCC708Fonts is left unchanged for now.

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 0ff837d..5e948be 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::forceBlackBackground = 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 e6a57cc..420137d 100644
    a b const uint k708AttrOpacityFlash = 1; 
    106106const uint k708AttrOpacityTranslucent = 2;
    107107const uint k708AttrOpacityTransparent = 3;
    108108
    109 bool CC708Window::forceBlackBackground = 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 (forceBlackBackground)
    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 (forceBlackBackground)
    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 (forceBlackBackground)
    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 (forceBlackBackground)
    374     {
    375         GetCCChar().attr.bg_color   = k708AttrColorBlack;
    376         GetCCChar().attr.bg_opacity = k708AttrOpacityTranslucent;
    377     }
    378352    GetCCChar().character = ch;
    379353    int c = pen.column;
    380354    int r = pen.row;
    void CC708Pen::SetPenStyle(uint style) 
    531505    attr.font_tag   = style2font[style];
    532506    attr.italics    = 0;
    533507    attr.underline  = 0;
     508    attr.boldface   = 0;
    534509    attr.edge_type  = 0;
    535510    attr.fg_color   = k708AttrColorWhite;
    536511    attr.fg_opacity = k708AttrOpacitySolid;
    void CC708Pen::SetPenStyle(uint style) 
    538513    attr.bg_opacity = (style<6) ?
    539514        k708AttrOpacitySolid : k708AttrOpacityTransparent;
    540515    attr.edge_color = k708AttrColorBlack;
     516    attr.override_fg_color = false;
    541517}
    542518
    543519CC708Character::CC708Character(const CC708Window &win)
    544520{
    545521    attr = win.pen.attr;
    546     if (CC708Window::forceBlackBackground)
    547     {
    548         attr.fg_opacity = k708AttrOpacityTransparent;
    549         attr.bg_opacity = k708AttrOpacityTransparent;
    550     }
    551522    character = ' ';
    552523}
    553524
  • mythtv/libs/libmythtv/cc708window.h

    diff --git a/mythtv/libs/libmythtv/cc708window.h b/mythtv/libs/libmythtv/cc708window.h
    index ccce79e..c5657db 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    }
     112    CC708CharacterAttribute(void) : override_fg_color(false) {}
     113
    35114    // remove this
    36115    uint FontIndex(void) const
    37116    {
    class CC708CharacterAttribute 
    41120    static QColor ConvertToQColor(uint eia708color);
    42121    QColor GetFGColor(void) const
    43122    {
    44         QColor fg = ConvertToQColor(fg_color);
     123        QColor fg = (override_fg_color ?
     124                     actual_fg_color : ConvertToQColor(fg_color));
    45125        fg.setAlpha(GetFGAlpha());
    46126        return fg;
    47127    }
    class CC708Pen 
    88168        attr.edge_type = edge_type;
    89169        attr.underline = underline;
    90170        attr.italics   = italics;
     171        attr.boldface  = 0;
    91172    }
    92173  public:
    93174    CC708CharacterAttribute attr;
    class MTV_PUBLIC CC708Window 
    200281    bool            exists;
    201282    bool            changed;
    202283
    203     static bool     forceBlackBackground;
    204 
    205284    mutable QMutex  lock;
    206285};
    207286
    class CC708Service 
    215294    CC708Window windows[8];
    216295};
    217296
    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 
    271297#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 c9b951e..0ead516 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;
    1920
    2021SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name,
    SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name, 
    2627    m_textFontZoom(100),                    m_refreshArea(false),
    2728    m_fontStretch(fontStretch)
    2829{
    29     m_708fontSizes[0] = 36;
    30     m_708fontSizes[1] = 45;
    31     m_708fontSizes[2] = 60;
    3230    m_removeHTML.setMinimal(true);
    3331
    3432#ifdef USING_LIBASS
    void SubtitleScreen::DisplayAVSubtitles(void) 
    346344
    347345void SubtitleScreen::DisplayTextSubtitles(void)
    348346{
    349     if (!InitialiseFont(m_fontStretch) || !m_player || !m_subreader)
     347    if (!Initialise708Fonts(m_fontStretch) || !m_player || !m_subreader)
    350348        return;
    351349
    352350    bool changed = false;
    void SubtitleScreen::DisplayTextSubtitles(void) 
    421419
    422420void SubtitleScreen::DisplayRawTextSubtitles(void)
    423421{
    424     if (!InitialiseFont(m_fontStretch) || !m_player || !m_subreader)
     422    if (!Initialise708Fonts(m_fontStretch) || !m_player || !m_subreader)
    425423        return;
    426424
    427425    uint64_t duration;
    void SubtitleScreen::DisplayRawTextSubtitles(void) 
    445443void SubtitleScreen::DrawTextSubtitles(QStringList &wrappedsubs,
    446444                                       uint64_t start, uint64_t duration)
    447445{
    448     FormattedTextSubtitle fsub(m_safeArea);
     446    FormattedTextSubtitle fsub(m_safeArea, m_useBackground, this);
    449447    fsub.InitFromSRT(wrappedsubs, m_textFontZoom);
    450448    fsub.WrapLongLines();
    451     fsub.Draw(this);
    452     m_refreshArea = true;
     449    fsub.Layout();
     450    m_refreshArea = m_refreshArea || fsub.Draw(0, start, duration);
    453451}
    454452
    455453void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
    static QString extract_cc608( 
    583581
    584582void SubtitleScreen::DisplayCC608Subtitles(void)
    585583{
    586     if (!InitialiseFont(m_fontStretch) || !m_608reader)
     584    if (!Initialise708Fonts(m_fontStretch) || !m_608reader)
    587585        return;
    588586
    589587    bool changed = false;
    void SubtitleScreen::DisplayCC608Subtitles(void) 
    619617        return;
    620618    }
    621619
    622     FormattedTextSubtitle fsub(m_safeArea);
     620    FormattedTextSubtitle fsub(m_safeArea, m_useBackground, this);
    623621    fsub.InitFromCC608(textlist->buffers);
    624     fsub.Draw(this);
    625     m_refreshArea = true;
     622    fsub.Layout();
     623    m_refreshArea = m_refreshArea || fsub.Draw();
    626624    textlist->lock.unlock();
    627625}
    628626
    void SubtitleScreen::DisplayCC708Subtitles(void) 
    646644            m_708fontSizes[1] = size;
    647645            m_708fontSizes[0] = size * 32 / 42;
    648646            m_708fontSizes[2] = size * 42 / 32;
     647            m_708fontSizes[3] = 1; // just to be safe
    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, this);
     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(&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
    bool SubtitleScreen::Initialise708Fonts(int fontStretch) 
    980778}
    981779
    982780MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr)
     781    const
    983782{
    984783    MythFontProperties *mythfont = gCC708Fonts[attr.font_tag & 0x7];
    985784    if (!mythfont)
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    988787    mythfont->GetFace()->setItalic(attr.italics);
    989788    mythfont->GetFace()->setPixelSize(m_708fontSizes[attr.pen_size & 0x3]);
    990789    mythfont->GetFace()->setUnderline(attr.underline);
     790    mythfont->GetFace()->setBold(attr.boldface);
    991791    mythfont->SetColor(attr.GetFGColor());
    992792
    993793    int off = m_708fontSizes[attr.pen_size & 0x3] / 20;
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    1019819    return mythfont;
    1020820}
    1021821
    1022 QSize FormattedTextChunk::CalcSize(int pixelSize) const
     822static QString srtColorString(QColor color)
    1023823{
    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     int width = fm.width(text) + fm.maxWidth() * PAD_WIDTH;
    1031     int height = fm.height() * (1 + PAD_HEIGHT);
    1032     return QSize(width, height);
     824    return QString("#%1%2%3")
     825        .arg(color.red(),   2, 16, QLatin1Char('0'))
     826        .arg(color.green(), 2, 16, QLatin1Char('0'))
     827        .arg(color.blue(),  2, 16, QLatin1Char('0'));
    1033828}
    1034829
    1035830void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers)
    void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers) 
    1044839        return;
    1045840    vector<CC608Text*>::iterator i = buffers.begin();
    1046841    bool teletextmode = (*i)->teletextmode;
    1047     m_useBackground = m_useBackground && !teletextmode;
     842    bool useBackground = m_useBackground && !teletextmode;
    1048843    int xscale = teletextmode ? 40 : 36;
    1049844    int yscale = teletextmode ? 25 : 17;
    1050     m_pixelSize = m_safeArea.height() / (yscale * 1.1765f);
     845    int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING);
     846    if (parent)
     847        parent->SetFontSizes(pixelSize, pixelSize, pixelSize);
    1051848
    1052849    for (; i != buffers.end(); ++i)
    1053850    {
    void FormattedTextSubtitle::InitFromCC608(vector<CC608Text*> &buffers) 
    1063860        int orig_y = teletextmode ? cc->x : cc->y;
    1064861        int y = (int)(((float)orig_y / (float)yscale) *
    1065862                      (float)m_safeArea.height());
    1066         FormattedTextLine line(x, y);
     863        FormattedTextLine line(x, y, orig_x, orig_y);
    1067864        for (int chunk = 0; text != QString::null; chunk++)
    1068865        {
    1069866            QString captionText =
    1070867                extract_cc608(text, cc->teletextmode,
    1071868                              color, isItalic, isUnderline);
    1072             FormattedTextChunk chunk(captionText,
    1073                                      isItalic, isBold, isUnderline,
    1074                                      clr[min(max(0, color), 7)]);
     869            CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
     870                                         clr[min(max(0, color), 7)],
     871                                         useBackground);
     872            FormattedTextChunk chunk(captionText, attr, parent);
    1075873            line.chunks += chunk;
    1076874            LOG(VB_VBI, LOG_INFO,
    1077                 QString("Adding cc608 chunk: x=%1 y=%2 "
    1078                         "uline=%3 ital=%4 color=%5 text='%6'")
    1079                 .arg(cc->x).arg(cc->y)
    1080                 .arg(isUnderline).arg(isItalic).arg(color).arg(captionText));
     875                QString("Adding cc608 chunk (%1,%2): %3")
     876                .arg(cc->x).arg(cc->y).arg(chunk.ToLogString()));
    1081877        }
    1082878        m_lines += line;
    1083879    }
    1084880}
    1085881
     882void FormattedTextSubtitle::InitFromCC708(const CC708Window &win, int num,
     883                                          const vector<CC708String*> &list,
     884                                          float aspect,
     885                                          int textFontZoom)
     886{
     887    LOG(VB_VBI, LOG_INFO,LOC +
     888        QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, "
     889                "relative %5")
     890            .arg(num).arg(win.anchor_point).arg(win.anchor_horizontal)
     891            .arg(win.anchor_vertical).arg(win.relative_pos));
     892    int pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     893    if (parent)
     894        parent->SetFontSizes(pixelSize * 32 / 42, pixelSize, pixelSize * 42 / 32);
     895
     896    float xrange  = win.relative_pos ? 100.0f :
     897                    (aspect > 1.4f) ? 210.0f : 160.0f;
     898    float yrange  = win.relative_pos ? 100.0f : 75.0f;
     899    float xmult   = (float)m_safeArea.width() / xrange;
     900    float ymult   = (float)m_safeArea.height() / yrange;
     901    uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal);
     902    uint anchor_y = (uint)(ymult * (float)win.anchor_vertical);
     903    m_xAnchorPoint = win.anchor_point % 3;
     904    m_yAnchorPoint = win.anchor_point / 3;
     905    m_xAnchor = anchor_x;
     906    m_yAnchor = anchor_y;
     907
     908    for (uint i = 0; i < list.size(); i++)
     909    {
     910        if (list[i]->y >= (uint)m_lines.size())
     911            m_lines.resize(list[i]->y + 1);
     912        if (m_useBackground)
     913        {
     914            list[i]->attr.bg_color = k708AttrColorBlack;
     915            list[i]->attr.bg_opacity = k708AttrOpacitySolid;
     916        }
     917        FormattedTextChunk chunk(list[i]->str, list[i]->attr, parent);
     918        m_lines[list[i]->y].chunks += chunk;
     919        LOG(VB_VBI, LOG_INFO, QString("Adding cc708 chunk: win %1 row %2: %3")
     920            .arg(num).arg(i).arg(chunk.ToLogString()));
     921    }
     922}
     923
    1086924void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom)
    1087925{
    1088926    // Does a simplistic parsing of HTML tags from the strings.
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    1099937    // <font color="#xxyyzz"> - change font color
    1100938    // </font> - reset font color to white
    1101939
    1102     m_pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     940    int pixelSize = (m_safeArea.height() * textFontZoom) / 2000;
     941    if (parent)
     942        parent->SetFontSizes(pixelSize, pixelSize, pixelSize);
     943    m_xAnchorPoint = 1; // center
     944    m_yAnchorPoint = 2; // bottom
     945    m_xAnchor = m_safeArea.width() / 2;
     946    m_yAnchor = m_safeArea.height();
    1103947
    1104948    bool isItalic = false;
    1105949    bool isBold = false;
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    1117961            int pos = text.indexOf(htmlTag);
    1118962            if (pos != 0) // don't add a zero-length string
    1119963            {
    1120                 FormattedTextChunk chunk(
    1121                     text.left(pos), isItalic, isBold, isUnderline, color);
     964                CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
     965                                             color, m_useBackground);
     966                FormattedTextChunk chunk(text.left(pos), attr, parent);
    1122967                line.chunks += chunk;
    1123968                text = (pos < 0 ? "" : text.mid(pos));
    1124                 LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk '%1'")
    1125                     .arg(chunk.text));
     969                LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk: %1")
     970                    .arg(chunk.ToLogString()));
    1126971            }
    1127972            if (pos >= 0)
    1128973            {
    void FormattedTextSubtitle::InitFromSRT(QStringList &subs, int textFontZoom) 
    11711016
    11721017                LOG(VB_VBI, LOG_INFO,
    11731018                    QString("SRT formatting change '%1', "
    1174                             "new ital=%2 bold=%3 uline=%4 color=#%5%6%7)")
     1019                            "new ital=%2 bold=%3 uline=%4 color=%5)")
    11751020                    .arg(html).arg(isItalic).arg(isBold).arg(isUnderline)
    1176                     .arg(color.red(),   2, 16, QLatin1Char('0'))
    1177                     .arg(color.green(), 2, 16, QLatin1Char('0'))
    1178                     .arg(color.blue(),  2, 16, QLatin1Char('0')));
     1021                    .arg(srtColorString(color)));
    11791022            }
    11801023        }
    11811024        m_lines += line;
    bool FormattedTextChunk::Split(FormattedTextChunk &newChunk) 
    11931036            QString("Failed to split chunk '%1'").arg(text));
    11941037        return false;
    11951038    }
    1196     newChunk.isItalic = isItalic;
    1197     newChunk.isBold = isBold;
    1198     newChunk.isUnderline = isUnderline;
    1199     newChunk.color = color;
     1039    newChunk.format = format;
    12001040    newChunk.text = text.mid(lastSpace + 1).trimmed() + ' ';
    12011041    text = text.left(lastSpace).trimmed();
    12021042    LOG(VB_VBI, LOG_INFO,
    bool FormattedTextChunk::Split(FormattedTextChunk &newChunk) 
    12041044    return true;
    12051045}
    12061046
     1047QString FormattedTextChunk::ToLogString(void) const
     1048{
     1049    QString str("");
     1050    str += QString("fg=%1.%2 ")
     1051        .arg(srtColorString(format.GetFGColor()))
     1052        .arg(format.GetFGAlpha());
     1053    str += QString("bg=%1.%2 ")
     1054        .arg(srtColorString(format.GetBGColor()))
     1055        .arg(format.GetBGAlpha());
     1056    str += QString("edge=%1.%2 ")
     1057        .arg(srtColorString(format.GetEdgeColor()))
     1058        .arg(format.edge_type);
     1059    str += QString("off=%1 pensize=%2 ")
     1060        .arg(format.offset)
     1061        .arg(format.pen_size);
     1062    str += QString("it=%1 ul=%2 bf=%3 ")
     1063        .arg(format.italics)
     1064        .arg(format.underline)
     1065        .arg(format.boldface);
     1066    str += QString("font=%1 ").arg(format.font_tag);
     1067    str += QString(" text='%1'").arg(text);
     1068    return str;
     1069}
     1070
    12071071void FormattedTextSubtitle::WrapLongLines(void)
    12081072{
    12091073    int maxWidth = m_safeArea.width();
    12101074    for (int i = 0; i < m_lines.size(); i++)
    12111075    {
    1212         int width = m_lines[i].CalcSize(m_pixelSize).width();
     1076        int width = m_lines[i].CalcSize().width();
    12131077        // Move entire chunks to the next line as necessary.  Leave at
    12141078        // least one chunk on the current line.
    12151079        while (width > maxWidth && m_lines[i].chunks.size() > 1)
    12161080        {
    1217             width -= m_lines[i].chunks.back().CalcSize(m_pixelSize).width();
     1081            width -= m_lines[i].chunks.back().CalcSize().width();
    12181082            // Make sure there's a next line to wrap into.
    12191083            if (m_lines.size() == i + 1)
    12201084                m_lines += FormattedTextLine(m_lines[i].x_indent,
    void FormattedTextSubtitle::WrapLongLines(void) 
    12381102                    m_lines += FormattedTextLine(m_lines[i].x_indent,
    12391103                                                 m_lines[i].y_indent);
    12401104                m_lines[i+1].chunks.prepend(newChunk);
    1241                 width = m_lines[i].CalcSize(m_pixelSize).width();
     1105                width = m_lines[i].CalcSize().width();
    12421106            }
    12431107        }
    12441108    }
    12451109}
    12461110
    1247 void FormattedTextSubtitle::Draw(SubtitleScreen *parent,
    1248                                  uint64_t start, uint64_t duration) const
     1111// Resolves any TBD x_indent and y_indent values in FormattedTextLine
     1112// objects.  Calculates m_bounds.  Prunes most leading and all
     1113// trailing whitespace from each line so that displaying with a black
     1114// background doesn't look clumsy.
     1115void FormattedTextSubtitle::Layout(void)
    12491116{
    1250     bool useBackground = m_useBackground && parent->GetUseBackground();
    1251     gTextSubFont->GetFace()->setPixelSize(m_pixelSize);
    1252     QFontMetrics font(*(gTextSubFont->GetFace()));
    1253     int pad_width = font.maxWidth() * PAD_WIDTH;
    1254     QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
     1117    // Calculate dimensions of bounding rectangle
     1118    int anchor_width = 0;
     1119    int anchor_height = 0;
     1120    for (int i = 0; i < m_lines.size(); i++)
     1121    {
     1122        QSize sz = m_lines[i].CalcSize();
     1123        anchor_width = max(anchor_width, sz.width());
     1124        anchor_height += sz.height() * LINE_SPACING;
     1125    }
    12551126
     1127    // Adjust the anchor point according to actual width and height
     1128    int anchor_x = m_xAnchor;
     1129    int anchor_y = m_yAnchor;
     1130    if (m_xAnchorPoint == 1)
     1131        anchor_x -= anchor_width / 2;
     1132    else if (m_xAnchorPoint == 2)
     1133        anchor_x -= anchor_width;
     1134    if (m_yAnchorPoint == 1)
     1135        anchor_y -= anchor_height / 2;
     1136    else if (m_yAnchorPoint == 2)
     1137        anchor_y -= anchor_height;
     1138
     1139    m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height);
     1140
     1141    // Fill in missing coordinates
     1142    int y = anchor_y;
    12561143    for (int i = 0; i < m_lines.size(); i++)
    12571144    {
    1258         int x = m_lines[i].x_indent, y = m_lines[i].y_indent;
    1259         QSize sz;
    1260         if ((x < 0) || (y < 0) || useBackground)
    1261             sz = m_lines[i].CalcSize(m_pixelSize);
    1262         if (x < 0) // centering
    1263             x = (m_safeArea.width() - sz.width()) / 2;
    1264         if (y < 0) // stack lines at bottom
     1145        if (m_lines[i].x_indent < 0)
     1146            m_lines[i].x_indent = anchor_x;
     1147        if (m_lines[i].y_indent < 0)
     1148            m_lines[i].y_indent = y;
     1149        y += m_lines[i].CalcSize().height() * LINE_SPACING;
     1150        // Prune leading all-whitespace chunks.
     1151        while (!m_lines[i].chunks.isEmpty() &&
     1152               m_lines[i].chunks.first().text.trimmed().isEmpty())
    12651153        {
    1266             y = m_safeArea.height();
    1267             y -= (m_lines.size() - i) * sz.height() * 1.1765f;
     1154            m_lines[i].x_indent +=
     1155                m_lines[i].chunks.first().CalcSize().width();
     1156            m_lines[i].chunks.removeFirst();
    12681157        }
    1269 
    1270         if (useBackground)
     1158        // Prune trailing all-whitespace chunks.
     1159        while (!m_lines[i].chunks.isEmpty() &&
     1160               m_lines[i].chunks.last().text.trimmed().isEmpty())
    12711161        {
    1272             QRect bgrect(x - pad_width, y,
    1273                          sz.width() + pad_width, sz.height());
    1274             // Special case.  If the first chunk is entirely
    1275             // whitespace, don't put a black background behind that
    1276             // chunk.
    1277             //
    1278             // This often happens when a line of cc608 caption text
    1279             // begins with a mid-row format control like italics or a
    1280             // color change.  The spec says the mid-row control
    1281             // implies a space character, which needs to be preserved
    1282             // so that the rest of the text is accurately laid out.  A
    1283             // leading space looks clumsy against the black
    1284             // background, so we adjust the background accordingly.
    1285             if (!m_lines[i].chunks.isEmpty() &&
    1286                 m_lines[i].chunks[0].text.trimmed().isEmpty())
    1287             {
    1288                 bgrect.setLeft(
    1289                     bgrect.left() +
    1290                     m_lines[i].chunks[0].CalcSize(m_pixelSize).width());
    1291             }
    1292             MythUIShape *shape =
    1293                 new MythUIShape(parent, QString("subbg%1_%2").arg(x).arg(y));
    1294             shape->SetFillBrush(bgfill);
    1295             shape->SetArea(MythRect(bgrect));
    1296             if (duration > 0)
    1297                 parent->RegisterExpiration(shape, start + duration);
     1162            m_lines[i].chunks.removeLast();
    12981163        }
     1164        // Trim trailing whitespace from last chunk.  (Trimming
     1165        // leading whitespace from all chunks is handled in the Draw()
     1166        // routine.)
     1167        if (!m_lines[i].chunks.isEmpty())
     1168        {
     1169            QString *str = &m_lines[i].chunks.last().text;
     1170            int idx = str->length() - 1;
     1171            while (idx >= 0 && str->at(idx) == ' ')
     1172                --idx;
     1173            str->truncate(idx + 1);
     1174        }
     1175    }
     1176}
     1177
     1178// Returns true if anything new was drawn, false if not.  The caller
     1179// should call SubtitleScreen::OptimiseDisplayedArea() if true is
     1180// returned.
     1181bool FormattedTextSubtitle::Draw(QList<MythUIType*> *imageCache,
     1182                                 uint64_t start, uint64_t duration) const
     1183{
     1184    bool result = false;
    12991185
     1186    for (int i = 0; i < m_lines.size(); i++)
     1187    {
     1188        int x = m_lines[i].x_indent, y = m_lines[i].y_indent;
     1189        int height = m_lines[i].CalcSize().height();
    13001190        QList<FormattedTextChunk>::const_iterator chunk;
     1191        bool first = true;
    13011192        for (chunk = m_lines[i].chunks.constBegin();
    13021193             chunk != m_lines[i].chunks.constEnd();
    13031194             ++chunk)
    13041195        {
     1196            MythFontProperties *mythfont = parent->Get708Font((*chunk).format);
     1197            if (!mythfont)
     1198                continue;
     1199            QFontMetrics font(*(mythfont->GetFace()));
    13051200            // If the chunk starts with whitespace, the leading
    13061201            // whitespace ultimately gets lost due to the
    13071202            // text.trimmed() operation in the MythUISimpleText
    void FormattedTextSubtitle::Draw(SubtitleScreen *parent, 
    13141209                ++count;
    13151210            }
    13161211            int x_adjust = count * font.width(" ");
    1317             gTextSubFont->GetFace()->setItalic((*chunk).isItalic);
    1318             gTextSubFont->GetFace()->setBold((*chunk).isBold);
    1319             gTextSubFont->GetFace()->setUnderline((*chunk).isUnderline);
    1320             gTextSubFont->SetColor((*chunk).color);
    1321             QSize chunk_sz = (*chunk).CalcSize(m_pixelSize);
     1212            QSize chunk_sz = (*chunk).CalcSize();
     1213            if ((*chunk).format.GetBGAlpha())
     1214            {
     1215                QBrush bgfill = QBrush((*chunk).format.GetBGColor());
     1216                QRect bgrect(x, y, chunk_sz.width(), height);
     1217                if (first)
     1218                    bgrect.setLeft(bgrect.left() + x_adjust -
     1219                                   font.maxWidth() * PAD_WIDTH);
     1220                MythUIShape *bgshape = new MythUIShape(parent,
     1221                        QString("subbg%1x%2@%3,%4")
     1222                                     .arg(chunk_sz.width())
     1223                                     .arg(height)
     1224                                     .arg(x).arg(y));
     1225                bgshape->SetFillBrush(bgfill);
     1226                bgshape->SetArea(MythRect(bgrect));
     1227                if (imageCache)
     1228                    imageCache->append(bgshape);
     1229                if (duration > 0)
     1230                    parent->RegisterExpiration(bgshape, start + duration);
     1231                result = true;
     1232            }
    13221233            QRect rect(x + x_adjust, y,
    1323                        chunk_sz.width() - x_adjust, chunk_sz.height());
     1234                       chunk_sz.width() - x_adjust, height);
    13241235
    13251236            MythUISimpleText *text =
    1326                 new MythUISimpleText((*chunk).text, *gTextSubFont, rect,
     1237                new MythUISimpleText((*chunk).text, *mythfont, rect,
    13271238                                     Qt::AlignLeft, (MythUIType*)parent,
    13281239                                     QString("subtxt%1x%2@%3,%4")
    13291240                                     .arg(chunk_sz.width())
    1330                                      .arg(chunk_sz.height())
     1241                                     .arg(height)
    13311242                                     .arg(x).arg(y));
     1243            if (imageCache)
     1244                imageCache->append(text);
    13321245            if (duration > 0)
    13331246                parent->RegisterExpiration(text, start + duration);
     1247            result = true;
    13341248
    13351249            LOG(VB_VBI, LOG_INFO,
    1336                 QString("Drawing chunk at (%1,%2) with "
    1337                         "ital=%3 bold=%4 uline=%5 color=#%6%7%8 "
    1338                         "text='%9'")
    1339                 .arg(x).arg(y)
    1340                 .arg((*chunk).isItalic)
    1341                 .arg((*chunk).isBold)
    1342                 .arg((*chunk).isUnderline)
    1343                 .arg((*chunk).color.red(),   2, 16, QLatin1Char('0'))
    1344                 .arg((*chunk).color.green(), 2, 16, QLatin1Char('0'))
    1345                 .arg((*chunk).color.blue(),  2, 16, QLatin1Char('0'))
    1346                 .arg((*chunk).text));
     1250                QString("Drawing chunk at (%1,%2): %3")
     1251                .arg(x).arg(y).arg((*chunk).ToLogString()));
    13471252
    13481253            x += chunk_sz.width();
     1254            first = false;
     1255        }
     1256    }
     1257    return result;
     1258}
     1259
     1260QStringList FormattedTextSubtitle::ToSRT(void) const
     1261{
     1262    QStringList result;
     1263    for (int i = 0; i < m_lines.size(); i++)
     1264    {
     1265        QString line;
     1266        if (m_lines[i].orig_x > 0)
     1267            line.fill(' ', m_lines[i].orig_x);
     1268        QList<FormattedTextChunk>::const_iterator chunk;
     1269        for (chunk = m_lines[i].chunks.constBegin();
     1270             chunk != m_lines[i].chunks.constEnd();
     1271             ++chunk)
     1272        {
     1273            const QString &text = (*chunk).text;
     1274            const CC708CharacterAttribute &attr = (*chunk).format;
     1275            bool isBlank = !attr.underline && text.trimmed().isEmpty();
     1276            if (!isBlank)
     1277            {
     1278                if (attr.boldface)
     1279                    line += "<b>";
     1280                if (attr.italics)
     1281                    line += "<i>";
     1282                if (attr.underline)
     1283                    line += "<u>";
     1284                if (attr.GetFGColor() != Qt::white)
     1285                    line += QString("<font color=\"%1\">")
     1286                        .arg(srtColorString(attr.GetFGColor()));
     1287            }
     1288            line += text;
     1289            if (!isBlank)
     1290            {
     1291                if (attr.GetFGColor() != Qt::white)
     1292                    line += QString("</font>");
     1293                if (attr.underline)
     1294                    line += "</u>";
     1295                if (attr.italics)
     1296                    line += "</i>";
     1297                if (attr.boldface)
     1298                    line += "</b>";
     1299            }
    13491300        }
     1301        if (!line.trimmed().isEmpty())
     1302            result += line;
    13501303    }
     1304    return result;
     1305}
     1306
     1307void SubtitleScreen::SetFontSizes(int small, int medium, int large)
     1308{
     1309    m_708fontSizes[k708AttrSizeSmall]    = small;
     1310    m_708fontSizes[k708AttrSizeStandard] = medium;
     1311    m_708fontSizes[k708AttrSizeLarge]    = large;
     1312}
     1313
     1314QSize SubtitleScreen::CalcTextSize(const QString &text,
     1315                                   const CC708CharacterAttribute &format) const
     1316{
     1317    QFont *font = Get708Font(format)->GetFace();
     1318    QFontMetrics fm(*font);
     1319    int width = fm.width(text) + fm.maxWidth() * PAD_WIDTH;
     1320    int height = fm.height() * (1 + PAD_HEIGHT);
     1321    return QSize(width, height);
    13511322}
    13521323
    13531324#ifdef USING_LIBASS
  • mythtv/libs/libmythtv/subtitlescreen.h

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
    index c8f805a..ab40bd0 100644
    a b extern "C" { 
    2323
    2424class SubtitleScreen : public MythScreenType
    2525{
    26     static bool InitialiseFont(int fontStretch = QFont::Unstretched);
     26    friend class FormattedTextSubtitle;
     27
    2728    static bool Initialise708Fonts(int fontStretch = QFont::Unstretched);
    2829
    2930  public:
    class SubtitleScreen : public MythScreenType 
    4041    void ExpireSubtitles(void);
    4142    void DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos);
    4243
     44    QSize CalcTextSize(const QString &text,
     45                       const CC708CharacterAttribute &format) const;
     46
    4347    void RegisterExpiration(MythUIType *shape, long long endTime)
    4448    {
    4549        m_expireTimes.insert(shape, endTime);
    class SubtitleScreen : public MythScreenType 
    6266    void DisplayCC708Subtitles(void);
    6367    void AddScaledImage(QImage &img, QRect &pos);
    6468    void Clear708Cache(int num);
    65     void Display708Strings(const CC708Window &win, int num,
    66                            float aspect, vector<CC708String*> &list);
    67     MythFontProperties* Get708Font(CC708CharacterAttribute attr);
     69    MythFontProperties* Get708Font(CC708CharacterAttribute attr) const;
     70    void SetFontSizes(int small, int medium, int large);
    6871
    6972    MythPlayer        *m_player;
    7073    SubtitleReader    *m_subreader;
    class SubtitleScreen : public MythScreenType 
    7578    QRegExp            m_removeHTML;
    7679    int                m_subtitleType;
    7780    QHash<MythUIType*, long long> m_expireTimes;
    78     int                m_708fontSizes[3];
    79     int                m_textFontZoom;
     81    int                m_708fontSizes[4];
     82    int                m_textFontZoom; // valid for 708 & text subs
    8083    bool               m_refreshArea;
    8184    QHash<int,QList<MythUIType*> > m_708imageCache;
    8285    int                m_fontStretch;
    class SubtitleScreen : public MythScreenType 
    102105class FormattedTextChunk
    103106{
    104107  public:
    105     FormattedTextChunk(
    106         const QString &t, bool ital, bool bold, bool uline, QColor clr) :
    107         text(t), isItalic(ital), isBold(bold), isUnderline(uline), color(clr)
     108    FormattedTextChunk(const QString &t, CC708CharacterAttribute formatting,
     109                       SubtitleScreen *p)
     110        : text(t), format(formatting), parent(p)
    108111    {
    109112    }
    110113    FormattedTextChunk(void) {}
    111114
    112     QSize CalcSize(int pixelSize) const;
     115    QSize CalcSize(void) const
     116    {
     117        return parent->CalcTextSize(text, format);
     118    }
    113119    bool Split(FormattedTextChunk &newChunk);
     120    QString ToLogString(void) const;
    114121
    115122    QString text;
    116     bool isItalic;
    117     bool isBold;
    118     bool isUnderline;
    119     QColor color;
     123    CC708CharacterAttribute format;
     124    SubtitleScreen *parent; // where fonts and sizes are kept
    120125};
    121126
    122127class FormattedTextLine
    123128{
    124129  public:
    125     FormattedTextLine(int x = -1, int y = -1) : x_indent(x), y_indent(y) {}
     130    FormattedTextLine(int x = -1, int y = -1, int o_x = -1, int o_y = -1)
     131        : x_indent(x), y_indent(y), orig_x(o_x), orig_y(o_y) {}
    126132
    127     QSize CalcSize(int pixelSize) const
     133    QSize CalcSize(void) const
    128134    {
    129135        int height = 0, width = 0;
    130136        QList<FormattedTextChunk>::const_iterator it;
    131137        for (it = chunks.constBegin(); it != chunks.constEnd(); ++it)
    132138        {
    133             QSize tmp = (*it).CalcSize(pixelSize);
     139            QSize tmp = (*it).CalcSize();
    134140            height = max(height, tmp.height());
    135141            width += tmp.width();
    136142        }
    class FormattedTextLine 
    140146    QList<FormattedTextChunk> chunks;
    141147    int x_indent; // -1 means TBD i.e. centered
    142148    int y_indent; // -1 means TBD i.e. relative to bottom
     149    int orig_x, orig_y; // original, unscaled coordinates
    143150};
    144151
    145152class FormattedTextSubtitle
    146153{
    147154  public:
    148     FormattedTextSubtitle(const QRect &safearea) :
    149         m_safeArea(safearea), m_useBackground(true) {}
     155    FormattedTextSubtitle(const QRect &safearea, bool useBackground,
     156                          SubtitleScreen *p)
     157        : m_safeArea(safearea), m_useBackground(useBackground),
     158          parent(p) {}
     159    FormattedTextSubtitle(void)
     160        : m_safeArea(QRect()), m_useBackground(false), parent(0) {}
    150161    void InitFromCC608(vector<CC608Text*> &buffers);
     162    void InitFromCC708(const CC708Window &win, int num,
     163                       const vector<CC708String*> &list,
     164                       float aspect = 1.77777f,
     165                       int textFontZoom = 100);
    151166    void InitFromSRT(QStringList &subs, int textFontZoom);
    152167    void WrapLongLines(void);
    153     void Draw(SubtitleScreen *parent,
     168    void Layout(void);
     169    bool Draw(QList<MythUIType*> *imageCache = 0,
    154170              uint64_t start = 0, uint64_t duration = 0) const;
     171    QStringList ToSRT(void) const;
     172    QRect m_bounds;
    155173
    156174  private:
    157175    QVector<FormattedTextLine> m_lines;
    158176    const QRect m_safeArea;
    159     bool m_useBackground;
    160     int m_pixelSize;
     177    const bool m_useBackground;
     178    SubtitleScreen *parent; // where fonts and sizes are kept
     179    int m_xAnchorPoint; // 0=left, 1=center, 2=right
     180    int m_yAnchorPoint; // 0=top,  1=center, 2=bottom
     181    int m_xAnchor; // pixels from left
     182    int m_yAnchor; // pixels from top
    161183};
    162184
    163185#endif // SUBTITLESCREEN_H