2
* Inkscape::Text::Layout::ScanlineMaker - text layout engine shape measurers
5
* Richard Hughes <cyreve@users.sf.net>
7
* Copyright (C) 2005 Richard Hughes
9
* Released under GNU GPL, read the file 'COPYING' for more information
11
#include "Layout-TNG-Scanline-Maker.h"
12
#include "livarot/Shape.h"
13
#include "livarot/float-line.h"
18
// *********************** infinite version
20
Layout::InfiniteScanlineMaker::InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression)
22
_current_line_height.ascent = 0.0;
23
_current_line_height.descent = 0.0;
24
_current_line_height.leading = 0.0;
25
switch (block_progression) {
36
_negative_block_progression = block_progression == RIGHT_TO_LEFT || block_progression == BOTTOM_TO_TOP;
40
Layout::InfiniteScanlineMaker::~InfiniteScanlineMaker()
44
std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::LineHeight const &line_height)
46
std::vector<ScanRun> runs(1);
48
runs[0].x_end = FLT_MAX; // we could use DBL_MAX, but this just seems safer
50
_current_line_height = line_height;
54
void Layout::InfiniteScanlineMaker::completeLine()
56
if (_negative_block_progression)
57
_y -= _current_line_height.total();
59
_y += _current_line_height.total();
60
_current_line_height.ascent = 0.0;
61
_current_line_height.descent = 0.0;
62
_current_line_height.leading = 0.0;
65
void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y)
70
bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &line_height)
72
_current_line_height = line_height;
76
// *********************** real shapes version
78
Layout::ShapeScanlineMaker::ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression)
80
if (block_progression == TOP_TO_BOTTOM) {
81
_rotated_shape = const_cast<Shape*>(shape);
82
_shape_needs_freeing = false;
84
Shape *temp_rotated_shape = new Shape;
85
_shape_needs_freeing = true;
86
temp_rotated_shape->Copy(const_cast<Shape*>(shape));
87
switch (block_progression) {
88
case BOTTOM_TO_TOP: temp_rotated_shape->Transform(Geom::Matrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); break; // reflect about x axis
89
case LEFT_TO_RIGHT: temp_rotated_shape->Transform(Geom::Matrix(0.0, 1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=x
90
case RIGHT_TO_LEFT: temp_rotated_shape->Transform(Geom::Matrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=-x
93
_rotated_shape = new Shape;
94
_rotated_shape->ConvertToShape(temp_rotated_shape);
95
delete temp_rotated_shape;
97
_rotated_shape->CalcBBox(true);
98
_bounding_box_top = _rotated_shape->topY;
99
_bounding_box_bottom = _rotated_shape->bottomY;
100
_y = _rasterizer_y = _bounding_box_top;
101
_current_rasterization_point = 0;
102
_rotated_shape->BeginRaster(_y, _current_rasterization_point);
103
_negative_block_progression = block_progression == RIGHT_TO_LEFT || block_progression == BOTTOM_TO_TOP;
107
Layout::ShapeScanlineMaker::~ShapeScanlineMaker()
109
_rotated_shape->EndRaster();
110
if (_shape_needs_freeing)
111
delete _rotated_shape;
114
std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::LineHeight const &line_height)
116
FloatLigne line_rasterization;
117
FloatLigne line_decent_length_runs;
118
float line_text_height = (float)(line_height.ascent + line_height.descent);
120
if (_y > _bounding_box_bottom)
121
return std::vector<ScanRun>();
123
if (_y < _bounding_box_top)
124
_y = _bounding_box_top;
126
if (line_text_height == 0.0)
127
line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do
129
_current_line_height = (float)line_height.total();
131
// I think what's going on here is that we're moving the top of the scanline to the given position...
132
_rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y, line_text_height);
133
// ...then actually retreiving the scanline (which alters the first two parameters)
134
_rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y + line_text_height , &line_rasterization, true, line_text_height);
135
// sanitise the raw rasterisation, which could have weird overlaps
136
line_rasterization.Flatten();
137
// cut out runs that cover less than 90% of the line
138
line_decent_length_runs.Over(&line_rasterization, 0.9 * line_text_height);
140
if (line_decent_length_runs.runs.empty())
142
if (line_rasterization.runs.empty())
143
return std::vector<ScanRun>(); // stop the flow
144
// make up a pointless run: anything that's not an empty vector
145
std::vector<ScanRun> result(1);
146
result[0].x_start = line_rasterization.runs[0].st;
147
result[0].x_end = line_rasterization.runs[0].st;
148
result[0].y = _negative_block_progression ? -_current_line_height - _y : _y;
152
// convert the FloatLigne to what we use: vector<ScanRun>
153
std::vector<ScanRun> result(line_decent_length_runs.runs.size());
154
for (unsigned i = 0 ; i < result.size() ; i++) {
155
result[i].x_start = line_decent_length_runs.runs[i].st;
156
result[i].x_end = line_decent_length_runs.runs[i].en;
157
result[i].y = _negative_block_progression ? -_current_line_height - _y : _y;
163
void Layout::ShapeScanlineMaker::completeLine()
165
_y += _current_line_height;
168
double Layout::ShapeScanlineMaker::yCoordinate()
170
if (_negative_block_progression) return -_current_line_height - _y;
174
void Layout::ShapeScanlineMaker::setNewYCoordinate(double new_y)
177
if (_negative_block_progression) _y = -_current_line_height - _y;
178
// what will happen with the rasteriser if we move off the shape?
179
// it's not an important question because <flowSpan> doesn't have a y attribute
182
bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &/*line_height*/)
184
//we actually could return true if only the leading changed, but that's too much effort for something that rarely happens
189
}//namespace Inkscape