+ return y;
+}
+
+
+/** @param subtitles A list of subtitles that are all on the same line,
+ * at the same time and with the same fade in/out.
+ */
+static PositionImage
+render_line (list<StringText> subtitles, list<shared_ptr<Font>> fonts, dcp::Size target, DCPTime time, int frame_rate)
+{
+ /* XXX: this method can only handle italic / bold changes mid-line,
+ nothing else yet.
+ */
+
+ DCPOMATIC_ASSERT (!subtitles.empty ());
+ auto const& first = subtitles.front ();
+
+ auto const font_name = setup_font (first, fonts);
+ auto const fade_factor = calculate_fade_factor (first, time, frame_rate);
+ auto const markup = marked_up (subtitles, target.height, fade_factor, font_name);
+ auto layout = create_layout ();
+ setup_layout (layout, font_name, markup);
+ dcp::Size size;
+ layout->get_pixel_size (size.width, size.height);
+
+ /* Calculate x and y scale factors. These are only used to stretch
+ the font away from its normal aspect ratio.
+ */
+ float x_scale = 1;
+ float y_scale = 1;
+ if (fabs (first.aspect_adjust() - 1.0) > dcp::ASPECT_ADJUST_EPSILON) {
+ if (first.aspect_adjust() < 1) {
+ x_scale = max (0.25f, first.aspect_adjust ());
+ y_scale = 1;
+ } else {
+ x_scale = 1;
+ y_scale = 1 / min (4.0f, first.aspect_adjust ());
+ }
+ }
+
+ auto const border_width = first.effect() == dcp::Effect::BORDER ? (first.outline_width * target.width / 2048.0) : 0;
+ size.width += 2 * ceil (border_width);
+ size.height += 2 * ceil (border_width);
+
+ size.width *= x_scale;
+ size.height *= y_scale;
+
+ /* Shuffle the subtitle over by the border width (if we have any) so it's not cut off */
+ int const x_offset = ceil (border_width);
+ /* Move down a bit so that accents on capital letters can be seen */
+ int const y_offset = target.height / 100.0;
+
+ size.width += x_offset;
+ size.height += y_offset;
+
+ auto image = create_image (size);
+ auto surface = create_surface (image);
+ auto context = Cairo::Context::create (surface);
+
+ context->set_line_width (1);
+ context->scale (x_scale, y_scale);
+ layout->update_from_cairo_context (context);
+
+ if (first.effect() == dcp::Effect::SHADOW) {
+ /* Drop-shadow effect */
+ set_source_rgba (context, first.effect_colour(), fade_factor);
+ context->move_to (x_offset + 4, y_offset + 4);
+ layout->add_to_cairo_context (context);
+ context->fill ();
+ }
+
+ if (first.effect() == dcp::Effect::BORDER) {
+ /* Border effect */
+ set_source_rgba (context, first.effect_colour(), fade_factor);
+ context->set_line_width (border_width);
+ context->set_line_join (Cairo::LINE_JOIN_ROUND);
+ context->move_to (x_offset, y_offset);
+ layout->add_to_cairo_context (context);
+ context->stroke ();
+ }
+
+ /* The actual subtitle */
+
+ set_source_rgba (context, first.colour(), fade_factor);
+
+ context->move_to (x_offset, y_offset);
+ layout->add_to_cairo_context (context);
+ context->fill ();
+
+ context->set_line_width (0.5);
+ context->move_to (x_offset, y_offset);
+ layout->add_to_cairo_context (context);
+ context->stroke ();
+
+ int const x = x_position (first, target.width, size.width);
+ int const y = y_position (first, target.height, size.height);
+ return PositionImage (image, Position<int>(max (0, x), max(0, y)));