Ticket #12057: 12057.patch
File 12057.patch, 37.6 KB (added by , 10 years ago) |
---|
-
mythtv/libs/libmythtv/subtitlescreen.cpp
diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp index 965e3b0..b40b9cf 100644
a b public: 72 72 MythImage *GetImage(void) { return m_Images[0]; } 73 73 }; 74 74 75 // Used to lookup fonts by family, attributes, zoom and stretch factors. 76 class SubtitleFontKey 77 { 78 public: 79 SubtitleFontKey(const QString &family, 80 const CC708CharacterAttribute &attr, 81 int zoom, int stretch) 82 : m_family(family), m_attr(attr), m_zoom(zoom), m_stretch(stretch) 83 {} 84 ~SubtitleFontKey(void) {} 85 86 QString m_family; 87 CC708CharacterAttribute m_attr; 88 int m_zoom; 89 int m_stretch; 90 91 bool operator==(const SubtitleFontKey &other) const; 92 }; 93 94 bool 95 SubtitleFontKey::operator==(const SubtitleFontKey &other) const 96 { 97 return 98 (m_family == other.m_family && 99 m_attr.pen_size == other.m_attr.pen_size && 100 m_attr.offset == other.m_attr.offset && 101 m_attr.text_tag == other.m_attr.text_tag && 102 m_attr.font_tag == other.m_attr.font_tag && 103 m_attr.edge_type == other.m_attr.edge_type && 104 m_attr.underline == other.m_attr.underline && 105 m_attr.italics == other.m_attr.italics && 106 m_attr.boldface == other.m_attr.boldface && 107 m_attr.fg_color == other.m_attr.fg_color && 108 m_attr.fg_opacity == other.m_attr.fg_opacity && 109 m_attr.bg_color == other.m_attr.bg_color && 110 m_attr.bg_opacity == other.m_attr.bg_opacity && 111 m_attr.edge_color == other.m_attr.edge_color && 112 m_attr.actual_fg_color == other.m_attr.actual_fg_color && 113 m_zoom == other.m_zoom && 114 m_stretch == other.m_stretch); 115 } 116 117 uint qHash(const SubtitleFontKey &key); 118 119 uint 120 qHash(const SubtitleFontKey &key) 121 { 122 return qHash(key.m_family) + 123 key.m_attr.pen_size + 124 key.m_attr.offset + 125 key.m_attr.text_tag + 126 key.m_attr.font_tag + 127 key.m_attr.edge_type + 128 key.m_attr.underline + 129 key.m_attr.italics + 130 key.m_attr.boldface + 131 key.m_attr.fg_color + 132 key.m_attr.fg_opacity + 133 key.m_attr.bg_color + 134 key.m_attr.bg_opacity + 135 key.m_attr.edge_color + 136 qHash(key.m_attr.actual_fg_color.name()) + 137 key.m_zoom + 138 key.m_stretch; 139 } 140 75 141 //////////////////////////////////////////////////////////////////////////// 76 142 77 143 // Class SubtitleFormat manages fonts and backgrounds for subtitles. … … public: 130 196 class SubtitleFormat 131 197 { 132 198 public: 133 SubtitleFormat(void) {} 199 SubtitleFormat(SubtitleScreen* screen = 0, 200 MythPlayer *player = 0, 201 int stretch = 100); 134 202 ~SubtitleFormat(void); 135 203 MythFontProperties *GetFont(const QString &family, 136 204 const CC708CharacterAttribute &attr, 137 int pixelSize, int zoom, int stretch);205 int zoom); 138 206 SubShape *GetBackground(MythUIType *parent, const QString &name, 139 207 const QString &family, 140 208 const CC708CharacterAttribute &attr, … … public: 143 211 int start, int duration); 144 212 static QString MakePrefix(const QString &family, 145 213 const CC708CharacterAttribute &attr); 214 215 // Temporary method until teletextscreen.cpp is refactored into 216 // subtitlescreen.cpp 217 // GetTeletextFontName is the only public method that should be called 218 // when m_subScreen and m_player are null 219 QString GetTeletextFontName(void); 220 146 221 private: 147 222 void Load(const QString &family, 148 223 const CC708CharacterAttribute &attr); … … private: 164 239 MythUIShape *bg1, 165 240 MythUIShape *bg2); 166 241 242 // Hash table of default font properties by family 167 243 QHash<QString, MythFontProperties *> m_fontMap; 168 244 QHash<QString, MythUIShape *> m_shapeMap; 169 245 QHash<QString, QSet<QString> > m_changeMap; … … private: 173 249 QHash<QString, int> m_pixelSizeMap; 174 250 QHash<QString, int> m_outlineSizeMap; 175 251 QHash<QString, QPoint> m_shadowOffsetMap; 252 253 // Hash table of font properties by family, atttributes, zoom & stretch 254 QHash<SubtitleFontKey, MythFontProperties *> m_fullFontMap; 255 176 256 QVector<MythUIType *> m_cleanup; 257 SubtitleScreen* m_subScreen; 258 MythPlayer* m_player; 259 int m_fontStretch; 177 260 }; 178 261 179 262 static const QString kSubProvider("provider"); … … static QString fontToString(MythFontProperties *f) 243 326 MythFontProperties * 244 327 SubtitleFormat::GetFont(const QString &family, 245 328 const CC708CharacterAttribute &attr, 246 int pixelSize, int zoom, int stretch)329 int zoom) 247 330 { 248 int origPixelSize = pixelSize; 331 QString prefix = MakePrefix(family, attr); 332 SubtitleFontKey key(prefix, attr, zoom, m_fontStretch); 333 if (m_fullFontMap.contains(key)) 334 return m_fullFontMap[key]; 335 336 if (!m_fontMap.contains(prefix)) 337 Load(family, attr); 338 339 // Make a copy we can modify once and reuse many times 340 MythFontProperties *result = new MythFontProperties(*(m_fontMap[prefix])); 341 m_fullFontMap[key] = result; 342 249 343 float scale = zoom / 100.0; 250 344 if ((attr.pen_size & 0x3) == k708AttrSizeSmall) 251 345 scale = scale * 32 / 42; 252 346 else if ((attr.pen_size & 0x3) == k708AttrSizeLarge) 253 347 scale = scale * 42 / 32; 254 348 255 QString prefix = MakePrefix(family, attr);256 if (!m_fontMap.contains(prefix))257 Load(family, attr);258 MythFontProperties *result = m_fontMap[prefix];259 260 349 // Apply the scaling factor to pixelSize even if the theme 261 350 // explicitly sets pixelSize. 262 i f (!IsUnlocked(prefix, kSubAttrPixelsize))263 pixelSize = m_pixelSizeMap[prefix];351 int pixelSize = m_pixelSizeMap[prefix]; 352 int origPixelSize = pixelSize; 264 353 pixelSize *= scale; 265 354 result->GetFace()->setPixelSize(pixelSize); 266 355 267 result->GetFace()->setStretch(stretch); 356 // Stretch is now set in SubtitleFormat::Load 357 // result->GetFace()->setStretch(stretch); 358 268 359 if (IsUnlocked(prefix, kSubAttrItalics)) 269 360 result->GetFace()->setItalic(attr.italics); 270 361 if (IsUnlocked(prefix, kSubAttrUnderline)) … … SubtitleFormat::GetFont(const QString &family, 300 391 else 301 392 { 302 393 offset = m_shadowOffsetMap[prefix]; 303 offset.NormPoint(); 394 // Shadow offset has already been scaled from theme to screen 395 // Why do it again? 396 // offset.NormPoint(); 304 397 offset.setX(offset.x() * scale + 0.5); 305 398 offset.setY(offset.y() * scale + 0.5); 306 399 } … … SubtitleFormat::GetFont(const QString &family, 328 421 else 329 422 { 330 423 off = m_outlineSizeMap[prefix]; 331 MythPoint point(off, off); 332 point.NormPoint(); 333 off = point.x() * scale + 0.5; 424 // Outline has already been scaled by SubtitleFormat::Load. 425 // Why do it again? 426 // MythPoint point(off, off); 427 // point.NormPoint(); 428 off = off * scale + 0.5; 334 429 } 335 430 result->SetOutline(outline, color, off, alpha); 336 431 337 432 LOG(VB_VBI, LOG_DEBUG, 338 433 QString("GetFont(family=%1, prefix=%2, orig pixelSize=%3, " 339 " new pixelSize=%4 zoom=%5) = %6")340 .arg(family).arg(prefix).arg(origPixelSize) .arg(pixelSize)341 .arg(zoom).arg( fontToString(result)));434 "zoom=%4, stretch=%5) = %6") 435 .arg(family).arg(prefix).arg(origPixelSize) 436 .arg(zoom).arg(m_fontStretch).arg(fontToString(result))); 342 437 return result; 343 438 } 344 439 440 QString SubtitleFormat::GetTeletextFontName(void) 441 { 442 CC708CharacterAttribute attr(false, false, false, Qt::white); 443 444 QString prefix = MakePrefix(kSubFamilyTeletext, attr); 445 if (!m_fontMap.contains(prefix)) 446 Load(kSubFamilyTeletext, attr); 447 MythFontProperties *result = m_fontMap[prefix]; 448 return result->face().family(); 449 } 450 451 SubtitleFormat::SubtitleFormat(SubtitleScreen* screen, MythPlayer* player, 452 int stretch) : 453 m_subScreen(screen), m_player(player), m_fontStretch(stretch) 454 { 455 } 456 345 457 SubtitleFormat::~SubtitleFormat(void) 346 458 { 459 QHash<SubtitleFontKey, MythFontProperties*>::const_iterator it; 460 for (it = m_fullFontMap.constBegin(); it != m_fullFontMap.constEnd(); it++) 461 { 462 delete (*it); 463 } 464 347 465 for (int i = 0; i < m_cleanup.size(); ++i) 348 466 { 349 467 m_cleanup[i]->DeleteAllChildren(); … … void SubtitleFormat::CreateProviderDefault(const QString &family, 402 520 403 521 if (isComplement) 404 522 Complement(font, bg); 405 parent->AddFont(kSubProvider, font);406 523 407 *returnFont = font; 524 // This ultimately calls FontMap::AddFont, which makes a deep copy 525 // so we need to delete font. 526 // In case something changes underneath, we make sure the value 527 // returned by parent->GetFont is indeed different. 528 parent->AddFont(kSubProvider, font); 529 *returnFont = parent->GetFont(kSubProvider); 530 if (*returnFont != font) 531 delete font; 408 532 *returnBg = bg; 409 533 } 410 534 … … void SubtitleFormat::Load(const QString &family, 501 625 QPoint offset; 502 626 QColor color; 503 627 int alpha; 504 int size;505 628 resultFont->GetShadow(offset, color, alpha); 629 m_shadowOffsetMap[prefix] = offset; 630 631 // Shadow offset is scaled from theme to screen when it is parsed. 632 // But outline size is not. 633 // As long as this inconsistency exists, we scale outline size here. 634 int size; 506 635 resultFont->GetOutline(color, size, alpha); 636 MythPoint outline(size, size); 637 outline.NormPoint(); 638 size = outline.x(); 507 639 m_outlineSizeMap[prefix] = size; 508 m_shadowOffsetMap[prefix] = offset;509 m_pixelSizeMap[prefix] = resultFont->GetFace()->pixelSize();510 640 511 delete negFont; 641 // Fixed memory leak in SubtitleFormat::CreateProviderDefault, 642 // so negFont shouldn't be deleted here. 643 // It will be deleted later when negParent is deleted via m_cleanup 644 // delete negFont; 645 646 // Font stretch is constant for the life of each SubtitleScreen instance. 647 // So the same is true for SubtitleFormat. 648 // It is 100 for most playback profiles. 649 // But the Slim profile changes it whenever the video zoom factor changes. 650 // When that happens, the current SubtitleScreen is deleted 651 // and a new SubtitleScreen with a new font stretch is instantiated. 652 resultFont->GetFace()->setStretch(m_fontStretch); 653 654 // If the user hasn't defined a pixelsize 655 // and not called via teletextscreen.cpp (where m_subScreen is null), 656 // set a default 657 if (IsUnlocked(prefix, kSubAttrPixelsize) && m_subScreen != 0) 658 { 659 QRect safeArea = m_subScreen->GetSafeArea(); 660 LOG(VB_VBI, LOG_DEBUG, 661 QString("safeArea=%1x%2@%3,%4") 662 .arg(safeArea.width()) 663 .arg(safeArea.height()) 664 .arg(safeArea.x()) 665 .arg(safeArea.y())); 666 667 // Start with 608 row,col dimensions 668 int cols = 32; // 608 max columns 669 int rows = 15; // 608 max rows 670 671 // Adjust by family 672 if (kSubFamily708 == family || kSubFamilyText == family) 673 { 674 // Assumption: .srt and .txt line lengths will be within 675 // the limits of 708 captions, whose # of columns depends on 676 // the source video's aspect ratio. 677 cols = (m_player->GetVideoAspect() > 1.4f) ? 42 : 32; 678 rows = 15; 679 } 680 //else if (kSubFamilyAV == family) 681 //{ 682 // DVB bitmapped subtitles? 683 //} 684 else if (kSubFamilyTeletext == family) 685 { 686 // Constants defined in teletextscreen.cpp 687 // Copied values rather than depend on something that 688 // going to be refactored? 689 cols = 40; // TeletextScreen::kTeletextColumns 690 rows = 26; // TeletextScreen::kTeletextRows 691 } 692 693 // Add one to cols to account for 1/2 char width left&right padding. 694 cols++; 695 696 // Target lineHeight 697 int lineHeight = safeArea.height() / rows; 698 699 // Set pixelSize to the target lineHeight 700 int pixelSize = lineHeight; 701 // Reduce by shadow offset or outline size 702 pixelSize -= max(abs(offset.y()), size); 703 // It is a first guess pixelSize, which will almost certainly be off 704 705 QFont *font = resultFont->GetFace(); 706 font->setPixelSize(pixelSize); 707 QFontMetrics fm(*font); 708 709 // Font metrics for various fonts are inconsistent in how 710 // they provide a realistic line height value. 711 // The max of what they call height and lineSpacing 712 // provides a resonable value for most fonts. 713 int newLineHeight = max(fm.height(), fm.lineSpacing()); 714 // Increase by shadow offset or outline size 715 newLineHeight += max(abs(offset.y()), size); 716 717 int offBy = newLineHeight - lineHeight; 718 int newPixelSize = pixelSize; 719 if (offBy != 0) 720 { 721 // We tried a pixelSize equal to the desired line height 722 // with shadow & outline adjustments, 723 // but it didn't quite get us there. 724 // We make a better guess by applying a ratio of 725 // our first guess divided by the actual height. 726 // This should be "good enough" for most fonts. 727 newPixelSize = (int)((float)pixelSize*pixelSize/newLineHeight + 0.5); 728 font->setPixelSize(newPixelSize); 729 fm = QFontMetrics(*font); 730 newLineHeight = max(fm.height(), fm.lineSpacing()); 731 newLineHeight += max(abs(offset.y()), size); 732 } 733 734 int fontwidth = fm.averageCharWidth(); 735 int maxwidth = (safeArea.width() - max(abs(offset.x()), size)) / cols; 736 737 LOG(VB_VBI, LOG_DEBUG, 738 QString("family=%1 default-pixelSize=%2->%3 lineHeight=%4->%5 " 739 "offBy=%6 fontwidth=%7 maxwidth=%8 shadow-offset=%9,%10 " 740 "outline=%11") 741 .arg(family).arg(pixelSize).arg(newPixelSize) 742 .arg(lineHeight).arg(newLineHeight) 743 .arg(offBy).arg(fontwidth).arg(maxwidth) 744 .arg(offset.x()).arg(offset.y()).arg(size)); 745 746 // Check if fontwidth exceeds maxwidth 747 // Just log it for now. We'll deal with it, if/when someone 748 // reports a problem. 749 if (fontwidth > maxwidth) 750 { 751 LOG(VB_GENERAL, LOG_WARNING, 752 QString("fontwidth=%1 exceeds maxwidth=%2") 753 .arg(fontwidth).arg(maxwidth)); 754 } 755 756 m_pixelSizeMap[prefix] = newPixelSize; 757 } 758 else 759 { 760 int pixelSize = resultFont->GetFace()->pixelSize(); 761 LOG(VB_VBI, LOG_DEBUG, 762 QString("family=%1 user defined pixelSize=%2") 763 .arg(family).arg(pixelSize)); 764 m_pixelSizeMap[prefix] = pixelSize; 765 } 512 766 } 513 767 514 768 QSet<QString> SubtitleFormat::Diff(const QString &family, … … SubtitleFormat::GetBackground(MythUIType *parent, const QString &name, 615 869 616 870 //////////////////////////////////////////////////////////////////////////// 617 871 618 QSize FormattedTextChunk::CalcSize(float layoutSpacing) const872 QSize FormattedTextChunk::CalcSize(float layoutSpacing) 619 873 { 620 return parent->CalcTextSize(text, m_format, layoutSpacing); 874 if (!textFont) 875 textFont = parent->GetFont(m_format); 876 return parent->CalcTextSize(text, m_format, layoutSpacing, textFont); 621 877 } 622 878 623 879 void FormattedTextChunk::CalcPadding(bool isFirst, bool isLast, 624 int &left, int &right) const880 int &left, int &right) 625 881 { 626 parent->CalcPadding(m_format, isFirst, isLast, left, right); 882 if (!textFont) 883 textFont = parent->GetFont(m_format); 884 parent->CalcPadding(m_format, isFirst, isLast, left, right, textFont); 627 885 } 628 886 629 887 bool FormattedTextChunk::Split(FormattedTextChunk &newChunk) … … QString FormattedTextChunk::ToLogString(void) const 673 931 bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 674 932 int &x, int y, int height) 675 933 { 676 textFont = parent->GetFont(m_format);677 934 if (!textFont) 678 return false; 935 textFont = parent->GetFont(m_format); 936 679 937 QFontMetrics font(*(textFont->GetFace())); 680 938 // If the chunk starts with whitespace, the leading whitespace 681 939 // ultimately gets lost due to the text.trimmed() operation in the … … bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 690 948 int leftPadding, rightPadding; 691 949 CalcPadding(isFirst, isLast, leftPadding, rightPadding); 692 950 // Account for extra padding before the first chunk. 693 if (isFirst) 694 x += leftPadding; 951 // No, this will cause everything to be off center to the right 952 // by the value of leftPadding. 953 // if (isFirst) 954 // x += leftPadding; 695 955 QSize chunk_sz = CalcSize(); 696 956 QRect bgrect(x - leftPadding, y, 697 957 chunk_sz.width() + leftPadding + rightPadding, … … bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 710 970 textRect = QRect(x + x_adjust, y, 711 971 chunk_sz.width() - x_adjust + rightPadding, height); 712 972 973 // If this chunk is in italics, add a few pixels to the width. 974 // This is to compensate for some font/char combos that would otherwise 975 // have the top right corner of the last char clipped. 976 // The effect can be seen with Droid Sans Mono and certain upper case chars 977 // like E or W. 978 // But don't add this padding to the next chunk's x coordinate. 979 // That would add too much spacing between chunks. 980 if (m_format.italics) 981 { 982 int oldWidth = textRect.width(); 983 textRect.setWidth(oldWidth + font.averageCharWidth() / 2); 984 LOG(VB_VBI, LOG_DEBUG, 985 QString("Pad for italics width %1 -> %2") 986 .arg(oldWidth).arg(textRect.width())); 987 } 988 713 989 x += chunk_sz.width(); 714 990 return true; 715 991 } 716 992 717 QSize FormattedTextLine::CalcSize(float layoutSpacing ) const993 QSize FormattedTextLine::CalcSize(float layoutSpacing, bool addPadding) 718 994 { 719 995 int height = 0, width = 0; 720 996 int leftPadding = 0, rightPadding = 0; 721 QList<FormattedTextChunk>:: const_iterator it;722 bool isFirst = true;723 for (it = chunks. constBegin(); it != chunks.constEnd(); ++it)997 QList<FormattedTextChunk>::iterator it; 998 bool isFirst = (addPadding ? true : false); 999 for (it = chunks.begin(); it != chunks.end(); ++it) 724 1000 { 725 bool isLast = ( it + 1 == chunks.constEnd());1001 bool isLast = (addPadding ? (it + 1 == chunks.constEnd()) : false); 726 1002 QSize tmp = (*it).CalcSize(layoutSpacing); 727 1003 height = max(height, tmp.height()); 728 1004 width += tmp.width(); 729 (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding); 1005 // We don't need to call CalcPadding if addPadding is false 1006 if (addPadding) 1007 (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding); 730 1008 if (it == chunks.constBegin()) 731 1009 width += leftPadding; 732 1010 isFirst = false; … … FormattedTextSubtitle::FormattedTextSubtitle(void) : 761 1039 // Normal font height is designed to be 1/20 of safe area height, with 762 1040 // extra blank space between lines to make 17 lines within the safe 763 1041 // area. 764 static const float LINE_SPACING = (20.0 / 17.0); 1042 // static const float LINE_SPACING = (20.0 / 17.0); 1043 static const float LINE_SPACING = 0.0; 765 1044 static const float PAD_WIDTH = 0.5; 766 static const float PAD_HEIGHT = 0.04;1045 // static const float PAD_HEIGHT = 0.04; 767 1046 768 1047 // Resolves any TBD x_indent and y_indent values in FormattedTextLine 769 1048 // objects. Calculates m_bounds. Prunes most leading and all … … void FormattedTextSubtitle::Layout(void) 776 1055 int anchor_height = 0; 777 1056 for (int i = 0; i < m_lines.size(); i++) 778 1057 { 779 QSize sz = m_lines[i].CalcSize(LINE_SPACING); 1058 // We don't want padding added at this point. 1059 // Padding applies to the background. 1060 // We want to know where the txt should be drawn, 1061 // not where the background shoould be drawn. 1062 QSize sz = m_lines[i].CalcSize(LINE_SPACING, false); 780 1063 anchor_width = max(anchor_width, sz.width()); 781 1064 anchor_height += sz.height(); 782 1065 } … … void FormattedTextSubtitle::Layout(void) 797 1080 anchor_y = max(0, min(anchor_y, m_safeArea.height() - anchor_height)); 798 1081 anchor_x = max(0, min(anchor_x, m_safeArea.width() - anchor_width)); 799 1082 800 m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height); 1083 // m_bounds needs padding. 1084 // Get it using the first chunk of the first line. 1085 int left = 0; 1086 int right = 0; 1087 m_lines[0].chunks.first().CalcPadding(true, true, left, right); 1088 m_bounds = QRect(anchor_x-left, 1089 anchor_y, 1090 anchor_width+left+right, 1091 anchor_height); 801 1092 802 1093 // Fill in missing coordinates 803 1094 int y = anchor_y; … … void FormattedTextSubtitle::Layout(void) 807 1098 m_lines[i].x_indent = anchor_x; 808 1099 if (m_lines[i].y_indent < 0) 809 1100 m_lines[i].y_indent = y; 810 y += m_lines[i].CalcSize(LINE_SPACING ).height();1101 y += m_lines[i].CalcSize(LINE_SPACING, false).height(); 811 1102 // Prune leading all-whitespace chunks. 812 1103 while (!m_lines[i].chunks.isEmpty() && 813 1104 m_lines[i].chunks.first().text.trimmed().isEmpty()) … … void FormattedTextSubtitle::PreRender(void) 842 1133 { 843 1134 int x = m_lines[i].x_indent; 844 1135 int y = m_lines[i].y_indent; 845 int height = m_lines[i].CalcSize( ).height();1136 int height = m_lines[i].CalcSize(LINE_SPACING, false).height(); 846 1137 QList<FormattedTextChunk>::iterator chunk; 847 1138 bool isFirst = true; 848 1139 for (chunk = m_lines[i].chunks.begin(); … … void FormattedTextSubtitle::Draw(void) 871 1162 { 872 1163 MythFontProperties *mythfont = 873 1164 m_subScreen->GetFont((*chunk).m_format); 874 if (!mythfont) 875 continue; 1165 // Never returns NULL 1166 // if (!mythfont) 1167 // continue; 876 1168 // Note: NULL is passed as the parent argument to the 877 1169 // MythUI constructors so that we can control the drawing 878 1170 // order of the children. In particular, background 879 1171 // shapes should be added/drawn first, and text drawn on 880 1172 // top. 1173 LOG(VB_VBI, LOG_DEBUG, 1174 QString("i=%1 rect=%2x%3@%4,%5 bgrect=%6x%7@%8,%9 text=%10") 1175 .arg(i) 1176 .arg(chunk->textRect.width()) 1177 .arg(chunk->textRect.height()) 1178 .arg(chunk->textRect.x()) 1179 .arg(chunk->textRect.y()) 1180 .arg(chunk->bgShapeRect.width()) 1181 .arg(chunk->bgShapeRect.height()) 1182 .arg(chunk->bgShapeRect.x()) 1183 .arg(chunk->bgShapeRect.y()) 1184 .arg(chunk->text)); 881 1185 if ((*chunk).textRect.width() > 0) { 882 1186 SubSimpleText *text = 883 1187 new SubSimpleText((*chunk).text, *mythfont, … … void FormattedTextSubtitleSRT::Init(const QStringList &subs) 972 1276 // <font color="#xxyyzz"> - change font color 973 1277 // </font> - reset font color to white 974 1278 975 int pixelSize = m_safeArea.height() / 20;976 if (m_subScreen)977 m_subScreen->SetFontSize(pixelSize);978 1279 m_xAnchorPoint = 1; // center 979 1280 m_yAnchorPoint = 2; // bottom 980 1281 m_xAnchor = m_safeArea.width() / 2; … … void FormattedTextSubtitle608::Layout(void) 1182 1483 int y = m_lines[i].y_indent; 1183 1484 if (i == 0) 1184 1485 firstY = prevY = y; 1185 int height = m_lines[i].CalcSize( ).height();1486 int height = m_lines[i].CalcSize(LINE_SPACING, false).height(); 1186 1487 heights[i] = height; 1187 1488 spaceBefore[i] = y - prevY; 1188 1489 totalSpace += (y - prevY); … … void FormattedTextSubtitle608::Layout(void) 1203 1504 m_lines[i].y_indent = prevY + spaceBefore[i] * shrink; 1204 1505 prevY = m_lines[i].y_indent + heights[i]; 1205 1506 } 1507 LOG(VB_VBI, LOG_DEBUG, 1508 QString("Shrink overage=%1 totalSpace=%2 shrink=%3 firstY=%4 prevY=%5") 1509 .arg(overage).arg(totalSpace).arg(shrink).arg(firstY).arg(prevY)); 1206 1510 } 1207 1511 1208 1512 // Shift Y coordinates back up into the safe area. … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1224 1528 if (buffers.empty()) 1225 1529 return; 1226 1530 vector<CC608Text*>::const_iterator i = buffers.begin(); 1227 int xscale = 36; 1228 int yscale = 17; 1229 int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING); 1531 1532 int xscale = 32; // 608 max columns 1533 int yscale = 15; // 608 max rows 1534 1535 int lineHeight = m_safeArea.height() / yscale; 1230 1536 int fontwidth = 0; 1231 1537 int xmid = 0; 1232 int zoom = 100;1538 // int zoom = 100; 1233 1539 if (m_subScreen) 1234 1540 { 1235 zoom = m_subScreen->GetZoom(); 1236 m_subScreen->SetFontSize(pixelSize); 1541 // zoom = m_subScreen->GetZoom(); 1237 1542 CC708CharacterAttribute def_attr(false, false, false, clr[0]); 1238 QFont *font = m_subScreen->GetFont(def_attr)->GetFace(); 1543 MythFontProperties* mythfont = m_subScreen->GetFont(def_attr); 1544 QFont *font = mythfont->GetFace(); 1239 1545 QFontMetrics fm(*font); 1240 1546 fontwidth = fm.averageCharWidth(); 1241 1547 xmid = m_safeArea.width() / 2; 1548 1549 // Font metrics for various fonts are inconsistent in how 1550 // they provide a realistic line height value. 1551 // The max of what they call height and lineSpacing 1552 // provides a resonable value for most fonts. 1553 lineHeight = max(fm.height(), fm.lineSpacing()); 1554 1555 // Increase by shadow offset and/or outline size 1556 QPoint offset; 1557 QColor color; 1558 int alpha; 1559 mythfont->GetShadow(offset, color, alpha); 1560 1561 int size; 1562 mythfont->GetOutline(color, size, alpha); 1563 1564 lineHeight += max(abs(offset.y()), size); 1565 1242 1566 // Disable centering for zoom factor >= 100% 1243 if (zoom >= 100) 1244 xscale = m_safeArea.width() / fontwidth; 1567 // Why?? If disabled, 608 captions are shifted to left unless 1568 // the user sets the zoom to 99% or less. 1569 // The Layout method should shift left-right and up-down 1570 // as needed for zoom factor. 1571 // If zoom factor is too large, the user can reduce it. 1572 // If they don't we'll clip what doesn't fit. 1573 //if (zoom >= 100) 1574 // xscale = m_safeArea.width() / fontwidth; 1245 1575 } 1246 1576 1247 1577 for (; i != buffers.end(); ++i) … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1252 1582 const bool isBold = false; 1253 1583 QString text(cc->text); 1254 1584 1585 // Note: cc-x (and orig_x) is column # ranging from 0 through 31, 1255 1586 int orig_x = cc->x; 1256 1587 // position as if we use a fixed size font 1257 1588 // - font size already has zoom factor applied … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1264 1595 // fallback 1265 1596 x = (orig_x + 3) * m_safeArea.width() / xscale; 1266 1597 1598 // Note: cc-y (and orig_y) is row # ranging from 1 through 15, 1599 // we need zero based rows 1267 1600 int orig_y = cc->y; 1268 1601 int y; 1269 if (orig_y < yscale / 2)1602 if (orig_y <= yscale / 2) 1270 1603 // top half -- anchor up 1271 y = (orig_y * m_safeArea.height() * zoom / (yscale * 100));1604 y = (orig_y-1) * lineHeight; 1272 1605 else 1273 1606 // bottom half -- anchor down 1274 y = m_safeArea.height() - 1275 ((yscale - orig_y - 0.5) * m_safeArea.height() * zoom / 1276 (yscale * 100)); 1607 y = m_safeArea.height() - ((yscale - (orig_y-1)) * lineHeight); 1277 1608 1278 1609 FormattedTextLine line(x, y, orig_x, orig_y); 1279 1610 while (!text.isNull()) … … void FormattedTextSubtitle708::Init(const CC708Window &win, 1319 1650 "relative %5") 1320 1651 .arg(m_num).arg(win.anchor_point).arg(win.anchor_horizontal) 1321 1652 .arg(win.anchor_vertical).arg(win.relative_pos)); 1322 int pixelSize = m_safeArea.height() / 20;1323 if (m_subScreen)1324 m_subScreen->SetFontSize(pixelSize);1325 1653 1326 1654 float xrange = win.relative_pos ? 100.0f : 1327 1655 (aspect > 1.4f) ? 210.0f : 160.0f; 1328 1656 float yrange = win.relative_pos ? 100.0f : 75.0f; 1329 float xmult = (float)m_safeArea.width() / xrange; 1657 1658 // Center the window addressable area based on the first string's font. 1659 // Assumption: Most caption providers do not change font within a window 1660 MythFontProperties* mythFont = m_subScreen->GetFont(list[0]->attr); 1661 QFont* font = mythFont->GetFace(); 1662 QFontMetrics fm(*font); 1663 int cols = (aspect > 1.4f) ? 42 : 32; 1664 int centerWidth = min(m_safeArea.width(), cols * fm.averageCharWidth()); 1665 int xoffset = (m_safeArea.width() - centerWidth) / 2; 1666 1667 float xmult = (float)centerWidth / xrange; 1330 1668 float ymult = (float)m_safeArea.height() / yrange; 1331 1669 uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal); 1332 1670 uint anchor_y = (uint)(ymult * (float)win.anchor_vertical); 1333 1671 m_xAnchorPoint = win.anchor_point % 3; 1334 1672 m_yAnchorPoint = win.anchor_point / 3; 1335 m_xAnchor = anchor_x; 1673 1674 // Should work equally for both left & right anchor points. 1675 m_xAnchor = (m_xAnchorPoint == 1) ? anchor_x : xoffset + anchor_x; 1336 1676 m_yAnchor = anchor_y; 1337 1677 1678 LOG(VB_VBI, LOG_INFO, 1679 QString("708 centerWidth=%1 xoffset=%2 anchorPoints=%3,%4 anchors=%5,%6") 1680 .arg(centerWidth).arg(xoffset) 1681 .arg(m_xAnchorPoint).arg(m_yAnchorPoint) 1682 .arg(m_xAnchor).arg(m_yAnchor)); 1683 1338 1684 for (uint i = 0; i < list.size(); i++) 1339 1685 { 1340 1686 if (list[i]->y >= (uint)m_lines.size()) … … SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name, 1354 1700 m_player(player), m_subreader(NULL), m_608reader(NULL), 1355 1701 m_708reader(NULL), m_safeArea(QRect()), 1356 1702 m_removeHTML(QRegExp("</?.+>")), m_subtitleType(kDisplayNone), 1357 m_fontSize(0),1358 1703 m_textFontZoom(100), m_textFontZoomPrev(100), 1359 1704 m_textFontDelayMs(0), m_textFontDelayMsPrev(0), 1360 1705 m_refreshModified(false), m_refreshDeleted(false), 1361 1706 m_fontStretch(fontStretch), 1362 m_format(new SubtitleFormat )1707 m_format(new SubtitleFormat(this, player, fontStretch)) 1363 1708 { 1364 1709 m_removeHTML.setMinimal(true); 1365 1710 … … void SubtitleScreen::Clear708Cache(uint64_t mask) 1573 1918 // the subtitle screen. 1574 1919 void SubtitleScreen::SetElementAdded(void) 1575 1920 { 1921 if (!m_refreshModified) 1922 SetRedraw(); 1576 1923 m_refreshModified = true; 1577 1924 } 1578 1925 … … static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont) 1605 1952 if (mythfont->hasOutline()) 1606 1953 { 1607 1954 mythfont->GetOutline(color, outlineSize, alpha); 1608 MythPoint outline(outlineSize, outlineSize); 1609 outline.NormPoint(); 1610 outlineSize = outline.x(); 1955 // Outline has already been scaled by SubtitleFormat::Load 1956 // MythPoint outline(outlineSize, outlineSize); 1957 // outline.NormPoint(); 1958 // outlineSize = outline.x(); 1611 1959 } 1612 1960 if (mythfont->hasShadow()) 1613 1961 { 1614 1962 MythPoint shadowOffset; 1615 1963 mythfont->GetShadow(shadowOffset, color, alpha); 1616 shadowOffset.NormPoint(); 1964 // Shadow offset has already been scaled from theme to screen 1965 // Why do it again? 1966 // shadowOffset.NormPoint(); 1617 1967 shadowWidth = abs(shadowOffset.x()); 1618 1968 shadowHeight = abs(shadowOffset.y()); 1619 1969 // Shadow and outline overlap, so don't just add them. … … static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont) 1625 1975 1626 1976 QSize SubtitleScreen::CalcTextSize(const QString &text, 1627 1977 const CC708CharacterAttribute &format, 1628 float layoutSpacing) const 1978 float layoutSpacing, 1979 MythFontProperties* mythfont) const 1629 1980 { 1630 MythFontProperties *mythfont = GetFont(format); 1981 if (!mythfont) 1982 mythfont = GetFont(format); 1631 1983 QFont *font = mythfont->GetFace(); 1632 1984 QFontMetrics fm(*font); 1633 1985 int width = fm.width(text); 1634 int height = fm.height() * (1 + PAD_HEIGHT); 1986 1987 // Font metrics for various fonts are inconsistent in how 1988 // they provide a realistic line height value. 1989 // The max of what they call height and lineSpacing 1990 // provides a resonable value for most fonts. 1991 int height = max(fm.height(), fm.lineSpacing()); 1992 1635 1993 if (layoutSpacing > 0 && !text.trimmed().isEmpty()) 1636 1994 height = max(height, (int)(font->pixelSize() * layoutSpacing)); 1637 1995 height += CalcShadowOffsetPadding(mythfont).height(); … … QSize SubtitleScreen::CalcTextSize(const QString &text, 1643 2001 // right needs to add the shadow and offset padding. 1644 2002 void SubtitleScreen::CalcPadding(const CC708CharacterAttribute &format, 1645 2003 bool isFirst, bool isLast, 1646 int &left, int &right) const 2004 int &left, int &right, 2005 MythFontProperties* mythfont) const 1647 2006 { 1648 MythFontProperties *mythfont = GetFont(format); 2007 if (!mythfont) 2008 mythfont = GetFont(format); 1649 2009 QFont *font = mythfont->GetFace(); 1650 2010 QFontMetrics fm(*font); 1651 2011 int basicPadding = fm.maxWidth() * PAD_WIDTH; … … void SubtitleScreen::CalcPadding(const CC708CharacterAttribute &format, 1657 2017 MythFontProperties * 1658 2018 SubtitleScreen::GetFont(const CC708CharacterAttribute &attr) const 1659 2019 { 1660 return m_format->GetFont(m_family, attr, m_fontSize, 1661 m_textFontZoom, m_fontStretch); 2020 return m_format->GetFont(m_family, attr, m_textFontZoom); 2021 } 2022 2023 QRect 2024 SubtitleScreen::GetSafeArea() 2025 { 2026 return m_player->GetVideoOutput()->GetSafeRect(); 1662 2027 } 1663 2028 1664 2029 QString SubtitleScreen::GetTeletextFontName(void) 1665 2030 { 1666 2031 SubtitleFormat format; 1667 CC708CharacterAttribute attr(false, false, false, Qt::white); 1668 MythFontProperties *mythfont = 1669 format.GetFont(kSubFamilyTeletext, attr, 1670 /*pixelsize*/20, /*zoom*/100, /*stretch*/100); 1671 return mythfont->face().family(); 2032 return format.GetTeletextFontName(); 1672 2033 } 1673 2034 1674 2035 bool SubtitleScreen::Create(void) … … void SubtitleScreen::OptimiseDisplayedArea(void) 1783 2144 return; 1784 2145 1785 2146 QRect bounding = visible.boundingRect(); 2147 LOG(VB_VBI, LOG_DEBUG, 2148 QString("Visible bounds=%1x%2@%3,%4") 2149 .arg(bounding.width()).arg(bounding.height()) 2150 .arg(bounding.x()).arg(bounding.y())); 2151 1786 2152 bounding = bounding.translated(m_safeArea.topLeft()); 2153 LOG(VB_VBI, LOG_DEBUG, 2154 QString("Translated bounds=%1x%2@%3,%4") 2155 .arg(bounding.width()).arg(bounding.height()) 2156 .arg(bounding.x()).arg(bounding.y())); 2157 1787 2158 bounding = m_safeArea.intersected(bounding); 1788 2159 int left = m_safeArea.left() - bounding.left(); 1789 2160 int top = m_safeArea.top() - bounding.top(); 2161 LOG(VB_VBI, LOG_DEBUG, 2162 QString("Intersected bounds=%1x%2@%3,%4 left=%5 top=%6") 2163 .arg(bounding.width()).arg(bounding.height()) 2164 .arg(bounding.x()).arg(bounding.y()) 2165 .arg(left).arg(top)); 1790 2166 SetArea(MythRect(bounding)); 1791 2167 1792 2168 i.toFront(); -
mythtv/libs/libmythtv/subtitlescreen.h
diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h index 4583a0b..2dc52c1 100644
a b public: 35 35 : text(t), m_format(formatting), parent(p), textFont(NULL) {} 36 36 FormattedTextChunk(void) : parent(NULL), textFont(NULL) {} 37 37 38 QSize CalcSize(float layoutSpacing = 0.0f) const;39 void CalcPadding(bool isFirst, bool isLast, int &left, int &right) const;38 QSize CalcSize(float layoutSpacing = 0.0f); 39 void CalcPadding(bool isFirst, bool isLast, int &left, int &right); 40 40 bool Split(FormattedTextChunk &newChunk); 41 41 QString ToLogString(void) const; 42 42 bool PreRender(bool isFirst, bool isLast, int &x, int y, int height); … … public: 59 59 FormattedTextLine(int x = -1, int y = -1, int o_x = -1, int o_y = -1) 60 60 : x_indent(x), y_indent(y), orig_x(o_x), orig_y(o_y) {} 61 61 62 QSize CalcSize(float layoutSpacing = 0.0f ) const;62 QSize CalcSize(float layoutSpacing = 0.0f, bool addPadding = true); 63 63 64 64 QList<FormattedTextChunk> chunks; 65 65 int x_indent; // -1 means TBD i.e. centered … … public: 190 190 191 191 QSize CalcTextSize(const QString &text, 192 192 const CC708CharacterAttribute &format, 193 float layoutSpacing) const; 193 float layoutSpacing, 194 MythFontProperties* mythfont = 0) const; 194 195 void CalcPadding(const CC708CharacterAttribute &format, 195 196 bool isFirst, bool isLast, 196 int &left, int &right) const; 197 int &left, int &right, 198 MythFontProperties* mythfont = 0) const; 197 199 MythFontProperties* GetFont(const CC708CharacterAttribute &attr) const; 198 void SetFontSize(int pixelSize) { m_fontSize = pixelSize; }200 QRect GetSafeArea(); 199 201 200 202 // Temporary method until teletextscreen.cpp is refactored into 201 203 // subtitlescreen.cpp … … private: 229 231 QRect m_safeArea; 230 232 QRegExp m_removeHTML; 231 233 int m_subtitleType; 232 int m_fontSize;233 234 int m_textFontZoom; // valid for 708 & text subs 234 235 int m_textFontZoomPrev; 235 236 int m_textFontDelayMs; // valid for text subs