Code

Mnemonics in "Fill and stroke", "Align and distribute", and "Transform" dialogs ...
[inkscape.git] / src / libnrtype / Layout-TNG-OutIter.cpp
index 2471da3dd181078ee201e034a9e60b3799e24b4b..0682e3570d4fb3ae2f696eebe291419a7cd05ec8 100644 (file)
@@ -12,8 +12,7 @@
 #include "livarot/Path.h"
 #include "font-instance.h"
 #include "svg/svg-length.h"
-#include "libnr/nr-matrix-translate-ops.h"
-#include "libnr/nr-translate-rotate-ops.h"
+#include <2geom/transforms.h>
 #include "style.h"
 
 namespace Inkscape {
@@ -56,7 +55,7 @@ double Layout::_getChunkWidth(unsigned chunk_index) const
     unsigned span_index;
     if (chunk_index) {
         span_index = _lineToSpan(_chunks[chunk_index].in_line);
-        for ( ; span_index < _spans.size() && _spans[span_index].in_chunk < chunk_index ; span_index++);
+        for ( ; span_index < _spans.size() && _spans[span_index].in_chunk < chunk_index ; span_index++){};
     } else
         span_index = 0;
     for ( ; span_index < _spans.size() && _spans[span_index].in_chunk == chunk_index ; span_index++)
@@ -86,7 +85,7 @@ Layout::iterator Layout::getNearestCursorPositionTo(double x, double y) const
     double local_y = y;
 
     if (_path_fitted) {
-        Path::cut_position position = const_cast<Path*>(_path_fitted)->PointToCurvilignPosition(NR::Point(x, y));
+        Path::cut_position position = const_cast<Path*>(_path_fitted)->PointToCurvilignPosition(Geom::Point(x, y));
         local_x = const_cast<Path*>(_path_fitted)->PositionToLength(position.piece, position.t);
         return _cursorXOnLineToIterator(0, local_x + _chunks.front().left_x);
     }
@@ -157,11 +156,11 @@ Layout::iterator Layout::getNearestCursorPositionTo(double x, double y) const
 
 Layout::iterator Layout::getLetterAt(double x, double y) const
 {
-    NR::Point point(x, y);
+    Geom::Point point(x, y);
 
     double rotation;
     for (iterator it = begin() ; it != end() ; it.nextCharacter()) {
-        NR::Rect box = characterBoundingBox(it, &rotation);
+        Geom::Rect box = characterBoundingBox(it, &rotation);
         // todo: rotation
         if (box.contains(point)) return it;
     }
@@ -201,20 +200,20 @@ Layout::iterator Layout::sourceToIterator(void *source_cookie) const
     return sourceToIterator(source_cookie, Glib::ustring::const_iterator(std::string::const_iterator(NULL)));
 }
 
-NR::Maybe<NR::Rect> Layout::glyphBoundingBox(iterator const &it, double *rotation) const
+Geom::OptRect 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);
 }
 
-NR::Point Layout::characterAnchorPoint(iterator const &it) const
+Geom::Point Layout::characterAnchorPoint(iterator const &it) const
 {
     if (_characters.empty())
         return _empty_cursor_shape.position;
     if (it._char_index == _characters.size()) {
-        return NR::Point(_chunks.back().left_x + _spans.back().x_end, _lines.back().baseline_y + _spans.back().baseline_shift);
+        return Geom::Point(_chunks.back().left_x + _spans.back().x_end, _lines.back().baseline_y + _spans.back().baseline_shift);
     } else {
-        return NR::Point(_characters[it._char_index].chunk(this).left_x
+        return Geom::Point(_characters[it._char_index].chunk(this).left_x
                              + _spans[_characters[it._char_index].in_span].x_start
                              + _characters[it._char_index].x,
                          _characters[it._char_index].line(this).baseline_y
@@ -222,12 +221,41 @@ NR::Point Layout::characterAnchorPoint(iterator const &it) const
     }
 }
 
-NR::Point Layout::chunkAnchorPoint(iterator const &it) const
+boost::optional<Geom::Point> Layout::baselineAnchorPoint() const
+{
+    iterator pos = this->begin();
+    Geom::Point left_pt = this->characterAnchorPoint(pos);
+    pos.thisEndOfLine();
+    Geom::Point right_pt = this->characterAnchorPoint(pos);
+
+    if (this->_blockProgression() == LEFT_TO_RIGHT || this->_blockProgression() == RIGHT_TO_LEFT) {
+        left_pt = Geom::Point(left_pt[Geom::Y], left_pt[Geom::X]);
+        right_pt = Geom::Point(right_pt[Geom::Y], right_pt[Geom::X]);
+    }
+
+    switch (this->paragraphAlignment(pos)) {
+        case LEFT:
+        case FULL:
+            return left_pt;
+            break;
+        case CENTER:
+            return (left_pt + right_pt)/2; // middle point
+            break;
+        case RIGHT:
+            return right_pt;
+            break;
+        default:
+            return boost::optional<Geom::Point>();
+            break;
+    }
+}
+
+Geom::Point Layout::chunkAnchorPoint(iterator const &it) const
 {
     unsigned chunk_index;
 
     if (_chunks.empty())
-        return NR::Point(0.0, 0.0);
+        return Geom::Point(0.0, 0.0);
 
     if (_characters.empty())
         chunk_index = 0;
@@ -237,18 +265,18 @@ NR::Point Layout::chunkAnchorPoint(iterator const &it) const
 
     Alignment alignment = _paragraphs[_lines[_chunks[chunk_index].in_line].in_paragraph].alignment;
     if (alignment == LEFT || alignment == FULL)
-        return NR::Point(_chunks[chunk_index].left_x, _lines[chunk_index].baseline_y);
+        return Geom::Point(_chunks[chunk_index].left_x, _lines[chunk_index].baseline_y);
 
     double chunk_width = _getChunkWidth(chunk_index);
     if (alignment == RIGHT)
-        return NR::Point(_chunks[chunk_index].left_x + chunk_width, _lines[chunk_index].baseline_y);
+        return Geom::Point(_chunks[chunk_index].left_x + chunk_width, _lines[chunk_index].baseline_y);
     //centre
-    return NR::Point(_chunks[chunk_index].left_x + chunk_width * 0.5, _lines[chunk_index].baseline_y);
+    return Geom::Point(_chunks[chunk_index].left_x + chunk_width * 0.5, _lines[chunk_index].baseline_y);
 }
 
-NR::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) const
+Geom::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) const
 {
-    NR::Point top_left, bottom_right;
+    Geom::Point top_left, bottom_right;
     unsigned char_index = it._char_index;
 
     if (_path_fitted) {
@@ -261,16 +289,16 @@ NR::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) cons
         int unused = 0;
         Path::cut_position *midpoint_otp = const_cast<Path*>(_path_fitted)->CurvilignToPosition(1, &midpoint_offset, unused);
         if (midpoint_offset >= 0.0 && midpoint_otp != NULL && midpoint_otp[0].piece >= 0) {
-            NR::Point midpoint;
-            NR::Point tangent;
+            Geom::Point midpoint;
+            Geom::Point tangent;
             Span const &span = _characters[char_index].span(this);
 
             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] - span.line_height.ascent;
-            bottom_right[NR::X] = midpoint[NR::X] + cluster_half_width;
-            bottom_right[NR::Y] = midpoint[NR::Y] + span.line_height.descent;
-            NR::Point normal = tangent.cw();
+            top_left[Geom::X] = midpoint[Geom::X] - cluster_half_width;
+            top_left[Geom::Y] = midpoint[Geom::Y] - span.line_height.ascent;
+            bottom_right[Geom::X] = midpoint[Geom::X] + cluster_half_width;
+            bottom_right[Geom::Y] = midpoint[Geom::Y] + span.line_height.descent;
+            Geom::Point normal = tangent.cw();
             top_left += span.baseline_shift * normal;
             bottom_right += span.baseline_shift * normal;
             if (rotation)
@@ -279,27 +307,27 @@ NR::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) cons
         g_free(midpoint_otp);
     } else {
         if (it._char_index == _characters.size()) {
-            top_left[NR::X] = bottom_right[NR::X] = _chunks.back().left_x + _spans.back().x_end;
+            top_left[Geom::X] = bottom_right[Geom::X] = _chunks.back().left_x + _spans.back().x_end;
             char_index--;
         } else {
             double span_x = _spans[_characters[it._char_index].in_span].x_start + _characters[it._char_index].chunk(this).left_x;
-            top_left[NR::X] = span_x + _characters[it._char_index].x;
+            top_left[Geom::X] = span_x + _characters[it._char_index].x;
             if (it._char_index + 1 == _characters.size() || _characters[it._char_index + 1].in_span != _characters[it._char_index].in_span)
-                bottom_right[NR::X] = _spans[_characters[it._char_index].in_span].x_end + _characters[it._char_index].chunk(this).left_x;
+                bottom_right[Geom::X] = _spans[_characters[it._char_index].in_span].x_end + _characters[it._char_index].chunk(this).left_x;
             else
-                bottom_right[NR::X] = span_x + _characters[it._char_index + 1].x;
+                bottom_right[Geom::X] = span_x + _characters[it._char_index + 1].x;
         }
 
         double baseline_y = _characters[char_index].line(this).baseline_y + _characters[char_index].span(this).baseline_shift;
         if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
             double span_height = _spans[_characters[char_index].in_span].line_height.ascent + _spans[_characters[char_index].in_span].line_height.descent;
-            top_left[NR::Y] = top_left[NR::X];
-            top_left[NR::X] = baseline_y - span_height * 0.5;
-            bottom_right[NR::Y] = bottom_right[NR::X];
-            bottom_right[NR::X] = baseline_y + span_height * 0.5;
+            top_left[Geom::Y] = top_left[Geom::X];
+            top_left[Geom::X] = baseline_y - span_height * 0.5;
+            bottom_right[Geom::Y] = bottom_right[Geom::X];
+            bottom_right[Geom::X] = baseline_y + span_height * 0.5;
         } else {
-            top_left[NR::Y] = baseline_y - _spans[_characters[char_index].in_span].line_height.ascent;
-            bottom_right[NR::Y] = baseline_y + _spans[_characters[char_index].in_span].line_height.descent;
+            top_left[Geom::Y] = baseline_y - _spans[_characters[char_index].in_span].line_height.ascent;
+            bottom_right[Geom::Y] = baseline_y + _spans[_characters[char_index].in_span].line_height.descent;
         }
 
         if (rotation) {
@@ -312,12 +340,12 @@ NR::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) cons
         }
     }
 
-    return NR::Rect(top_left, bottom_right);
+    return Geom::Rect(top_left, bottom_right);
 }
 
-std::vector<NR::Point> Layout::createSelectionShape(iterator const &it_start, iterator const &it_end, NR::Matrix const &transform) const
+std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Matrix const &transform) const
 {
-    std::vector<NR::Point> quads;
+    std::vector<Geom::Point> quads;
     unsigned char_index;
     unsigned end_char_index;
     
@@ -336,53 +364,53 @@ std::vector<NR::Point> Layout::createSelectionShape(iterator const &it_start, it
         double char_rotation = _glyphs[_characters[char_index].in_glyph].rotation;
         unsigned span_index = _characters[char_index].in_span;
 
-        NR::Point top_left, bottom_right;
+        Geom::Point top_left, bottom_right;
         if (_path_fitted || char_rotation != 0.0) {
-            NR::Rect box = characterBoundingBox(iterator(this, char_index), &char_rotation);
+            Geom::Rect box = characterBoundingBox(iterator(this, char_index), &char_rotation);
             top_left = box.min();
             bottom_right = box.max();
             char_index++;
         } else {   // for straight text we can be faster by combining all the character boxes in a span into one box
             double span_x = _spans[span_index].x_start + _spans[span_index].chunk(this).left_x;
-            top_left[NR::X] = span_x + _characters[char_index].x;
+            top_left[Geom::X] = span_x + _characters[char_index].x;
             while (char_index < end_char_index && _characters[char_index].in_span == span_index)
                 char_index++;
             if (char_index == _characters.size() || _characters[char_index].in_span != span_index)
-                bottom_right[NR::X] = _spans[span_index].x_end + _spans[span_index].chunk(this).left_x;
+                bottom_right[Geom::X] = _spans[span_index].x_end + _spans[span_index].chunk(this).left_x;
             else
-                bottom_right[NR::X] = span_x + _characters[char_index].x;
+                bottom_right[Geom::X] = span_x + _characters[char_index].x;
 
             double baseline_y = _spans[span_index].line(this).baseline_y + _spans[span_index].baseline_shift;
             if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
                 double span_height = _spans[span_index].line_height.ascent + _spans[span_index].line_height.descent;
-                top_left[NR::Y] = top_left[NR::X];
-                top_left[NR::X] = baseline_y - span_height * 0.5;
-                bottom_right[NR::Y] = bottom_right[NR::X];
-                bottom_right[NR::X] = baseline_y + span_height * 0.5;
+                top_left[Geom::Y] = top_left[Geom::X];
+                top_left[Geom::X] = baseline_y - span_height * 0.5;
+                bottom_right[Geom::Y] = bottom_right[Geom::X];
+                bottom_right[Geom::X] = baseline_y + span_height * 0.5;
             } else {
-                top_left[NR::Y] = baseline_y - _spans[span_index].line_height.ascent;
-                bottom_right[NR::Y] = baseline_y + _spans[span_index].line_height.descent;
+                top_left[Geom::Y] = baseline_y - _spans[span_index].line_height.ascent;
+                bottom_right[Geom::Y] = baseline_y + _spans[span_index].line_height.descent;
             }
         }
 
-        NR::Rect char_box(top_left, bottom_right);
-        if (char_box.extent(NR::X) == 0.0 || char_box.extent(NR::Y) == 0.0)
+        Geom::Rect char_box(top_left, bottom_right);
+        if (char_box.dimensions()[Geom::X] == 0.0 || char_box.dimensions()[Geom::Y] == 0.0)
             continue;
-        NR::Point center_of_rotation((top_left[NR::X] + bottom_right[NR::X]) * 0.5,
-                                     top_left[NR::Y] + _spans[span_index].line_height.ascent);
-        NR::Matrix total_transform = NR::translate(-center_of_rotation) * NR::rotate(char_rotation) * NR::translate(center_of_rotation) * transform;
+        Geom::Point center_of_rotation((top_left[Geom::X] + bottom_right[Geom::X]) * 0.5,
+                                     top_left[Geom::Y] + _spans[span_index].line_height.ascent);
+        Geom::Matrix total_transform = Geom::Translate(-center_of_rotation) * Geom::Rotate(char_rotation) * Geom::Translate(center_of_rotation) * transform;
         for(int i = 0; i < 4; i ++)
             quads.push_back(char_box.corner(i) * total_transform);
     }
     return quads;
 }
 
-void Layout::queryCursorShape(iterator const &it, NR::Point *position, double *height, double *rotation) const
+void Layout::queryCursorShape(iterator const &it, Geom::Point &position, double &height, double &rotation) const
 {
     if (_characters.empty()) {
-        *position = _empty_cursor_shape.position;
-        *height = _empty_cursor_shape.height;
-        *rotation = _empty_cursor_shape.rotation;
+        position = _empty_cursor_shape.position;
+        height = _empty_cursor_shape.height;
+        rotation = _empty_cursor_shape.rotation;
     } else {
         // we want to cursor to be positioned where the left edge of a character that is about to be typed will be.
         // this means x & rotation are the current values but y & height belong to the previous character.
@@ -416,50 +444,54 @@ void Layout::queryCursorShape(iterator const &it, NR::Point *position, double *h
             }
             g_free(path_parameter_list);
 
-            NR::Point point;
-            NR::Point tangent;
+            Geom::Point point;
+            Geom::Point tangent;
             const_cast<Path*>(_path_fitted)->PointAndTangentAt(path_parameter.piece, path_parameter.t, point, tangent);
             if (x < 0.0)
                 point += x * tangent;
             if (x > path_length )
                 point += (x - path_length) * tangent;
-            *rotation = atan2(tangent);
-            (*position)[NR::X] = point[NR::X] - tangent[NR::Y] * span->baseline_shift;
-            (*position)[NR::Y] = point[NR::Y] + tangent[NR::X] * span->baseline_shift;
+            rotation = atan2(tangent);
+            position[Geom::X] = point[Geom::X] - tangent[Geom::Y] * span->baseline_shift;
+            position[Geom::Y] = point[Geom::Y] + tangent[Geom::X] * span->baseline_shift;
         } else {
             // text is not on a path
             if (it._char_index >= _characters.size()) {
                 span = &_spans.back();
-                (*position)[NR::X] = _chunks[span->in_chunk].left_x + span->x_end;
-                *rotation = _glyphs.empty() ? 0.0 : _glyphs.back().rotation;
+                position[Geom::X] = _chunks[span->in_chunk].left_x + span->x_end;
+                rotation = _glyphs.empty() ? 0.0 : _glyphs.back().rotation;
             } else {
                 span = &_spans[_characters[it._char_index].in_span];
-                (*position)[NR::X] = _chunks[span->in_chunk].left_x + span->x_start + _characters[it._char_index].x;
-                if (it._glyph_index == -1) *rotation = 0.0;
-                else if(it._glyph_index == 0) *rotation = _glyphs[0].rotation;
-                else *rotation = _glyphs[it._glyph_index - 1].rotation;
+                position[Geom::X] = _chunks[span->in_chunk].left_x + span->x_start + _characters[it._char_index].x;
+                if (it._glyph_index == -1) {
+                    rotation = 0.0;
+                } else if(it._glyph_index == 0) {
+                    rotation = _glyphs[0].rotation;
+                } else{
+                    rotation = _glyphs[it._glyph_index - 1].rotation;
+                }
                 // the first char in a line wants to have the y of the new line, so in that case we don't switch to the previous span
                 if (it._char_index != 0 && _characters[it._char_index - 1].chunk(this).in_line == _chunks[span->in_chunk].in_line)
                     span = &_spans[_characters[it._char_index - 1].in_span];
             }
-            (*position)[NR::Y] = span->line(this).baseline_y + span->baseline_shift;
+            position[Geom::Y] = span->line(this).baseline_y + span->baseline_shift;
         }
         // up to now *position is the baseline point, not the final point which will be the bottom of the descent
         if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
-            *height = span->line_height.ascent + span->line_height.descent;
-            *rotation += M_PI / 2;
-            std::swap((*position)[NR::X], (*position)[NR::Y]);
-            (*position)[NR::X] -= sin(*rotation) * *height * 0.5;
-            (*position)[NR::Y] += cos(*rotation) * *height * 0.5;
+            height = span->line_height.ascent + span->line_height.descent;
+            rotation += M_PI / 2;
+            std::swap(position[Geom::X], position[Geom::Y]);
+            position[Geom::X] -= sin(rotation) * height * 0.5;
+            position[Geom::Y] += cos(rotation) * height * 0.5;
         } else {
             double caret_slope_run = 0.0, caret_slope_rise = 1.0;
             if (span->font)
                 const_cast<font_instance*>(span->font)->FontSlope(caret_slope_run, caret_slope_rise);
             double caret_slope = atan2(caret_slope_run, caret_slope_rise);
-            *height = (span->line_height.ascent + span->line_height.descent) / cos(caret_slope);
-            *rotation += caret_slope;
-            (*position)[NR::X] -= sin(*rotation) * span->line_height.descent;
-            (*position)[NR::Y] += cos(*rotation) * span->line_height.descent;
+            height = (span->line_height.ascent + span->line_height.descent) / cos(caret_slope);
+            rotation += caret_slope;
+            position[Geom::X] -= sin(rotation) * span->line_height.descent;
+            position[Geom::Y] += cos(rotation) * span->line_height.descent;
         }
     }
 }
@@ -515,7 +547,7 @@ void Layout::simulateLayoutUsingKerning(iterator const &from, iterator const &to
         unsigned prev_cluster_char_index;
         for (prev_cluster_char_index = char_index - 1 ;
              prev_cluster_char_index != 0 && !_characters[prev_cluster_char_index].char_attributes.is_cursor_position ;
-             prev_cluster_char_index--);
+             prev_cluster_char_index--){};
         if (_characters[char_index].span(this).in_chunk == _characters[char_index - 1].span(this).in_chunk) {
             // dx is zero for the first char in a chunk
             // this algorithm works by comparing the summed widths of the glyphs with the observed
@@ -702,7 +734,7 @@ bool Layout::iterator::nextLineCursor(int n)
     unsigned line_index = _parent_layout->_characters[_char_index].chunk(_parent_layout).in_line;
     if (line_index == _parent_layout->_lines.size() - 1) 
         return false; // nowhere to go
-               else
+    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
@@ -725,7 +757,7 @@ bool Layout::iterator::prevLineCursor(int n)
         line_index = _parent_layout->_characters[_char_index].chunk(_parent_layout).in_line;
     if (line_index == 0) 
         return false; // nowhere to go
-               else 
+    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
@@ -905,7 +937,7 @@ bool Layout::iterator::_cursorLeftOrRightLocalXByWord(Direction direction)
 {
     bool r;
     while ((r = _cursorLeftOrRightLocalX(direction))
-           && !_parent_layout->_characters[_char_index].char_attributes.is_word_start);
+           && !_parent_layout->_characters[_char_index].char_attributes.is_word_start){};
     return r;
 }