Ticket #12057: 12057_v2.patch
File 12057_v2.patch, 37.6 KB (added by , 9 years ago) |
---|
-
mythtv/libs/libmythtv/subtitlescreen.cpp
diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp index afbe759..3dce6ae 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: 144 212 int GetBackgroundAlpha(const QString &family); 145 213 static QString MakePrefix(const QString &family, 146 214 const CC708CharacterAttribute &attr); 215 216 // Temporary method until teletextscreen.cpp is refactored into 217 // subtitlescreen.cpp 218 // GetTeletextFontName is the only public method that should be called 219 // when m_subScreen and m_player are null 220 QString GetTeletextFontName(void); 221 147 222 private: 148 223 void Load(const QString &family, 149 224 const CC708CharacterAttribute &attr); … … private: 165 240 MythUIShape *bg1, 166 241 MythUIShape *bg2); 167 242 243 // Hash table of default font properties by family 168 244 QHash<QString, MythFontProperties *> m_fontMap; 169 245 QHash<QString, MythUIShape *> m_shapeMap; 170 246 QHash<QString, QSet<QString> > m_changeMap; … … private: 174 250 QHash<QString, int> m_pixelSizeMap; 175 251 QHash<QString, int> m_outlineSizeMap; 176 252 QHash<QString, QPoint> m_shadowOffsetMap; 253 254 // Hash table of font properties by family, atttributes, zoom & stretch 255 QHash<SubtitleFontKey, MythFontProperties *> m_fullFontMap; 256 177 257 QVector<MythUIType *> m_cleanup; 258 SubtitleScreen* m_subScreen; 259 MythPlayer* m_player; 260 int m_fontStretch; 178 261 }; 179 262 180 263 static const QString kSubProvider("provider"); … … static QString fontToString(MythFontProperties *f) 244 327 MythFontProperties * 245 328 SubtitleFormat::GetFont(const QString &family, 246 329 const CC708CharacterAttribute &attr, 247 int pixelSize, int zoom, int stretch)330 int zoom) 248 331 { 249 int origPixelSize = pixelSize; 332 QString prefix = MakePrefix(family, attr); 333 SubtitleFontKey key(prefix, attr, zoom, m_fontStretch); 334 if (m_fullFontMap.contains(key)) 335 return m_fullFontMap[key]; 336 337 if (!m_fontMap.contains(prefix)) 338 Load(family, attr); 339 340 // Make a copy we can modify once and reuse many times 341 MythFontProperties *result = new MythFontProperties(*(m_fontMap[prefix])); 342 m_fullFontMap[key] = result; 343 250 344 float scale = zoom / 100.0; 251 345 if ((attr.pen_size & 0x3) == k708AttrSizeSmall) 252 346 scale = scale * 32 / 42; 253 347 else if ((attr.pen_size & 0x3) == k708AttrSizeLarge) 254 348 scale = scale * 42 / 32; 255 349 256 QString prefix = MakePrefix(family, attr);257 if (!m_fontMap.contains(prefix))258 Load(family, attr);259 MythFontProperties *result = m_fontMap[prefix];260 261 350 // Apply the scaling factor to pixelSize even if the theme 262 351 // explicitly sets pixelSize. 263 i f (!IsUnlocked(prefix, kSubAttrPixelsize))264 pixelSize = m_pixelSizeMap[prefix];352 int pixelSize = m_pixelSizeMap[prefix]; 353 int origPixelSize = pixelSize; 265 354 pixelSize *= scale; 266 355 result->GetFace()->setPixelSize(pixelSize); 267 356 268 result->GetFace()->setStretch(stretch); 357 // Stretch is now set in SubtitleFormat::Load 358 // result->GetFace()->setStretch(stretch); 359 269 360 if (IsUnlocked(prefix, kSubAttrItalics)) 270 361 result->GetFace()->setItalic(attr.italics); 271 362 if (IsUnlocked(prefix, kSubAttrUnderline)) … … SubtitleFormat::GetFont(const QString &family, 301 392 else 302 393 { 303 394 offset = m_shadowOffsetMap[prefix]; 304 offset.NormPoint(); 395 // Shadow offset has already been scaled from theme to screen 396 // Why do it again? 397 // offset.NormPoint(); 305 398 offset.setX(offset.x() * scale + 0.5); 306 399 offset.setY(offset.y() * scale + 0.5); 307 400 } … … SubtitleFormat::GetFont(const QString &family, 329 422 else 330 423 { 331 424 off = m_outlineSizeMap[prefix]; 332 MythPoint point(off, off); 333 point.NormPoint(); 334 off = point.x() * scale + 0.5; 425 // Outline has already been scaled by SubtitleFormat::Load. 426 // Why do it again? 427 // MythPoint point(off, off); 428 // point.NormPoint(); 429 off = off * scale + 0.5; 335 430 } 336 431 result->SetOutline(outline, color, off, alpha); 337 432 338 433 LOG(VB_VBI, LOG_DEBUG, 339 434 QString("GetFont(family=%1, prefix=%2, orig pixelSize=%3, " 340 " new pixelSize=%4 zoom=%5) = %6")341 .arg(family).arg(prefix).arg(origPixelSize) .arg(pixelSize)342 .arg(zoom).arg( fontToString(result)));435 "zoom=%4, stretch=%5) = %6") 436 .arg(family).arg(prefix).arg(origPixelSize) 437 .arg(zoom).arg(m_fontStretch).arg(fontToString(result))); 343 438 return result; 344 439 } 345 440 441 QString SubtitleFormat::GetTeletextFontName(void) 442 { 443 CC708CharacterAttribute attr(false, false, false, Qt::white); 444 445 QString prefix = MakePrefix(kSubFamilyTeletext, attr); 446 if (!m_fontMap.contains(prefix)) 447 Load(kSubFamilyTeletext, attr); 448 MythFontProperties *result = m_fontMap[prefix]; 449 return result->face().family(); 450 } 451 452 SubtitleFormat::SubtitleFormat(SubtitleScreen* screen, MythPlayer* player, 453 int stretch) : 454 m_subScreen(screen), m_player(player), m_fontStretch(stretch) 455 { 456 } 457 346 458 SubtitleFormat::~SubtitleFormat(void) 347 459 { 460 QHash<SubtitleFontKey, MythFontProperties*>::const_iterator it; 461 for (it = m_fullFontMap.constBegin(); it != m_fullFontMap.constEnd(); it++) 462 { 463 delete (*it); 464 } 465 348 466 for (int i = 0; i < m_cleanup.size(); ++i) 349 467 { 350 468 m_cleanup[i]->DeleteAllChildren(); … … void SubtitleFormat::CreateProviderDefault(const QString &family, 412 530 413 531 if (isComplement) 414 532 Complement(font, bg); 415 parent->AddFont(kSubProvider, font);416 533 417 *returnFont = font; 534 // This ultimately calls FontMap::AddFont, which makes a deep copy 535 // so we need to delete font. 536 // In case something changes underneath, we make sure the value 537 // returned by parent->GetFont is indeed different. 538 parent->AddFont(kSubProvider, font); 539 *returnFont = parent->GetFont(kSubProvider); 540 if (*returnFont != font) 541 delete font; 418 542 *returnBg = bg; 419 543 } 420 544 … … void SubtitleFormat::Load(const QString &family, 511 635 QPoint offset; 512 636 QColor color; 513 637 int alpha; 514 int size;515 638 resultFont->GetShadow(offset, color, alpha); 639 m_shadowOffsetMap[prefix] = offset; 640 641 // Shadow offset is scaled from theme to screen when it is parsed. 642 // But outline size is not. 643 // As long as this inconsistency exists, we scale outline size here. 644 int size; 516 645 resultFont->GetOutline(color, size, alpha); 646 MythPoint outline(size, size); 647 outline.NormPoint(); 648 size = outline.x(); 517 649 m_outlineSizeMap[prefix] = size; 518 m_shadowOffsetMap[prefix] = offset;519 m_pixelSizeMap[prefix] = resultFont->GetFace()->pixelSize();520 650 521 delete negFont; 651 // Fixed memory leak in SubtitleFormat::CreateProviderDefault, 652 // so negFont shouldn't be deleted here. 653 // It will be deleted later when negParent is deleted via m_cleanup 654 // delete negFont; 655 656 // Font stretch is constant for the life of each SubtitleScreen instance. 657 // So the same is true for SubtitleFormat. 658 // It is 100 for most playback profiles. 659 // But the Slim profile changes it whenever the video zoom factor changes. 660 // When that happens, the current SubtitleScreen is deleted 661 // and a new SubtitleScreen with a new font stretch is instantiated. 662 resultFont->GetFace()->setStretch(m_fontStretch); 663 664 // If the user hasn't defined a pixelsize 665 // and not called via teletextscreen.cpp (where m_subScreen is null), 666 // set a default 667 if (IsUnlocked(prefix, kSubAttrPixelsize) && m_subScreen != 0) 668 { 669 QRect safeArea = m_subScreen->GetSafeArea(); 670 LOG(VB_VBI, LOG_DEBUG, 671 QString("safeArea=%1x%2@%3,%4") 672 .arg(safeArea.width()) 673 .arg(safeArea.height()) 674 .arg(safeArea.x()) 675 .arg(safeArea.y())); 676 677 // Start with 608 row,col dimensions 678 int cols = 32; // 608 max columns 679 int rows = 15; // 608 max rows 680 681 // Adjust by family 682 if (kSubFamily708 == family || kSubFamilyText == family) 683 { 684 // Assumption: .srt and .txt line lengths will be within 685 // the limits of 708 captions, whose # of columns depends on 686 // the source video's aspect ratio. 687 cols = (m_player->GetVideoAspect() > 1.4f) ? 42 : 32; 688 rows = 15; 689 } 690 //else if (kSubFamilyAV == family) 691 //{ 692 // DVB bitmapped subtitles? 693 //} 694 else if (kSubFamilyTeletext == family) 695 { 696 // Constants defined in teletextscreen.cpp 697 // Copied values rather than depend on something that 698 // going to be refactored? 699 cols = 40; // TeletextScreen::kTeletextColumns 700 rows = 26; // TeletextScreen::kTeletextRows 701 } 702 703 // Add one to cols to account for 1/2 char width left&right padding. 704 cols++; 705 706 // Target lineHeight 707 int lineHeight = safeArea.height() / rows; 708 709 // Set pixelSize to the target lineHeight 710 int pixelSize = lineHeight; 711 // Reduce by shadow offset or outline size 712 pixelSize -= max(abs(offset.y()), size); 713 // It is a first guess pixelSize, which will almost certainly be off 714 715 QFont *font = resultFont->GetFace(); 716 font->setPixelSize(pixelSize); 717 QFontMetrics fm(*font); 718 719 // Font metrics for various fonts are inconsistent in how 720 // they provide a realistic line height value. 721 // The max of what they call height and lineSpacing 722 // provides a resonable value for most fonts. 723 int newLineHeight = max(fm.height(), fm.lineSpacing()); 724 // Increase by shadow offset or outline size 725 newLineHeight += max(abs(offset.y()), size); 726 727 int offBy = newLineHeight - lineHeight; 728 int newPixelSize = pixelSize; 729 if (offBy != 0) 730 { 731 // We tried a pixelSize equal to the desired line height 732 // with shadow & outline adjustments, 733 // but it didn't quite get us there. 734 // We make a better guess by applying a ratio of 735 // our first guess divided by the actual height. 736 // This should be "good enough" for most fonts. 737 newPixelSize = (int)((float)pixelSize*pixelSize/newLineHeight + 0.5); 738 font->setPixelSize(newPixelSize); 739 fm = QFontMetrics(*font); 740 newLineHeight = max(fm.height(), fm.lineSpacing()); 741 newLineHeight += max(abs(offset.y()), size); 742 } 743 744 int fontwidth = fm.averageCharWidth(); 745 int maxwidth = (safeArea.width() - max(abs(offset.x()), size)) / cols; 746 747 LOG(VB_VBI, LOG_DEBUG, 748 QString("family=%1 default-pixelSize=%2->%3 lineHeight=%4->%5 " 749 "offBy=%6 fontwidth=%7 maxwidth=%8 shadow-offset=%9,%10 " 750 "outline=%11") 751 .arg(family).arg(pixelSize).arg(newPixelSize) 752 .arg(lineHeight).arg(newLineHeight) 753 .arg(offBy).arg(fontwidth).arg(maxwidth) 754 .arg(offset.x()).arg(offset.y()).arg(size)); 755 756 // Check if fontwidth exceeds maxwidth 757 // Just log it for now. We'll deal with it, if/when someone 758 // reports a problem. 759 if (fontwidth > maxwidth) 760 { 761 LOG(VB_GENERAL, LOG_WARNING, 762 QString("fontwidth=%1 exceeds maxwidth=%2") 763 .arg(fontwidth).arg(maxwidth)); 764 } 765 766 m_pixelSizeMap[prefix] = newPixelSize; 767 } 768 else 769 { 770 int pixelSize = resultFont->GetFace()->pixelSize(); 771 LOG(VB_VBI, LOG_DEBUG, 772 QString("family=%1 user defined pixelSize=%2") 773 .arg(family).arg(pixelSize)); 774 m_pixelSizeMap[prefix] = pixelSize; 775 } 522 776 } 523 777 524 778 QSet<QString> SubtitleFormat::Diff(const QString &family, … … int SubtitleFormat::GetBackgroundAlpha(const QString &family) 637 891 638 892 //////////////////////////////////////////////////////////////////////////// 639 893 640 QSize FormattedTextChunk::CalcSize(float layoutSpacing) const894 QSize FormattedTextChunk::CalcSize(float layoutSpacing) 641 895 { 642 return parent->CalcTextSize(text, m_format, layoutSpacing); 896 if (!textFont) 897 textFont = parent->GetFont(m_format); 898 return parent->CalcTextSize(text, m_format, layoutSpacing, textFont); 643 899 } 644 900 645 901 void FormattedTextChunk::CalcPadding(bool isFirst, bool isLast, 646 int &left, int &right) const902 int &left, int &right) 647 903 { 648 parent->CalcPadding(m_format, isFirst, isLast, left, right); 904 if (!textFont) 905 textFont = parent->GetFont(m_format); 906 parent->CalcPadding(m_format, isFirst, isLast, left, right, textFont); 649 907 } 650 908 651 909 bool FormattedTextChunk::Split(FormattedTextChunk &newChunk) … … QString FormattedTextChunk::ToLogString(void) const 695 953 bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 696 954 int &x, int y, int height) 697 955 { 698 textFont = parent->GetFont(m_format);699 956 if (!textFont) 700 return false; 957 textFont = parent->GetFont(m_format); 958 701 959 QFontMetrics font(*(textFont->GetFace())); 702 960 // If the chunk starts with whitespace, the leading whitespace 703 961 // ultimately gets lost due to the text.trimmed() operation in the … … bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 712 970 int leftPadding, rightPadding; 713 971 CalcPadding(isFirst, isLast, leftPadding, rightPadding); 714 972 // Account for extra padding before the first chunk. 715 if (isFirst) 716 x += leftPadding; 973 // No, this will cause everything to be off center to the right 974 // by the value of leftPadding. 975 // if (isFirst) 976 // x += leftPadding; 717 977 QSize chunk_sz = CalcSize(); 718 978 QRect bgrect(x - leftPadding, y, 719 979 chunk_sz.width() + leftPadding + rightPadding, … … bool FormattedTextChunk::PreRender(bool isFirst, bool isLast, 732 992 textRect = QRect(x + x_adjust, y, 733 993 chunk_sz.width() - x_adjust + rightPadding, height); 734 994 995 // If this chunk is in italics, add a few pixels to the width. 996 // This is to compensate for some font/char combos that would otherwise 997 // have the top right corner of the last char clipped. 998 // The effect can be seen with Droid Sans Mono and certain upper case chars 999 // like E or W. 1000 // But don't add this padding to the next chunk's x coordinate. 1001 // That would add too much spacing between chunks. 1002 if (m_format.italics) 1003 { 1004 int oldWidth = textRect.width(); 1005 textRect.setWidth(oldWidth + font.averageCharWidth() / 2); 1006 LOG(VB_VBI, LOG_DEBUG, 1007 QString("Pad for italics width %1 -> %2") 1008 .arg(oldWidth).arg(textRect.width())); 1009 } 1010 735 1011 x += chunk_sz.width(); 736 1012 return true; 737 1013 } 738 1014 739 QSize FormattedTextLine::CalcSize(float layoutSpacing ) const1015 QSize FormattedTextLine::CalcSize(float layoutSpacing, bool addPadding) 740 1016 { 741 1017 int height = 0, width = 0; 742 1018 int leftPadding = 0, rightPadding = 0; 743 QList<FormattedTextChunk>:: const_iterator it;744 bool isFirst = true;745 for (it = chunks. constBegin(); it != chunks.constEnd(); ++it)1019 QList<FormattedTextChunk>::iterator it; 1020 bool isFirst = (addPadding ? true : false); 1021 for (it = chunks.begin(); it != chunks.end(); ++it) 746 1022 { 747 bool isLast = ( it + 1 == chunks.constEnd());1023 bool isLast = (addPadding ? (it + 1 == chunks.constEnd()) : false); 748 1024 QSize tmp = (*it).CalcSize(layoutSpacing); 749 1025 height = max(height, tmp.height()); 750 1026 width += tmp.width(); 751 (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding); 1027 // We don't need to call CalcPadding if addPadding is false 1028 if (addPadding) 1029 (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding); 752 1030 if (it == chunks.constBegin()) 753 1031 width += leftPadding; 754 1032 isFirst = false; … … FormattedTextSubtitle::FormattedTextSubtitle(void) : 783 1061 // Normal font height is designed to be 1/20 of safe area height, with 784 1062 // extra blank space between lines to make 17 lines within the safe 785 1063 // area. 786 static const float LINE_SPACING = (20.0 / 17.0); 1064 // static const float LINE_SPACING = (20.0 / 17.0); 1065 static const float LINE_SPACING = 0.0; 787 1066 static const float PAD_WIDTH = 0.5; 788 static const float PAD_HEIGHT = 0.04;1067 // static const float PAD_HEIGHT = 0.04; 789 1068 790 1069 // Resolves any TBD x_indent and y_indent values in FormattedTextLine 791 1070 // objects. Calculates m_bounds. Prunes most leading and all … … void FormattedTextSubtitle::Layout(void) 798 1077 int anchor_height = 0; 799 1078 for (int i = 0; i < m_lines.size(); i++) 800 1079 { 801 QSize sz = m_lines[i].CalcSize(LINE_SPACING); 1080 // We don't want padding added at this point. 1081 // Padding applies to the background. 1082 // We want to know where the txt should be drawn, 1083 // not where the background shoould be drawn. 1084 QSize sz = m_lines[i].CalcSize(LINE_SPACING, false); 802 1085 anchor_width = max(anchor_width, sz.width()); 803 1086 anchor_height += sz.height(); 804 1087 } … … void FormattedTextSubtitle::Layout(void) 819 1102 anchor_y = max(0, min(anchor_y, m_safeArea.height() - anchor_height)); 820 1103 anchor_x = max(0, min(anchor_x, m_safeArea.width() - anchor_width)); 821 1104 822 m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height); 1105 // m_bounds needs padding. 1106 // Get it using the first chunk of the first line. 1107 int left = 0; 1108 int right = 0; 1109 m_lines[0].chunks.first().CalcPadding(true, true, left, right); 1110 m_bounds = QRect(anchor_x-left, 1111 anchor_y, 1112 anchor_width+left+right, 1113 anchor_height); 823 1114 824 1115 // Fill in missing coordinates 825 1116 int y = anchor_y; … … void FormattedTextSubtitle::Layout(void) 829 1120 m_lines[i].x_indent = anchor_x; 830 1121 if (m_lines[i].y_indent < 0) 831 1122 m_lines[i].y_indent = y; 832 y += m_lines[i].CalcSize(LINE_SPACING ).height();1123 y += m_lines[i].CalcSize(LINE_SPACING, false).height(); 833 1124 // Prune leading all-whitespace chunks. 834 1125 while (!m_lines[i].chunks.isEmpty() && 835 1126 m_lines[i].chunks.first().text.trimmed().isEmpty()) … … void FormattedTextSubtitle::PreRender(void) 864 1155 { 865 1156 int x = m_lines[i].x_indent; 866 1157 int y = m_lines[i].y_indent; 867 int height = m_lines[i].CalcSize( ).height();1158 int height = m_lines[i].CalcSize(LINE_SPACING, false).height(); 868 1159 QList<FormattedTextChunk>::iterator chunk; 869 1160 bool isFirst = true; 870 1161 for (chunk = m_lines[i].chunks.begin(); … … void FormattedTextSubtitle::Draw(void) 893 1184 { 894 1185 MythFontProperties *mythfont = 895 1186 m_subScreen->GetFont((*chunk).m_format); 896 if (!mythfont) 897 continue; 1187 // Never returns NULL 1188 // if (!mythfont) 1189 // continue; 898 1190 // Note: NULL is passed as the parent argument to the 899 1191 // MythUI constructors so that we can control the drawing 900 1192 // order of the children. In particular, background 901 1193 // shapes should be added/drawn first, and text drawn on 902 1194 // top. 1195 LOG(VB_VBI, LOG_DEBUG, 1196 QString("i=%1 rect=%2x%3@%4,%5 bgrect=%6x%7@%8,%9 text=%10") 1197 .arg(i) 1198 .arg(chunk->textRect.width()) 1199 .arg(chunk->textRect.height()) 1200 .arg(chunk->textRect.x()) 1201 .arg(chunk->textRect.y()) 1202 .arg(chunk->bgShapeRect.width()) 1203 .arg(chunk->bgShapeRect.height()) 1204 .arg(chunk->bgShapeRect.x()) 1205 .arg(chunk->bgShapeRect.y()) 1206 .arg(chunk->text)); 903 1207 if ((*chunk).textRect.width() > 0) { 904 1208 SubSimpleText *text = 905 1209 new SubSimpleText((*chunk).text, *mythfont, … … void FormattedTextSubtitleSRT::Init(const QStringList &subs) 994 1298 // <font color="#xxyyzz"> - change font color 995 1299 // </font> - reset font color to white 996 1300 997 int pixelSize = m_safeArea.height() / 20;998 if (m_subScreen)999 m_subScreen->SetFontSize(pixelSize);1000 1301 m_xAnchorPoint = 1; // center 1001 1302 m_yAnchorPoint = 2; // bottom 1002 1303 m_xAnchor = m_safeArea.width() / 2; … … void FormattedTextSubtitle608::Layout(void) 1197 1498 int y = m_lines[i].y_indent; 1198 1499 if (i == 0) 1199 1500 firstY = prevY = y; 1200 int height = m_lines[i].CalcSize( ).height();1501 int height = m_lines[i].CalcSize(LINE_SPACING, false).height(); 1201 1502 heights[i] = height; 1202 1503 spaceBefore[i] = y - prevY; 1203 1504 totalSpace += (y - prevY); … … void FormattedTextSubtitle608::Layout(void) 1218 1519 m_lines[i].y_indent = prevY + spaceBefore[i] * shrink; 1219 1520 prevY = m_lines[i].y_indent + heights[i]; 1220 1521 } 1522 LOG(VB_VBI, LOG_DEBUG, 1523 QString("Shrink overage=%1 totalSpace=%2 shrink=%3 firstY=%4 prevY=%5") 1524 .arg(overage).arg(totalSpace).arg(shrink).arg(firstY).arg(prevY)); 1221 1525 } 1222 1526 1223 1527 // Shift Y coordinates back up into the safe area. … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1239 1543 if (buffers.empty()) 1240 1544 return; 1241 1545 vector<CC608Text*>::const_iterator i = buffers.begin(); 1242 int xscale = 36; 1243 int yscale = 17; 1244 int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING); 1546 1547 int xscale = 32; // 608 max columns 1548 int yscale = 15; // 608 max rows 1549 1550 int lineHeight = m_safeArea.height() / yscale; 1245 1551 int fontwidth = 0; 1246 1552 int xmid = 0; 1247 int zoom = 100;1553 // int zoom = 100; 1248 1554 if (m_subScreen) 1249 1555 { 1250 zoom = m_subScreen->GetZoom(); 1251 m_subScreen->SetFontSize(pixelSize); 1556 // zoom = m_subScreen->GetZoom(); 1252 1557 CC708CharacterAttribute def_attr(false, false, false, clr[0]); 1253 QFont *font = m_subScreen->GetFont(def_attr)->GetFace(); 1558 MythFontProperties* mythfont = m_subScreen->GetFont(def_attr); 1559 QFont *font = mythfont->GetFace(); 1254 1560 QFontMetrics fm(*font); 1255 1561 fontwidth = fm.averageCharWidth(); 1256 1562 xmid = m_safeArea.width() / 2; 1563 1564 // Font metrics for various fonts are inconsistent in how 1565 // they provide a realistic line height value. 1566 // The max of what they call height and lineSpacing 1567 // provides a resonable value for most fonts. 1568 lineHeight = max(fm.height(), fm.lineSpacing()); 1569 1570 // Increase by shadow offset and/or outline size 1571 QPoint offset; 1572 QColor color; 1573 int alpha; 1574 mythfont->GetShadow(offset, color, alpha); 1575 1576 int size; 1577 mythfont->GetOutline(color, size, alpha); 1578 1579 lineHeight += max(abs(offset.y()), size); 1580 1257 1581 // Disable centering for zoom factor >= 100% 1258 if (zoom >= 100) 1259 xscale = m_safeArea.width() / fontwidth; 1582 // Why?? If disabled, 608 captions are shifted to left unless 1583 // the user sets the zoom to 99% or less. 1584 // The Layout method should shift left-right and up-down 1585 // as needed for zoom factor. 1586 // If zoom factor is too large, the user can reduce it. 1587 // If they don't we'll clip what doesn't fit. 1588 //if (zoom >= 100) 1589 // xscale = m_safeArea.width() / fontwidth; 1260 1590 } 1261 1591 1262 1592 for (; i != buffers.end(); ++i) … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1267 1597 const bool isBold = false; 1268 1598 QString text(cc->text); 1269 1599 1600 // Note: cc-x (and orig_x) is column # ranging from 0 through 31, 1270 1601 int orig_x = cc->x; 1271 1602 // position as if we use a fixed size font 1272 1603 // - font size already has zoom factor applied … … void FormattedTextSubtitle608::Init(const vector<CC608Text*> &buffers) 1279 1610 // fallback 1280 1611 x = (orig_x + 3) * m_safeArea.width() / xscale; 1281 1612 1613 // Note: cc-y (and orig_y) is row # ranging from 1 through 15, 1614 // we need zero based rows 1282 1615 int orig_y = cc->y; 1283 1616 int y; 1284 if (orig_y < yscale / 2)1617 if (orig_y <= yscale / 2) 1285 1618 // top half -- anchor up 1286 y = (orig_y * m_safeArea.height() * zoom / (yscale * 100));1619 y = (orig_y-1) * lineHeight; 1287 1620 else 1288 1621 // bottom half -- anchor down 1289 y = m_safeArea.height() - 1290 ((yscale - orig_y - 0.5) * m_safeArea.height() * zoom / 1291 (yscale * 100)); 1622 y = m_safeArea.height() - ((yscale - (orig_y-1)) * lineHeight); 1292 1623 1293 1624 FormattedTextLine line(x, y, orig_x, orig_y); 1294 1625 while (!text.isNull()) … … void FormattedTextSubtitle708::Init(const CC708Window &win, 1334 1665 "relative %5") 1335 1666 .arg(m_num).arg(win.anchor_point).arg(win.anchor_horizontal) 1336 1667 .arg(win.anchor_vertical).arg(win.relative_pos)); 1337 int pixelSize = m_safeArea.height() / 20;1338 if (m_subScreen)1339 m_subScreen->SetFontSize(pixelSize);1340 1668 1341 1669 float xrange = win.relative_pos ? 100.0f : 1342 1670 (aspect > 1.4f) ? 210.0f : 160.0f; 1343 1671 float yrange = win.relative_pos ? 100.0f : 75.0f; 1344 float xmult = (float)m_safeArea.width() / xrange; 1672 1673 // Center the window addressable area based on the first string's font. 1674 // Assumption: Most caption providers do not change font within a window 1675 MythFontProperties* mythFont = m_subScreen->GetFont(list[0]->attr); 1676 QFont* font = mythFont->GetFace(); 1677 QFontMetrics fm(*font); 1678 int cols = (aspect > 1.4f) ? 42 : 32; 1679 int centerWidth = min(m_safeArea.width(), cols * fm.averageCharWidth()); 1680 int xoffset = (m_safeArea.width() - centerWidth) / 2; 1681 1682 float xmult = (float)centerWidth / xrange; 1345 1683 float ymult = (float)m_safeArea.height() / yrange; 1346 1684 uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal); 1347 1685 uint anchor_y = (uint)(ymult * (float)win.anchor_vertical); 1348 1686 m_xAnchorPoint = win.anchor_point % 3; 1349 1687 m_yAnchorPoint = win.anchor_point / 3; 1350 m_xAnchor = anchor_x; 1688 1689 // Should work equally for both left & right anchor points. 1690 m_xAnchor = (m_xAnchorPoint == 1) ? anchor_x : xoffset + anchor_x; 1351 1691 m_yAnchor = anchor_y; 1352 1692 1693 LOG(VB_VBI, LOG_INFO, 1694 QString("708 centerWidth=%1 xoffset=%2 anchorPoints=%3,%4 anchors=%5,%6") 1695 .arg(centerWidth).arg(xoffset) 1696 .arg(m_xAnchorPoint).arg(m_yAnchorPoint) 1697 .arg(m_xAnchor).arg(m_yAnchor)); 1698 1353 1699 for (uint i = 0; i < list.size(); i++) 1354 1700 { 1355 1701 if (list[i]->y >= (uint)m_lines.size()) … … SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name, 1369 1715 m_player(player), m_subreader(NULL), m_608reader(NULL), 1370 1716 m_708reader(NULL), m_safeArea(QRect()), 1371 1717 m_removeHTML(QRegExp("</?.+>")), m_subtitleType(kDisplayNone), 1372 m_fontSize(0),1373 1718 m_textFontZoom(100), m_textFontZoomPrev(100), 1374 1719 m_textFontDelayMs(0), m_textFontDelayMsPrev(0), 1375 1720 m_refreshModified(false), m_refreshDeleted(false), 1376 1721 m_fontStretch(fontStretch), 1377 m_format(new SubtitleFormat )1722 m_format(new SubtitleFormat(this, player, fontStretch)) 1378 1723 { 1379 1724 m_removeHTML.setMinimal(true); 1380 1725 … … void SubtitleScreen::Clear708Cache(uint64_t mask) 1588 1933 // the subtitle screen. 1589 1934 void SubtitleScreen::SetElementAdded(void) 1590 1935 { 1936 if (!m_refreshModified) 1937 SetRedraw(); 1591 1938 m_refreshModified = true; 1592 1939 } 1593 1940 … … static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont) 1620 1967 if (mythfont->hasOutline()) 1621 1968 { 1622 1969 mythfont->GetOutline(color, outlineSize, alpha); 1623 MythPoint outline(outlineSize, outlineSize); 1624 outline.NormPoint(); 1625 outlineSize = outline.x(); 1970 // Outline has already been scaled by SubtitleFormat::Load 1971 // MythPoint outline(outlineSize, outlineSize); 1972 // outline.NormPoint(); 1973 // outlineSize = outline.x(); 1626 1974 } 1627 1975 if (mythfont->hasShadow()) 1628 1976 { 1629 1977 MythPoint shadowOffset; 1630 1978 mythfont->GetShadow(shadowOffset, color, alpha); 1631 shadowOffset.NormPoint(); 1979 // Shadow offset has already been scaled from theme to screen 1980 // Why do it again? 1981 // shadowOffset.NormPoint(); 1632 1982 shadowWidth = abs(shadowOffset.x()); 1633 1983 shadowHeight = abs(shadowOffset.y()); 1634 1984 // Shadow and outline overlap, so don't just add them. … … static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont) 1640 1990 1641 1991 QSize SubtitleScreen::CalcTextSize(const QString &text, 1642 1992 const CC708CharacterAttribute &format, 1643 float layoutSpacing) const 1993 float layoutSpacing, 1994 MythFontProperties* mythfont) const 1644 1995 { 1645 MythFontProperties *mythfont = GetFont(format); 1996 if (!mythfont) 1997 mythfont = GetFont(format); 1646 1998 QFont *font = mythfont->GetFace(); 1647 1999 QFontMetrics fm(*font); 1648 2000 int width = fm.width(text); 1649 int height = fm.height() * (1 + PAD_HEIGHT); 2001 2002 // Font metrics for various fonts are inconsistent in how 2003 // they provide a realistic line height value. 2004 // The max of what they call height and lineSpacing 2005 // provides a resonable value for most fonts. 2006 int height = max(fm.height(), fm.lineSpacing()); 2007 1650 2008 if (layoutSpacing > 0 && !text.trimmed().isEmpty()) 1651 2009 height = max(height, (int)(font->pixelSize() * layoutSpacing)); 1652 2010 height += CalcShadowOffsetPadding(mythfont).height(); … … QSize SubtitleScreen::CalcTextSize(const QString &text, 1658 2016 // right needs to add the shadow and offset padding. 1659 2017 void SubtitleScreen::CalcPadding(const CC708CharacterAttribute &format, 1660 2018 bool isFirst, bool isLast, 1661 int &left, int &right) const 2019 int &left, int &right, 2020 MythFontProperties* mythfont) const 1662 2021 { 1663 MythFontProperties *mythfont = GetFont(format); 2022 if (!mythfont) 2023 mythfont = GetFont(format); 1664 2024 QFont *font = mythfont->GetFace(); 1665 2025 QFontMetrics fm(*font); 1666 2026 int basicPadding = fm.maxWidth() * PAD_WIDTH; … … void SubtitleScreen::CalcPadding(const CC708CharacterAttribute &format, 1672 2032 MythFontProperties * 1673 2033 SubtitleScreen::GetFont(const CC708CharacterAttribute &attr) const 1674 2034 { 1675 return m_format->GetFont(m_family, attr, m_fontSize, 1676 m_textFontZoom, m_fontStretch); 2035 return m_format->GetFont(m_family, attr, m_textFontZoom); 2036 } 2037 2038 QRect 2039 SubtitleScreen::GetSafeArea() 2040 { 2041 return m_player->GetVideoOutput()->GetSafeRect(); 1677 2042 } 1678 2043 1679 2044 QString SubtitleScreen::GetTeletextFontName(void) 1680 2045 { 1681 2046 SubtitleFormat format; 1682 CC708CharacterAttribute attr(false, false, false, Qt::white); 1683 MythFontProperties *mythfont = 1684 format.GetFont(kSubFamilyTeletext, attr, 1685 /*pixelsize*/20, /*zoom*/100, /*stretch*/100); 1686 return mythfont->face().family(); 2047 return format.GetTeletextFontName(); 1687 2048 } 1688 2049 1689 2050 int SubtitleScreen::GetTeletextBackgroundAlpha(void) … … void SubtitleScreen::OptimiseDisplayedArea(void) 1804 2165 return; 1805 2166 1806 2167 QRect bounding = visible.boundingRect(); 2168 LOG(VB_VBI, LOG_DEBUG, 2169 QString("Visible bounds=%1x%2@%3,%4") 2170 .arg(bounding.width()).arg(bounding.height()) 2171 .arg(bounding.x()).arg(bounding.y())); 2172 1807 2173 bounding = bounding.translated(m_safeArea.topLeft()); 2174 LOG(VB_VBI, LOG_DEBUG, 2175 QString("Translated bounds=%1x%2@%3,%4") 2176 .arg(bounding.width()).arg(bounding.height()) 2177 .arg(bounding.x()).arg(bounding.y())); 2178 1808 2179 bounding = m_safeArea.intersected(bounding); 1809 2180 int left = m_safeArea.left() - bounding.left(); 1810 2181 int top = m_safeArea.top() - bounding.top(); 2182 LOG(VB_VBI, LOG_DEBUG, 2183 QString("Intersected bounds=%1x%2@%3,%4 left=%5 top=%6") 2184 .arg(bounding.width()).arg(bounding.height()) 2185 .arg(bounding.x()).arg(bounding.y()) 2186 .arg(left).arg(top)); 1811 2187 SetArea(MythRect(bounding)); 1812 2188 1813 2189 i.toFront(); -
mythtv/libs/libmythtv/subtitlescreen.h
diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h index 1c7f74a..bb27768 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 methods until teletextscreen.cpp is refactored into 201 203 // subtitlescreen.cpp … … private: 230 232 QRect m_safeArea; 231 233 QRegExp m_removeHTML; 232 234 int m_subtitleType; 233 int m_fontSize;234 235 int m_textFontZoom; // valid for 708 & text subs 235 236 int m_textFontZoomPrev; 236 237 int m_textFontDelayMs; // valid for text subs