MythTV  master
subtitlescreen.cpp
Go to the documentation of this file.
1 #include <QFontMetrics>
2 
3 #include "mythlogging.h"
4 #include "mythfontproperties.h"
5 #include "mythuisimpletext.h"
6 #include "mythuishape.h"
7 #include "mythuiimage.h"
8 #include "mythpainter.h"
10 
11 #define LOC QString("Subtitles: ")
12 #define LOC_WARN QString("Subtitles Warning: ")
13 
14 // Class SubWrapper is used to attach caching structures to MythUIType
15 // objects in the SubtitleScreen's m_ChildrenList. If these objects
16 // inherit from SubWrapper, they can carry relevant information and an
17 // external caching object is not required.
18 //
19 // The following caching information is represented here:
20 // 1. Original m_Area, used for OptimiseDisplayedArea().
21 // 2. Which cc708 window it belongs to, used for Clear708Cache().
22 // 3. Subtitle expire time, primarily for AV subtitles.
24 {
25 protected:
26  SubWrapper(const MythRect &rect,
27  long long expireTime,
28  int whichImageCache = -1) :
29  m_swOrigArea(rect),
30  m_swWhichImageCache(whichImageCache),
31  m_swExpireTime(expireTime)
32  {
33  }
34 public:
35  long long GetExpireTime(void) const { return m_swExpireTime; }
36  MythRect GetOrigArea(void) const { return m_swOrigArea; }
37  int GetWhichImageCache(void) const { return m_swWhichImageCache; }
38 protected:
39  // Returns true if the object was deleted.
41  const int m_swWhichImageCache; // cc708 only; -1 = none
42  const long long m_swExpireTime; // avsubs only; -1 = none
43 };
44 
46 {
47 public:
48  SubSimpleText(const QString &text, const MythFontProperties &font,
49  const QRect &rect, Qt::Alignment align,
50  MythUIType *parent, const QString &name,
51  int whichImageCache, long long expireTime) :
52  MythUISimpleText(text, font, rect, align, parent, name),
53  SubWrapper(MythRect(rect), expireTime, whichImageCache) {}
54 };
55 
56 class SubShape : public MythUIShape, public SubWrapper
57 {
58 public:
59  SubShape(MythUIType *parent, const QString &name, const MythRect &area,
60  int whichImageCache, long long expireTime) :
61  MythUIShape(parent, name),
62  SubWrapper(area, expireTime, whichImageCache) {}
63 };
64 
65 class SubImage : public MythUIImage, public SubWrapper
66 {
67 public:
68  SubImage(MythUIType *parent, const QString &name, const MythRect &area,
69  long long expireTime) :
70  MythUIImage(parent, name),
71  SubWrapper(area, expireTime) {}
72  MythImage *GetImage(void) { return m_images[0]; }
73 };
74 
76 
77 // Class SubtitleFormat manages fonts and backgrounds for subtitles.
78 //
79 // Formatting is specified by the theme in the new file
80 // osd_subtitle.xml, in the osd_subtitle window. Subtitle types are
81 // text, teletext, 608, 708_0, 708_1, ..., 708_7. Each subtitle type
82 // has a fontdef component for the text and a shape component for the
83 // background. By default, the attributes of a subtitle type come
84 // from either the provider (e.g. font color, italics) or the system
85 // default (e.g. font family). These attributes can be overridden by
86 // the xml file.
87 //
88 // The fontdef name and the background shape name are both simply the
89 // name of the subtitle type. The fontdef and shape should ultimately
90 // inherit from the special value "provider", otherwise all provider
91 // values will be ignored.
92 //
93 // The following example forces .srt subtitles to be rendered in
94 // yellow text, FreeSans font, black shadow, with a translucent black
95 // background. The fontdef and shape names are "text" since the
96 // subtitles come from a .srt file. Note that in this example, color
97 // formatting controls in the .srt file will be ignored due to the
98 // explicit setting of yellow text.
99 //
100 // <?xml version="1.0" encoding="utf-8"?>
101 // <!DOCTYPE mythuitheme SYSTEM "http://www.mythtv.org/schema/mythuitheme.dtd">
102 // <mythuitheme>
103 // <window name="osd_subtitle">
104 // <fontdef name="text" face="FreeSans" from="provider">
105 // <color>#FFFF00</color>
106 // <shadowoffset>2,2</shadowoffset>
107 // <shadowcolor>#000000</shadowcolor>
108 // </fontdef>
109 // <shape name="text" from="provider">
110 // <fill color="#000000" alpha="100" />
111 // </shape>
112 // </window>
113 // </mythuitheme>
114 //
115 // All elements/attributes of fontdef and shape can be used. Note
116 // however that area and position are explicitly ignored, as these are
117 // dictated by the subtitle layout.
118 //
119 // This is implemented with almost no MythUI changes. Two copies of a
120 // "provider" object are created, with default/representative provider
121 // attributes. One copy is then "complemented" to have a different
122 // value for each attribute that a provider might change. The
123 // osd_subtitle.xml file is loaded twice, once with respect to each
124 // provider object, and the desired fontdef or shape is looked up.
125 // The two fontdefs or shapes are compared attribute by attribute, and
126 // each attribute that is different is an attribute that the provider
127 // may modify, whereas each identical attribute represents one that is
128 // fixed by the theme.
129 
131 {
132 public:
133  SubtitleFormat(void) = default;
134  ~SubtitleFormat(void);
135  MythFontProperties *GetFont(const QString &family,
136  const CC708CharacterAttribute &attr,
137  int pixelSize, int zoom, int stretch);
138  SubShape *GetBackground(MythUIType *parent, const QString &name,
139  const QString &family,
140  const CC708CharacterAttribute &attr,
141  const MythRect &area,
142  int whichImageCache,
143  int start, int duration);
144  int GetBackgroundAlpha(const QString &family);
145  static QString MakePrefix(const QString &family,
146  const CC708CharacterAttribute &attr);
147 private:
148  void Load(const QString &family,
149  const CC708CharacterAttribute &attr);
150  bool IsUnlocked(const QString &prefix, const QString &property) const
151  {
152  return m_changeMap[prefix].contains(property);
153  }
154  static void CreateProviderDefault(const QString &family,
155  const CC708CharacterAttribute &attr,
156  MythUIType *parent,
157  bool isComplement,
158  MythFontProperties **font,
159  MythUIShape **bg);
160  static void Complement(MythFontProperties *font, MythUIShape *bg);
161  static QSet<QString> Diff(const QString &family,
162  const CC708CharacterAttribute &attr,
163  MythFontProperties *font1,
164  MythFontProperties *font2,
165  MythUIShape *bg1,
166  MythUIShape *bg2);
167 
168  QHash<QString, MythFontProperties *> m_fontMap;
169  QHash<QString, MythUIShape *> m_shapeMap;
170  QHash<QString, QSet<QString> > m_changeMap;
171  // The following m_*Map fields are the original values from the
172  // m_fontMap, which are preserved because the text font zoom
173  // factor affects the actual values stored in the font.
174  QHash<QString, int> m_pixelSizeMap;
175  QHash<QString, int> m_outlineSizeMap;
176  QHash<QString, QPoint> m_shadowOffsetMap;
177  QVector<MythUIType *> m_cleanup;
178 };
179 
180 static const QString kSubProvider("provider");
181 static const QString kSubFileName ("osd_subtitle.xml");
182 static const QString kSubWindowName("osd_subtitle");
183 static const QString kSubFamily608 ("608");
184 static const QString kSubFamily708 ("708");
185 static const QString kSubFamilyText ("text");
186 static const QString kSubFamilyAV ("AV");
187 static const QString kSubFamilyTeletext("teletext");
188 
189 static const QString kSubAttrItalics ("italics");
190 static const QString kSubAttrBold ("bold");
191 static const QString kSubAttrUnderline("underline");
192 static const QString kSubAttrPixelsize("pixelsize");
193 static const QString kSubAttrColor ("color");
194 static const QString kSubAttrBGfill ("bgfill");
195 static const QString kSubAttrShadow ("shadow"); // unused
196 static const QString kSubAttrShadowoffset("shadowoffset");
197 static const QString kSubAttrShadowcolor ("shadowcolor");
198 static const QString kSubAttrShadowalpha ("shadowalpha");
199 static const QString kSubAttrOutline ("outline"); // unused
200 static const QString kSubAttrOutlinecolor("outlinecolor");
201 static const QString kSubAttrOutlinesize ("outlinesize");
202 static const QString kSubAttrOutlinealpha("outlinealpha");
203 
204 static QString srtColorString(const QColor& color)
205 {
206  return QString("#%1%2%3")
207  .arg(color.red(), 2, 16, QLatin1Char('0'))
208  .arg(color.green(), 2, 16, QLatin1Char('0'))
209  .arg(color.blue(), 2, 16, QLatin1Char('0'));
210 }
211 
213 {
214  QString result;
215  result = QString("face=%1 pixelsize=%2 color=%3 "
216  "italics=%4 weight=%5 underline=%6")
217  .arg(f->GetFace()->family())
218  .arg(f->GetFace()->pixelSize())
219  .arg(srtColorString(f->color()))
220  .arg(static_cast<int>(f->GetFace()->italic()))
221  .arg(f->GetFace()->weight())
222  .arg(static_cast<int>(f->GetFace()->underline()));
223  QPoint offset;
224  QColor color;
225  int alpha = 0;
226  int size = 0;
227  f->GetShadow(offset, color, alpha);
228  result += QString(" shadow=%1 shadowoffset=%2 "
229  "shadowcolor=%3 shadowalpha=%4")
230  .arg(static_cast<int>(f->hasShadow()))
231  .arg(QString("(%1,%2)").arg(offset.x()).arg(offset.y()))
232  .arg(srtColorString(color))
233  .arg(alpha);
234  f->GetOutline(color, size, alpha);
235  result += QString(" outline=%1 outlinecolor=%2 "
236  "outlinesize=%3 outlinealpha=%4")
237  .arg(static_cast<int>(f->hasOutline()))
238  .arg(srtColorString(color))
239  .arg(size)
240  .arg(alpha);
241  return result;
242 }
243 
245 SubtitleFormat::GetFont(const QString &family,
246  const CC708CharacterAttribute &attr,
247  int pixelSize, int zoom, int stretch)
248 {
249  int origPixelSize = pixelSize;
250  float scale = zoom / 100.0;
251  if ((attr.m_penSize & 0x3) == k708AttrSizeSmall)
252  scale = scale * 32 / 42;
253  else if ((attr.m_penSize & 0x3) == k708AttrSizeLarge)
254  scale = scale * 42 / 32;
255 
256  QString prefix = MakePrefix(family, attr);
257  if (!m_fontMap.contains(prefix))
258  Load(family, attr);
260 
261  // Apply the scaling factor to pixelSize even if the theme
262  // explicitly sets pixelSize.
264  pixelSize = m_pixelSizeMap[prefix];
265  pixelSize *= scale;
266  result->GetFace()->setPixelSize(pixelSize);
267 
268  result->GetFace()->setStretch(stretch);
270  result->GetFace()->setItalic(attr.m_italics);
272  result->GetFace()->setUnderline(attr.m_underline);
274  result->GetFace()->setBold(attr.m_boldface);
276  result->SetColor(attr.GetFGColor());
277 
278  MythPoint offset;
279  QColor color;
280  int alpha = 0;
281  bool shadow = result->hasShadow();
282  result->GetShadow(offset, color, alpha);
284  color = attr.GetEdgeColor();
286  alpha = attr.GetFGAlpha();
288  {
289  int off = lroundf(scale * pixelSize / 20);
290  offset = QPoint(off, off);
292  {
293  shadow = true;
294  offset.setX(-off);
295  }
296  else if (attr.m_edgeType == k708AttrEdgeRightDropShadow)
297  shadow = true;
298  else
299  shadow = false;
300  }
301  else
302  {
303  offset = m_shadowOffsetMap[prefix];
304  offset.NormPoint();
305  offset.setX(lroundf(offset.x() * scale));
306  offset.setY(lroundf(offset.y() * scale));
307  }
308  result->SetShadow(shadow, offset, color, alpha);
309 
310  int off = 0;
311  bool outline = result->hasOutline();
312  result->GetOutline(color, off, alpha);
314  color = attr.GetEdgeColor();
316  alpha = attr.GetFGAlpha();
318  {
319  if (attr.m_edgeType == k708AttrEdgeUniform ||
320  attr.m_edgeType == k708AttrEdgeRaised ||
322  {
323  outline = true;
324  off = lroundf(scale * pixelSize / 20);
325  }
326  else
327  outline = false;
328  }
329  else
330  {
331  off = m_outlineSizeMap[prefix];
332  MythPoint point(off, off);
333  point.NormPoint();
334  off = lroundf(point.x() * scale);
335  }
336  result->SetOutline(outline, color, off, alpha);
337 
338  LOG(VB_VBI, LOG_DEBUG,
339  QString("GetFont(family=%1, prefix=%2, orig pixelSize=%3, "
340  "new pixelSize=%4 zoom=%5) = %6")
341  .arg(family).arg(prefix).arg(origPixelSize).arg(pixelSize)
342  .arg(zoom).arg(fontToString(result)));
343  return result;
344 }
345 
347 {
348  // NOLINTNEXTLINE(modernize-loop-convert)
349  for (int i = 0; i < m_cleanup.size(); ++i)
350  {
351  m_cleanup[i]->DeleteAllChildren();
352  m_cleanup[i]->deleteLater();
353  m_cleanup[i] = nullptr; // just to be safe
354  }
355 }
356 
357 QString SubtitleFormat::MakePrefix(const QString &family,
358  const CC708CharacterAttribute &attr)
359 {
360  if (family == kSubFamily708)
361  return family + "_" + QString::number(attr.m_fontTag & 0x7);
362  return family;
363 }
364 
365 void SubtitleFormat::CreateProviderDefault(const QString &family,
366  const CC708CharacterAttribute &attr,
367  MythUIType *parent,
368  bool isComplement,
369  MythFontProperties **returnFont,
370  MythUIShape **returnBg)
371 {
372  auto *font = new MythFontProperties();
373  auto *bg = new MythUIShape(parent, kSubProvider);
374  if (family == kSubFamily608)
375  {
376  font->GetFace()->setFamily("FreeMono");
377  QBrush brush(Qt::black);
378  bg->SetFillBrush(brush);
379  bg->SetLinePen(QPen(brush, 0));
380  }
381  else if (family == kSubFamily708)
382  {
383  static const std::array<const std::string,8> s_cc708Fonts {
384  "FreeMono", // default
385  "FreeMono", // mono serif
386  "Droid Serif", // prop serif
387  "Droid Sans Mono", // mono sans
388  "Droid Sans", // prop sans
389  "Purisa", // casual
390  "TeX Gyre Chorus", // cursive
391  "Droid Serif" // small caps, QFont::SmallCaps will be applied
392  };
393  font->GetFace()->setFamily(QString::fromStdString(s_cc708Fonts[attr.m_fontTag & 0x7]));
394  }
395  else if (family == kSubFamilyText)
396  {
397  font->GetFace()->setFamily("Droid Sans");
398  QBrush brush(Qt::black);
399  bg->SetFillBrush(brush);
400  bg->SetLinePen(QPen(brush, 0));
401  }
402  else if (family == kSubFamilyTeletext)
403  {
404  font->GetFace()->setFamily("FreeMono");
405  // Set up a background with default alpha=100% so that the theme can
406  // override the background alpha.
407  QBrush brush(Qt::black);
408  bg->SetFillBrush(brush);
409  bg->SetLinePen(QPen(brush, 0));
410  }
411  font->GetFace()->setPixelSize(10);
412 
413  if (isComplement)
414  Complement(font, bg);
415  parent->AddFont(kSubProvider, font);
416 
417  *returnFont = font;
418  *returnBg = bg;
419 }
420 
421 static QColor differentColor(const QColor &color)
422 {
423  return color == Qt::white ? Qt::black : Qt::white;
424 }
425 
426 // Change everything (with respect to the == operator) that the
427 // provider might define or override.
429 {
430  QPoint offset;
431  QColor color;
432  int alpha = 0;
433  int size = 0;
434  QFont *face = font->GetFace();
435  face->setItalic(!face->italic());
436  face->setPixelSize(face->pixelSize() + 1);
437  face->setUnderline(!face->underline());
438  face->setWeight((face->weight() + 1) % 32);
439  font->SetColor(differentColor(font->color()));
440 
441  font->GetShadow(offset, color, alpha);
442  offset.setX(offset.x() + 1);
443  font->SetShadow(!font->hasShadow(), offset, differentColor(color),
444  255 - alpha);
445 
446  font->GetOutline(color, size, alpha);
447  font->SetOutline(!font->hasOutline(), differentColor(color),
448  size + 1, 255 - alpha);
449 
450  bg->SetFillBrush(bg->m_fillBrush == Qt::NoBrush ?
451  Qt::SolidPattern : Qt::NoBrush);
452 }
453 
454 void SubtitleFormat::Load(const QString &family,
455  const CC708CharacterAttribute &attr)
456 {
457  // Widgets for the actual values
458  auto *baseParent = new MythUIType(nullptr, "base");
459  m_cleanup += baseParent;
460  MythFontProperties *providerBaseFont = nullptr;
461  MythUIShape *providerBaseShape = nullptr;
462  CreateProviderDefault(family, attr, baseParent, false,
463  &providerBaseFont, &providerBaseShape);
464 
465  // Widgets for the "negative" values
466  auto *negParent = new MythUIType(nullptr, "base");
467  m_cleanup += negParent;
468  MythFontProperties *negFont = nullptr;
469  MythUIShape *negBG = nullptr;
470  CreateProviderDefault(family, attr, negParent, true, &negFont, &negBG);
471 
472  bool posResult =
474  baseParent);
475  bool negResult =
477  negParent);
478  if (!posResult || !negResult)
479  LOG(VB_VBI, LOG_INFO,
480  QString("Couldn't load theme file %1").arg(kSubFileName));
481  QString prefix = MakePrefix(family, attr);
482  MythFontProperties *resultFont = baseParent->GetFont(prefix);
483  if (!resultFont)
484  resultFont = providerBaseFont;
485  auto *resultBG = dynamic_cast<MythUIShape *>(baseParent->GetChild(prefix));
486 
487  // The providerBaseShape object is not leaked here. It is added
488  // to a list of children in its base class constructor.
489  if (!resultBG)
490  resultBG = providerBaseShape;
491  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
492  MythFontProperties *testFont = negParent->GetFont(prefix);
493  if (!testFont)
494  testFont = negFont;
495  auto *testBG = dynamic_cast<MythUIShape *>(negParent->GetChild(prefix));
496  if (!testBG)
497  testBG = negBG;
498  if (family == kSubFamily708 &&
499  (attr.m_fontTag & 0x7) == k708AttrFontSmallCaps)
500  resultFont->GetFace()->setCapitalization(QFont::SmallCaps);
501  m_fontMap[prefix] = resultFont;
502  m_shapeMap[prefix] = resultBG;
503  LOG(VB_VBI, LOG_DEBUG,
504  QString("providerBaseFont = %1").arg(fontToString(providerBaseFont)));
505  LOG(VB_VBI, LOG_DEBUG,
506  QString("negFont = %1").arg(fontToString(negFont)));
507  LOG(VB_VBI, LOG_DEBUG,
508  QString("resultFont = %1").arg(fontToString(resultFont)));
509  LOG(VB_VBI, LOG_DEBUG,
510  QString("testFont = %1").arg(fontToString(testFont)));
511  m_changeMap[prefix] = Diff(family, attr, resultFont, testFont,
512  resultBG, testBG);
513  QPoint offset;
514  QColor color;
515  int alpha = 0;
516  int size = 0;
517  resultFont->GetShadow(offset, color, alpha);
518  resultFont->GetOutline(color, size, alpha);
519  m_outlineSizeMap[prefix] = size;
520  m_shadowOffsetMap[prefix] = offset;
521  m_pixelSizeMap[prefix] = resultFont->GetFace()->pixelSize();
522 
523  delete negFont;
524 }
525 
526 QSet<QString> SubtitleFormat::Diff(const QString &family,
527  const CC708CharacterAttribute &attr,
528  MythFontProperties *font1,
529  MythFontProperties *font2,
530  MythUIShape *bg1,
531  MythUIShape *bg2)
532 {
533  bool is708 = (family == kSubFamily708);
534  QSet<QString> result;
535  QFont *face1 = font1->GetFace();
536  QFont *face2 = font2->GetFace();
537  if (face1->italic() != face2->italic())
538  result << kSubAttrItalics;
539  if (face1->weight() != face2->weight())
540  result << kSubAttrBold;
541  if (face1->underline() != face2->underline())
542  result << kSubAttrUnderline;
543  if (face1->pixelSize() != face2->pixelSize())
544  result << kSubAttrPixelsize;
545  if (font1->color() != font2->color())
546  result << kSubAttrColor;
547  if (is708 && font1->hasShadow() != font2->hasShadow())
548  {
549  result << kSubAttrShadow;
550  QPoint offset1;
551  QPoint offset2;
552  QColor color1;
553  QColor color2;
554  int alpha1 = 0;
555  int alpha2 = 0;
556  font1->GetShadow(offset1, color1, alpha1);
557  font2->GetShadow(offset2, color2, alpha2);
558  if (offset1 != offset2)
559  result << kSubAttrShadowoffset;
560  if (color1 != color2)
561  result << kSubAttrShadowcolor;
562  if (alpha1 != alpha2)
563  result << kSubAttrShadowalpha;
564  }
565  if (is708 && font1->hasOutline() != font2->hasOutline())
566  {
567  result << kSubAttrOutline;
568  QColor color1;
569  QColor color2;
570  int size1 = 0;
571  int size2 = 0;
572  int alpha1 = 0;
573  int alpha2 = 0;
574  font1->GetOutline(color1, size1, alpha1);
575  font2->GetOutline(color2, size2, alpha2);
576  if (color1 != color2)
577  result << kSubAttrOutlinecolor;
578  if (size1 != size2)
579  result << kSubAttrOutlinesize;
580  if (alpha1 != alpha2)
581  result << kSubAttrOutlinealpha;
582  }
583  if (bg1->m_fillBrush != bg2->m_fillBrush)
584  result << kSubAttrBGfill;
585 
586  QString values = "";
587  for (auto i = result.constBegin(); i != result.constEnd(); ++i)
588  values += " " + (*i);
589  LOG(VB_VBI, LOG_INFO,
590  QString("Subtitle family %1 allows provider to change:%2")
591  .arg(MakePrefix(family, attr)).arg(values));
592 
593  return result;
594 }
595 
596 SubShape *
597 SubtitleFormat::GetBackground(MythUIType *parent, const QString &name,
598  const QString &family,
599  const CC708CharacterAttribute &attr,
600  const MythRect &area,
601  int whichImageCache,
602  int start,
603  int duration)
604 {
605  QString prefix = MakePrefix(family, attr);
606  if (!m_shapeMap.contains(prefix))
607  Load(family, attr);
608  if (m_shapeMap[prefix]->GetAlpha() == 0)
609  return nullptr;
610  auto *result = new SubShape(parent, name, area, whichImageCache,
611  start + duration);
612  result->CopyFrom(m_shapeMap[prefix]);
613  if (family == kSubFamily708)
614  {
616  {
617  QBrush brush(attr.GetBGColor());
618  result->SetFillBrush(brush);
619  result->SetLinePen(QPen(brush, 0));
620  }
621  }
622  else if (family == kSubFamilyTeletext)
623  {
624  // add code here when teletextscreen.cpp is refactored
625  }
626  LOG(VB_VBI, LOG_DEBUG,
627  QString("GetBackground(prefix=%1) = "
628  "{type=%2 alpha=%3 brushstyle=%4 brushcolor=%5}")
629  .arg(prefix).arg(result->m_type).arg(result->GetAlpha())
630  .arg(result->m_fillBrush.style())
631  .arg(srtColorString(result->m_fillBrush.color())));
632  return result;
633 }
634 
635 int SubtitleFormat::GetBackgroundAlpha(const QString &family)
636 {
637  // This is a "temporary" hack for allowing teletextscreen.cpp to get the
638  // background alpha value from osd_subtitle.xml.
639  CC708CharacterAttribute attr(false, false, false, Qt::white);
640  SubShape *bgShape = GetBackground(nullptr, "dummyName", family, attr,
641  MythRect(), -1, 0, -1);
642  return bgShape->m_fillBrush.color().alpha();
643 }
644 
646 
647 QSize FormattedTextChunk::CalcSize(float layoutSpacing) const
648 {
649  return m_parent->CalcTextSize(m_text, m_format, layoutSpacing);
650 }
651 
652 void FormattedTextChunk::CalcPadding(bool isFirst, bool isLast,
653  int &left, int &right) const
654 {
655  m_parent->CalcPadding(m_format, isFirst, isLast, left, right);
656 }
657 
659 {
660  LOG(VB_VBI, LOG_INFO,
661  QString("Attempting to split chunk '%1'").arg(m_text));
662  int lastSpace = m_text.lastIndexOf(' ', -2); // -2 to ignore trailing space
663  if (lastSpace < 0)
664  {
665  LOG(VB_VBI, LOG_INFO,
666  QString("Failed to split chunk '%1'").arg(m_text));
667  return false;
668  }
669  newChunk.m_parent = m_parent;
670  newChunk.m_format = m_format;
671  newChunk.m_text = m_text.mid(lastSpace + 1).trimmed() + ' ';
672  m_text = m_text.left(lastSpace).trimmed();
673  LOG(VB_VBI, LOG_INFO,
674  QString("Split chunk into '%1' + '%2'").arg(m_text).arg(newChunk.m_text));
675  return true;
676 }
677 
679 {
680  QString str("");
681  str += QString("fg=%1.%2 ")
683  .arg(m_format.GetFGAlpha());
684  str += QString("bg=%1.%2 ")
686  .arg(m_format.GetBGAlpha());
687  str += QString("edge=%1.%2 ")
689  .arg(m_format.m_edgeType);
690  str += QString("off=%1 pensize=%2 ")
691  .arg(m_format.m_offset)
692  .arg(m_format.m_penSize);
693  str += QString("it=%1 ul=%2 bf=%3 ")
694  .arg(static_cast<int>(m_format.m_italics))
695  .arg(static_cast<int>(m_format.m_underline))
696  .arg(static_cast<int>(m_format.m_boldface));
697  str += QString("font=%1 ").arg(m_format.m_fontTag);
698  str += QString(" text='%1'").arg(m_text);
699  return str;
700 }
701 
702 bool FormattedTextChunk::PreRender(bool isFirst, bool isLast,
703  int &x, int y, int height)
704 {
706  if (!m_textFont)
707  return false;
708  QFontMetrics font(*(m_textFont->GetFace()));
709  // If the chunk starts with whitespace, the leading whitespace
710  // ultimately gets lost due to the text.trimmed() operation in the
711  // MythUISimpleText constructor. To compensate, we manually
712  // indent the chunk accordingly.
713  int count = 0;
714  while (count < m_text.length() && m_text.at(count) == ' ')
715  {
716  ++count;
717  }
718 #if QT_VERSION < QT_VERSION_CHECK(5,11,0)
719  int x_adjust = count * font.width(" ");
720 #else
721  int x_adjust = count * font.horizontalAdvance(" ");
722 #endif
723  int leftPadding = 0;
724  int rightPadding = 0;
725  CalcPadding(isFirst, isLast, leftPadding, rightPadding);
726  // Account for extra padding before the first chunk.
727  if (isFirst)
728  x += leftPadding;
729  QSize chunk_sz = CalcSize();
730  QRect bgrect(x - leftPadding, y,
731  chunk_sz.width() + leftPadding + rightPadding,
732  height);
733  // Don't draw a background behind leading spaces.
734  if (isFirst)
735  bgrect.setLeft(bgrect.left() + x_adjust);
736  m_bgShapeName = QString("subbg%1x%2@%3,%4")
737  .arg(chunk_sz.width()).arg(height).arg(x).arg(y);
738  m_bgShapeRect = bgrect;
739  // Shift to the right to account for leading spaces that
740  // are removed by the MythUISimpleText constructor. Also
741  // add in padding at the end to avoid clipping.
742  m_textName = QString("subtxt%1x%2@%3,%4")
743  .arg(chunk_sz.width()).arg(height).arg(x).arg(y);
744  m_textRect = QRect(x + x_adjust, y,
745  chunk_sz.width() - x_adjust + rightPadding, height);
746 
747  x += chunk_sz.width();
748  return true;
749 }
750 
751 QSize FormattedTextLine::CalcSize(float layoutSpacing) const
752 {
753  int height = 0;
754  int width = 0;
755  int leftPadding = 0;
756  int rightPadding = 0;
757  QList<FormattedTextChunk>::const_iterator it;
758  bool isFirst = true;
759  for (it = chunks.constBegin(); it != chunks.constEnd(); ++it)
760  {
761  bool isLast = (it + 1 == chunks.constEnd());
762  QSize tmp = (*it).CalcSize(layoutSpacing);
763  height = std::max(height, tmp.height());
764  width += tmp.width();
765  (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding);
766  if (it == chunks.constBegin())
767  width += leftPadding;
768  isFirst = false;
769  }
770  return {width + rightPadding, height};
771 }
772 
773 // Normal font height is designed to be 1/20 of safe area height, with
774 // extra blank space between lines to make 17 lines within the safe
775 // area.
776 static const float LINE_SPACING = (20.0 / 17.0);
777 static const float PAD_WIDTH = 0.5;
778 static const float PAD_HEIGHT = 0.04;
779 
780 // Resolves any TBD x_indent and y_indent values in FormattedTextLine
781 // objects. Calculates m_bounds. Prunes most leading and all
782 // trailing whitespace from each line so that displaying with a black
783 // background doesn't look clumsy.
785 {
786  // Calculate dimensions of bounding rectangle
787  int anchor_width = 0;
788  int anchor_height = 0;
789  for (const auto & line : qAsConst(m_lines))
790  {
791  QSize sz = line.CalcSize(LINE_SPACING);
792  anchor_width = std::max(anchor_width, sz.width());
793  anchor_height += sz.height();
794  }
795 
796  // Adjust the anchor point according to actual width and height
797  int anchor_x = m_xAnchor;
798  int anchor_y = m_yAnchor;
799  if (m_xAnchorPoint == 1)
800  anchor_x -= anchor_width / 2;
801  else if (m_xAnchorPoint == 2)
802  anchor_x -= anchor_width;
803  if (m_yAnchorPoint == 1)
804  anchor_y -= anchor_height / 2;
805  else if (m_yAnchorPoint == 2)
806  anchor_y -= anchor_height;
807 
808  // Shift the anchor point back into the safe area if necessary/possible.
809  anchor_y = std::max(0, std::min(anchor_y, m_safeArea.height() - anchor_height));
810  anchor_x = std::max(0, std::min(anchor_x, m_safeArea.width() - anchor_width));
811 
812  m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height);
813 
814  // Fill in missing coordinates
815  int y = anchor_y;
816  // NOLINTNEXTLINE(modernize-loop-convert)
817  for (int i = 0; i < m_lines.size(); i++)
818  {
819  if (m_lines[i].m_xIndent < 0)
820  m_lines[i].m_xIndent = anchor_x;
821  if (m_lines[i].m_yIndent < 0)
822  m_lines[i].m_yIndent = y;
823  y += m_lines[i].CalcSize(LINE_SPACING).height();
824  // Prune leading all-whitespace chunks.
825  while (!m_lines[i].chunks.isEmpty() &&
826  m_lines[i].chunks.first().m_text.trimmed().isEmpty())
827  {
828  m_lines[i].m_xIndent +=
829  m_lines[i].chunks.first().CalcSize().width();
830  m_lines[i].chunks.removeFirst();
831  }
832  // Prune trailing all-whitespace chunks.
833  while (!m_lines[i].chunks.isEmpty() &&
834  m_lines[i].chunks.last().m_text.trimmed().isEmpty())
835  {
836  m_lines[i].chunks.removeLast();
837  }
838  // Trim trailing whitespace from last chunk. (Trimming
839  // leading whitespace from all chunks is handled in the Draw()
840  // routine.)
841  if (!m_lines[i].chunks.isEmpty())
842  {
843  QString *str = &m_lines[i].chunks.last().m_text;
844  int idx = str->length() - 1;
845  while (idx >= 0 && str->at(idx) == ' ')
846  --idx;
847  str->truncate(idx + 1);
848  }
849  }
850 }
851 
853 {
854  // NOLINTNEXTLINE(modernize-loop-convert)
855  for (int i = 0; i < m_lines.size(); i++)
856  {
857  int x = m_lines[i].m_xIndent;
858  int y = m_lines[i].m_yIndent;
859  int height = m_lines[i].CalcSize().height();
860  QList<FormattedTextChunk>::iterator chunk;
861  bool isFirst = true;
862  for (chunk = m_lines[i].chunks.begin();
863  chunk != m_lines[i].chunks.end();
864  ++chunk)
865  {
866  bool isLast = (chunk + 1 == m_lines[i].chunks.end());
867  (*chunk).PreRender(isFirst, isLast, x, y, height);
868  isFirst = false;
869  }
870  }
871 }
872 
873 // Returns true if anything new was drawn, false if not. The caller
874 // should call SubtitleScreen::OptimiseDisplayedArea() if true is
875 // returned.
877 {
878  QList<MythUIType *> textList;
879  QList<MythUIType *> shapeList;
880  for (auto & line : m_lines)
881  {
882  QList<FormattedTextChunk>::const_iterator chunk;
883  for (chunk = line.chunks.constBegin();
884  chunk != line.chunks.constEnd();
885  ++chunk)
886  {
887  MythFontProperties *mythfont =
888  m_subScreen->GetFont((*chunk).m_format);
889  if (!mythfont)
890  continue;
891  // Note: nullptr is passed as the parent argument to the
892  // MythUI constructors so that we can control the drawing
893  // order of the children. In particular, background
894  // shapes should be added/drawn first, and text drawn on
895  // top.
896  if ((*chunk).m_textRect.width() > 0) {
897  auto *text = new SubSimpleText((*chunk).m_text, *mythfont,
898  (*chunk).m_textRect,
899  Qt::AlignLeft|Qt::AlignTop,
900  /*m_subScreen*/nullptr,
901  (*chunk).m_textName, CacheNum(),
902  m_start + m_duration);
903  textList += text;
904  }
905  if ((*chunk).m_bgShapeRect.width() > 0) {
907  GetBackground(/*m_subScreen*/nullptr,
908  (*chunk).m_bgShapeName,
909  m_base, (*chunk).m_format,
910  MythRect((*chunk).m_bgShapeRect), CacheNum(),
912  if (bgshape)
913  {
914  bgshape->SetArea(MythRect((*chunk).m_bgShapeRect));
915  shapeList += bgshape;
916  }
917  }
918  }
919  }
920  while (!shapeList.isEmpty())
921  m_subScreen->AddChild(shapeList.takeFirst());
922  while (!textList.isEmpty())
923  m_subScreen->AddChild(textList.takeFirst());
924 }
925 
926 QStringList FormattedTextSubtitle::ToSRT(void) const
927 {
928  QStringList result;
929  for (const auto & ftl : qAsConst(m_lines))
930  {
931  QString line;
932  if (ftl.m_origX > 0)
933  line.fill(' ', ftl.m_origX);
934  QList<FormattedTextChunk>::const_iterator chunk;
935  for (chunk = ftl.chunks.constBegin();
936  chunk != ftl.chunks.constEnd();
937  ++chunk)
938  {
939  const QString &text = (*chunk).m_text;
940  const CC708CharacterAttribute &attr = (*chunk).m_format;
941  bool isBlank = !attr.m_underline && text.trimmed().isEmpty();
942  if (!isBlank)
943  {
944  if (attr.m_boldface)
945  line += "<b>";
946  if (attr.m_italics)
947  line += "<i>";
948  if (attr.m_underline)
949  line += "<u>";
950  if (attr.GetFGColor() != Qt::white)
951  line += QString("<font color=\"%1\">")
952  .arg(srtColorString(attr.GetFGColor()));
953  }
954  line += text;
955  if (!isBlank)
956  {
957  if (attr.GetFGColor() != Qt::white)
958  line += QString("</font>");
959  if (attr.m_underline)
960  line += "</u>";
961  if (attr.m_italics)
962  line += "</i>";
963  if (attr.m_boldface)
964  line += "</b>";
965  }
966  }
967  if (!line.trimmed().isEmpty())
968  result += line;
969  }
970  return result;
971 }
972 
973 void FormattedTextSubtitleSRT::Init(const QStringList &subs)
974 {
975  // Does a simplistic parsing of HTML tags from the strings.
976  // Nesting is not implemented. Stray whitespace may cause
977  // legitimate tags to be ignored. All other HTML tags are
978  // stripped and ignored.
979  //
980  // <i> - enable italics
981  // </i> - disable italics
982  // <b> - enable boldface
983  // </b> - disable boldface
984  // <u> - enable underline
985  // </u> - disable underline
986  // <font color="#xxyyzz"> - change font color
987  // </font> - reset font color to white
988 
989  int pixelSize = m_safeArea.height() / 20;
990  if (m_subScreen)
991  m_subScreen->SetFontSize(pixelSize);
992  m_xAnchorPoint = 1; // center
993  m_yAnchorPoint = 2; // bottom
994  m_xAnchor = m_safeArea.width() / 2;
995  m_yAnchor = m_safeArea.height();
996 
997  bool isItalic = false;
998  bool isBold = false;
999  bool isUnderline = false;
1000  QColor color(Qt::white);
1001  QRegExp htmlTag("</?.+>");
1002  QString htmlPrefix("<font color=\"");
1003  QString htmlSuffix("\">");
1004  htmlTag.setMinimal(true);
1005  for (const QString& subtitle : qAsConst(subs))
1006  {
1007  FormattedTextLine line;
1008  QString text(subtitle);
1009  while (!text.isEmpty())
1010  {
1011  int pos = text.indexOf(htmlTag);
1012  if (pos != 0) // don't add a zero-length string
1013  {
1014  CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
1015  color);
1016  FormattedTextChunk chunk(text.left(pos), attr, m_subScreen);
1017  line.chunks += chunk;
1018  text = (pos < 0 ? "" : text.mid(pos));
1019  LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk: %1")
1020  .arg(chunk.ToLogString()));
1021  }
1022  if (pos >= 0)
1023  {
1024  int htmlLen = htmlTag.matchedLength();
1025  QString html = text.left(htmlLen).toLower();
1026  text = text.mid(htmlLen);
1027  if (html == "<i>")
1028  isItalic = true;
1029  else if (html == "</i>")
1030  isItalic = false;
1031  else if (html.startsWith(htmlPrefix) &&
1032  html.endsWith(htmlSuffix))
1033  {
1034  int colorLen = html.length() -
1035  (htmlPrefix.length() + htmlSuffix.length());
1036  QString colorString(
1037  html.mid(htmlPrefix.length(), colorLen));
1038  QColor newColor(colorString);
1039  if (newColor.isValid())
1040  {
1041  color = newColor;
1042  }
1043  else
1044  {
1045  LOG(VB_VBI, LOG_INFO,
1046  QString("Ignoring invalid SRT color specification: "
1047  "'%1'").arg(colorString));
1048  }
1049  }
1050  else if (html == "</font>")
1051  color = Qt::white;
1052  else if (html == "<b>")
1053  isBold = true;
1054  else if (html == "</b>")
1055  isBold = false;
1056  else if (html == "<u>")
1057  isUnderline = true;
1058  else if (html == "</u>")
1059  isUnderline = false;
1060  else
1061  {
1062  LOG(VB_VBI, LOG_INFO,
1063  QString("Ignoring unknown SRT formatting: '%1'")
1064  .arg(html));
1065  }
1066 
1067  LOG(VB_VBI, LOG_INFO,
1068  QString("SRT formatting change '%1', "
1069  "new ital=%2 bold=%3 uline=%4 color=%5)")
1070  .arg(html).arg(isItalic).arg(isBold).arg(isUnderline)
1071  .arg(srtColorString(color)));
1072  }
1073  }
1074  m_lines += line;
1075  }
1076 }
1077 
1079 {
1080  int maxWidth = m_safeArea.width();
1081  for (int i = 0; i < m_lines.size(); i++)
1082  {
1083  int width = m_lines[i].CalcSize().width();
1084  // Move entire chunks to the next line as necessary. Leave at
1085  // least one chunk on the current line.
1086  while (width > maxWidth && m_lines[i].chunks.size() > 1)
1087  {
1088  width -= m_lines[i].chunks.back().CalcSize().width();
1089  // Make sure there's a next line to wrap into.
1090  if (m_lines.size() == i + 1)
1091  m_lines += FormattedTextLine(m_lines[i].m_xIndent,
1092  m_lines[i].m_yIndent);
1093  m_lines[i+1].chunks.prepend(m_lines[i].chunks.takeLast());
1094  LOG(VB_VBI, LOG_INFO,
1095  QString("Wrapping chunk to next line: '%1'")
1096  .arg(m_lines[i+1].chunks[0].m_text));
1097  }
1098  // Split the last chunk until width is small enough or until
1099  // no more splits are possible.
1100  bool isSplitPossible = true;
1101  while (width > maxWidth && isSplitPossible)
1102  {
1103  FormattedTextChunk newChunk;
1104  isSplitPossible = m_lines[i].chunks.back().Split(newChunk);
1105  if (isSplitPossible)
1106  {
1107  // Make sure there's a next line to split into.
1108  if (m_lines.size() == i + 1)
1109  m_lines += FormattedTextLine(m_lines[i].m_xIndent,
1110  m_lines[i].m_yIndent);
1111  m_lines[i+1].chunks.prepend(newChunk);
1112  width = m_lines[i].CalcSize().width();
1113  }
1114  }
1115  }
1116 }
1117 
1123 static QString extract_cc608(QString &text, int &color,
1124  bool &isItalic, bool &isUnderline)
1125 {
1126  QString result;
1127 
1128  // Handle an initial control sequence.
1129  if (text.length() >= 1 && text[0] >= 0x7000)
1130  {
1131  int op = text[0].unicode() - 0x7000;
1132  isUnderline = ((op & 0x1) != 0);
1133  switch (op & ~1)
1134  {
1135  case 0x0e:
1136  // color unchanged
1137  isItalic = true;
1138  break;
1139  case 0x1e:
1140  color = op >> 1;
1141  isItalic = true;
1142  break;
1143  case 0x20:
1144  // color unchanged
1145  // italics unchanged
1146  break;
1147  default:
1148  color = (op & 0xf) >> 1;
1149  isItalic = false;
1150  break;
1151  }
1152  text = text.mid(1);
1153  }
1154 
1155  // Copy the string into the result, up to the next control
1156  // character.
1157  int nextControl = text.indexOf(QRegExp("[\\x7000-\\x7fff]"));
1158  if (nextControl < 0)
1159  {
1160  result = text;
1161  text.clear();
1162  }
1163  else
1164  {
1165  result = text.left(nextControl);
1166  text = text.mid(nextControl);
1167  }
1168 
1169  return result;
1170 }
1171 
1172 // Adjusts the Y coordinates to avoid overlap, which could happen as a
1173 // result of a large text zoom factor. Then, if the total height
1174 // exceeds the safe area, compresses each piece of vertical blank
1175 // space proportionally to make it fit.
1177 {
1178  int totalHeight = 0;
1179  int totalSpace = 0;
1180  int firstY = 0;
1181  int prevY = 0;
1182  QVector<int> heights(m_lines.size());
1183  QVector<int> spaceBefore(m_lines.size());
1184  // Calculate totalHeight and totalSpace
1185  for (int i = 0; i < m_lines.size(); i++)
1186  {
1187  m_lines[i].m_yIndent = std::max(m_lines[i].m_yIndent, prevY); // avoid overlap
1188  int y = m_lines[i].m_yIndent;
1189  if (i == 0)
1190  firstY = prevY = y;
1191  int height = m_lines[i].CalcSize().height();
1192  heights[i] = height;
1193  spaceBefore[i] = y - prevY;
1194  totalSpace += (y - prevY);
1195  prevY = y + height;
1196  totalHeight += height;
1197  }
1198  int safeHeight = m_safeArea.height();
1199  int overage = std::min(totalHeight - safeHeight, totalSpace);
1200 
1201  // Recalculate Y coordinates, applying the shrink factor to space
1202  // between each line.
1203  if (overage > 0 && totalSpace > 0)
1204  {
1205  float shrink = (totalSpace - overage) / (float)totalSpace;
1206  prevY = firstY;
1207  for (int i = 0; i < m_lines.size(); i++)
1208  {
1209  m_lines[i].m_yIndent = prevY + spaceBefore[i] * shrink;
1210  prevY = m_lines[i].m_yIndent + heights[i];
1211  }
1212  }
1213 
1214  // Shift Y coordinates back up into the safe area.
1215  int shift = std::min(firstY, std::max(0, prevY - safeHeight));
1216  // NOLINTNEXTLINE(modernize-loop-convert)
1217  for (int i = 0; i < m_lines.size(); i++)
1218  m_lines[i].m_yIndent -= shift;
1219 
1221 }
1222 
1223 void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers)
1224 {
1225  static const std::array<const QColor,8> kClr
1226  {
1227  Qt::white, Qt::green, Qt::blue, Qt::cyan,
1228  Qt::red, Qt::yellow, Qt::magenta, Qt::white,
1229  };
1230 
1231  if (buffers.empty())
1232  return;
1233  auto i = buffers.cbegin();
1234  int xscale = 36;
1235  int yscale = 17;
1236  int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING);
1237  int fontwidth = 0;
1238  int xmid = 0;
1239  int zoom = 100;
1240  if (m_subScreen)
1241  {
1242  zoom = m_subScreen->GetZoom();
1243  m_subScreen->SetFontSize(pixelSize);
1244  CC708CharacterAttribute def_attr(false, false, false, kClr[0]);
1245  QFont *font = m_subScreen->GetFont(def_attr)->GetFace();
1246  QFontMetrics fm(*font);
1247  fontwidth = fm.averageCharWidth();
1248  xmid = m_safeArea.width() / 2;
1249  // Disable centering for zoom factor >= 100%
1250  if (zoom >= 100)
1251  xscale = m_safeArea.width() / fontwidth;
1252  }
1253 
1254  for (; i != buffers.cend(); ++i)
1255  {
1256  CC608Text *cc = (*i);
1257  int color = 0;
1258  bool isItalic = false;
1259  bool isUnderline = false;
1260  const bool isBold = false;
1261  QString text(cc->m_text);
1262 
1263  int orig_x = cc->m_x;
1264  // position as if we use a fixed size font
1265  // - font size already has zoom factor applied
1266 
1267  int x = 0;
1268  if (xmid)
1269  {
1270  // center horizontally
1271  x = xmid + (orig_x - xscale / 2) * fontwidth;
1272  }
1273  else
1274  {
1275  // fallback
1276  x = (orig_x + 3) * m_safeArea.width() / xscale;
1277  }
1278 
1279  int orig_y = cc->m_y;
1280  int y = 0;
1281  if (orig_y < yscale / 2)
1282  {
1283  // top half -- anchor up
1284  y = (orig_y * m_safeArea.height() * zoom / (yscale * 100));
1285  }
1286  else
1287  {
1288  // bottom half -- anchor down
1289  y = m_safeArea.height() -
1290  ((yscale - orig_y - 0.5) * m_safeArea.height() * zoom /
1291  (yscale * 100));
1292  }
1293 
1294  FormattedTextLine line(x, y, orig_x, orig_y);
1295  while (!text.isNull())
1296  {
1297  QString captionText =
1298  extract_cc608(text, color, isItalic, isUnderline);
1299  CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
1300  kClr[std::min(std::max(0, color), 7)]);
1301  FormattedTextChunk chunk(captionText, attr, m_subScreen);
1302  line.chunks += chunk;
1303  LOG(VB_VBI, LOG_INFO,
1304  QString("Adding cc608 chunk (%1,%2): %3")
1305  .arg(cc->m_x).arg(cc->m_y).arg(chunk.ToLogString()));
1306  }
1307  m_lines += line;
1308  }
1309 }
1310 
1312 {
1313  // Draw the window background after calculating bounding rectangle
1314  // in Layout()
1315  if (m_bgFillAlpha) // TODO border?
1316  {
1317  QBrush fill(m_bgFillColor, Qt::SolidPattern);
1318  auto *shape = new SubShape(m_subScreen, QString("cc708bg%1").arg(m_num),
1320  shape->SetFillBrush(fill);
1321  shape->SetArea(MythRect(m_bounds));
1322  }
1323  // The background is drawn first so that it appears behind
1324  // everything else.
1326 }
1327 
1329  const vector<CC708String*> &list,
1330  float aspect)
1331 {
1332  LOG(VB_VBI, LOG_DEBUG,LOC +
1333  QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, "
1334  "relative %5")
1336  .arg(win.m_anchor_vertical).arg(win.m_relative_pos));
1337  int pixelSize = m_safeArea.height() / 20;
1338  if (m_subScreen)
1339  m_subScreen->SetFontSize(pixelSize);
1340 
1341  float xrange = win.m_relative_pos ? 100.0F :
1342  (aspect > 1.4F) ? 210.0F : 160.0F;
1343  float yrange = win.m_relative_pos ? 100.0F : 75.0F;
1344  float xmult = (float)m_safeArea.width() / xrange;
1345  float ymult = (float)m_safeArea.height() / yrange;
1346  uint anchor_x = (uint)(xmult * (float)win.m_anchor_horizontal);
1347  uint anchor_y = (uint)(ymult * (float)win.m_anchor_vertical);
1348  m_xAnchorPoint = win.m_anchor_point % 3;
1349  m_yAnchorPoint = win.m_anchor_point / 3;
1350  m_xAnchor = anchor_x;
1351  m_yAnchor = anchor_y;
1352 
1353  for (auto *str708 : list)
1354  {
1355  if (str708->m_y >= (uint)m_lines.size())
1356  m_lines.resize(str708->m_y + 1);
1357  FormattedTextChunk chunk(str708->m_str, str708->m_attr, m_subScreen);
1358  m_lines[str708->m_y].chunks += chunk;
1359  LOG(VB_VBI, LOG_INFO, QString("Adding cc708 chunk: win %1 row %2: %3")
1360  .arg(m_num).arg(str708->m_y).arg(chunk.ToLogString()));
1361  }
1362 }
1363 
1365 
1367  const QString &Name, int FontStretch)
1368  : MythScreenType(static_cast<MythScreenType*>(nullptr), Name),
1369  m_player(Player),
1370  m_fontStretch(FontStretch),
1371  m_format(new SubtitleFormat)
1372 {
1373  m_painter = Painter;
1374  m_removeHTML.setMinimal(true);
1375 }
1376 
1378 {
1380  delete m_format;
1381 #ifdef USING_LIBASS
1383 #endif
1384 }
1385 
1386 void SubtitleScreen::EnableSubtitles(int type, bool forced_only)
1387 {
1388  int prevType = m_subtitleType;
1389  m_subtitleType = type;
1390 
1391  if (forced_only)
1392  {
1393  if (prevType == kDisplayNone)
1394  {
1396  SetVisible(true);
1397  SetArea(MythRect());
1398  }
1399  }
1400  else
1401  {
1402  if (m_subreader)
1403  {
1407  }
1408  if (m_cc608reader)
1410  if (m_cc708reader)
1414  SetArea(MythRect());
1415  }
1416  if (!forced_only || m_family.isEmpty()) {
1417  switch (m_subtitleType)
1418  {
1419  case kDisplayTextSubtitle:
1422  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1423  break;
1424  case kDisplayCC608:
1426  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1427  break;
1428  case kDisplayCC708:
1430  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1431  break;
1432  case kDisplayAVSubtitle:
1434  m_textFontZoom = gCoreContext->GetNumSetting("OSDAVSubZoom", 100);
1435  break;
1436  }
1437  }
1442 }
1443 
1445 {
1447  return;
1449  SetVisible(false);
1450  SetArea(MythRect());
1451 }
1452 
1454 {
1457 #ifdef USING_LIBASS
1458  if (m_assTrack)
1459  ass_flush_events(m_assTrack);
1460 #endif
1461 }
1462 
1464 {
1470  m_cc608reader->ClearBuffers(true, true);
1473 }
1474 
1476 {
1479 }
1480 
1481 void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
1482 {
1483  if (!dvdButton || !m_player)
1484  return;
1485 
1487  if (!vo)
1488  return;
1489 
1492 
1493  float tmp = 0.0;
1494  QRect dummy;
1495  vo->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
1496 
1497  AVSubtitleRect *hl_button = dvdButton->rects[0];
1498  uint h = hl_button->h;
1499  uint w = hl_button->w;
1500  QRect rect = QRect(hl_button->x, hl_button->y, w, h);
1501  QImage bg_image(hl_button->data[0], w, h, w, QImage::Format_Indexed8);
1502  auto *bgpalette = (uint32_t *)(hl_button->data[1]);
1503 
1504  QVector<uint32_t> bg_palette(4);
1505  for (int i = 0; i < 4; i++)
1506  bg_palette[i] = bgpalette[i];
1507  bg_image.setColorTable(bg_palette);
1508 
1509  // copy button region of background image
1510  const QRect fg_rect(buttonPos.translated(-hl_button->x, -hl_button->y));
1511  QImage fg_image = bg_image.copy(fg_rect);
1512  QVector<uint32_t> fg_palette(4);
1513  auto *fgpalette = (uint32_t *)(dvdButton->rects[1]->data[1]);
1514  if (fgpalette)
1515  {
1516  for (int i = 0; i < 4; i++)
1517  fg_palette[i] = fgpalette[i];
1518  fg_image.setColorTable(fg_palette);
1519  }
1520 
1521  bg_image = bg_image.convertToFormat(QImage::Format_ARGB32);
1522  fg_image = fg_image.convertToFormat(QImage::Format_ARGB32);
1523 
1524  // set pixel of highlight area to highlight color
1525  for (int x=fg_rect.x(); x < fg_rect.x()+fg_rect.width(); ++x)
1526  {
1527  if ((x < 0) || (x > hl_button->w))
1528  continue;
1529  for (int y=fg_rect.y(); y < fg_rect.y()+fg_rect.height(); ++y)
1530  {
1531  if ((y < 0) || (y > hl_button->h))
1532  continue;
1533  bg_image.setPixel(x, y, fg_image.pixel(x-fg_rect.x(),y-fg_rect.y()));
1534  }
1535  }
1536 
1537  AddScaledImage(bg_image, rect);
1538 }
1539 
1540 void SubtitleScreen::SetZoom(int percent)
1541 {
1542  m_textFontZoom = percent;
1543  if (m_family == kSubFamilyAV)
1544  gCoreContext->SaveSetting("OSDAVSubZoom", percent);
1545  else
1546  gCoreContext->SaveSetting("OSDCC708TextZoom", percent);
1547 }
1548 
1550 {
1551  return m_textFontZoom;
1552 }
1553 
1555 {
1556  m_textFontDelayMs = ms;
1557 }
1558 
1560 {
1561  return m_textFontDelayMs;
1562 }
1563 
1565 {
1566  QList<MythUIType *> list = m_childrenList;
1567  QList<MythUIType *>::iterator it;
1568  for (it = list.begin(); it != list.end(); ++it)
1569  {
1570  MythUIType *child = *it;
1571  auto *wrapper = dynamic_cast<SubWrapper *>(child);
1572  if (wrapper)
1573  {
1574  int whichImageCache = wrapper->GetWhichImageCache();
1575  if (whichImageCache != -1 && (mask & (1UL << whichImageCache)))
1576  {
1578  DeleteChild(child);
1579  }
1580  }
1581  }
1582 }
1583 
1584 // SetElementAdded() should be called after a new element is added to
1585 // the subtitle screen.
1587 {
1588  m_refreshModified = true;
1589 }
1590 
1591 // SetElementResized() should be called after a subtitle screen
1592 // element's size is changed.
1594 {
1595  SetElementAdded();
1596 }
1597 
1598 // SetElementAdded() should be called *before* an element is deleted
1599 // from the subtitle screen.
1601 {
1602  if (!m_refreshDeleted)
1603  SetRedraw();
1604  m_refreshDeleted = true;
1605 }
1606 
1607 // The QFontMetrics class does not account for the MythFontProperties
1608 // shadow and offset properties. This method calculates the
1609 // additional padding to the right and below that is needed for proper
1610 // bounding box computation.
1612 {
1613  QColor color;
1614  int alpha = 0;
1615  int outlineSize = 0;
1616  int shadowWidth = 0;
1617  int shadowHeight = 0;
1618  if (mythfont->hasOutline())
1619  {
1620  mythfont->GetOutline(color, outlineSize, alpha);
1621  MythPoint outline(outlineSize, outlineSize);
1622  outline.NormPoint();
1623  outlineSize = outline.x();
1624  }
1625  if (mythfont->hasShadow())
1626  {
1627  MythPoint shadowOffset;
1628  mythfont->GetShadow(shadowOffset, color, alpha);
1629  shadowOffset.NormPoint();
1630  shadowWidth = abs(shadowOffset.x());
1631  shadowHeight = abs(shadowOffset.y());
1632  // Shadow and outline overlap, so don't just add them.
1633  shadowWidth = std::max(shadowWidth, outlineSize);
1634  shadowHeight = std::max(shadowHeight, outlineSize);
1635  }
1636  return {shadowWidth + outlineSize, shadowHeight + outlineSize};
1637 }
1638 
1639 QSize SubtitleScreen::CalcTextSize(const QString &text,
1640  const CC708CharacterAttribute &format,
1641  float layoutSpacing) const
1642 {
1643  MythFontProperties *mythfont = GetFont(format);
1644  QFont *font = mythfont->GetFace();
1645  QFontMetrics fm(*font);
1646 #if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1647  int width = fm.width(text);
1648 #else
1649  int width = fm.horizontalAdvance(text);
1650 #endif
1651  int height = fm.height() * (1 + PAD_HEIGHT);
1652  if (layoutSpacing > 0 && !text.trimmed().isEmpty())
1653  height = std::max(height, (int)(font->pixelSize() * layoutSpacing));
1654  height += CalcShadowOffsetPadding(mythfont).height();
1655  return {width, height};
1656 }
1657 
1658 // Padding calculation is different depending on whether the padding
1659 // is on the left side or the right side of the text. Padding on the
1660 // right needs to add the shadow and offset padding.
1662  bool isFirst, bool isLast,
1663  int &left, int &right) const
1664 {
1665  MythFontProperties *mythfont = GetFont(format);
1666  QFont *font = mythfont->GetFace();
1667  QFontMetrics fm(*font);
1668  int basicPadding = fm.maxWidth() * PAD_WIDTH;
1669  left = isFirst ? basicPadding : 0;
1670  right = CalcShadowOffsetPadding(mythfont).width() +
1671  (isLast ? basicPadding : 0);
1672 }
1673 
1676 {
1677  return m_format->GetFont(m_family, attr, m_fontSize,
1679 }
1680 
1682 {
1683  SubtitleFormat format;
1684  CC708CharacterAttribute attr(false, false, false, Qt::white);
1685  MythFontProperties *mythfont =
1686  format.GetFont(kSubFamilyTeletext, attr,
1687  /*pixelsize*/20, /*zoom*/100, /*stretch*/100);
1688  return mythfont->face().family();
1689 }
1690 
1692 {
1693  SubtitleFormat format;
1694  return format.GetBackgroundAlpha(kSubFamilyTeletext);
1695 }
1696 
1698 {
1699  if (!m_player)
1700  return false;
1701 
1705  if (!m_subreader)
1706  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get subtitle reader.");
1707  if (!m_cc608reader)
1708  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get CEA-608 reader.");
1709  if (!m_cc708reader)
1710  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get CEA-708 reader.");
1711 
1712  return true;
1713 }
1714 
1716 {
1717  QList<MythUIType *>::iterator it;
1718  QList<MythUIType *>::iterator itNext;
1719 
1720  MythVideoOutput *videoOut = m_player->GetVideoOutput();
1721  MythVideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : nullptr;
1722  long long now = currentFrame ? currentFrame->m_timecode : LLONG_MAX;
1723  bool needRescale = (m_textFontZoom != m_textFontZoomPrev);
1724 
1725  for (it = m_childrenList.begin(); it != m_childrenList.end(); it = itNext)
1726  {
1727  itNext = it + 1;
1728  MythUIType *child = *it;
1729  auto *wrapper = dynamic_cast<SubWrapper *>(child);
1730  if (!wrapper)
1731  continue;
1732 
1733  // Expire the subtitle object if needed.
1734  long long expireTime = wrapper->GetExpireTime();
1735  if (expireTime > 0 && expireTime < now)
1736  {
1737  DeleteChild(child);
1739  continue;
1740  }
1741 
1742  // Rescale the AV subtitle image if the zoom changed.
1743  if (expireTime > 0 && needRescale)
1744  {
1745  auto *image = dynamic_cast<SubImage *>(child);
1746  if (image)
1747  {
1748  double factor = m_textFontZoom / (double)m_textFontZoomPrev;
1749  QSize size = image->GetImage()->size();
1750  size *= factor;
1751  image->GetImage()->Resize(size);
1753  }
1754  }
1755  }
1756 
1757  DisplayAVSubtitles(); // allow forced subtitles to work
1758 
1761  else if (kDisplayCC608 == m_subtitleType)
1763  else if (kDisplayCC708 == m_subtitleType)
1767  while (!m_qInited.isEmpty())
1768  {
1769  FormattedTextSubtitle *fsub = m_qInited.takeFirst();
1770  fsub->WrapLongLines();
1771  fsub->Layout();
1772  fsub->PreRender();
1773  fsub->Draw();
1774  delete fsub;
1775  SetElementAdded();
1776  }
1777 
1785 }
1786 
1788 {
1789  m_refreshModified = false;
1790  m_refreshDeleted = false;
1791 }
1792 
1794 {
1795  if (!m_refreshModified)
1796  return;
1797 
1798  QRegion visible;
1799  QListIterator<MythUIType *> i(m_childrenList);
1800  while (i.hasNext())
1801  {
1802  MythUIType *img = i.next();
1803  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1804  if (wrapper && img->IsVisible())
1805  visible = visible.united(wrapper->GetOrigArea());
1806  }
1807 
1808  if (visible.isEmpty())
1809  return;
1810 
1811  QRect bounding = visible.boundingRect();
1812  bounding = bounding.translated(m_safeArea.topLeft());
1813  bounding = m_safeArea.intersected(bounding);
1814  int left = m_safeArea.left() - bounding.left();
1815  int top = m_safeArea.top() - bounding.top();
1816  SetArea(MythRect(bounding));
1817 
1818  i.toFront();
1819  while (i.hasNext())
1820  {
1821  MythUIType *img = i.next();
1822  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1823  if (wrapper && img->IsVisible())
1824  img->SetArea(MythRect(wrapper->GetOrigArea().translated(left, top)));
1825  }
1826 }
1827 
1829 {
1830  if (!m_player || !m_subreader)
1831  return;
1832 
1834  QMutexLocker lock(&(subs->m_lock));
1835  if (subs->m_buffers.empty() && (kDisplayAVSubtitle != m_subtitleType))
1836  return;
1837 
1838  MythVideoOutput *videoOut = m_player->GetVideoOutput();
1839  MythVideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : nullptr;
1840 
1841  if (!currentFrame || !videoOut)
1842  return;
1843 
1844  float tmp = 0.0;
1845  QRect dummy;
1846  videoOut->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
1847 
1848  while (!subs->m_buffers.empty())
1849  {
1850  AVSubtitle subtitle = subs->m_buffers.front();
1851  if (subtitle.start_display_time > currentFrame->m_timecode)
1852  break;
1853 
1854  long long displayfor = subtitle.end_display_time -
1855  subtitle.start_display_time;
1856  if (displayfor == 0)
1857  displayfor = 60000;
1858  displayfor = (displayfor < 50) ? 50 : displayfor;
1859  long long late = currentFrame->m_timecode -
1860  subtitle.start_display_time;
1861 
1863  subs->m_buffers.pop_front();
1864  for (std::size_t i = 0; i < subtitle.num_rects; ++i)
1865  {
1866  AVSubtitleRect* rect = subtitle.rects[i];
1867 
1868  bool displaysub = true;
1869  if (!subs->m_buffers.empty() &&
1870  subs->m_buffers.front().end_display_time <
1871  currentFrame->m_timecode)
1872  {
1873  displaysub = false;
1874  }
1875 
1876  if (displaysub && rect->type == SUBTITLE_BITMAP)
1877  {
1878  QRect display(rect->display_x, rect->display_y,
1879  rect->display_w, rect->display_h);
1880 
1881  // XSUB and some DVD/DVB subs are based on the original video
1882  // size before the video was converted. We need to guess the
1883  // original size and allow for the difference
1884 
1885  int right = rect->x + rect->w;
1886  int bottom = rect->y + rect->h;
1887  if (subs->m_fixPosition || (currentFrame->m_height < bottom) ||
1888  (currentFrame->m_width < right) ||
1889  !display.width() || !display.height())
1890  {
1891  int sd_height = 576;
1892  if ((m_player->GetFrameRate() > 26.0F ||
1893  m_player->GetFrameRate() < 24.0F) && bottom <= 480)
1894  sd_height = 480;
1895  int height = ((currentFrame->m_height <= sd_height) &&
1896  (bottom <= sd_height)) ? sd_height :
1897  ((currentFrame->m_height <= 720) && bottom <= 720)
1898  ? 720 : 1080;
1899  int width = ((currentFrame->m_width <= 720) &&
1900  (right <= 720)) ? 720 :
1901  ((currentFrame->m_width <= 1280) &&
1902  (right <= 1280)) ? 1280 : 1920;
1903  display = QRect(0, 0, width, height);
1904  }
1905 
1906  // split into upper/lower to allow zooming
1907  QRect bbox;
1908  int uh = display.height() / 2 - rect->y;
1909  long long displayuntil = currentFrame->m_timecode + displayfor;
1910  if (uh > 0)
1911  {
1912  bbox = QRect(0, 0, rect->w, uh);
1913  uh = DisplayScaledAVSubtitles(rect, bbox, true, display,
1914  subtitle.forced,
1915  QString("avsub%1t").arg(i),
1916  displayuntil, late);
1917  }
1918  else
1919  uh = 0;
1920  int lh = rect->h - uh;
1921  if (lh > 0)
1922  {
1923  bbox = QRect(0, uh, rect->w, lh);
1924  DisplayScaledAVSubtitles(rect, bbox, false, display,
1925  subtitle.forced,
1926  QString("avsub%1b").arg(i),
1927  displayuntil, late);
1928  }
1929  }
1930 #ifdef USING_LIBASS
1931  else if (displaysub && rect->type == SUBTITLE_ASS)
1932  {
1934  AddAssEvent(rect->ass);
1935  }
1936 #endif
1937  }
1939  }
1940 #ifdef USING_LIBASS
1941  RenderAssTrack(currentFrame->m_timecode);
1942 #endif
1943 }
1944 
1945 int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect,
1946  QRect &bbox, bool top,
1947  QRect &display, int forced,
1948  const QString& imagename,
1949  long long displayuntil,
1950  long long late)
1951 {
1952  // split image vertically if it spans middle of display
1953  // - split point is empty line nearest the middle
1954  // crop image to reduce scaling time
1955  bool prev_empty = false;
1956 
1957  // initialize to opposite edges
1958  int xmin = bbox.right();
1959  int xmax = bbox.left();
1960  int ymin = bbox.bottom();
1961  int ymax = bbox.top();
1962  int ylast = bbox.top();
1963  int ysplit = bbox.bottom();
1964 
1965  // find bounds of active image
1966  for (int y = bbox.top(); y <= bbox.bottom(); ++y)
1967  {
1968  if (y >= rect->h)
1969  {
1970  // end of image
1971  if (!prev_empty)
1972  ylast = y;
1973  break;
1974  }
1975 
1976  bool empty = true;
1977  for (int x = bbox.left(); x <= bbox.right(); ++x)
1978  {
1979  const uint8_t color =
1980  rect->data[0][y * rect->linesize[0] + x];
1981  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
1982  if (pixel & 0xff000000)
1983  {
1984  empty = false;
1985  if (x < xmin)
1986  xmin = x;
1987  if (x > xmax)
1988  xmax = x;
1989  }
1990  }
1991 
1992  if (!empty)
1993  {
1994  if (y < ymin)
1995  ymin = y;
1996  if (y > ymax)
1997  ymax = y;
1998  }
1999  else if (!prev_empty)
2000  {
2001  // remember uppermost empty line
2002  ylast = y;
2003  }
2004  prev_empty = empty;
2005  }
2006 
2007  if (ymax <= ymin)
2008  return 0;
2009 
2010  if (top)
2011  {
2012  if (ylast < ymin)
2013  // no empty lines
2014  return 0;
2015 
2016  if (ymax == bbox.bottom())
2017  {
2018  ymax = ylast;
2019  ysplit = ylast;
2020  }
2021  }
2022 
2023  // set new bounds
2024  bbox.setLeft(xmin);
2025  bbox.setRight(xmax);
2026  bbox.setTop(ymin);
2027  bbox.setBottom(ymax);
2028 
2029  // copy active region
2030  // AVSubtitleRect's image data's not guaranteed to be 4 byte
2031  // aligned.
2032 
2033  QRect orig_rect(bbox.left(), bbox.top(), bbox.width(), bbox.height());
2034 
2035  QImage qImage(bbox.width(), bbox.height(), QImage::Format_ARGB32);
2036  for (int y = 0; y < bbox.height(); ++y)
2037  {
2038  int ysrc = y + bbox.top();
2039  for (int x = 0; x < bbox.width(); ++x)
2040  {
2041  int xsrc = x + bbox.left();
2042  const uint8_t color =
2043  rect->data[0][ysrc * rect->linesize[0] + xsrc];
2044  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
2045  qImage.setPixel(x, y, pixel);
2046  }
2047  }
2048 
2049  // translate to absolute coordinates
2050  bbox.translate(rect->x, rect->y);
2051 
2052  // scale and move according to zoom factor
2053  bbox.setWidth(bbox.width() * m_textFontZoom / 100);
2054  bbox.setHeight(bbox.height() * m_textFontZoom / 100);
2055 
2056  MythVideoOutput *videoOut = m_player->GetVideoOutput();
2057  QRect scaled = videoOut->GetImageRect(bbox, &display);
2058 
2059  if (scaled.size() != orig_rect.size())
2060  qImage = qImage.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2061 
2062  int hsize = m_safeArea.width();
2063  int vsize = m_safeArea.height();
2064 
2065  scaled.moveLeft(((100 - m_textFontZoom) * hsize / 2 + m_textFontZoom * scaled.left()) / 100);
2066  if (top)
2067  {
2068  // anchor up
2069  scaled.moveTop(scaled.top() * m_textFontZoom / 100);
2070  }
2071  else
2072  {
2073  // anchor down
2074  scaled.moveTop(((100 - m_textFontZoom) * vsize + m_textFontZoom * scaled.top()) / 100);
2075  }
2076 
2077  MythImage* image = m_painter->GetFormatImage();
2078  SubImage *uiimage = nullptr;
2079 
2080  if (image)
2081  {
2082  image->Assign(qImage);
2083  uiimage = new SubImage(this, imagename, MythRect(scaled), displayuntil);
2084  if (uiimage)
2085  {
2086  uiimage->SetImage(image);
2087  uiimage->SetArea(MythRect(scaled));
2088  SetElementAdded();
2089  }
2090  image->DecrRef();
2091  image = nullptr;
2092  }
2093 
2094  if (uiimage)
2095  {
2096  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display %1AV sub until %2ms")
2097  .arg(forced ? "FORCED " : "").arg(displayuntil));
2098  if (late > 50)
2099  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sub was %1ms late").arg(late));
2100  }
2101 
2102  return (ysplit + 1);
2103 }
2104 
2106 {
2107  if (!m_player || !m_subreader)
2108  return;
2109 
2110  bool changed = (m_textFontZoom != m_textFontZoomPrev);
2111  changed |= (m_textFontDelayMs != m_textFontDelayMsPrev);
2115  if (!vo)
2116  return;
2117  m_safeArea = vo->GetSafeRect();
2118 
2119  MythVideoFrame *currentFrame = vo->GetLastShownFrame();
2120  if (!currentFrame)
2121  return;
2122 
2124  subs->Lock();
2125  uint64_t playPos = 0;
2126  int playPosAdj = m_textFontDelayMs;
2127  if (subs->IsFrameBasedTiming())
2128  {
2129  // frame based subtitles get out of synch after running mythcommflag
2130  // for the file, i.e., the following number is wrong and does not
2131  // match the subtitle frame numbers:
2132  playPos = currentFrame->m_frameNumber;
2133  playPosAdj /= m_player->GetFrameRate();
2134  }
2135  else
2136  {
2137  // Use timecodes for time based SRT subtitles. Feeding this into
2138  // NormalizeVideoTimecode() should adjust for non-zero start times
2139  // and wraps. For MPEG, wraps will occur just once every 26.5 hours
2140  // and other formats less frequently so this should be sufficient.
2141  // Note: timecodes should now always be valid even in the case
2142  // when a frame doesn't have a valid timestamp. If an exception is
2143  // found where this is not true then we need to use the frameNumber
2144  // when timecode is not defined by uncommenting the following lines.
2145  //if (currentFrame->timecode == 0)
2146  // playPos = (uint64_t)
2147  // ((currentFrame->frameNumber / video_frame_rate) * 1000);
2148  //else
2149  playPos = m_player->GetDecoder()->NormalizeVideoTimecode(currentFrame->m_timecode);
2150  }
2151  playPos -= playPosAdj;
2152  if (playPos != 0)
2153  changed |= subs->HasSubtitleChanged(playPos);
2154  if (!changed)
2155  {
2156  subs->Unlock();
2157  return;
2158  }
2159 
2162 
2163  if (playPos == 0)
2164  {
2165  subs->Unlock();
2166  return;
2167  }
2168 
2169  QStringList rawsubs = subs->GetSubtitles(playPos);
2170  if (rawsubs.empty())
2171  {
2172  subs->Unlock();
2173  return;
2174  }
2175 
2176  subs->Unlock();
2177  DrawTextSubtitles(rawsubs, 0, 0);
2178 }
2179 
2181 {
2182  if (!m_player || !m_subreader)
2183  return;
2184 
2185  uint64_t duration = 0;
2186  QStringList subs = m_subreader->GetRawTextSubtitles(duration);
2187  if (subs.empty())
2188  return;
2189 
2191  if (!vo)
2192  return;
2193 
2194  MythVideoFrame *currentFrame = vo->GetLastShownFrame();
2195  if (!currentFrame)
2196  return;
2197 
2198  m_safeArea = vo->GetSafeRect();
2199 
2200  // delete old subs that may still be on screen
2203  DrawTextSubtitles(subs, currentFrame->m_timecode, duration);
2204 }
2205 
2206 void SubtitleScreen::DrawTextSubtitles(const QStringList &subs,
2207  uint64_t start, uint64_t duration)
2208 {
2209  auto *fsub = new FormattedTextSubtitleSRT(m_family, m_safeArea, start,
2210  duration, this, subs);
2211  m_qInited.append(fsub);
2212 }
2213 
2215 {
2216  if (!m_cc608reader)
2217  return;
2218 
2219  bool changed = (m_textFontZoom != m_textFontZoomPrev);
2220 
2221  if (!m_player || !m_player->GetVideoOutput())
2222  return;
2224 
2225  CC608Buffer* textlist = m_cc608reader->GetOutputText(changed);
2226  if (!changed)
2227  return;
2228 
2231 
2232  if (!textlist)
2233  return;
2234 
2235  QMutexLocker locker(&textlist->m_lock);
2236 
2237  if (textlist->m_buffers.empty())
2238  return;
2239 
2240  auto *fsub = new FormattedTextSubtitle608(textlist->m_buffers, m_family,
2241  m_safeArea, this/*, m_textFontZoom*/);
2242  m_qInited.append(fsub);
2243 }
2244 
2246 {
2248  return;
2249 
2250  CC708Service *cc708service = m_cc708reader->GetCurrentService();
2251  float video_aspect = m_player->GetVideoAspect();
2252  QRect oldsafe = m_safeArea;
2254  bool changed = (oldsafe != m_safeArea || m_textFontZoom != m_textFontZoomPrev);
2255  if (changed)
2256  {
2257  for (auto & window : cc708service->m_windows)
2258  window.SetChanged();
2259  }
2260 
2261  uint64_t clearMask = 0;
2262  QList<FormattedTextSubtitle *> addList;
2263  for (int i = 0; i < k708MaxWindows; i++)
2264  {
2265  CC708Window &win = cc708service->m_windows[i];
2266  if (win.GetExists() && win.GetVisible() && !win.GetChanged())
2267  continue;
2268  if (!win.GetChanged())
2269  continue;
2270 
2271  clearMask |= (1UL << i);
2272  win.ResetChanged();
2273  if (!win.GetExists() || !win.GetVisible())
2274  continue;
2275 
2276  QMutexLocker locker(&win.m_lock);
2277  vector<CC708String*> list = win.GetStrings();
2278  if (!list.empty())
2279  {
2280  auto *fsub = new FormattedTextSubtitle708(win, i, list, m_family,
2281  m_safeArea, this, video_aspect);
2282  addList.append(fsub);
2283  }
2285  }
2286  if (clearMask)
2287  {
2288  Clear708Cache(clearMask);
2289  }
2290  if (!addList.empty())
2291  m_qInited.append(addList);
2292 }
2293 
2294 void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos)
2295 {
2297  if (!vo)
2298  return;
2299 
2300  QRect scaled = vo->GetImageRect(pos);
2301  if (scaled.size() != pos.size())
2302  {
2303  img = img.scaled(scaled.width(), scaled.height(),
2304  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2305  }
2306 
2307  MythImage* image = m_painter->GetFormatImage();
2308  if (image)
2309  {
2310  image->Assign(img);
2311  MythUIImage *uiimage = new SubImage(this, "dvd_button", MythRect(scaled), 0);
2312  if (uiimage)
2313  {
2314  uiimage->SetImage(image);
2315  uiimage->SetArea(MythRect(scaled));
2316  SetElementAdded();
2317  }
2318  image->DecrRef();
2319  }
2320 }
2321 
2322 #ifdef USING_LIBASS
2323 static void myth_libass_log(int level, const char *fmt, va_list vl, void */*ctx*/)
2324 {
2325  uint64_t verbose_mask = VB_GENERAL;
2326  LogLevel_t verbose_level = LOG_INFO;
2327 
2328  switch (level)
2329  {
2330  case 0: //MSGL_FATAL
2331  verbose_level = LOG_EMERG;
2332  break;
2333  case 1: //MSGL_ERR
2334  verbose_level = LOG_ERR;
2335  break;
2336  case 2: //MSGL_WARN
2337  verbose_level = LOG_WARNING;
2338  break;
2339  case 4: //MSGL_INFO
2340  verbose_level = LOG_INFO;
2341  break;
2342  case 6: //MSGL_V
2343  case 7: //MSGL_DBG2
2344  verbose_level = LOG_DEBUG;
2345  break;
2346  default:
2347  return;
2348  }
2349 
2350  if (!VERBOSE_LEVEL_CHECK(verbose_mask, verbose_level))
2351  return;
2352 
2353  static QMutex s_stringLock;
2354  s_stringLock.lock();
2355 
2356  QString str = QString::vasprintf(fmt, vl);
2357  LOG(verbose_mask, verbose_level, QString("libass: %1").arg(str));
2358  s_stringLock.unlock();
2359 }
2360 
2362 {
2363  if (m_assLibrary && m_assRenderer)
2364  return true;
2365 
2366  if (!m_assLibrary)
2367  {
2368  m_assLibrary = ass_library_init();
2369  if (!m_assLibrary)
2370  return false;
2371 
2372  ass_set_message_cb(m_assLibrary, myth_libass_log, nullptr);
2373  ass_set_extract_fonts(m_assLibrary, static_cast<int>(true));
2374  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass object.");
2375  }
2376 
2377  LoadAssFonts();
2378 
2379  if (!m_assRenderer)
2380  {
2381  m_assRenderer = ass_renderer_init(m_assLibrary);
2382  if (!m_assRenderer)
2383  return false;
2384 
2385 #ifdef Q_OS_ANDROID
2386  // fontconfig doesn't yet work for us on Android. For the
2387  // time being, more explicitly set a font we know should
2388  // exist. This was adapted from VLC master as of 2019-01-21.
2389  const char *psz_font = "/system/fonts/DroidSans.ttf";
2390  const char *psz_font_family = "Droid Sans";
2391 #else
2392  const char *psz_font = nullptr;
2393  const char *psz_font_family = "sans-serif";
2394 #endif
2395  ass_set_fonts(m_assRenderer, psz_font, psz_font_family, 1, nullptr, 1);
2396  ass_set_hinting(m_assRenderer, ASS_HINTING_LIGHT);
2397  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass renderer.");
2398  }
2399 
2400  return true;
2401 }
2402 
2404 {
2405  if (!m_assLibrary || !m_player)
2406  return;
2407 
2409  if (m_assFontCount == count)
2410  return;
2411 
2412  ass_clear_fonts(m_assLibrary);
2413  m_assFontCount = 0;
2414 
2415  // TODO these need checking and/or reinitialising after a stream change
2416  for (uint i = 0; i < count; ++i)
2417  {
2418  QByteArray filename;
2419  QByteArray font;
2421  ass_add_font(m_assLibrary, filename.data(), font.data(), font.size());
2422  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Retrieved font '%1'")
2423  .arg(filename.constData()));
2424  m_assFontCount++;
2425  }
2426 }
2427 
2429 {
2430  CleanupAssTrack();
2431 
2432  if (m_assRenderer)
2433  ass_renderer_done(m_assRenderer);
2434  m_assRenderer = nullptr;
2435 
2436  if (m_assLibrary)
2437  {
2438  ass_clear_fonts(m_assLibrary);
2439  m_assFontCount = 0;
2440  ass_library_done(m_assLibrary);
2441  }
2442  m_assLibrary = nullptr;
2443 }
2444 
2446 {
2447  if (!InitialiseAssLibrary() || !m_player)
2448  return;
2449 
2450  if (tracknum == m_assTrackNum && m_assTrack)
2451  return;
2452 
2453  LoadAssFonts();
2454  CleanupAssTrack();
2455  m_assTrack = ass_new_track(m_assLibrary);
2456  m_assTrackNum = tracknum;
2457 
2458  QByteArray header = m_player->GetDecoder()->GetSubHeader(tracknum);
2459  if (!header.isNull())
2460  ass_process_codec_private(m_assTrack, header.data(), header.size());
2461 
2464 }
2465 
2467 {
2468  if (m_assTrack)
2469  ass_free_track(m_assTrack);
2470  m_assTrack = nullptr;
2471 }
2472 
2474 {
2475  if (m_assTrack && event)
2476  ass_process_data(m_assTrack, event, strlen(event));
2477 }
2478 
2480 {
2481  ass_set_frame_size(m_assRenderer, m_safeArea.width(), m_safeArea.height());
2482  ass_set_margins(m_assRenderer, 0, 0, 0, 0);
2483  ass_set_use_margins(m_assRenderer, static_cast<int>(true));
2484  ass_set_font_scale(m_assRenderer, 1.0);
2485 }
2486 
2487 void SubtitleScreen::RenderAssTrack(uint64_t timecode)
2488 {
2489  if (!m_player || !m_assRenderer || !m_assTrack)
2490  return;
2491 
2493  if (!vo )
2494  return;
2495 
2496  QRect oldscreen = m_safeArea;
2498  if (oldscreen != m_safeArea)
2500 
2501  int changed = 0;
2502  ASS_Image *images = ass_render_frame(m_assRenderer, m_assTrack, timecode, &changed);
2503  if (!changed)
2504  return;
2505 
2506  int count = 0;
2509  while (images)
2510  {
2511  if (images->w == 0 || images->h == 0)
2512  {
2513  images = images->next;
2514  continue;
2515  }
2516 
2517  uint8_t alpha = images->color & 0xFF;
2518  uint8_t blue = images->color >> 8 & 0xFF;
2519  uint8_t green = images->color >> 16 & 0xFF;
2520  uint8_t red = images->color >> 24 & 0xFF;
2521 
2522  if (alpha == 255)
2523  {
2524  images = images->next;
2525  continue;
2526  }
2527 
2528  QSize img_size(images->w, images->h);
2529  QRect img_rect(images->dst_x,images->dst_y,
2530  images->w, images->h);
2531  QImage qImage(img_size, QImage::Format_ARGB32);
2532  qImage.fill(0x00000000);
2533 
2534  unsigned char *src = images->bitmap;
2535  for (int y = 0; y < images->h; ++y)
2536  {
2537  for (int x = 0; x < images->w; ++x)
2538  {
2539  uint8_t value = src[x];
2540  if (value)
2541  {
2542  uint32_t pixel = (value * (255 - alpha) / 255 << 24) |
2543  (red << 16) | (green << 8) | blue;
2544  qImage.setPixel(x, y, pixel);
2545  }
2546  }
2547  src += images->stride;
2548  }
2549 
2550  MythImage* image = m_painter->GetFormatImage();
2551  SubImage *uiimage = nullptr;
2552 
2553  if (image)
2554  {
2555  image->Assign(qImage);
2556  QString name = QString("asssub%1").arg(count);
2557  uiimage = new SubImage(this, name, MythRect(img_rect), 0);
2558  if (uiimage)
2559  {
2560  uiimage->SetImage(image);
2561  uiimage->SetArea(MythRect(img_rect));
2562  SetElementAdded();
2563  }
2564  image->DecrRef();
2565  }
2566 
2567  images = images->next;
2568  count++;
2569  }
2570 }
2571 #endif // USING_LIBASS
SubtitleScreen::DrawTextSubtitles
void DrawTextSubtitles(const QStringList &subs, uint64_t start, uint64_t duration)
Definition: subtitlescreen.cpp:2206
SubtitleScreen::DisplayRawTextSubtitles
void DisplayRawTextSubtitles(void)
Definition: subtitlescreen.cpp:2180
kSubAttrOutlinealpha
static const QString kSubAttrOutlinealpha("outlinealpha")
FormattedTextSubtitle
Definition: subtitlescreen.h:75
CC608Buffer::m_lock
QMutex m_lock
Definition: cc608reader.h:50
MythVideoOutput::GetOSDBounds
virtual void GetOSDBounds(QRect &Total, QRect &Visible, float &VisibleAspect, float &FontScaling, float ThemeAspect) const
Definition: mythvideoout.cpp:237
FormattedTextSubtitle::CacheNum
virtual int CacheNum(void) const
Definition: subtitlescreen.h:92
kSubAttrShadowcolor
static const QString kSubAttrShadowcolor("shadowcolor")
k708AttrEdgeDepressed
const uint k708AttrEdgeDepressed
Definition: cc708window.cpp:95
SubWrapper::m_swExpireTime
const long long m_swExpireTime
Definition: subtitlescreen.cpp:42
FormattedTextSubtitle::Layout
virtual void Layout(void)
Definition: subtitlescreen.cpp:784
CC608Text
Definition: cc608reader.h:19
SubtitleFormat::GetBackgroundAlpha
int GetBackgroundAlpha(const QString &family)
Definition: subtitlescreen.cpp:635
LINE_SPACING
static const float LINE_SPACING
Definition: subtitlescreen.cpp:776
differentColor
static QColor differentColor(const QColor &color)
Definition: subtitlescreen.cpp:421
SubtitleFormat::IsUnlocked
bool IsUnlocked(const QString &prefix, const QString &property) const
Definition: subtitlescreen.cpp:150
SubtitleScreen::m_textFontZoom
int m_textFontZoom
Definition: subtitlescreen.h:242
SubtitleScreen::m_cc708reader
CC708Reader * m_cc708reader
Definition: subtitlescreen.h:237
DecoderBase::GetTrack
int GetTrack(uint Type)
Definition: decoderbase.cpp:951
SubtitleScreen::m_textFontDelayMs
int m_textFontDelayMs
Definition: subtitlescreen.h:244
SubtitleScreen::Pulse
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: subtitlescreen.cpp:1715
CC708CharacterAttribute::GetEdgeColor
QColor GetEdgeColor(void) const
Definition: cc708window.h:128
MythPlayer::GetVideoOutput
MythVideoOutput * GetVideoOutput(void)
Definition: mythplayer.h:184
SubWrapper
Definition: subtitlescreen.cpp:24
SubtitleFormat::m_shapeMap
QHash< QString, MythUIShape * > m_shapeMap
Definition: subtitlescreen.cpp:169
TextSubtitles::Unlock
void Unlock(void)
Definition: textsubtitleparser.h:87
SubtitleScreen::m_removeHTML
QRegExp m_removeHTML
Definition: subtitlescreen.h:239
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:98
MythVideoOutput
Definition: mythvideoout.h:31
FormattedTextSubtitle::m_base
QString m_base
Definition: subtitlescreen.h:96
MythUIType::DeleteChild
void DeleteChild(const QString &name)
Delete a named child of this UIType.
Definition: mythuitype.cpp:146
FormattedTextSubtitleSRT::Init
void Init(const QStringList &subs)
Definition: subtitlescreen.cpp:973
CC708Service::m_windows
std::array< CC708Window, k708MaxWindows > m_windows
Definition: cc708window.h:319
SubtitleScreen::m_assLibrary
ASS_Library * m_assLibrary
Definition: subtitlescreen.h:268
FormattedTextChunk::Split
bool Split(FormattedTextChunk &newChunk)
Definition: subtitlescreen.cpp:658
SubtitleScreen::RenderAssTrack
void RenderAssTrack(uint64_t timecode)
Definition: subtitlescreen.cpp:2487
FormattedTextLine
Definition: subtitlescreen.h:60
MythUIImage::m_images
QHash< int, MythImage * > m_images
Definition: mythuiimage.h:170
FormattedTextSubtitle::m_start
uint64_t m_start
Definition: subtitlescreen.h:99
CC708CharacterAttribute::m_edgeType
uint m_edgeType
Definition: cc708window.h:90
SubtitleScreen::GetTeletextBackgroundAlpha
static int GetTeletextBackgroundAlpha(void)
Definition: subtitlescreen.cpp:1691
SubtitleReader::GetRawTextSubtitles
QStringList GetRawTextSubtitles(uint64_t &duration)
Definition: subtitlereader.cpp:101
kSubAttrOutlinecolor
static const QString kSubAttrOutlinecolor("outlinecolor")
SubtitleScreen::InitialiseAssLibrary
bool InitialiseAssLibrary(void)
Definition: subtitlescreen.cpp:2361
SubtitleScreen::SetDelay
void SetDelay(int ms)
Definition: subtitlescreen.cpp:1554
DecoderBase::NormalizeVideoTimecode
virtual int64_t NormalizeVideoTimecode(int64_t timecode)
Definition: decoderbase.h:184
CC708Reader::ClearBuffers
void ClearBuffers(void)
Definition: cc708reader.cpp:40
CC708CharacterAttribute::m_penSize
uint m_penSize
Definition: cc708window.h:86
CC708Window
Definition: cc708window.h:194
SubtitleScreen::AddScaledImage
void AddScaledImage(QImage &img, QRect &pos)
Definition: subtitlescreen.cpp:2294
kSubAttrUnderline
static const QString kSubAttrUnderline("underline")
kDisplayTextSubtitle
@ kDisplayTextSubtitle
Definition: mythplayer.h:70
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:540
CC708CharacterAttribute::m_fontTag
uint m_fontTag
Definition: cc708window.h:89
kTrackTypeAttachment
@ kTrackTypeAttachment
Definition: decoderbase.h:37
CC708Reader::GetCurrentService
CC708Service * GetCurrentService(void)
Definition: cc708reader.h:23
CC708Reader::SetEnabled
void SetEnabled(bool enable)
Definition: cc708reader.h:24
SubWrapper::m_swOrigArea
const MythRect m_swOrigArea
Definition: subtitlescreen.cpp:40
kSubWindowName
static const QString kSubWindowName("osd_subtitle")
MythFontProperties::GetFace
QFont * GetFace(void)
Definition: mythfontproperties.h:18
mythuisimpletext.h
FormattedTextSubtitle708::m_num
int m_num
Definition: subtitlescreen.h:167
cc
Definition: cc.h:10
DecoderBase::GetAttachmentData
virtual void GetAttachmentData(uint, QByteArray &, QByteArray &)
Definition: decoderbase.h:250
CC608Buffer::m_buffers
std::vector< CC608Text * > m_buffers
Definition: cc608reader.h:51
kSubAttrShadowoffset
static const QString kSubAttrShadowoffset("shadowoffset")
SubtitleScreen::m_assRenderer
ASS_Renderer * m_assRenderer
Definition: subtitlescreen.h:269
SubtitleScreen::DisplayCC708Subtitles
void DisplayCC708Subtitles(void)
Definition: subtitlescreen.cpp:2245
TextSubtitles::HasSubtitleChanged
bool HasSubtitleChanged(uint64_t timecode) const
Returns true in case the subtitle to display has changed since the last GetSubtitles() call.
Definition: textsubtitleparser.cpp:167
FormattedTextSubtitleSRT
Definition: subtitlescreen.h:110
arg
arg(title).arg(filename).arg(doDelete))
FormattedTextSubtitle::m_yAnchor
int m_yAnchor
Definition: subtitlescreen.h:105
MythFontProperties::face
QFont face(void) const
Definition: mythfontproperties.cpp:38
SubtitleScreen::Create
bool Create(void) override
Definition: subtitlescreen.cpp:1697
SubtitleScreen::DisplayTextSubtitles
void DisplayTextSubtitles(void)
Definition: subtitlescreen.cpp:2105
CC708CharacterAttribute
Definition: cc708window.h:84
SubSimpleText::SubSimpleText
SubSimpleText(const QString &text, const MythFontProperties &font, const QRect &rect, Qt::Alignment align, MythUIType *parent, const QString &name, int whichImageCache, long long expireTime)
Definition: subtitlescreen.cpp:48
kSubProvider
static const QString kSubProvider("provider")
MythUIType::AddFont
bool AddFont(const QString &text, MythFontProperties *fontProp)
Definition: mythuitype.cpp:1308
MythVideoFrame::m_width
int m_width
Definition: mythframe.h:112
x3
static int x3
Definition: mythsocket.cpp:62
MythUIType::SetArea
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:595
MythFontProperties::hasShadow
bool hasShadow(void) const
Definition: mythfontproperties.h:29
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:153
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
SubtitleFormat::MakePrefix
static QString MakePrefix(const QString &family, const CC708CharacterAttribute &attr)
Definition: subtitlescreen.cpp:357
kSubFileName
static const QString kSubFileName("osd_subtitle.xml")
SubtitleFormat::~SubtitleFormat
~SubtitleFormat(void)
Definition: subtitlescreen.cpp:346
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
FormattedTextSubtitle708::m_bgFillAlpha
uint m_bgFillAlpha
Definition: subtitlescreen.h:168
SubtitleScreen::DisplayAVSubtitles
void DisplayAVSubtitles(void)
Definition: subtitlescreen.cpp:1828
SubtitleScreen::m_assTrack
ASS_Track * m_assTrack
Definition: subtitlescreen.h:271
SubtitleScreen::CleanupAssLibrary
void CleanupAssLibrary(void)
Definition: subtitlescreen.cpp:2428
MythFontProperties::SetColor
void SetColor(const QColor &color)
Definition: mythfontproperties.cpp:47
MythPlayer::GetCC708Reader
virtual CC708Reader * GetCC708Reader(uint=0)
Definition: mythplayer.h:215
CC708Window::m_anchor_vertical
uint m_anchor_vertical
Definition: cc708window.h:251
pixel
static guint32 * pixel
--------------------------------------------------—**
Definition: goom_core.cpp:29
FormattedTextSubtitle::m_xAnchor
int m_xAnchor
Definition: subtitlescreen.h:104
SubtitleScreen::m_refreshModified
bool m_refreshModified
Definition: subtitlescreen.h:250
MythPlayer
Definition: mythplayer.h:100
SubtitleReader::EnableAVSubtitles
void EnableAVSubtitles(bool enable)
Definition: subtitlereader.cpp:11
FormattedTextChunk::m_bgShapeRect
QRect m_bgShapeRect
Definition: subtitlescreen.h:53
FormattedTextLine::CalcSize
QSize CalcSize(float layoutSpacing=0.0F) const
Definition: subtitlescreen.cpp:751
LOC
#define LOC
Definition: subtitlescreen.cpp:11
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:18
MythUIType::Pulse
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuitype.cpp:441
MythFontProperties::SetShadow
void SetShadow(bool on, const QPoint &offset, const QColor &color, int alpha)
Definition: mythfontproperties.cpp:53
k708AttrEdgeUniform
const uint k708AttrEdgeUniform
Definition: cc708window.cpp:96
SubWrapper::SubWrapper
SubWrapper(const MythRect &rect, long long expireTime, int whichImageCache=-1)
Definition: subtitlescreen.cpp:26
MythVideoBounds::GetDisplayVideoRect
QRect GetDisplayVideoRect(void) const
Definition: mythvideobounds.h:77
kSubAttrShadowalpha
static const QString kSubAttrShadowalpha("shadowalpha")
FormattedTextSubtitle708
Definition: subtitlescreen.h:144
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
mythuiimage.h
FormattedTextSubtitle608
Definition: subtitlescreen.h:128
SubtitleFormat::m_shadowOffsetMap
QHash< QString, QPoint > m_shadowOffsetMap
Definition: subtitlescreen.cpp:176
MythUIType::DeleteAllChildren
void DeleteAllChildren(void)
Delete all child widgets.
Definition: mythuitype.cpp:203
TextSubtitles::GetSubtitles
QStringList GetSubtitles(uint64_t timecode)
Returns the subtitles to display at the given timecode.
Definition: textsubtitleparser.cpp:180
FormattedTextSubtitle::m_safeArea
const QRect m_safeArea
Definition: subtitlescreen.h:98
SubtitleScreen::GetZoom
int GetZoom(void) const
Definition: subtitlescreen.cpp:1549
SubtitleScreen::m_fontStretch
int m_fontStretch
Definition: subtitlescreen.h:252
PAD_WIDTH
static const float PAD_WIDTH
Definition: subtitlescreen.cpp:777
SubtitleFormat::m_changeMap
QHash< QString, QSet< QString > > m_changeMap
Definition: subtitlescreen.cpp:170
SubtitleScreen::m_family
QString m_family
Definition: subtitlescreen.h:253
MythUIShape::SetFillBrush
void SetFillBrush(QBrush fill)
Definition: mythuishape.cpp:41
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
CC608Reader::GetOutputText
CC608Buffer * GetOutputText(bool &changed, int &streamIdx)
Definition: cc608reader.cpp:53
MythFontProperties::hasOutline
bool hasOutline(void) const
Definition: mythfontproperties.h:32
MythVideoFrame::m_timecode
long long m_timecode
Definition: mythframe.h:122
SubtitleScreen::m_refreshDeleted
bool m_refreshDeleted
Definition: subtitlescreen.h:251
SubtitleReader::ClearAVSubtitles
void ClearAVSubtitles(void)
Definition: subtitlereader.cpp:71
MythUIType::AddChild
void AddChild(MythUIType *child)
Add a child UIType.
Definition: mythuitype.cpp:86
SubtitleScreen::~SubtitleScreen
~SubtitleScreen() override
Definition: subtitlescreen.cpp:1377
SubImage::GetImage
MythImage * GetImage(void)
Definition: subtitlescreen.cpp:72
SubtitleFormat::SubtitleFormat
SubtitleFormat(void)=default
CC708Window::GetVisible
bool GetVisible(void) const
Definition: cc708window.h:287
SubtitleFormat::Diff
static QSet< QString > Diff(const QString &family, const CC708CharacterAttribute &attr, MythFontProperties *font1, MythFontProperties *font2, MythUIShape *bg1, MythUIShape *bg2)
Definition: subtitlescreen.cpp:526
CC708CharacterAttribute::m_boldface
bool m_boldface
Definition: cc708window.h:93
MythVideoOutput::GetImageRect
QRect GetImageRect(const QRect &Rect, QRect *DisplayRect=nullptr)
translates caption/dvd button rectangle into 'screen' space
Definition: mythvideoout.cpp:357
SubtitleScreen::m_textFontMinDurationMs
int m_textFontMinDurationMs
Definition: subtitlescreen.h:246
SubtitleScreen::DisplayCC608Subtitles
void DisplayCC608Subtitles(void)
Definition: subtitlescreen.cpp:2214
DecoderBase::GetTrackCount
virtual uint GetTrackCount(uint Type)
Definition: decoderbase.cpp:903
CC708Window::m_relative_pos
uint m_relative_pos
Definition: cc708window.h:250
FormattedTextChunk::CalcPadding
void CalcPadding(bool isFirst, bool isLast, int &left, int &right) const
Definition: subtitlescreen.cpp:652
srtColorString
static QString srtColorString(const QColor &color)
Definition: subtitlescreen.cpp:204
mythfontproperties.h
FormattedTextChunk
Definition: subtitlescreen.h:33
mythlogging.h
kSubFamilyText
static const QString kSubFamilyText("text")
subtitlescreen.h
CC708CharacterAttribute::GetFGColor
QColor GetFGColor(void) const
Definition: cc708window.h:115
kDisplayNone
@ kDisplayNone
Definition: mythplayer.h:64
SubtitleScreen::LoadAssFonts
void LoadAssFonts(void)
Definition: subtitlescreen.cpp:2403
SubtitleScreen::ResetElementState
void ResetElementState(void)
Definition: subtitlescreen.cpp:1787
SubtitleScreen::CalcTextSize
QSize CalcTextSize(const QString &text, const CC708CharacterAttribute &format, float layoutSpacing) const
Definition: subtitlescreen.cpp:1639
kSubFamilyTeletext
static const QString kSubFamilyTeletext("teletext")
SubtitleScreen::GetTeletextFontName
static QString GetTeletextFontName(void)
Definition: subtitlescreen.cpp:1681
SubtitleReader::EnableTextSubtitles
void EnableTextSubtitles(bool enable)
Definition: subtitlereader.cpp:16
SubtitleScreen::Clear708Cache
void Clear708Cache(uint64_t mask)
Definition: subtitlescreen.cpp:1564
CC708Service
Definition: cc708window.h:313
SubtitleScreen::EnableSubtitles
void EnableSubtitles(int type, bool forced_only=false)
Definition: subtitlescreen.cpp:1386
FormattedTextSubtitle608::Init
void Init(const vector< CC608Text * > &buffers)
Definition: subtitlescreen.cpp:1223
SubtitleScreen::m_qInited
QList< FormattedTextSubtitle * > m_qInited
Definition: subtitlescreen.h:255
MythFontProperties
Definition: mythfontproperties.h:14
CC608Buffer
Definition: cc608reader.h:38
SubtitleScreen::AddAssEvent
void AddAssEvent(char *event)
Definition: subtitlescreen.cpp:2473
CC708CharacterAttribute::GetFGAlpha
uint GetFGAlpha(void) const
Definition: cc708window.h:130
k708AttrEdgeLeftDropShadow
const uint k708AttrEdgeLeftDropShadow
Definition: cc708window.cpp:97
kSubAttrShadow
static const QString kSubAttrShadow("shadow")
FormattedTextSubtitle::m_xAnchorPoint
int m_xAnchorPoint
Definition: subtitlescreen.h:102
MythPlayer::GetCC608Reader
virtual CC608Reader * GetCC608Reader(uint=0)
Definition: mythplayer.h:216
SubtitleScreen::m_fontSize
int m_fontSize
Definition: subtitlescreen.h:241
FormattedTextSubtitleSRT::WrapLongLines
void WrapLongLines(void) override
Definition: subtitlescreen.cpp:1078
FormattedTextChunk::m_parent
const SubtitleScreen * m_parent
Definition: subtitlescreen.h:49
PAD_HEIGHT
static const float PAD_HEIGHT
Definition: subtitlescreen.cpp:778
AVSubtitles
Definition: subtitlereader.h:14
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:120
MythPoint::setY
void setY(const QString &sY)
Definition: mythrect.cpp:541
MythFontProperties::color
QColor color(void) const
Definition: mythfontproperties.h:26
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:54
SubtitleReader::ClearRawTextSubtitles
void ClearRawTextSubtitles(void)
Definition: subtitlereader.cpp:124
SubtitleScreen::CleanupAssTrack
void CleanupAssTrack(void)
Definition: subtitlescreen.cpp:2466
SubtitleScreen::ClearDisplayedSubtitles
void ClearDisplayedSubtitles(void)
Definition: subtitlescreen.cpp:1475
SubtitleScreen::ResizeAssRenderer
void ResizeAssRenderer(void)
Definition: subtitlescreen.cpp:2479
MythUIType::m_childrenList
QList< MythUIType * > m_childrenList
Definition: mythuitype.h:231
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
TextSubtitles
Definition: textsubtitleparser.h:35
SubtitleReader::FreeAVSubtitle
static void FreeAVSubtitle(AVSubtitle &sub)
Definition: subtitlereader.cpp:82
SubtitleReader::GetTextSubtitles
TextSubtitles * GetTextSubtitles(void)
Definition: subtitlereader.h:48
MythFontProperties::GetOutline
void GetOutline(QColor &color, int &size, int &alpha) const
Definition: mythfontproperties.cpp:80
SubtitleFormat::m_pixelSizeMap
QHash< QString, int > m_pixelSizeMap
Definition: subtitlescreen.cpp:174
SubtitleScreen::DisplayDVDButton
void DisplayDVDButton(AVSubtitle *dvdButton, QRect &buttonPos)
Definition: subtitlescreen.cpp:1481
SubtitleFormat::Load
void Load(const QString &family, const CC708CharacterAttribute &attr)
Definition: subtitlescreen.cpp:454
FormattedTextChunk::m_textFont
MythFontProperties * m_textFont
Definition: subtitlescreen.h:54
f
QTextStream t & f
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:603
SubtitleFormat::CreateProviderDefault
static void CreateProviderDefault(const QString &family, const CC708CharacterAttribute &attr, MythUIType *parent, bool isComplement, MythFontProperties **font, MythUIShape **bg)
Definition: subtitlescreen.cpp:365
SubtitleFormat::GetFont
MythFontProperties * GetFont(const QString &family, const CC708CharacterAttribute &attr, int pixelSize, int zoom, int stretch)
Definition: subtitlescreen.cpp:245
mythpainter.h
FormattedTextSubtitle608::Layout
void Layout(void) override
Definition: subtitlescreen.cpp:1176
SubShape
Definition: subtitlescreen.cpp:57
SubtitleReader::EnableRawTextSubtitles
void EnableRawTextSubtitles(bool enable)
Definition: subtitlereader.cpp:21
SubtitleScreen::GetDelay
int GetDelay(void) const
Definition: subtitlescreen.cpp:1559
MythPoint::NormPoint
void NormPoint(void)
Definition: mythrect.cpp:472
FormattedTextChunk::m_textRect
QRect m_textRect
Definition: subtitlescreen.h:56
kSubFamilyAV
static const QString kSubFamilyAV("AV")
uint
unsigned int uint
Definition: compat.h:140
SubtitleScreen::m_assTrackNum
int m_assTrackNum
Definition: subtitlescreen.h:270
FormattedTextSubtitle::m_duration
uint64_t m_duration
Definition: subtitlescreen.h:100
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
SubtitleScreen::m_textFontZoomPrev
int m_textFontZoomPrev
Definition: subtitlescreen.h:243
SubtitleScreen::DisableForcedSubtitles
void DisableForcedSubtitles(void)
Definition: subtitlescreen.cpp:1444
SubtitleScreen::SetZoom
void SetZoom(int percent)
Definition: subtitlescreen.cpp:1540
FormattedTextSubtitle708::Draw
void Draw(void) override
Definition: subtitlescreen.cpp:1311
k708AttrSizeLarge
const uint k708AttrSizeLarge
Definition: cc708window.cpp:78
CC708CharacterAttribute::GetBGColor
QColor GetBGColor(void) const
Definition: cc708window.h:122
CC708CharacterAttribute::GetBGAlpha
uint GetBGAlpha(void) const
Definition: cc708window.h:137
myth_libass_log
static void myth_libass_log(int level, const char *fmt, va_list vl, void *)
Definition: subtitlescreen.cpp:2323
kDisplayAVSubtitle
@ kDisplayAVSubtitle
Definition: mythplayer.h:67
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:929
SubtitleScreen::SetElementDeleted
void SetElementDeleted(void)
Definition: subtitlescreen.cpp:1600
MythFontProperties::GetShadow
void GetShadow(QPoint &offset, QColor &color, int &alpha) const
Definition: mythfontproperties.cpp:73
MythPlayer::GetDecoder
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:205
kTrackTypeSubtitle
@ kTrackTypeSubtitle
Definition: decoderbase.h:31
SubtitleScreen::m_textFontDurationExtensionMs
int m_textFontDurationExtensionMs
Definition: subtitlescreen.h:248
kSubAttrBGfill
static const QString kSubAttrBGfill("bgfill")
FormattedTextChunk::m_textName
QString m_textName
Definition: subtitlescreen.h:55
FormattedTextChunk::m_text
QString m_text
Definition: subtitlescreen.h:47
kDisplayRawTextSubtitle
@ kDisplayRawTextSubtitle
Definition: mythplayer.h:72
DecoderBase::GetSubHeader
virtual QByteArray GetSubHeader(uint)
Definition: decoderbase.h:249
MythPlayer::GetSubReader
virtual SubtitleReader * GetSubReader(uint=0)
Definition: mythplayer.h:217
kSubAttrItalics
static const QString kSubAttrItalics("italics")
SubtitleFormat::GetBackground
SubShape * GetBackground(MythUIType *parent, const QString &name, const QString &family, const CC708CharacterAttribute &attr, const MythRect &area, int whichImageCache, int start, int duration)
Definition: subtitlescreen.cpp:597
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:66
kSubAttrBold
static const QString kSubAttrBold("bold")
MythUIShape
A widget for rendering primitive shapes and lines.
Definition: mythuishape.h:22
FormattedTextSubtitle::m_lines
QVector< FormattedTextLine > m_lines
Definition: subtitlescreen.h:97
k708MaxWindows
const int k708MaxWindows
Definition: cc708window.h:72
SubtitleReader::GetAVSubtitles
AVSubtitles * GetAVSubtitles(void)
Definition: subtitlereader.h:42
kDisplayCC708
@ kDisplayCC708
Definition: mythplayer.h:69
SubtitleFormat::m_cleanup
QVector< MythUIType * > m_cleanup
Definition: subtitlescreen.cpp:177
k708AttrSizeSmall
const uint k708AttrSizeSmall
Definition: cc708window.cpp:76
buffers
Definition: freesurround.cpp:50
TextSubtitles::Lock
void Lock(void)
Definition: textsubtitleparser.h:86
prevY
unsigned int prevY
Definition: filters.cpp:110
CalcShadowOffsetPadding
static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont)
Definition: subtitlescreen.cpp:1611
SubtitleScreen::m_textFontMinDurationMsPrev
int m_textFontMinDurationMsPrev
Definition: subtitlescreen.h:247
kDisplayCC608
@ kDisplayCC608
Definition: mythplayer.h:68
FormattedTextSubtitle708::m_bgFillColor
QColor m_bgFillColor
Definition: subtitlescreen.h:169
kSubAttrPixelsize
static const QString kSubAttrPixelsize("pixelsize")
k708AttrEdgeRightDropShadow
const uint k708AttrEdgeRightDropShadow
Definition: cc708window.cpp:98
MythFontProperties::SetOutline
void SetOutline(bool on, const QColor &color, int size, int alpha)
Definition: mythfontproperties.cpp:63
FormattedTextChunk::CalcSize
QSize CalcSize(float layoutSpacing=0.0F) const
Definition: subtitlescreen.cpp:647
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
k708AttrEdgeRaised
const uint k708AttrEdgeRaised
Definition: cc708window.cpp:94
CC708Window::GetChanged
bool GetChanged(void) const
Definition: cc708window.h:288
SubtitleScreen::m_textFontDurationExtensionMsPrev
int m_textFontDurationExtensionMsPrev
Definition: subtitlescreen.h:249
SubtitleFormat::m_outlineSizeMap
QHash< QString, int > m_outlineSizeMap
Definition: subtitlescreen.cpp:175
AVSubtitles::m_buffers
MythDeque< AVSubtitle > m_buffers
Definition: subtitlereader.h:17
FormattedTextChunk::ToLogString
QString ToLogString(void) const
Definition: subtitlescreen.cpp:678
SubtitleScreen::ClearNonDisplayedSubtitles
void ClearNonDisplayedSubtitles(void)
Definition: subtitlescreen.cpp:1463
SubtitleScreen::InitialiseAssTrack
void InitialiseAssTrack(int tracknum)
Definition: subtitlescreen.cpp:2445
SubImage::SubImage
SubImage(MythUIType *parent, const QString &name, const MythRect &area, long long expireTime)
Definition: subtitlescreen.cpp:68
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
MythPainter
Definition: mythpainter.h:33
SubtitleScreen::GetSubtitleFormat
class SubtitleFormat * GetSubtitleFormat(void)
Definition: subtitlescreen.h:193
MythImage
Definition: mythimage.h:37
fontToString
static QString fontToString(MythFontProperties *f)
Definition: subtitlescreen.cpp:212
SubtitleScreen::m_textFontDelayMsPrev
int m_textFontDelayMsPrev
Definition: subtitlescreen.h:245
SubtitleScreen::m_format
class SubtitleFormat * m_format
Definition: subtitlescreen.h:256
SubtitleFormat::Complement
static void Complement(MythFontProperties *font, MythUIShape *bg)
Definition: subtitlescreen.cpp:428
Name
Definition: channelsettings.cpp:47
FormattedTextSubtitle708::Init
void Init(const CC708Window &win, const vector< CC708String * > &list, float aspect)
Definition: subtitlescreen.cpp:1328
SubtitleFormat::m_fontMap
QHash< QString, MythFontProperties * > m_fontMap
Definition: subtitlescreen.cpp:168
AVSubtitles::m_fixPosition
bool m_fixPosition
Definition: subtitlereader.h:19
kSubAttrOutline
static const QString kSubAttrOutline("outline")
SubtitleScreen::m_assFontCount
uint m_assFontCount
Definition: subtitlescreen.h:272
MythUIShape::m_fillBrush
QBrush m_fillBrush
Definition: mythuishape.h:42
SubtitleScreen::SetElementResized
void SetElementResized(void)
Definition: subtitlescreen.cpp:1593
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:152
FormattedTextSubtitle::PreRender
virtual void PreRender(void)
Definition: subtitlescreen.cpp:852
FormattedTextChunk::m_bgShapeName
QString m_bgShapeName
Definition: subtitlescreen.h:52
FormattedTextChunk::m_format
CC708CharacterAttribute m_format
Definition: subtitlescreen.h:48
CC708Window::GetStrings
std::vector< CC708String * > GetStrings(void) const
Definition: cc708window.cpp:284
CC708Window::DisposeStrings
static void DisposeStrings(std::vector< CC708String * > &strings)
Definition: cc708window.cpp:376
SubtitleScreen::OptimiseDisplayedArea
void OptimiseDisplayedArea(void)
Definition: subtitlescreen.cpp:1793
MythVideoOutput::GetSafeRect
QRect GetSafeRect()
Returns a QRect describing an area of the screen on which it is 'safe' to render the On Screen Displa...
Definition: mythvideoout.cpp:411
AVSubtitles::m_lock
QMutex m_lock
Definition: subtitlereader.h:18
SubtitleScreen::SetElementAdded
void SetElementAdded(void)
Definition: subtitlescreen.cpp:1586
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1086
SubWrapper::GetOrigArea
MythRect GetOrigArea(void) const
Definition: subtitlescreen.cpp:36
MythUIType::m_painter
MythPainter * m_painter
Definition: mythuitype.h:273
TextSubtitles::IsFrameBasedTiming
bool IsFrameBasedTiming(void) const
Returns true in case the subtitle timing data is frame-based.
Definition: textsubtitleparser.h:55
CC708CharacterAttribute::m_offset
uint m_offset
Definition: cc708window.h:87
SubSimpleText
Definition: subtitlescreen.cpp:46
FormattedTextSubtitle::m_subScreen
SubtitleScreen * m_subScreen
Definition: subtitlescreen.h:101
CC708Window::ResetChanged
void ResetChanged(void)
Definition: cc708window.h:305
FormattedTextSubtitle::ToSRT
QStringList ToSRT(void) const
Definition: subtitlescreen.cpp:926
CC708Window::m_lock
QMutex m_lock
Definition: cc708window.h:309
SubtitleScreen::m_subtitleType
int m_subtitleType
Definition: subtitlescreen.h:240
MythVideoFrame::m_height
int m_height
Definition: mythframe.h:113
SubtitleScreen::SubtitleScreen
SubtitleScreen(MythPlayer *Player, MythPainter *Painter, const QString &Name, int FontStretch)
Definition: subtitlescreen.cpp:1366
MythUIImage::SetImage
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:748
FormattedTextSubtitle::m_yAnchorPoint
int m_yAnchorPoint
Definition: subtitlescreen.h:103
kSubAttrColor
static const QString kSubAttrColor("color")
k708AttrFontSmallCaps
const uint k708AttrFontSmallCaps
Definition: cc708window.cpp:91
SubtitleScreen::m_safeArea
QRect m_safeArea
Definition: subtitlescreen.h:238
CC608Reader::ClearBuffers
void ClearBuffers(bool input, bool output, int outputStreamIdx=-1)
Definition: cc608reader.cpp:440
SubtitleScreen::m_cc608reader
CC608Reader * m_cc608reader
Definition: subtitlescreen.h:236
CC708Window::m_anchor_point
uint m_anchor_point
Definition: cc708window.h:249
CC708CharacterAttribute::m_italics
bool m_italics
Definition: cc708window.h:92
CC608Reader::SetEnabled
void SetEnabled(bool enable)
Definition: cc608reader.h:84
SubtitleScreen::m_subreader
SubtitleReader * m_subreader
Definition: subtitlescreen.h:235
Player
Definition: zmliveplayer.h:35
MythPoint::setX
void setX(const QString &sX)
Definition: mythrect.cpp:531
MythVideoFrame
Definition: mythframe.h:83
MythUISimpleText
Simplified text widget, displays a text string.
Definition: mythuisimpletext.h:23
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:898
MythImage::Assign
void Assign(const QImage &img)
Definition: mythimage.cpp:79
FormattedTextChunk::PreRender
bool PreRender(bool isFirst, bool isLast, int &x, int y, int height)
Definition: subtitlescreen.cpp:702
SubtitleFormat
Definition: subtitlescreen.cpp:131
SubWrapper::m_swWhichImageCache
const int m_swWhichImageCache
Definition: subtitlescreen.cpp:41
SubtitleScreen::m_player
MythPlayer * m_player
Definition: subtitlescreen.h:234
MythVideoOutput::GetLastShownFrame
virtual MythVideoFrame * GetLastShownFrame()
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
Definition: mythvideoout.cpp:351
SubWrapper::GetWhichImageCache
int GetWhichImageCache(void) const
Definition: subtitlescreen.cpp:37
SubShape::SubShape
SubShape(MythUIType *parent, const QString &name, const MythRect &area, int whichImageCache, long long expireTime)
Definition: subtitlescreen.cpp:59
SubtitleScreen::CalcPadding
void CalcPadding(const CC708CharacterAttribute &format, bool isFirst, bool isLast, int &left, int &right) const
Definition: subtitlescreen.cpp:1661
SubWrapper::GetExpireTime
long long GetExpireTime(void) const
Definition: subtitlescreen.cpp:35
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:294
kSubFamily608
static const QString kSubFamily608("608")
MythUIType::IsVisible
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:888
SubtitleScreen::SetFontSize
void SetFontSize(int pixelSize)
Definition: subtitlescreen.h:206
SubtitleScreen::GetFont
MythFontProperties * GetFont(const CC708CharacterAttribute &attr) const
Definition: subtitlescreen.cpp:1675
kSubFamily708
static const QString kSubFamily708("708")
FormattedTextLine::chunks
QList< FormattedTextChunk > chunks
Definition: subtitlescreen.h:67
SubImage
Definition: subtitlescreen.cpp:66
CC708Window::m_anchor_horizontal
uint m_anchor_horizontal
Definition: cc708window.h:252
kSubAttrOutlinesize
static const QString kSubAttrOutlinesize("outlinesize")
mythuishape.h
FormattedTextSubtitle::Draw
virtual void Draw(void)
Definition: subtitlescreen.cpp:876
FormattedTextSubtitle::m_bounds
QRect m_bounds
Definition: subtitlescreen.h:106
FormattedTextSubtitle::WrapLongLines
virtual void WrapLongLines(void)
Definition: subtitlescreen.h:87
SubtitleScreen::DisplayScaledAVSubtitles
int DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox, bool top, QRect &display, int forced, const QString &imagename, long long displayuntil, long long late)
Definition: subtitlescreen.cpp:1945
SubtitleScreen::ClearAllSubtitles
void ClearAllSubtitles(void)
Definition: subtitlescreen.cpp:1453
CC708CharacterAttribute::m_underline
bool m_underline
Definition: cc708window.h:91
extract_cc608
static QString extract_cc608(QString &text, int &color, bool &isItalic, bool &isUnderline)
Extract everything from the text buffer up until the next format control character.
Definition: subtitlescreen.cpp:1123
MythPoint
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:89
CC708Window::GetExists
bool GetExists(void) const
Definition: cc708window.h:286