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 (kDisplayCC608 == m_subtitleType)
1763  else if (kDisplayCC708 == m_subtitleType)
1767  while (!m_qInited.isEmpty())
1768  {
1769  FormattedTextSubtitle *fsub = m_qInited.takeFirst();
1770  fsub->WrapLongLines();
1771  fsub->Layout();
1772  fsub->PreRender();
1773  fsub->Draw();
1774  delete fsub;
1775  SetElementAdded();
1776  }
1777 
1785 }
1786 
1788 {
1789  m_refreshModified = false;
1790  m_refreshDeleted = false;
1791 }
1792 
1794 {
1795  if (!m_refreshModified)
1796  return;
1797 
1798  QRegion visible;
1799  QListIterator<MythUIType *> i(m_childrenList);
1800  while (i.hasNext())
1801  {
1802  MythUIType *img = i.next();
1803  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1804  if (wrapper && img->IsVisible())
1805  visible = visible.united(wrapper->GetOrigArea());
1806  }
1807 
1808  if (visible.isEmpty())
1809  return;
1810 
1811  QRect bounding = visible.boundingRect();
1812  bounding = bounding.translated(m_safeArea.topLeft());
1813  bounding = m_safeArea.intersected(bounding);
1814  int left = m_safeArea.left() - bounding.left();
1815  int top = m_safeArea.top() - bounding.top();
1816  SetArea(MythRect(bounding));
1817 
1818  i.toFront();
1819  while (i.hasNext())
1820  {
1821  MythUIType *img = i.next();
1822  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1823  if (wrapper && img->IsVisible())
1824  img->SetArea(MythRect(wrapper->GetOrigArea().translated(left, top)));
1825  }
1826 }
1827 
1829 {
1830  if (!m_player || !m_subreader)
1831  return;
1832 
1834  QMutexLocker lock(&(subs->m_lock));
1835  if (subs->m_buffers.empty() && (kDisplayAVSubtitle != m_subtitleType))
1836  return;
1837 
1838  MythVideoOutput *videoOut = m_player->GetVideoOutput();
1839  MythVideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : nullptr;
1840 
1841  if (!currentFrame || !videoOut)
1842  return;
1843 
1844  float tmp = 0.0;
1845  QRect dummy;
1846  videoOut->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
1847 
1848  while (!subs->m_buffers.empty())
1849  {
1850  AVSubtitle subtitle = subs->m_buffers.front();
1851  if (subtitle.start_display_time > currentFrame->m_timecode.count())
1852  break;
1853 
1854  auto displayfor = std::chrono::milliseconds(subtitle.end_display_time -
1855  subtitle.start_display_time);
1856  if (displayfor == 0ms)
1857  displayfor = 60s;
1858  displayfor = (displayfor < 50ms) ? 50ms : displayfor;
1859  std::chrono::milliseconds late = currentFrame->m_timecode -
1860  std::chrono::milliseconds(subtitle.start_display_time);
1861 
1863  subs->m_buffers.pop_front();
1864  for (std::size_t i = 0; i < subtitle.num_rects; ++i)
1865  {
1866  AVSubtitleRect* rect = subtitle.rects[i];
1867 
1868  bool displaysub = true;
1869  if (!subs->m_buffers.empty() &&
1870  subs->m_buffers.front().end_display_time <
1871  currentFrame->m_timecode.count())
1872  {
1873  displaysub = false;
1874  }
1875 
1876  if (displaysub && rect->type == SUBTITLE_BITMAP)
1877  {
1878  QRect display(rect->display_x, rect->display_y,
1879  rect->display_w, rect->display_h);
1880 
1881  // XSUB and some DVD/DVB subs are based on the original video
1882  // size before the video was converted. We need to guess the
1883  // original size and allow for the difference
1884 
1885  int right = rect->x + rect->w;
1886  int bottom = rect->y + rect->h;
1887  if (subs->m_fixPosition || (currentFrame->m_height < bottom) ||
1888  (currentFrame->m_width < right) ||
1889  !display.width() || !display.height())
1890  {
1891  int sd_height = 576;
1892  if ((m_player->GetFrameRate() > 26.0F ||
1893  m_player->GetFrameRate() < 24.0F) && bottom <= 480)
1894  sd_height = 480;
1895  int height = ((currentFrame->m_height <= sd_height) &&
1896  (bottom <= sd_height)) ? sd_height :
1897  ((currentFrame->m_height <= 720) && bottom <= 720)
1898  ? 720 : 1080;
1899  int width = ((currentFrame->m_width <= 720) &&
1900  (right <= 720)) ? 720 :
1901  ((currentFrame->m_width <= 1280) &&
1902  (right <= 1280)) ? 1280 : 1920;
1903  display = QRect(0, 0, width, height);
1904  }
1905 
1906  // split into upper/lower to allow zooming
1907  QRect bbox;
1908  int uh = display.height() / 2 - rect->y;
1909  std::chrono::milliseconds displayuntil = currentFrame->m_timecode + displayfor;
1910  if (uh > 0)
1911  {
1912  bbox = QRect(0, 0, rect->w, uh);
1913  uh = DisplayScaledAVSubtitles(rect, bbox, true, display,
1914  subtitle.forced,
1915  QString("avsub%1t").arg(i),
1916  displayuntil, late);
1917  }
1918  else
1919  uh = 0;
1920  int lh = rect->h - uh;
1921  if (lh > 0)
1922  {
1923  bbox = QRect(0, uh, rect->w, lh);
1924  DisplayScaledAVSubtitles(rect, bbox, false, display,
1925  subtitle.forced,
1926  QString("avsub%1b").arg(i),
1927  displayuntil, late);
1928  }
1929  }
1930 #ifdef USING_LIBASS
1931  else if (displaysub && rect->type == SUBTITLE_ASS)
1932  {
1934  AddAssEvent(rect->ass);
1935  }
1936 #endif
1937  }
1939  }
1940 #ifdef USING_LIBASS
1941  RenderAssTrack(currentFrame->m_timecode);
1942 #endif
1943 }
1944 
1945 int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect,
1946  QRect &bbox, bool top,
1947  QRect &display, int forced,
1948  const QString& imagename,
1949  std::chrono::milliseconds displayuntil,
1950  std::chrono::milliseconds late)
1951 {
1952  // split image vertically if it spans middle of display
1953  // - split point is empty line nearest the middle
1954  // crop image to reduce scaling time
1955  bool prev_empty = false;
1956 
1957  // initialize to opposite edges
1958  int xmin = bbox.right();
1959  int xmax = bbox.left();
1960  int ymin = bbox.bottom();
1961  int ymax = bbox.top();
1962  int ylast = bbox.top();
1963  int ysplit = bbox.bottom();
1964 
1965  // find bounds of active image
1966  for (int y = bbox.top(); y <= bbox.bottom(); ++y)
1967  {
1968  if (y >= rect->h)
1969  {
1970  // end of image
1971  if (!prev_empty)
1972  ylast = y;
1973  break;
1974  }
1975 
1976  bool empty = true;
1977  for (int x = bbox.left(); x <= bbox.right(); ++x)
1978  {
1979  const uint8_t color =
1980  rect->data[0][y * rect->linesize[0] + x];
1981  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
1982  if (pixel & 0xff000000)
1983  {
1984  empty = false;
1985  if (x < xmin)
1986  xmin = x;
1987  if (x > xmax)
1988  xmax = x;
1989  }
1990  }
1991 
1992  if (!empty)
1993  {
1994  if (y < ymin)
1995  ymin = y;
1996  if (y > ymax)
1997  ymax = y;
1998  }
1999  else if (!prev_empty)
2000  {
2001  // remember uppermost empty line
2002  ylast = y;
2003  }
2004  prev_empty = empty;
2005  }
2006 
2007  if (ymax <= ymin)
2008  return 0;
2009 
2010  if (top)
2011  {
2012  if (ylast < ymin)
2013  // no empty lines
2014  return 0;
2015 
2016  if (ymax == bbox.bottom())
2017  {
2018  ymax = ylast;
2019  ysplit = ylast;
2020  }
2021  }
2022 
2023  // set new bounds
2024  bbox.setLeft(xmin);
2025  bbox.setRight(xmax);
2026  bbox.setTop(ymin);
2027  bbox.setBottom(ymax);
2028 
2029  // copy active region
2030  // AVSubtitleRect's image data's not guaranteed to be 4 byte
2031  // aligned.
2032 
2033  QRect orig_rect(bbox.left(), bbox.top(), bbox.width(), bbox.height());
2034 
2035  QImage qImage(bbox.width(), bbox.height(), QImage::Format_ARGB32);
2036  for (int y = 0; y < bbox.height(); ++y)
2037  {
2038  int ysrc = y + bbox.top();
2039  for (int x = 0; x < bbox.width(); ++x)
2040  {
2041  int xsrc = x + bbox.left();
2042  const uint8_t color =
2043  rect->data[0][ysrc * rect->linesize[0] + xsrc];
2044  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
2045  qImage.setPixel(x, y, pixel);
2046  }
2047  }
2048 
2049  // translate to absolute coordinates
2050  bbox.translate(rect->x, rect->y);
2051 
2052  // scale and move according to zoom factor
2053  bbox.setWidth(bbox.width() * m_textFontZoom / 100);
2054  bbox.setHeight(bbox.height() * m_textFontZoom / 100);
2055 
2056  MythVideoOutput *videoOut = m_player->GetVideoOutput();
2057  QRect scaled = videoOut->GetImageRect(bbox, &display);
2058 
2059  if (scaled.size() != orig_rect.size())
2060  qImage = qImage.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2061 
2062  int hsize = m_safeArea.width();
2063  int vsize = m_safeArea.height();
2064 
2065  scaled.moveLeft(((100 - m_textFontZoom) * hsize / 2 + m_textFontZoom * scaled.left()) / 100);
2066  if (top)
2067  {
2068  // anchor up
2069  scaled.moveTop(scaled.top() * m_textFontZoom / 100);
2070  }
2071  else
2072  {
2073  // anchor down
2074  scaled.moveTop(((100 - m_textFontZoom) * vsize + m_textFontZoom * scaled.top()) / 100);
2075  }
2076 
2077  MythImage* image = m_painter->GetFormatImage();
2078  SubImage *uiimage = nullptr;
2079 
2080  if (image)
2081  {
2082  image->Assign(qImage);
2083  uiimage = new SubImage(this, imagename, MythRect(scaled), displayuntil);
2084  if (uiimage)
2085  {
2086  uiimage->SetImage(image);
2087  uiimage->SetArea(MythRect(scaled));
2088  SetElementAdded();
2089  }
2090  image->DecrRef();
2091  image = nullptr;
2092  }
2093 
2094  if (uiimage)
2095  {
2096  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display %1AV sub until %2ms")
2097  .arg(forced ? "FORCED " : "").arg(displayuntil.count()));
2098  if (late > 50ms)
2099  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sub was %1ms late").arg(late.count()));
2100  }
2101 
2102  return (ysplit + 1);
2103 }
2104 
2106 {
2107  if (!m_player || !m_subreader)
2108  return;
2109 
2110  bool changed = (m_textFontZoom != m_textFontZoomPrev);
2111  changed |= (m_textFontDelayMs != m_textFontDelayMsPrev);
2115  if (!vo)
2116  return;
2117  m_safeArea = vo->GetSafeRect();
2118 
2119  MythVideoFrame *currentFrame = vo->GetLastShownFrame();
2120  if (!currentFrame)
2121  return;
2122 
2124  subs->Lock();
2125  uint64_t playPos = 0;
2126  int playPosAdj = m_textFontDelayMs.count();
2127  if (subs->IsFrameBasedTiming())
2128  {
2129  // frame based subtitles get out of synch after running mythcommflag
2130  // for the file, i.e., the following number is wrong and does not
2131  // match the subtitle frame numbers:
2132  playPos = currentFrame->m_frameNumber;
2133  playPosAdj /= m_player->GetFrameRate();
2134  }
2135  else
2136  {
2137  // Use timecodes for time based SRT subtitles. Feeding this into
2138  // NormalizeVideoTimecode() should adjust for non-zero start times
2139  // and wraps. For MPEG, wraps will occur just once every 26.5 hours
2140  // and other formats less frequently so this should be sufficient.
2141  // Note: timecodes should now always be valid even in the case
2142  // when a frame doesn't have a valid timestamp. If an exception is
2143  // found where this is not true then we need to use the frameNumber
2144  // when timecode is not defined by uncommenting the following lines.
2145  //if (currentFrame->timecode == 0)
2146  // playPos = (uint64_t)
2147  // ((currentFrame->frameNumber / video_frame_rate) * 1000);
2148  //else
2149  auto tc_ms = currentFrame->m_timecode;
2150  playPos = m_player->GetDecoder()->NormalizeVideoTimecode(tc_ms).count();
2151  }
2152  playPos -= playPosAdj;
2153  if (playPos != 0)
2154  changed |= subs->HasSubtitleChanged(playPos);
2155  if (!changed)
2156  {
2157  subs->Unlock();
2158  return;
2159  }
2160 
2163 
2164  if (playPos == 0)
2165  {
2166  subs->Unlock();
2167  return;
2168  }
2169 
2170  QStringList rawsubs = subs->GetSubtitles(playPos);
2171  if (rawsubs.empty())
2172  {
2173  subs->Unlock();
2174  return;
2175  }
2176 
2177  subs->Unlock();
2178  DrawTextSubtitles(rawsubs, 0ms, 0ms);
2179 }
2180 
2182 {
2183  if (!m_player || !m_subreader)
2184  return;
2185 
2186  std::chrono::milliseconds duration = 0ms;
2187  QStringList subs = m_subreader->GetRawTextSubtitles(duration);
2188  if (subs.empty())
2189  return;
2190 
2192  if (!vo)
2193  return;
2194 
2195  MythVideoFrame *currentFrame = vo->GetLastShownFrame();
2196  if (!currentFrame)
2197  return;
2198 
2199  m_safeArea = vo->GetSafeRect();
2200 
2201  // delete old subs that may still be on screen
2204  DrawTextSubtitles(subs, currentFrame->m_timecode, duration);
2205 }
2206 
2207 void SubtitleScreen::DrawTextSubtitles(const QStringList &subs,
2208  std::chrono::milliseconds start,
2209  std::chrono::milliseconds duration)
2210 {
2211  auto *fsub = new FormattedTextSubtitleSRT(m_family, m_safeArea, start,
2212  duration, this, subs);
2213  m_qInited.append(fsub);
2214 }
2215 
2217 {
2218  if (!m_cc608reader)
2219  return;
2220 
2221  bool changed = (m_textFontZoom != m_textFontZoomPrev);
2222 
2223  if (!m_player || !m_player->GetVideoOutput())
2224  return;
2226 
2227  CC608Buffer* textlist = m_cc608reader->GetOutputText(changed);
2228  if (!changed)
2229  return;
2230 
2233 
2234  if (!textlist)
2235  return;
2236 
2237  QMutexLocker locker(&textlist->m_lock);
2238 
2239  if (textlist->m_buffers.empty())
2240  return;
2241 
2242  auto *fsub = new FormattedTextSubtitle608(textlist->m_buffers, m_family,
2243  m_safeArea, this/*, m_textFontZoom*/);
2244  m_qInited.append(fsub);
2245 }
2246 
2248 {
2250  return;
2251 
2252  CC708Service *cc708service = m_cc708reader->GetCurrentService();
2253  float video_aspect = m_player->GetVideoAspect();
2254  QRect oldsafe = m_safeArea;
2256  bool changed = (oldsafe != m_safeArea || m_textFontZoom != m_textFontZoomPrev);
2257  if (changed)
2258  {
2259  for (auto & window : cc708service->m_windows)
2260  window.SetChanged();
2261  }
2262 
2263  uint64_t clearMask = 0;
2264  QList<FormattedTextSubtitle *> addList;
2265  for (int i = 0; i < k708MaxWindows; i++)
2266  {
2267  CC708Window &win = cc708service->m_windows[i];
2268  if (win.GetExists() && win.GetVisible() && !win.GetChanged())
2269  continue;
2270  if (!win.GetChanged())
2271  continue;
2272 
2273  clearMask |= (1UL << i);
2274  win.ResetChanged();
2275  if (!win.GetExists() || !win.GetVisible())
2276  continue;
2277 
2278  QMutexLocker locker(&win.m_lock);
2279  std::vector<CC708String*> list = win.GetStrings();
2280  if (!list.empty())
2281  {
2282  auto *fsub = new FormattedTextSubtitle708(win, i, list, m_family,
2283  m_safeArea, this, video_aspect);
2284  addList.append(fsub);
2285  }
2287  }
2288  if (clearMask)
2289  {
2290  Clear708Cache(clearMask);
2291  }
2292  if (!addList.empty())
2293  m_qInited.append(addList);
2294 }
2295 
2296 void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos)
2297 {
2299  if (!vo)
2300  return;
2301 
2302  QRect scaled = vo->GetImageRect(pos);
2303  if (scaled.size() != pos.size())
2304  {
2305  img = img.scaled(scaled.width(), scaled.height(),
2306  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2307  }
2308 
2309  MythImage* image = m_painter->GetFormatImage();
2310  if (image)
2311  {
2312  image->Assign(img);
2313  MythUIImage *uiimage = new SubImage(this, "dvd_button", MythRect(scaled), 0ms);
2314  if (uiimage)
2315  {
2316  uiimage->SetImage(image);
2317  uiimage->SetArea(MythRect(scaled));
2318  SetElementAdded();
2319  }
2320  image->DecrRef();
2321  }
2322 }
2323 
2324 #ifdef USING_LIBASS
2325 static void myth_libass_log(int level, const char *fmt, va_list vl, void */*ctx*/)
2326 {
2327  uint64_t verbose_mask = VB_GENERAL;
2328  LogLevel_t verbose_level = LOG_INFO;
2329 
2330  switch (level)
2331  {
2332  case 0: //MSGL_FATAL
2333  verbose_level = LOG_EMERG;
2334  break;
2335  case 1: //MSGL_ERR
2336  verbose_level = LOG_ERR;
2337  break;
2338  case 2: //MSGL_WARN
2339  verbose_level = LOG_WARNING;
2340  break;
2341  case 4: //MSGL_INFO
2342  verbose_level = LOG_INFO;
2343  break;
2344  case 6: //MSGL_V
2345  case 7: //MSGL_DBG2
2346  verbose_level = LOG_DEBUG;
2347  break;
2348  default:
2349  return;
2350  }
2351 
2352  if (!VERBOSE_LEVEL_CHECK(verbose_mask, verbose_level))
2353  return;
2354 
2355  static QMutex s_stringLock;
2356  s_stringLock.lock();
2357 
2358  QString str = QString::vasprintf(fmt, vl);
2359  LOG(verbose_mask, verbose_level, QString("libass: %1").arg(str));
2360  s_stringLock.unlock();
2361 }
2362 
2364 {
2365  if (m_assLibrary && m_assRenderer)
2366  return true;
2367 
2368  if (!m_assLibrary)
2369  {
2370  m_assLibrary = ass_library_init();
2371  if (!m_assLibrary)
2372  return false;
2373 
2374  ass_set_message_cb(m_assLibrary, myth_libass_log, nullptr);
2375  ass_set_extract_fonts(m_assLibrary, static_cast<int>(true));
2376  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass object.");
2377  }
2378 
2379  LoadAssFonts();
2380 
2381  if (!m_assRenderer)
2382  {
2383  m_assRenderer = ass_renderer_init(m_assLibrary);
2384  if (!m_assRenderer)
2385  return false;
2386 
2387 #ifdef Q_OS_ANDROID
2388  // fontconfig doesn't yet work for us on Android. For the
2389  // time being, more explicitly set a font we know should
2390  // exist. This was adapted from VLC master as of 2019-01-21.
2391  const char *psz_font = "/system/fonts/DroidSans.ttf";
2392  const char *psz_font_family = "Droid Sans";
2393 #else
2394  const char *psz_font = nullptr;
2395  const char *psz_font_family = "sans-serif";
2396 #endif
2397  ass_set_fonts(m_assRenderer, psz_font, psz_font_family, 1, nullptr, 1);
2398  ass_set_hinting(m_assRenderer, ASS_HINTING_LIGHT);
2399  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass renderer.");
2400  }
2401 
2402  return true;
2403 }
2404 
2406 {
2407  if (!m_assLibrary || !m_player)
2408  return;
2409 
2411  if (m_assFontCount == count)
2412  return;
2413 
2414  ass_clear_fonts(m_assLibrary);
2415  m_assFontCount = 0;
2416 
2417  // TODO these need checking and/or reinitialising after a stream change
2418  for (uint i = 0; i < count; ++i)
2419  {
2420  QByteArray filename;
2421  QByteArray font;
2423  ass_add_font(m_assLibrary, filename.data(), font.data(), font.size());
2424  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Retrieved font '%1'")
2425  .arg(filename.constData()));
2426  m_assFontCount++;
2427  }
2428 }
2429 
2431 {
2432  CleanupAssTrack();
2433 
2434  if (m_assRenderer)
2435  ass_renderer_done(m_assRenderer);
2436  m_assRenderer = nullptr;
2437 
2438  if (m_assLibrary)
2439  {
2440  ass_clear_fonts(m_assLibrary);
2441  m_assFontCount = 0;
2442  ass_library_done(m_assLibrary);
2443  }
2444  m_assLibrary = nullptr;
2445 }
2446 
2448 {
2449  if (!InitialiseAssLibrary() || !m_player)
2450  return;
2451 
2452  if (tracknum == m_assTrackNum && m_assTrack)
2453  return;
2454 
2455  LoadAssFonts();
2456  CleanupAssTrack();
2457  m_assTrack = ass_new_track(m_assLibrary);
2458  m_assTrackNum = tracknum;
2459 
2460  QByteArray header = m_player->GetDecoder()->GetSubHeader(tracknum);
2461  if (!header.isNull())
2462  ass_process_codec_private(m_assTrack, header.data(), header.size());
2463 
2466 }
2467 
2469 {
2470  if (m_assTrack)
2471  ass_free_track(m_assTrack);
2472  m_assTrack = nullptr;
2473 }
2474 
2476 {
2477  if (m_assTrack && event)
2478  ass_process_data(m_assTrack, event, strlen(event));
2479 }
2480 
2482 {
2483  ass_set_frame_size(m_assRenderer, m_safeArea.width(), m_safeArea.height());
2484  ass_set_margins(m_assRenderer, 0, 0, 0, 0);
2485  ass_set_use_margins(m_assRenderer, static_cast<int>(true));
2486  ass_set_font_scale(m_assRenderer, 1.0);
2487 }
2488 
2489 void SubtitleScreen::RenderAssTrack(std::chrono::milliseconds timecode)
2490 {
2491  if (!m_player || !m_assRenderer || !m_assTrack)
2492  return;
2493 
2495  if (!vo )
2496  return;
2497 
2498  QRect oldscreen = m_safeArea;
2500  if (oldscreen != m_safeArea)
2502 
2503  int changed = 0;
2504  ASS_Image *images = ass_render_frame(m_assRenderer, m_assTrack, timecode.count(), &changed);
2505  if (!changed)
2506  return;
2507 
2508  int count = 0;
2511  while (images)
2512  {
2513  if (images->w == 0 || images->h == 0)
2514  {
2515  images = images->next;
2516  continue;
2517  }
2518 
2519  uint8_t alpha = images->color & 0xFF;
2520  uint8_t blue = images->color >> 8 & 0xFF;
2521  uint8_t green = images->color >> 16 & 0xFF;
2522  uint8_t red = images->color >> 24 & 0xFF;
2523 
2524  if (alpha == 255)
2525  {
2526  images = images->next;
2527  continue;
2528  }
2529 
2530  QSize img_size(images->w, images->h);
2531  QRect img_rect(images->dst_x,images->dst_y,
2532  images->w, images->h);
2533  QImage qImage(img_size, QImage::Format_ARGB32);
2534  qImage.fill(0x00000000);
2535 
2536  unsigned char *src = images->bitmap;
2537  for (int y = 0; y < images->h; ++y)
2538  {
2539  for (int x = 0; x < images->w; ++x)
2540  {
2541  uint8_t value = src[x];
2542  if (value)
2543  {
2544  uint32_t pixel = (value * (255 - alpha) / 255 << 24) |
2545  (red << 16) | (green << 8) | blue;
2546  qImage.setPixel(x, y, pixel);
2547  }
2548  }
2549  src += images->stride;
2550  }
2551 
2552  MythImage* image = m_painter->GetFormatImage();
2553  SubImage *uiimage = nullptr;
2554 
2555  if (image)
2556  {
2557  image->Assign(qImage);
2558  QString name = QString("asssub%1").arg(count);
2559  uiimage = new SubImage(this, name, MythRect(img_rect), 0ms);
2560  if (uiimage)
2561  {
2562  uiimage->SetImage(image);
2563  uiimage->SetArea(MythRect(img_rect));
2564  SetElementAdded();
2565  }
2566  image->DecrRef();
2567  }
2568 
2569  images = images->next;
2570  count++;
2571  }
2572 }
2573 #endif // USING_LIBASS
SubtitleScreen::DisplayRawTextSubtitles
void DisplayRawTextSubtitles(void)
Definition: subtitlescreen.cpp:2181
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
DecoderBase::NormalizeVideoTimecode
virtual std::chrono::milliseconds NormalizeVideoTimecode(std::chrono::milliseconds timecode)
Definition: decoderbase.h:184
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:166
SubWrapper
Definition: subtitlescreen.cpp:24
SubtitleFormat::m_shapeMap
QHash< QString, MythUIShape * > m_shapeMap
Definition: subtitlescreen.cpp:171
TextSubtitles::Unlock
void Unlock(void)
Definition: textsubtitleparser.h:94
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:2363
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:2296
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:2247
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
TextSubtitles::HasSubtitleChanged
bool HasSubtitleChanged(uint64_t timecode) const
Returns true in case the subtitle to display has changed since the last GetSubtitles() call.
Definition: textsubtitleparser.cpp:167
FormattedTextSubtitleSRT
Definition: subtitlescreen.h: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:1945
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
SubtitleScreen::DisplayTextSubtitles
void DisplayTextSubtitles(void)
Definition: subtitlescreen.cpp:2105
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:134
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:1828
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:2430
MythFontProperties::SetColor
void SetColor(const QColor &color)
Definition: mythfontproperties.cpp:49
MythPlayer::GetCC708Reader
virtual CC708Reader * GetCC708Reader(uint=0)
Definition: mythplayer.h:195
CC708Window::m_anchor_vertical
uint m_anchor_vertical
Definition: cc708window.h:256
pixel
static guint32 * pixel
--------------------------------------------------—**
Definition: goom_core.cpp:24
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:20
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
TextSubtitles::GetSubtitles
QStringList GetSubtitles(uint64_t timecode)
Returns the subtitles to display at the given timecode.
Definition: textsubtitleparser.cpp:180
FormattedTextSubtitle::m_safeArea
const QRect m_safeArea
Definition: subtitlescreen.h: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
SubtitleReader::ClearAVSubtitles
void ClearAVSubtitles(void)
Definition: subtitlereader.cpp:81
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:2216
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
SubtitleScreen::LoadAssFonts
void LoadAssFonts(void)
Definition: subtitlescreen.cpp:2405
SubtitleScreen::ResetElementState
void ResetElementState(void)
Definition: subtitlescreen.cpp:1787
SubtitleScreen::CalcTextSize
QSize CalcTextSize(const QString &text, const CC708CharacterAttribute &format, float layoutSpacing) const
Definition: subtitlescreen.cpp: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:25
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::AddAssEvent
void AddAssEvent(char *event)
Definition: subtitlescreen.cpp:2475
SubtitleScreen::RenderAssTrack
void RenderAssTrack(std::chrono::milliseconds timecode)
Definition: subtitlescreen.cpp:2489
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:196
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:2207
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:14
MythVideoOutput::GetImageRect
QRect GetImageRect(QRect Rect, QRect *DisplayRect=nullptr)
translates caption/dvd button rectangle into 'screen' space
Definition: mythvideoout.cpp:322
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:129
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:134
SubtitleScreen::CleanupAssTrack
void CleanupAssTrack(void)
Definition: subtitlescreen.cpp:2468
SubtitleScreen::ClearDisplayedSubtitles
void ClearDisplayedSubtitles(void)
Definition: subtitlescreen.cpp:1478
SubtitleScreen::ResizeAssRenderer
void ResizeAssRenderer(void)
Definition: subtitlescreen.cpp:2481
MythUIType::m_childrenList
QList< MythUIType * > m_childrenList
Definition: mythuitype.h:253
TextSubtitles
Definition: textsubtitleparser.h:36
SubtitleReader::FreeAVSubtitle
static void FreeAVSubtitle(AVSubtitle &sub)
Definition: subtitlereader.cpp:92
SubtitleReader::GetTextSubtitles
TextSubtitles * GetTextSubtitles(void)
Definition: subtitlereader.h:54
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:30
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:79
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:55
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:111
myth_libass_log
static void myth_libass_log(int level, const char *fmt, va_list vl, void *)
Definition: subtitlescreen.cpp:2325
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
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:186
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:197
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:48
SubtitleFormat::m_cleanup
QVector< MythUIType * > m_cleanup
Definition: subtitlescreen.cpp:179
k708AttrSizeSmall
const uint k708AttrSizeSmall
Definition: cc708window.cpp:76
buffers
Definition: freesurround.cpp:50
TextSubtitles::Lock
void Lock(void)
Definition: textsubtitleparser.h:93
prevY
unsigned int prevY
Definition: filters.cpp:110
CalcShadowOffsetPadding
static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont)
Definition: subtitlescreen.cpp:1614
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:18
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:2447
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:47
SubtitleFormat::m_fontMap
QHash< QString, MythFontProperties * > m_fontMap
Definition: subtitlescreen.cpp:170
AVSubtitles::m_fixPosition
bool m_fixPosition
Definition: subtitlereader.h:20
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:133
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:1793
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:19
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
TextSubtitles::IsFrameBasedTiming
bool IsFrameBasedTiming(void) const
Returns true in case the subtitle timing data is frame-based.
Definition: textsubtitleparser.h:62
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:749
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:881
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