Code

NR::Maybe => boost::optional
[inkscape.git] / src / libnrtype / Layout-TNG-Output.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 97d98d3..36c882d
@@ -9,16 +9,32 @@
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 #include <glib/gmem.h>
-#include <gtk/gtkversion.h>
 #include "Layout-TNG.h"
 #include "display/nr-arena-glyphs.h"
 #include "style.h"
 #include "print.h"
 #include "extension/print.h"
 #include "livarot/Path.h"
+#include "libnr/nr-matrix-fns.h"
 #include "libnr/nr-scale-matrix-ops.h"
+#include "libnr/nr-convert2geom.h"
 #include "font-instance.h"
 #include "svg/svg-length.h"
+#include "extension/internal/cairo-render-context.h"
+#include "display/curve.h"
+#include <2geom/pathvector.h>
+
+namespace Inkscape {
+    namespace Extension {
+        namespace Internal {
+            class CairoRenderContext;
+            class CairoGlyphInfo;
+        }
+    }
+}
+
+using Inkscape::Extension::Internal::CairoRenderContext;
+using Inkscape::Extension::Internal::CairoGlyphInfo;
 
 namespace Inkscape {
 namespace Text {
@@ -43,7 +59,7 @@ void Layout::LineHeight::max(LineHeight const &other)
     if (other.leading > leading) leading = other.leading;
 }
 
-void Layout::_getGlyphTransformMatrix(int glyph_index, NRMatrix *matrix) const
+void Layout::_getGlyphTransformMatrix(int glyph_index, NR::Matrix *matrix) const
 {
     Span const &span = _glyphs[glyph_index].span(this);
     double sin_rotation = sin(_glyphs[glyph_index].rotation);
@@ -74,7 +90,7 @@ void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const
         nr_arena_glyphs_group_set_style(nr_group, text_source->style);
         while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) {
             if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) {
-                NRMatrix glyph_matrix;
+                NR::Matrix glyph_matrix;
                 _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
                 nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, &glyph_matrix);
             }
@@ -96,30 +112,32 @@ void Layout::getBoundingBox(NRRect *bounding_box, NR::Matrix const &transform, i
             if ((int) _glyphs[glyph_index].in_character > start + length) continue;
         }
         // this could be faster
-        NRMatrix glyph_matrix;
+        NR::Matrix glyph_matrix;
         _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
         NR::Matrix total_transform = glyph_matrix;
         total_transform *= transform;
-        NR::Rect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
-        NR::Point bmi = glyph_rect.min(), bma = glyph_rect.max();
-        NR::Point tlp(bmi[0],bmi[1]), trp(bma[0],bmi[1]), blp(bmi[0],bma[1]), brp(bma[0],bma[1]);
-        tlp *= total_transform;
-        trp *= total_transform;
-        blp *= total_transform;
-        brp *= total_transform;
-        glyph_rect = NR::Rect(tlp,trp);
-        glyph_rect.expandTo(blp);
-        glyph_rect.expandTo(brp);
-        if ( (glyph_rect.min())[0] < bounding_box->x0 ) bounding_box->x0=(glyph_rect.min())[0];
-        if ( (glyph_rect.max())[0] > bounding_box->x1 ) bounding_box->x1=(glyph_rect.max())[0];
-        if ( (glyph_rect.min())[1] < bounding_box->y0 ) bounding_box->y0=(glyph_rect.min())[1];
-        if ( (glyph_rect.max())[1] > bounding_box->y1 ) bounding_box->y1=(glyph_rect.max())[1];
+        boost::optional<NR::Rect> glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
+        if (glyph_rect) {
+            NR::Point bmi = glyph_rect->min(), bma = glyph_rect->max();
+            NR::Point tlp(bmi[0],bmi[1]), trp(bma[0],bmi[1]), blp(bmi[0],bma[1]), brp(bma[0],bma[1]);
+            tlp *= total_transform;
+            trp *= total_transform;
+            blp *= total_transform;
+            brp *= total_transform;
+            *glyph_rect = NR::Rect(tlp,trp);
+            glyph_rect->expandTo(blp);
+            glyph_rect->expandTo(brp);
+            if ( (glyph_rect->min())[0] < bounding_box->x0 ) bounding_box->x0=(glyph_rect->min())[0];
+            if ( (glyph_rect->max())[0] > bounding_box->x1 ) bounding_box->x1=(glyph_rect->max())[0];
+            if ( (glyph_rect->min())[1] < bounding_box->y0 ) bounding_box->y0=(glyph_rect->min())[1];
+            if ( (glyph_rect->max())[1] > bounding_box->y1 ) bounding_box->y1=(glyph_rect->max())[1];
+        }
     }
 }
 
 void Layout::print(SPPrintContext *ctx,
                    NRRect const *pbox, NRRect const *dbox, NRRect const *bbox,
-                   NRMatrix const &ctm) const
+                   NR::Matrix const &ctm) const
 {
     if (_input_stream.empty()) return;
 
@@ -133,33 +151,30 @@ void Layout::print(SPPrintContext *ctx,
                 glyph_index++;
             continue;
         }
-        NRMatrix glyph_matrix;
+        NR::Matrix glyph_matrix;
         Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
         InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
         if (text_to_path || _path_fitted) {
-            NRBPath bpath;
-            bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
-            if (bpath.path) {
-                NRBPath abp;
+            Geom::PathVector const * pv = span.font->PathVector(_glyphs[glyph_index].glyph);
+            if (pv) {
                 _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
-                abp.path = nr_artpath_affine(bpath.path, glyph_matrix);
-                if (text_source->style->fill.type != SP_PAINT_TYPE_NONE)
-                    sp_print_fill(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
-                if (text_source->style->stroke.type != SP_PAINT_TYPE_NONE)
-                    sp_print_stroke(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
-                g_free(abp.path);
+                Geom::PathVector temp_pv = (*pv) * to_2geom(glyph_matrix);
+                if (!text_source->style->fill.isNone())
+                    sp_print_fill(ctx, temp_pv, &ctm, text_source->style, pbox, dbox, bbox);
+                if (!text_source->style->stroke.isNone())
+                    sp_print_stroke(ctx, temp_pv, &ctm, text_source->style, pbox, dbox, bbox);
             }
             glyph_index++;
         } else {
             NR::Point g_pos(0,0);    // all strings are output at (0,0) because we do the translation using the matrix
             glyph_matrix = NR::Matrix(NR::scale(1.0, -1.0) * NR::Matrix(NR::rotate(_glyphs[glyph_index].rotation)));
             if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) {
-                glyph_matrix.c[4] = span.line(this).baseline_y + span.baseline_shift;
+                glyph_matrix[4] = span.line(this).baseline_y + span.baseline_shift;
                 // since we're outputting character codes, not glyphs, we want the character x
-                glyph_matrix.c[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
+                glyph_matrix[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
             } else {
-                glyph_matrix.c[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
-                glyph_matrix.c[5] = span.line(this).baseline_y + span.baseline_shift;
+                glyph_matrix[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
+                glyph_matrix[5] = span.line(this).baseline_y + span.baseline_shift;
             }
             Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
             unsigned char_index = _glyphs[glyph_index].in_character;
@@ -193,6 +208,113 @@ void Layout::print(SPPrintContext *ctx,
     }
 }
 
+#ifdef HAVE_CAIRO_PDF
+void Layout::showGlyphs(CairoRenderContext *ctx) const
+{
+    if (_input_stream.empty()) return;
+    
+    bool clip_mode = false;//(ctx->getRenderMode() == CairoRenderContext::RENDER_MODE_CLIP);
+    std::vector<CairoGlyphInfo> glyphtext;
+
+    for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) {
+        if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) {
+            // invisible glyphs
+            unsigned same_character = _glyphs[glyph_index].in_character;
+            while (_glyphs[glyph_index].in_character == same_character)
+                glyph_index++;
+            continue;
+        }
+        Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
+        InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
+
+        NR::Matrix glyph_matrix;
+        _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
+        if (clip_mode) {
+            Geom::PathVector const *pathv = span.font->PathVector(_glyphs[glyph_index].glyph);
+            if (pathv) {
+                Geom::PathVector pathv_trans = (*pathv) * to_2geom(glyph_matrix);
+                SPStyle const *style = text_source->style;
+                ctx->renderPathVector(pathv_trans, style, NULL);
+            }
+            glyph_index++;
+            continue;
+        }
+
+        NR::Matrix font_matrix;
+        if (_path_fitted == NULL) {
+            font_matrix = glyph_matrix;
+            font_matrix[4] = 0;
+            font_matrix[5] = 0;
+        } else {
+            font_matrix.set_identity();
+        }
+
+        Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
+        unsigned char_index = _glyphs[glyph_index].in_character;
+        unsigned original_span = _characters[char_index].in_span;
+        while (char_index && _characters[char_index - 1].in_span == original_span) {
+            char_index--;
+            span_iter++;
+        }
+
+        // try to output as many characters as possible in one go
+        Glib::ustring span_string;
+        unsigned this_span_index = _characters[_glyphs[glyph_index].in_character].in_span;
+        unsigned int first_index = glyph_index;
+        glyphtext.clear();
+        do {
+            span_string += *span_iter;
+            span_iter++;
+
+            unsigned same_character = _glyphs[glyph_index].in_character;
+            while (glyph_index < _glyphs.size() && _glyphs[glyph_index].in_character == same_character) {
+                if (glyph_index != first_index)
+                    _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
+
+                CairoGlyphInfo info;
+                info.index = _glyphs[glyph_index].glyph;
+                if (_path_fitted == NULL) {
+                   info.x = glyph_matrix[4];
+                    info.y = glyph_matrix[5];
+                } else {
+                    info.x = 0;
+                    info.y = 0;                    
+                }
+                glyphtext.push_back(info);
+
+                glyph_index++;
+            }
+        } while (glyph_index < _glyphs.size()
+                 && _path_fitted == NULL
+                 && NR::transform_equalp(font_matrix, glyph_matrix, NR_EPSILON)
+                 && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index);
+         
+        // remove vertical flip
+        font_matrix[3] *= -1.0;
+
+        SPStyle const *style = text_source->style;
+        float opacity = SP_SCALE24_TO_FLOAT(style->opacity.value);
+        
+        if (_path_fitted) {
+            ctx->pushState();
+            ctx->transform(&glyph_matrix);
+        } else if (opacity != 1.0) {
+            ctx->pushState();
+            ctx->setStateForStyle(style);
+            ctx->pushLayer();
+        }
+        if (glyph_index - first_index > 0)
+            ctx->renderGlyphtext(span.font->pFont, &font_matrix, glyphtext, style);
+        if (_path_fitted)
+            ctx->popState();
+        else if (opacity != 1.0) {
+            ctx->popLayer();
+            ctx->popState();
+        }
+    }
+}
+#endif
+
 // these functions are for dumpAsText() only. No need to translate
 static char const *direction_to_text(Layout::Direction d)
 {
@@ -220,9 +342,7 @@ static char const *weight_to_text(PangoWeight w)
     switch (w) {
         case PANGO_WEIGHT_ULTRALIGHT: return "ultralight";
         case PANGO_WEIGHT_LIGHT     : return "light";
-#if GTK_CHECK_VERSION(2,6,0)                                      
         case PANGO_WEIGHT_SEMIBOLD  : return "semibold";
-#endif                                      
         case PANGO_WEIGHT_NORMAL    : return "normalweight";
         case PANGO_WEIGHT_BOLD      : return "bold";
         case PANGO_WEIGHT_ULTRABOLD : return "ultrabold";
@@ -421,15 +541,14 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_
     GSList *cc = NULL;
 
     for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) {
-        NRMatrix glyph_matrix;
+        NR::Matrix glyph_matrix;
         Span const &span = _glyphs[glyph_index].span(this);
         _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
 
-        NRBPath bpath;
-        bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
-        if (bpath.path) {
-            NArtBpath *abp = nr_artpath_affine(bpath.path, glyph_matrix);
-            SPCurve *c = sp_curve_new_from_bpath(abp);
+        Geom::PathVector const * pathv = span.font->PathVector(_glyphs[glyph_index].glyph);
+        if (pathv) {
+            Geom::PathVector pathv_trans = (*pathv) * to_2geom(glyph_matrix);
+            SPCurve *c = new SPCurve(pathv_trans);
             if (c) cc = g_slist_prepend(cc, c);
         }
     }
@@ -437,14 +556,14 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_
 
     SPCurve *curve;
     if ( cc ) {
-        curve = sp_curve_concat(cc);
+        curve = SPCurve::concat(cc);
     } else {
-        curve = sp_curve_new();
+        curve = new SPCurve();
     }
 
     while (cc) {
         /* fixme: This is dangerous, as we are mixing art_alloc and g_new */
-        sp_curve_unref((SPCurve *) cc->data);
+        reinterpret_cast<SPCurve *>(cc->data)->unref();
         cc = g_slist_remove(cc, cc->data);
     }