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