summaryrefslogtreecommitdiffstats
path: root/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnrtype/Layout-TNG-Scanline-Makers.cpp')
-rw-r--r--src/libnrtype/Layout-TNG-Scanline-Makers.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
new file mode 100644
index 0000000..8398bf1
--- /dev/null
+++ b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Text::Layout::ScanlineMaker - text layout engine shape measurers
+ *
+ * Authors:
+ * Richard Hughes <cyreve@users.sf.net>
+ *
+ * Copyright (C) 2005 Richard Hughes
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#include "Layout-TNG-Scanline-Maker.h"
+#include "livarot/Shape.h"
+#include "livarot/float-line.h"
+#include <limits>
+
+namespace Inkscape {
+namespace Text {
+
+// *********************** infinite version
+
+Layout::InfiniteScanlineMaker::InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression)
+{
+ _current_line_height.setZero();
+ switch (block_progression) {
+ case LEFT_TO_RIGHT:
+ case RIGHT_TO_LEFT:
+ _x = initial_y;
+ _y = initial_x;
+ break;
+ default:
+ _x = initial_x;
+ _y = initial_y;
+ break;
+ }
+ _negative_block_progression = block_progression == RIGHT_TO_LEFT || block_progression == BOTTOM_TO_TOP;
+
+}
+
+Layout::InfiniteScanlineMaker::~InfiniteScanlineMaker()
+= default;
+
+std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::FontMetrics const &line_height)
+{
+ std::vector<ScanRun> runs(1);
+ runs[0].x_start = _x;
+ runs[0].x_end = std::numeric_limits<float>::max(); // we could use DBL_MAX, but this just seems safer
+ runs[0].y = _y;
+ _current_line_height = line_height;
+ return runs;
+}
+
+void Layout::InfiniteScanlineMaker::completeLine()
+{
+ if (_negative_block_progression)
+ _y -= _current_line_height.emSize();
+ else
+ _y += _current_line_height.emSize();
+ _current_line_height.setZero();
+}
+
+void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y)
+{
+ _y = new_y;
+}
+
+bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &line_height)
+{
+ _current_line_height = line_height;
+ return true;
+}
+
+void Layout::InfiniteScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height)
+{
+ _current_line_height = line_height;
+}
+
+// *********************** real shapes version
+
+Layout::ShapeScanlineMaker::ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression)
+{
+ if (block_progression == TOP_TO_BOTTOM) {
+ _rotated_shape = const_cast<Shape*>(shape);
+ _shape_needs_freeing = false;
+ } else {
+ Shape *temp_rotated_shape = new Shape;
+ _shape_needs_freeing = true;
+ temp_rotated_shape->Copy(const_cast<Shape*>(shape));
+ switch (block_progression) {
+ case BOTTOM_TO_TOP: temp_rotated_shape->Transform(Geom::Affine(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); break; // reflect about x axis
+ case LEFT_TO_RIGHT: temp_rotated_shape->Transform(Geom::Affine(0.0, 1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=x
+ case RIGHT_TO_LEFT: temp_rotated_shape->Transform(Geom::Affine(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=-x
+ default: break;
+ }
+ _rotated_shape = new Shape;
+ _rotated_shape->ConvertToShape(temp_rotated_shape);
+ delete temp_rotated_shape;
+ }
+ _rotated_shape->CalcBBox(true);
+ _bounding_box_top = _rotated_shape->topY;
+ _bounding_box_bottom = _rotated_shape->bottomY;
+ _y = _rasterizer_y = _bounding_box_top;
+ _current_rasterization_point = 0;
+ _rotated_shape->BeginRaster(_y, _current_rasterization_point);
+ _negative_block_progression = block_progression == RIGHT_TO_LEFT || block_progression == BOTTOM_TO_TOP;
+}
+
+
+Layout::ShapeScanlineMaker::~ShapeScanlineMaker()
+{
+ _rotated_shape->EndRaster();
+ if (_shape_needs_freeing)
+ delete _rotated_shape;
+}
+
+std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::FontMetrics const &line_height)
+{
+ if (_y > _bounding_box_bottom)
+ return std::vector<ScanRun>();
+
+ if (_y < _bounding_box_top)
+ _y = _bounding_box_top;
+
+ FloatLigne line_rasterization;
+ FloatLigne line_decent_length_runs;
+ float line_text_height = (float)(line_height.emSize());
+ if (line_text_height < 0.001)
+ line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do
+
+ _current_line_height = (float)line_height.emSize();
+
+ // I think what's going on here is that we're moving the top of the scanline to the given position...
+ _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y, line_text_height);
+ // ...then actually retrieving the scanline (which alters the first two parameters)
+ _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y + line_text_height , &line_rasterization, true, line_text_height);
+ // sanitise the raw rasterisation, which could have weird overlaps
+ line_rasterization.Flatten();
+ // line_rasterization.Affiche();
+ // cut out runs that cover less than 90% of the line
+ line_decent_length_runs.Over(&line_rasterization, 0.9 * line_text_height);
+
+ if (line_decent_length_runs.runs.empty())
+ {
+ if (line_rasterization.runs.empty())
+ return std::vector<ScanRun>(); // stop the flow
+ // make up a pointless run: anything that's not an empty vector
+ std::vector<ScanRun> result(1);
+ result[0].x_start = line_rasterization.runs[0].st;
+ result[0].x_end = line_rasterization.runs[0].st;
+ result[0].y = _negative_block_progression ? - _y : _y;
+ return result;
+ }
+
+ // convert the FloatLigne to what we use: vector<ScanRun>
+ std::vector<ScanRun> result(line_decent_length_runs.runs.size());
+ for (unsigned i = 0 ; i < result.size() ; i++) {
+ result[i].x_start = line_decent_length_runs.runs[i].st;
+ result[i].x_end = line_decent_length_runs.runs[i].en;
+ result[i].y = _negative_block_progression ? - _y : _y;
+ }
+
+ return result;
+}
+
+void Layout::ShapeScanlineMaker::completeLine()
+{
+ _y += _current_line_height;
+}
+
+double Layout::ShapeScanlineMaker::yCoordinate()
+{
+ if (_negative_block_progression) return - _y;
+ return _y;
+}
+
+void Layout::ShapeScanlineMaker::setNewYCoordinate(double new_y)
+{
+ _y = (float)new_y;
+ if (_negative_block_progression) _y = - _y;
+ // what will happen with the rasteriser if we move off the shape?
+ // it's not an important question because <flowSpan> doesn't have a y attribute
+}
+
+bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &/*line_height*/)
+{
+ //we actually could return true if only the leading changed, but that's too much effort for something that rarely happens
+ return false;
+}
+
+void Layout::ShapeScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height)
+{
+ _current_line_height = line_height.emSize();
+}
+
+}//namespace Text
+}//namespace Inkscape