summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/text_asset.cc174
-rw-r--r--src/text_asset.h4
-rw-r--r--src/text_ruby.h95
-rw-r--r--src/text_with_position.h170
4 files changed, 368 insertions, 75 deletions
diff --git a/src/text_asset.cc b/src/text_asset.cc
index 1a58d22f..82423862 100644
--- a/src/text_asset.cc
+++ b/src/text_asset.cc
@@ -42,10 +42,11 @@
#include "load_font_node.h"
#include "raw_convert.h"
#include "reel_asset.h"
-#include "text_image.h"
-#include "text_string.h"
#include "text_asset.h"
#include "text_asset_internal.h"
+#include "text_image.h"
+#include "text_ruby.h"
+#include "text_string.h"
#include "util.h"
#include "xml.h"
#include <asdcp/AS_DCP.h>
@@ -229,6 +230,36 @@ TextAsset::text_node_state(xmlpp::Element const * node) const
TextAsset::ParseState
+TextAsset::ruby_node_state(xmlpp::Element const* node) const
+{
+ ParseState ps;
+
+ if (auto size = optional_string_attribute(node, "Size")) {
+ boost::replace_all(*size, "em", "");
+ ps.ruby_size = dcp::raw_convert<float>(*size);
+ }
+
+ if (auto position = optional_string_attribute(node, "Position")) {
+ ps.ruby_position = *position == "before" ? RubyPosition::BEFORE : RubyPosition::AFTER;
+ }
+
+ if (auto offset = optional_string_attribute(node, "Offset")) {
+ boost::replace_all(*offset, "em", "");
+ ps.ruby_offset = dcp::raw_convert<float>(*offset);
+ }
+
+ if (auto spacing = optional_string_attribute(node, "Spacing")) {
+ boost::replace_all(*spacing, "em", "");
+ ps.ruby_spacing = dcp::raw_convert<float>(*spacing);
+ }
+
+ if (auto aspect_adjust = optional_number_attribute<float>(node, "AspectAdjust")) {
+ ps.ruby_aspect_adjust = *aspect_adjust;
+ }
+}
+
+
+TextAsset::ParseState
TextAsset::image_node_state(xmlpp::Element const * node) const
{
ParseState ps;
@@ -275,26 +306,12 @@ TextAsset::fade_time(xmlpp::Element const * node, string name, optional<int> tcr
}
+/** Recursively scan node finding text, image and ruby content, keeping track of the currently applicable attributes so that
+ * TextString, TextImage or TextRuby objects can be added to _texts to reflect the contents of node.
+ */
void
TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, optional<int> tcr, Standard standard)
{
- if (node->get_name() == "Font") {
- state.push_back (font_node_state (node, standard));
- } else if (node->get_name() == "Subtitle") {
- state.push_back (subtitle_node_state (node, tcr));
- } else if (node->get_name() == "Text") {
- state.push_back (text_node_state (node));
- } else if (node->get_name() == "SubtitleList") {
- state.push_back (ParseState ());
- } else if (node->get_name() == "Image") {
- state.push_back (image_node_state (node));
- } else {
- throw XMLError ("unexpected node " + node->get_name());
- }
-
- float space_before = 0;
-
- /* Collect <Ruby>s first */
auto get_text_content = [](xmlpp::Element const* element) {
string all_content;
for (auto child: element->get_children()) {
@@ -306,61 +323,74 @@ TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, o
return all_content;
};
- vector<Ruby> rubies;
- for (auto child: node->get_children()) {
- auto element = dynamic_cast<xmlpp::Element const*>(child);
- if (element && element->get_name() == "Ruby") {
- optional<string> base;
- optional<string> annotation;
- optional<float> size;
- optional<RubyPosition> position;
- optional<float> offset;
- optional<float> spacing;
- optional<float> aspect_adjust;
- for (auto ruby_child: element->get_children()) {
- if (auto ruby_element = dynamic_cast<xmlpp::Element const*>(ruby_child)) {
- if (ruby_element->get_name() == "Rb") {
- base = get_text_content(ruby_element);
- } else if (ruby_element->get_name() == "Rt") {
- annotation = get_text_content(ruby_element);
- size = optional_number_attribute<float>(ruby_element, "Size");
- if (auto position_string = optional_string_attribute(ruby_element, "Position")) {
- if (*position_string == "before") {
- position = RubyPosition::BEFORE;
- } else if (*position_string == "after") {
- position = RubyPosition::AFTER;
- } else {
- DCP_ASSERT(false);
- }
+ if (node->get_name() == "Font") {
+ state.push_back (font_node_state (node, standard));
+ } else if (node->get_name() == "Subtitle") {
+ state.push_back (subtitle_node_state (node, tcr));
+ } else if (node->get_name() == "Text") {
+ state.push_back (text_node_state (node));
+ } else if (node->get_name() == "SubtitleList") {
+ state.push_back (ParseState ());
+ } else if (node->get_name() == "Image") {
+ state.push_back (image_node_state (node));
+ } else if (node->get_name() == "Ruby") {
+ optional<string> base;
+ optional<string> annotation;
+ optional<float> size;
+ optional<RubyPosition> position;
+ optional<float> offset;
+ optional<float> spacing;
+ optional<float> aspect_adjust;
+ for (auto ruby_child: node->get_children()) {
+ if (auto ruby_element = dynamic_cast<xmlpp::Element const*>(ruby_child)) {
+ if (ruby_element->get_name() == "Rb") {
+ base = get_text_content(ruby_element);
+ } else if (ruby_element->get_name() == "Rt") {
+ annotation = get_text_content(ruby_element);
+ size = optional_number_attribute<float>(ruby_element, "Size");
+ if (auto position_string = optional_string_attribute(ruby_element, "Position")) {
+ if (*position_string == "before") {
+ position = RubyPosition::BEFORE;
+ } else if (*position_string == "after") {
+ position = RubyPosition::AFTER;
+ } else {
+ DCP_ASSERT(false);
}
- offset = optional_number_attribute<float>(ruby_element, "Offset");
- spacing = optional_number_attribute<float>(ruby_element, "Spacing");
- aspect_adjust = optional_number_attribute<float>(ruby_element, "AspectAdjust");
}
+ offset = optional_number_attribute<float>(ruby_element, "Offset");
+ spacing = optional_number_attribute<float>(ruby_element, "Spacing");
+ aspect_adjust = optional_number_attribute<float>(ruby_element, "AspectAdjust");
}
}
- DCP_ASSERT(base);
- DCP_ASSERT(annotation);
- auto ruby = Ruby{*base, *annotation};
- if (size) {
- ruby.size = *size;
- }
- if (position) {
- ruby.position = *position;
- }
- if (offset) {
- ruby.offset = *offset;
- }
- if (spacing) {
- ruby.spacing = *spacing;
- }
- if (aspect_adjust) {
- ruby.aspect_adjust = *aspect_adjust;
- }
- rubies.push_back(ruby);
}
+ DCP_ASSERT(base);
+ DCP_ASSERT(annotation);
+ ParseState ps(state);
+ _texts.push_back(
+ make_shared<TextRuby>(
+ ps.in.get(),
+ ps.out.get(),
+ ps.h_position.get_value_or(0),
+ ps.h_align.get_value_or(HAlign::CENTER),
+ ps.v_position.get_value_or(0),
+ ps.v_align.get_value_or(VAlign::CENTER),
+ ps.z_position.get_value_or(0),
+ ps.direction.get_value_or (Direction::LTR),
+ *base,
+ *annotation,
+ size.get_value_or(0.5),
+ position.get_value_or(RubyPosition::BEFORE),
+ offset.get_value_or(0),
+ spacing.get_value_or(0),
+ aspect_adjust.get_value_or(1.0)
+ )
+ );
+ } else {
+ throw XMLError ("unexpected node " + node->get_name());
}
+ float space_before = 0;
+
for (auto i: node->get_children()) {
/* Handle actual content e.g. text */
@@ -382,8 +412,8 @@ TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, o
boost::replace_all(size, "em", "");
}
space_before += raw_convert<float>(size);
- } else if (e->get_name() != "Ruby") {
- parse_texts (e, state, tcr, standard);
+ } else {
+ parse_texts(e, state, tcr, standard);
}
}
}
@@ -397,8 +427,7 @@ TextAsset::maybe_add_text(
string text,
vector<ParseState> const & parse_state,
float space_before,
- Standard standard,
- vector<Ruby> const& rubies
+ Standard standard
)
{
auto wanted = [](ParseState const& ps) {
@@ -441,8 +470,7 @@ TextAsset::maybe_add_text(
ps.effect_colour.get_value_or (dcp::Colour (0, 0, 0)),
ps.fade_up_time.get_value_or(Time()),
ps.fade_down_time.get_value_or(Time()),
- space_before,
- rubies
+ space_before
)
);
break;
diff --git a/src/text_asset.h b/src/text_asset.h
index 0a8ed78c..eb2d7a37 100644
--- a/src/text_asset.h
+++ b/src/text_asset.h
@@ -178,6 +178,7 @@ protected:
ParseState text_node_state (xmlpp::Element const * node) const;
ParseState image_node_state (xmlpp::Element const * node) const;
ParseState subtitle_node_state (xmlpp::Element const * node, boost::optional<int> tcr) const;
+ ParseState ruby_node_state(xmlpp::Element const* node) const;
Time fade_time (xmlpp::Element const * node, std::string name, boost::optional<int> tcr) const;
void position_align (ParseState& ps, xmlpp::Element const * node) const;
@@ -224,8 +225,7 @@ private:
std::string text,
std::vector<ParseState> const & parse_state,
float space_before,
- Standard standard,
- std::vector<Ruby> const& rubies
+ Standard standard
);
static void pull_fonts (std::shared_ptr<order::Part> part);
diff --git a/src/text_ruby.h b/src/text_ruby.h
new file mode 100644
index 00000000..2b5da1ea
--- /dev/null
+++ b/src/text_ruby.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/text_ruby.h
+ * @brief TextRuby class
+ */
+
+
+#ifndef LIBDCP_TEXT_RUBY_H
+#define LIBDCP_TEXT_RUBY_H
+
+
+#include "text.h"
+
+
+namespace dcp {
+
+
+class TextRuby : public Text
+{
+public:
+ TextRuby(
+ Time in,
+ Time out,
+ float h_position,
+ HAlign h_align,
+ float v_position,
+ VAlign v_align,
+ float z_position,
+ Time fade_up_time,
+ Time fade_down_time,
+ std::string base,
+ std::string annotation,
+ float size,
+ RubyPosition position,
+ float offset,
+ float spacing,
+ float aspect_adjust
+ )
+ : _base(base)
+ , _annotation(annotation)
+ , _size(size)
+ , _position(position)
+ , _offset(offset)
+ , _spacing(spacing)
+ , _aspect_adjust(aspect_adjust)
+ {}
+
+private:
+ std::string _base;
+ std::string _annotation;
+ float _size;
+ RubyPosition _position;
+ float _offset;
+ float _spacing;
+ float _aspect_adjust;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/text_with_position.h b/src/text_with_position.h
new file mode 100644
index 00000000..b8f15757
--- /dev/null
+++ b/src/text_with_position.h
@@ -0,0 +1,170 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/text.h
+ * @brief Text class
+ */
+
+
+#ifndef LIBDCP_TEXT_H
+#define LIBDCP_TEXT_H
+
+
+#include "dcp_time.h"
+#include "h_align.h"
+#include "v_align.h"
+
+
+namespace dcp {
+
+
+class EqualityOptions;
+
+
+class Text
+{
+public:
+ virtual ~Text() {}
+
+ /** @return text start time (relative to the start of the reel) */
+ Time in () const {
+ return _in;
+ }
+
+ /** @return text finish time (relative to the start of the reel) */
+ Time out () const {
+ return _out;
+ }
+
+ float h_position () const {
+ return _h_position;
+ }
+
+ HAlign h_align () const {
+ return _h_align;
+ }
+
+ /** @return vertical position as a proportion of the screen height from the
+ * vertical alignment point.
+ * (between 0 and 1)
+ */
+ float v_position () const {
+ return _v_position;
+ }
+
+ VAlign v_align () const {
+ return _v_align;
+ }
+
+ float z_position() const {
+ return _z_position;
+ }
+
+ Time fade_up_time () const {
+ return _fade_up_time;
+ }
+
+ Time fade_down_time () const {
+ return _fade_down_time;
+ }
+
+ void set_in (Time i) {
+ _in = i;
+ }
+
+ void set_out (Time o) {
+ _out = o;
+ }
+
+ void set_h_position (float p) {
+ _h_position = p;
+ }
+
+ /** @param p New vertical position as a proportion of the screen height
+ * from the top (between 0 and 1)
+ */
+ void set_v_position (float p) {
+ _v_position = p;
+ }
+
+ void set_z_position(float z) {
+ _z_position = z;
+ }
+
+ void set_fade_up_time (Time t) {
+ _fade_up_time = t;
+ }
+
+ void set_fade_down_time (Time t) {
+ _fade_down_time = t;
+ }
+
+ virtual bool equals(std::shared_ptr<const dcp::Text> other, EqualityOptions const& options, NoteHandler note) const;
+
+protected:
+
+ Text(
+ Time in,
+ Time out,
+ float h_position,
+ HAlign h_align,
+ float v_position,
+ VAlign v_align,
+ float z_position,
+ Time fade_up_time,
+ Time fade_down_time
+ );
+
+ Time _in;
+ Time _out;
+ /** Horizontal position as a proportion of the screen width from the _h_align
+ * (between 0 and 1)
+ */
+ float _h_position = 0;
+ HAlign _h_align = HAlign::CENTER;
+ /** Vertical position as a proportion of the screen height from the _v_align
+ * (between 0 and 1)
+ */
+ float _v_position = 0;
+ VAlign _v_align = VAlign::CENTER;
+ float _z_position = 0;
+ Time _fade_up_time;
+ Time _fade_down_time;
+};
+
+
+}
+
+
+#endif