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