Code

Fix rendering of "plain" SVG text.
[inkscape.git] / src / libnrtype / Layout-TNG-Compute.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 4d83410..77e21ef
@@ -19,9 +19,9 @@ namespace Inkscape {
 namespace Text {
 
 //#define IFTRACE(_code) _code
-//#define TRACE(_args) g_print _args
 #define IFTRACE(_code)
-#define TRACE(_args)
+
+#define TRACE(_args) IFTRACE(g_print _args)
 
 // ******* enum conversion tables
 static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_pango_direction[] = {
@@ -76,7 +76,14 @@ class Layout::Calculator
 
     /** for y= attributes in tspan elements et al, we do the adjustment by moving each
     glyph individually by this number. The spec means that this is maintained across
-    paragraphs. */
+    paragraphs.
+
+    To do non-flow text layout, only the first "y" attribute is normally used. If there is only one
+    "y" attribute in a <tspan> other than the first <tspan>, it is ignored. This allows Inkscape to
+    insert a new line anywhere. On output, the Inkscape determined "y" is written out so other SVG
+    viewers know where to place the <tspans>.
+    */
+
     double _y_offset;
 
     /** to stop pango from hinting its output, the font factory creates all fonts very large.
@@ -117,8 +124,9 @@ class Layout::Calculator
         unsigned input_index;         /// index into Layout::_input_stream
         Glib::ustring::const_iterator input_stream_first_character;
         double font_size;
-        LineHeight line_height;
+        LineHeight line_height;         /// This is not the CSS line-height attribute!
         double line_height_multiplier;  /// calculated from the font-height css property
+        double baseline_shift;          /// calculated from the baseline-shift css property
         unsigned text_bytes;
         unsigned char_index_in_para;    /// the index of the first character in this span in the paragraph, for looking up char_attributes
         SVGLength x, y, dx, dy, rotate;  // these are reoriented copies of the <tspan> attributes. We change span when we encounter one.
@@ -153,10 +161,14 @@ class Layout::Calculator
         unsigned whitespace_count;
         bool ends_with_whitespace;
         double each_whitespace_width;
+        double letter_spacing; // Save so we can subtract from width at end of line (for center justification)
+        double word_spacing;
         void setZero();
     };
 
-    /** The definition of a chunk used here is the same as that used in Layout. */
+    /** The definition of a chunk used here is the same as that used in Layout:
+    A collection of contiguous broken spans on the same line. (One chunk per line
+    unless shape splits line into several sections... then one chunk per section. */
     struct ChunkInfo {
         std::vector<BrokenSpan> broken_spans;
         double scanrun_width;
@@ -291,7 +303,7 @@ class Layout::Calculator
         do {
             PangoLogAttr const &char_attributes = _charAttributes(para, span->end);
 
-            if (char_attributes.is_mandatory_break) {
+            if (char_attributes.is_mandatory_break && span->end != span->start) {
                 *last_emergency_break_span = *last_break_span = *span;
                 TRACE(("span %d end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
                 return false;
@@ -340,12 +352,21 @@ class Layout::Calculator
 
             span->end.increment();
 
-            if (span->width > maximum_width && !char_attributes.is_white) {       // whitespaces don't matter, we can put as many as we want at eol
+            // Width should not include letter_spacing (or word_spacing) after last letter at end of line.
+            // word_spacing is attached to white space that is already removed from line end (?)
+            double test_width = span->width - text_source->style->letter_spacing.computed;
+
+            // Save letter_spacing and word_spacing for subtraction later if span is last span in line.
+            span->letter_spacing = text_source->style->letter_spacing.computed;
+            span->word_spacing   = text_source->style->word_spacing.computed;
+
+            if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol
                 TRACE(("span %d exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
                 return false;
             }
 
         } while (span->end.char_byte != 0);  // while we haven't wrapped to the next span
+
         TRACE(("fitted span %d width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
         return true;
     }
@@ -369,7 +390,7 @@ class Layout::Calculator
                 case RIGHT:
                     return it_chunk->x - it_chunk->text_width;
                 case CENTER:
-                    return it_chunk->x - it_chunk->text_width / 2;
+                    return it_chunk->x - it_chunk->text_width/ 2;
             }
         }
 
@@ -399,6 +420,7 @@ class Layout::Calculator
     */
     void _outputLine(ParagraphInfo const &para, LineHeight const &line_height, std::vector<ChunkInfo> const &chunk_info)
     {
+        TRACE(("Start _outputLine\n"));
         if (chunk_info.empty()) {
             TRACE(("line too short to fit anything on it, go to next\n"));
             return;
@@ -418,19 +440,63 @@ class Layout::Calculator
             // add the chunk to the list
             Layout::Chunk new_chunk;
             new_chunk.in_line = _flow._lines.size() - 1;
+            TRACE(("  New chunk: in_line: %d\n", new_chunk.in_line));
             new_chunk.left_x = _getChunkLeftWithAlignment(para, it_chunk, &add_to_each_whitespace);
+
             // we may also have y move orders to deal with here (dx, dy and rotate are done per span)
-            if (!it_chunk->broken_spans.empty()    // this one only happens for empty paragraphs
-                && it_chunk->broken_spans.front().start.char_byte == 0
-                && it_chunk->broken_spans.front().start.iter_span->y._set) {
-                // if this is the start of a line, we should change the baseline rather than each glyph individually
-                if (_flow._characters.empty() || _flow._characters.back().chunk(&_flow).in_line != _flow._lines.size() - 1) {
-                    new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed;
-                    _flow._lines.back().baseline_y = new_line.baseline_y;
+
+            // Comment updated:  23 July 2010:
+            // We must handle two cases:
+            //
+            //   1. Inkscape SVG where the first line is placed by the read-in "y" value and the
+            //      rest are determined by 'font-size' and 'line-height' (and not by any
+            //      y-kerning). <tspan>s in this case are marked by sodipodi:role="line". This
+            //      allows new lines to be inserted in the middle of a <text> object. On output,
+            //      new "y" values are calculated for each <tspan> that represents a new line. Line
+            //      spacing is already handled by the calling routine.
+            //
+            //   2. Plain SVG where each <text> or <tspan> is placed by its own "x" and "y" values.
+            //      Note that in this case Inkscape treats each <text> object with any included
+            //      <tspan>s as a single line of text. This can be confusing in the code below.
+
+            if (!it_chunk->broken_spans.empty()                               // Not empty paragraph
+                && it_chunk->broken_spans.front().start.char_byte == 0 ) {    // Beginning of unbroken span
+
+                // If empty or new line (sodipode:role="line")
+                if( _flow._characters.empty() ||
+                    _flow._characters.back().chunk(&_flow).in_line != _flow._lines.size() - 1) {
+
+                    // This is the Inkscape SVG case.
+                    //
+                    // If <tspan> "y" attribute is set, use it (initial "y" attributes in
+                    // <tspans> other than the first have already been stripped for <tspans>
+                    // marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput).
+                    if( it_chunk->broken_spans.front().start.iter_span->y._set ) {
+
+                        // Use set "y" attribute
+                        new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed;
+
+                        // Save baseline
+                        _flow._lines.back().baseline_y = new_line.baseline_y;
+
+                        // Save new <tspan> y coordinate
+                        _scanline_maker->setNewYCoordinate(new_line.baseline_y - line_height.ascent);
+
+                    }
+
+                    // Reset relative y_offset ("dy" attribute is relative but should be reset at
+                    // the beginning of each line since each line will have a new "y" written out.)
                     _y_offset = 0.0;
-                    _scanline_maker->setNewYCoordinate(new_line.baseline_y - line_height.ascent);
-                } else
-                    _y_offset = it_chunk->broken_spans.front().start.iter_span->y.computed - new_line.baseline_y;
+
+                } else {
+
+                    // This is the plain SVG case
+                    //
+                    // "x" and "y" are used to place text, simulating lines as necessary
+                    if( it_chunk->broken_spans.front().start.iter_span->y._set ) {
+                        _y_offset = it_chunk->broken_spans.front().start.iter_span->y.computed - new_line.baseline_y;
+                    }
+                }
             }
             _flow._chunks.push_back(new_chunk);
 
@@ -455,7 +521,8 @@ class Layout::Calculator
                 UnbrokenSpan const &unbroken_span = *it_span->start.iter_span;
 
                 if (it_span->start.char_byte == 0) {
-                    // start of an unbroken span, we might have dx, dy or rotate still to process (x and y are done per chunk)
+                    // Start of an unbroken span, we might have dx, dy or rotate still to process
+                    // (x and y are done per chunk)
                     if (unbroken_span.dx._set) x += unbroken_span.dx.computed;
                     if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed;
                     if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180);
@@ -473,11 +540,11 @@ class Layout::Calculator
                 new_span.in_chunk = _flow._chunks.size() - 1;
                 new_span.line_height = unbroken_span.line_height;
                 new_span.in_input_stream_item = unbroken_span.input_index;
-                new_span.baseline_shift = _y_offset;
+                new_span.baseline_shift = 0.0;
                 new_span.block_progression = _block_progression;
-                if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) {
-                    new_span.font = para.pango_items[unbroken_span.pango_item_index].font;
-                    new_span.font->Ref();
+                if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font))
+                    {
+                   new_span.font->Ref();
                     new_span.font_size = unbroken_span.font_size;
                     new_span.direction = para.pango_items[unbroken_span.pango_item_index].item->analysis.level & 1 ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
                     new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte);
@@ -556,13 +623,18 @@ class Layout::Calculator
 
                         if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) {
                             new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier + new_span.line_height.ascent;
-                            new_glyph.y = _y_offset + (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset - unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier;
+                            new_glyph.y = _y_offset -
+                                unbroken_span.baseline_shift +
+                                (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset -
+                                 unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier;
                             new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, true);
                         } else {
                             new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier;
-                            new_glyph.y = _y_offset + unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier;
+                            new_glyph.y = _y_offset -
+                                unbroken_span.baseline_shift +
+                                unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier;
                             new_glyph.width = unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier;
-                            if (new_glyph.width == 0)
+                            if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font))
                                 new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, false);
                                 // for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info
                         }
@@ -615,7 +687,6 @@ class Layout::Calculator
                             iter_source_text++;
                             char_index_in_unbroken_span++;
                             char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base();
-                            glyph_rotate = 0.0;
                         }
 
                         advance_width *= direction_sign;
@@ -832,10 +903,12 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) cons
         } else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE) {
             Layout::InputStreamTextSource *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[input_index]);
 
-            PangoFontDescription *temp_descr = text_source->styleGetFontDescription();
-            PangoAttribute *attribute_font_description = pango_attr_font_desc_new(temp_descr);
-            pango_font_description_free(temp_descr);
+                       // create the font_instance
+                       font_instance *font = text_source->styleGetFontInstance();
+                       if (font == NULL)
+                               continue;  // bad news: we'll have to ignore all this text because we know of no font to render it
 
+            PangoAttribute *attribute_font_description = pango_attr_font_desc_new(font->descr);
             attribute_font_description->start_index = para_text.bytes();
             para_text.append(&*text_source->text_begin.base(), text_source->text_length);     // build the combined text
             attribute_font_description->end_index = para_text.bytes();
@@ -901,7 +974,8 @@ void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font
         line_height->setZero();
         *line_height_multiplier = 1.0;
     }
-    font->FontMetrics(line_height->ascent, line_height->descent, line_height->leading);
+    else
+       font->FontMetrics(line_height->ascent, line_height->descent, line_height->leading);
     *line_height *= font_size;
 
     // yet another borked SPStyle member that we're going to have to fix ourselves
@@ -927,13 +1001,14 @@ void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font
             }
             break;
         }
-        if (style->object->parent == NULL) break;
+        if (style->object == NULL || style->object->parent == NULL) break;
         style = style->object->parent->style;
         if (style == NULL) break;
     }
     *line_height_multiplier = LINE_HEIGHT_NORMAL * font_size / line_height->total();
 }
 
+
 /**
  * Split the paragraph into spans. Also call pango_shape() on them.
  *
@@ -971,6 +1046,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
             }
         } else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE && pango_item_index < para->pango_items.size()) {
             Layout::InputStreamTextSource const *text_source = static_cast<Layout::InputStreamTextSource const *>(_flow._input_stream[input_index]);
+
             unsigned char_index_in_source = 0;
 
             unsigned span_start_byte_in_source = 0;
@@ -987,6 +1063,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
                 unsigned const text_source_bytes = ( text_source->text_end.base()
                                                      - text_source->text_begin.base()
                                                      - span_start_byte_in_source );
+                TRACE(("New Span\n"));
                 UnbrokenSpan new_span;
                 new_span.text_bytes = std::min(text_source_bytes, pango_item_bytes);
                 new_span.input_stream_first_character = Glib::ustring::const_iterator(text_source->text_begin.base() + span_start_byte_in_source);
@@ -1011,6 +1088,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
                     if (text_source->dy.size() > char_index_in_source) new_span.dx = text_source->dy[char_index_in_source];
                 }
                 if (text_source->rotate.size() > char_index_in_source) new_span.rotate = text_source->rotate[char_index_in_source];
+                else if (char_index_in_source == 0) new_span.rotate = 0.f;
                 if (input_index == 0 && para->unbroken_spans.empty() && !new_span.y._set && _flow._input_wrap_shapes.empty()) {
                     // if we don't set an explicit y some of the automatic wrapping code takes over and moves the text vertically
                     // so that the top of the letters is at zero, not the baseline
@@ -1038,10 +1116,6 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
                 // now we know the length, do some final calculations and add the UnbrokenSpan to the list
                 new_span.font_size = text_source->styleComputeFontSize();
                 if (new_span.text_bytes) {
-                    int const original_bidi_level = para->pango_items[pango_item_index].item->analysis.level;
-                    para->pango_items[pango_item_index].item->analysis.level = 0;
-                    // pango_shape() will reorder glyphs in rtl sections which messes us up because
-                    // the svg spec requires us to draw glyphs in character order
                     new_span.glyph_string = pango_glyph_string_new();
                     /* Some assertions intended to help diagnose bug #1277746. */
                     g_assert( 0 < new_span.text_bytes );
@@ -1053,9 +1127,39 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
                                 new_span.text_bytes,
                                 &para->pango_items[pango_item_index].item->analysis,
                                 new_span.glyph_string);
-                    para->pango_items[pango_item_index].item->analysis.level = original_bidi_level;
+
+                    if (para->pango_items[pango_item_index].item->analysis.level & 1) {
+                        // pango_shape() will reorder glyphs in rtl sections into visual order which messes
+                        // us up because the svg spec requires us to draw glyphs in logical order
+                        // let's reverse the glyphstring on a cluster-by-cluster basis
+                        const unsigned nglyphs = new_span.glyph_string->num_glyphs;
+                        std::vector<PangoGlyphInfo> infos(nglyphs);
+                        std::vector<gint> clusters(nglyphs);
+                        unsigned i, cluster_start = 0;
+
+                        for (i = 0 ; i < nglyphs ; ++i) {
+                            if (new_span.glyph_string->glyphs[i].attr.is_cluster_start) {
+                                if (i != cluster_start) {
+                                    std::copy(&new_span.glyph_string->glyphs[cluster_start], &new_span.glyph_string->glyphs[i], infos.end() - i);
+                                    std::copy(&new_span.glyph_string->log_clusters[cluster_start], &new_span.glyph_string->log_clusters[i], clusters.end() - i);
+                                }
+                                cluster_start = i;
+                            }
+                        }
+                        if (i != cluster_start) {
+                            std::copy(&new_span.glyph_string->glyphs[cluster_start], &new_span.glyph_string->glyphs[i], infos.end() - i);
+                            std::copy(&new_span.glyph_string->log_clusters[cluster_start], &new_span.glyph_string->log_clusters[i], clusters.end() - i);
+                        }
+                        std::copy(infos.begin(), infos.end(), new_span.glyph_string->glyphs);
+                        std::copy(clusters.begin(), clusters.end(), new_span.glyph_string->log_clusters);
+                    }
                     new_span.pango_item_index = pango_item_index;
                     _computeFontLineHeight(para->pango_items[pango_item_index].font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier);
+
+                    // At some point we may want to calculate baseline_shift here (to take advantage
+                    // of otm features like superscript baseline), but for now we use style baseline_shift.
+                    new_span.baseline_shift = text_source->style->baseline_shift.computed;
+
                     // TODO: metrics for vertical text
                     TRACE(("add text span %d \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str()));
                     TRACE(("  %d glyphs\n", new_span.glyph_string->num_glyphs));
@@ -1157,8 +1261,9 @@ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const &para,
     UnbrokenSpanPosition span_pos;
     for( ; ; ) {
         std::vector<ScanlineMaker::ScanRun> scan_runs;
-        scan_runs = _scanline_maker->makeScanline(*line_height);
+        scan_runs = _scanline_maker->makeScanline(*line_height); // Only one line with "InfiniteScanlineMaker
         while (scan_runs.empty()) {
+            // Only used by ShapeScanlineMaker
             if (!_goToNextWrapShape()) return false;  // no more shapes to wrap in to
             scan_runs = _scanline_maker->makeScanline(*line_height);
         }
@@ -1313,6 +1418,13 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
         chunk_info->back().whitespace_count--;
     }
 
+    if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty() ) {
+        // for justification we need to discard line-spacing and word-spacing at end of the chunk
+        chunk_info->back().broken_spans.back().width -= chunk_info->back().broken_spans.back().letter_spacing;
+        chunk_info->back().text_width -= chunk_info->back().broken_spans.back().letter_spacing;
+        TRACE(("width after subtracting last letter_spacing: %f\n", chunk_info->back().broken_spans.back().width));
+    }
+
     return true;
 }
 
@@ -1321,10 +1433,16 @@ bool Layout::Calculator::calculate()
 {
     if (_flow._input_stream.empty())
         return false;
-    g_assert(_flow._input_stream.front()->Type() == TEXT_SOURCE);
+    /**
+    * hm, why do we want assert (crash) the application, now do simply return false
+    * \todo check if this is the correct behaviour
+    * g_assert(_flow._input_stream.front()->Type() == TEXT_SOURCE);
+    */
     if (_flow._input_stream.front()->Type() != TEXT_SOURCE)
+    {
+        g_warning("flow text is not of type TEXT_SOURCE. Abort.");
         return false;
-
+    }
     TRACE(("begin calculateFlow()\n"));
 
     _flow._clearOutputObjects();
@@ -1337,7 +1455,7 @@ bool Layout::Calculator::calculate()
     _createFirstScanlineMaker();
 
     ParagraphInfo para;
-    LineHeight line_height;     // needs to be maintained across paragraphs to be able to deal with blank paras (this is wrong)
+    LineHeight line_height; // needs to be maintained across paragraphs to be able to deal with blank paras
     for(para.first_input_index = 0 ; para.first_input_index < _flow._input_stream.size() ; ) {
         // jump to the next wrap shape if this is a SHAPE_BREAK control code
         if (_flow._input_stream[para.first_input_index]->Type() == CONTROL_CODE) {
@@ -1378,7 +1496,7 @@ bool Layout::Calculator::calculate()
                 break;   // out of shapes to wrap in to
 
             _outputLine(para, line_height, line_chunk_info);
-            _scanline_maker->completeLine();
+            _scanline_maker->completeLine(); // Increments y by line height
         } while (span_pos.iter_span != para.unbroken_spans.end());
 
         TRACE(("para %d end\n\n", _flow._paragraphs.size() - 1));
@@ -1437,15 +1555,19 @@ bool Layout::Calculator::calculate()
     }
 
     para.free();
-    if (_scanline_maker)
+    if (_scanline_maker) {
         delete _scanline_maker;
+        _flow._input_truncated = false;
+    } else {
+        _flow._input_truncated = true;
+    }
 
     return true;
 }
 
 void Layout::_calculateCursorShapeForEmpty()
 {
-    _empty_cursor_shape.position = NR::Point(0, 0);
+    _empty_cursor_shape.position = Geom::Point(0, 0);
     _empty_cursor_shape.height = 0.0;
     _empty_cursor_shape.rotation = 0.0;
     if (_input_stream.empty() || _input_stream.front()->Type() != TEXT_SOURCE)
@@ -1472,7 +1594,7 @@ void Layout::_calculateCursorShapeForEmpty()
     _empty_cursor_shape.rotation = caret_slope;
 
     if (_input_wrap_shapes.empty()) {
-        _empty_cursor_shape.position = NR::Point(text_source->x.empty() || !text_source->x.front()._set ? 0.0 : text_source->x.front().computed,
+        _empty_cursor_shape.position = Geom::Point(text_source->x.empty() || !text_source->x.front()._set ? 0.0 : text_source->x.front().computed,
                                                  text_source->y.empty() || !text_source->y.front()._set ? 0.0 : text_source->y.front().computed);
     } else {
         Direction block_progression = text_source->styleGetBlockProgression();
@@ -1480,9 +1602,9 @@ void Layout::_calculateCursorShapeForEmpty()
         std::vector<ScanlineMaker::ScanRun> scan_runs = scanline_maker.makeScanline(line_height);
         if (!scan_runs.empty()) {
             if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT)
-                _empty_cursor_shape.position = NR::Point(scan_runs.front().y + font_size, scan_runs.front().x_start);
+                _empty_cursor_shape.position = Geom::Point(scan_runs.front().y + font_size, scan_runs.front().x_start);
             else
-                _empty_cursor_shape.position = NR::Point(scan_runs.front().x_start, scan_runs.front().y + font_size);
+                _empty_cursor_shape.position = Geom::Point(scan_runs.front().x_start, scan_runs.front().y + font_size);
         }
     }
 }