Remove all use of add_child() from xmlpp.
[dcpomatic.git] / src / lib / text_content.cc
index 4ba2de348d076c79aee657aac4b79086bab60e4b..cfdaabcbc0bdf24e3bf133052d842563c4837e40 100644 (file)
@@ -81,10 +81,10 @@ TextContent::TextContent (Content* parent, TextType type, TextType original_type
 }
 
 /** @return TextContents from node or <Text> nodes under node (according to version).
- *  The list could be empty if no TextContents are found.
+ *  The vector could be empty if no TextContents are found.
  */
-list<shared_ptr<TextContent>>
-TextContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
+vector<shared_ptr<TextContent>>
+TextContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version, list<string>& notes)
 {
        if (version < 34) {
                /* With old metadata FFmpeg content has the subtitle-related tags even with no
@@ -101,22 +101,19 @@ TextContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
                if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
                        return {};
                }
-               return { make_shared<TextContent>(parent, node, version) };
+               return { make_shared<TextContent>(parent, node, version, notes) };
        }
 
-       if (!node->optional_node_child("Text")) {
-               return {};
-       }
-
-       list<shared_ptr<TextContent>> c;
+       vector<shared_ptr<TextContent>> content;
        for (auto i: node->node_children("Text")) {
-               c.push_back (make_shared<TextContent>(parent, i, version));
+               content.push_back(make_shared<TextContent>(parent, i, version, notes));
        }
 
-       return c;
+       return content;
 }
 
-TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
+
+TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version, list<string>& notes)
        : ContentPart (parent)
        , _use (false)
        , _burn (false)
@@ -151,8 +148,6 @@ TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
                _effect = dcp::Effect::BORDER;
        } else if (node->optional_bool_child("Shadow").get_value_or(false)) {
                _effect = dcp::Effect::SHADOW;
-       } else {
-               _effect = dcp::Effect::NONE;
        }
 
        auto effect = node->optional_string_child("Effect");
@@ -238,9 +233,27 @@ TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
 
        auto lang = node->optional_node_child("Language");
        if (lang) {
-               _language = dcp::LanguageTag(lang->content());
-               auto add = lang->optional_bool_attribute("Additional");
-               _language_is_additional = add && *add;
+               try {
+                       _language = dcp::LanguageTag(lang->content());
+                       auto additional = lang->optional_bool_attribute("Additional");
+                       if (!additional) {
+                               additional = lang->optional_bool_attribute("additional");
+                       }
+                       _language_is_additional = additional.get_value_or(false);
+               } catch (dcp::LanguageTagError&) {
+                       /* The language tag can be empty or invalid if it was loaded from a
+                        * 2.14.x metadata file; we'll just ignore it in that case.
+                        */
+                       if (version <= 37) {
+                               if (!lang->content().empty()) {
+                                       notes.push_back (String::compose(
+                                               _("A subtitle or closed caption file in this project is marked with the language '%1', "
+                                                 "which DCP-o-matic does not recognise.  The file's language has been cleared."), lang->content()));
+                               }
+                       } else {
+                               throw;
+                       }
+               }
        }
 }
 
@@ -343,63 +356,63 @@ TextContent::TextContent (Content* parent, vector<shared_ptr<Content>> c)
 
 /** _mutex must not be held on entry */
 void
-TextContent::as_xml (xmlpp::Node* root) const
+TextContent::as_xml(xmlpp::Element* root) const
 {
        boost::mutex::scoped_lock lm (_mutex);
 
-       auto text = root->add_child ("Text");
+       auto text = cxml::add_child(root, "Text");
 
-       text->add_child("Use")->add_child_text (_use ? "1" : "0");
-       text->add_child("Burn")->add_child_text (_burn ? "1" : "0");
-       text->add_child("XOffset")->add_child_text (raw_convert<string> (_x_offset));
-       text->add_child("YOffset")->add_child_text (raw_convert<string> (_y_offset));
-       text->add_child("XScale")->add_child_text (raw_convert<string> (_x_scale));
-       text->add_child("YScale")->add_child_text (raw_convert<string> (_y_scale));
+       cxml::add_text_child(text, "Use", _use ? "1" : "0");
+       cxml::add_text_child(text, "Burn", _burn ? "1" : "0");
+       cxml::add_text_child(text, "XOffset", raw_convert<string>(_x_offset));
+       cxml::add_text_child(text, "YOffset", raw_convert<string>(_y_offset));
+       cxml::add_text_child(text, "XScale", raw_convert<string>(_x_scale));
+       cxml::add_text_child(text, "YScale", raw_convert<string>(_y_scale));
        if (_colour) {
-               text->add_child("Red")->add_child_text (raw_convert<string> (_colour->r));
-               text->add_child("Green")->add_child_text (raw_convert<string> (_colour->g));
-               text->add_child("Blue")->add_child_text (raw_convert<string> (_colour->b));
+               cxml::add_text_child(text, "Red", raw_convert<string>(_colour->r));
+               cxml::add_text_child(text, "Green", raw_convert<string>(_colour->g));
+               cxml::add_text_child(text, "Blue", raw_convert<string>(_colour->b));
        }
        if (_effect) {
                switch (*_effect) {
                case dcp::Effect::NONE:
-                       text->add_child("Effect")->add_child_text("none");
+                       cxml::add_text_child(text, "Effect", "none");
                        break;
                case dcp::Effect::BORDER:
-                       text->add_child("Effect")->add_child_text("outline");
+                       cxml::add_text_child(text, "Effect", "outline");
                        break;
                case dcp::Effect::SHADOW:
-                       text->add_child("Effect")->add_child_text("shadow");
+                       cxml::add_text_child(text, "Effect", "shadow");
                        break;
                }
        }
        if (_effect_colour) {
-               text->add_child("EffectRed")->add_child_text (raw_convert<string> (_effect_colour->r));
-               text->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour->g));
-               text->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour->b));
+               cxml::add_text_child(text, "EffectRed", raw_convert<string>(_effect_colour->r));
+               cxml::add_text_child(text, "EffectGreen", raw_convert<string>(_effect_colour->g));
+               cxml::add_text_child(text, "EffectBlue", raw_convert<string>(_effect_colour->b));
        }
-       text->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing));
+       cxml::add_text_child(text, "LineSpacing", raw_convert<string>(_line_spacing));
        if (_fade_in) {
-               text->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in->get()));
+               cxml::add_text_child(text, "FadeIn", raw_convert<string>(_fade_in->get()));
        }
        if (_fade_out) {
-               text->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out->get()));
+               cxml::add_text_child(text, "FadeOut", raw_convert<string>(_fade_out->get()));
        }
-       text->add_child("OutlineWidth")->add_child_text (raw_convert<string> (_outline_width));
+       cxml::add_text_child(text, "OutlineWidth", raw_convert<string>(_outline_width));
 
        for (auto i: _fonts) {
-               i->as_xml (text->add_child("Font"));
+               i->as_xml(cxml::add_child(text, "Font"));
        }
 
-       text->add_child("Type")->add_child_text (text_type_to_string(_type));
-       text->add_child("OriginalType")->add_child_text (text_type_to_string(_original_type));
+       cxml::add_text_child(text, "Type", text_type_to_string(_type));
+       cxml::add_text_child(text, "OriginalType", text_type_to_string(_original_type));
        if (_dcp_track) {
-               _dcp_track->as_xml(text->add_child("DCPTrack"));
+               _dcp_track->as_xml(cxml::add_child(text, "DCPTrack"));
        }
        if (_language) {
-               auto lang = text->add_child("Language");
+               auto lang = cxml::add_child(text, "Language");
                lang->add_child_text (_language->to_string());
-               lang->set_attribute ("Additional", _language_is_additional ? "1" : "0");
+               lang->set_attribute("additional", _language_is_additional ? "1" : "0");
        }
 }
 
@@ -434,6 +447,9 @@ TextContent::identifier () const
 void
 TextContent::add_font (shared_ptr<Font> font)
 {
+       boost::mutex::scoped_lock lm(_mutex);
+
+       DCPOMATIC_ASSERT(!get_font_unlocked(font->id()));
        _fonts.push_back (font);
        connect_to_fonts ();
 }
@@ -636,3 +652,36 @@ TextContent::take_settings_from (shared_ptr<const TextContent> c)
        set_language (c->_language);
        set_language_is_additional (c->_language_is_additional);
 }
+
+
+shared_ptr<dcpomatic::Font>
+TextContent::get_font(string id) const
+{
+       boost::mutex::scoped_lock lm(_mutex);
+       return get_font_unlocked(id);
+}
+
+
+shared_ptr<dcpomatic::Font>
+TextContent::get_font_unlocked(string id) const
+{
+       auto iter = std::find_if(_fonts.begin(), _fonts.end(), [&id](shared_ptr<dcpomatic::Font> font) {
+               return font->id() == id;
+       });
+
+       if (iter == _fonts.end()) {
+               return {};
+       }
+
+       return *iter;
+}
+
+
+void
+TextContent::clear_fonts()
+{
+       boost::mutex::scoped_lock lm(_mutex);
+
+       _fonts.clear();
+}
+