return sourceToIterator(source_cookie, Glib::ustring::const_iterator(std::string::const_iterator(NULL)));
}
-NR::Rect Layout::glyphBoundingBox(iterator const &it, double *rotation) const
+boost::optional<NR::Rect> Layout::glyphBoundingBox(iterator const &it, double *rotation) const
{
if (rotation) *rotation = _glyphs[it._glyph_index].rotation;
return _glyphs[it._glyph_index].span(this).font->BBox(_glyphs[it._glyph_index].glyph);
@@ -264,14 +264,15 @@ NR::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) cons
NR::Point midpoint;
NR::Point tangent;
Span const &span = _characters[char_index].span(this);
- double top = span.baseline_shift - span.line_height.ascent;
- double bottom = span.baseline_shift + span.line_height.descent;
const_cast<Path*>(_path_fitted)->PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
top_left[NR::X] = midpoint[NR::X] - cluster_half_width;
- top_left[NR::Y] = midpoint[NR::Y] + top;
+ top_left[NR::Y] = midpoint[NR::Y] - span.line_height.ascent;
bottom_right[NR::X] = midpoint[NR::X] + cluster_half_width;
- bottom_right[NR::Y] = midpoint[NR::Y] + bottom;
+ bottom_right[NR::Y] = midpoint[NR::Y] + span.line_height.descent;
+ NR::Point normal = tangent.cw();
+ top_left += span.baseline_shift * normal;
+ bottom_right += span.baseline_shift * normal;
if (rotation)
*rotation = atan2(tangent[1], tangent[0]);
}
_cursor_moving_vertically = true;
}
-bool Layout::iterator::nextLineCursor()
+bool Layout::iterator::nextLineCursor(int n)
{
if (!_cursor_moving_vertically)
beginCursorUpDown();
if (_char_index == _parent_layout->_characters.size())
return false;
unsigned line_index = _parent_layout->_characters[_char_index].chunk(_parent_layout).in_line;
- if (line_index == _parent_layout->_lines.size() - 1) return false;
- if (_parent_layout->_lines[line_index + 1].in_shape != _parent_layout->_lines[line_index].in_shape) {
+ if (line_index == _parent_layout->_lines.size() - 1)
+ return false; // nowhere to go
+ else
+ n = MIN (n, static_cast<int>(_parent_layout->_lines.size() - 1 - line_index));
+ if (_parent_layout->_lines[line_index + n].in_shape != _parent_layout->_lines[line_index].in_shape) {
// switching between shapes: adjust the stored x to compensate
- _x_coordinate += _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index + 1)].in_chunk].left_x
+ _x_coordinate += _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index + n)].in_chunk].left_x
- _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index)].in_chunk].left_x;
}
- _char_index = _parent_layout->_cursorXOnLineToIterator(line_index + 1, _x_coordinate)._char_index;
+ _char_index = _parent_layout->_cursorXOnLineToIterator(line_index + n, _x_coordinate)._char_index;
_glyph_index = _parent_layout->_characters[_char_index].in_glyph;
return true;
}
-bool Layout::iterator::prevLineCursor()
+bool Layout::iterator::prevLineCursor(int n)
{
if (!_cursor_moving_vertically)
beginCursorUpDown();
line_index = _parent_layout->_lines.size() - 1;
else
line_index = _parent_layout->_characters[_char_index].chunk(_parent_layout).in_line;
- if (line_index == 0) return false;
- if (_parent_layout->_lines[line_index - 1].in_shape != _parent_layout->_lines[line_index].in_shape) {
+ if (line_index == 0)
+ return false; // nowhere to go
+ else
+ n = MIN (n, static_cast<int>(line_index));
+ if (_parent_layout->_lines[line_index - n].in_shape != _parent_layout->_lines[line_index].in_shape) {
// switching between shapes: adjust the stored x to compensate
- _x_coordinate += _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index - 1)].in_chunk].left_x
+ _x_coordinate += _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index - n)].in_chunk].left_x
- _parent_layout->_chunks[_parent_layout->_spans[_parent_layout->_lineToSpan(line_index)].in_chunk].left_x;
}
- _char_index = _parent_layout->_cursorXOnLineToIterator(line_index - 1, _x_coordinate)._char_index;
+ _char_index = _parent_layout->_cursorXOnLineToIterator(line_index - n, _x_coordinate)._char_index;
_glyph_index = _parent_layout->_characters[_char_index].in_glyph;
return true;
}
for ( ; ; ) { \
if (_char_index == 0) { \
_glyph_index = 0; \
- return true; \
+ return false; \
} \
_char_index--; \
if (_parent_layout->_characters[_char_index].char_attributes.attr) break; \
return r;
}
-bool Layout::iterator::cursorUp()
+bool Layout::iterator::cursorUp(int n)
{
Direction block_progression = _parent_layout->_blockProgression();
if(block_progression == TOP_TO_BOTTOM)
- return prevLineCursor();
+ return prevLineCursor(n);
else if(block_progression == BOTTOM_TO_TOP)
- return nextLineCursor();
+ return nextLineCursor(n);
else
return _cursorLeftOrRightLocalX(RIGHT_TO_LEFT);
}
-bool Layout::iterator::cursorDown()
+bool Layout::iterator::cursorDown(int n)
{
Direction block_progression = _parent_layout->_blockProgression();
if(block_progression == TOP_TO_BOTTOM)
- return nextLineCursor();
+ return nextLineCursor(n);
else if(block_progression == BOTTOM_TO_TOP)
- return prevLineCursor();
+ return prevLineCursor(n);
else
return _cursorLeftOrRightLocalX(LEFT_TO_RIGHT);
}